[WebAssembly] Add COMDAT support
See https://bugs.llvm.org/show_bug.cgi?id=35533, and D40844
Things covered:
* Removing duplicate data segments (as determined by COMDATs emitted
by the frontend)
* Removing duplicate globals and functions in COMDATs
* Checking that each time a COMDAT is seen it has the same symbols
as at other times (ie it's a stronger check than simply giving all
the symbols in the COMDAT weak linkage)
Patch by Nicholas Wilson!
Differential Revision: https://reviews.llvm.org/D40845
llvm-svn: 322415
diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index 34cade9..257c948 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -170,6 +170,11 @@
return Functions[FunctionIndex];
}
+bool ObjFile::isExcludedByComdat(InputChunk *Chunk) const {
+ StringRef Comdat = Chunk->getComdat();
+ return !Comdat.empty() && Symtab->findComdat(Comdat) != this;
+}
+
void ObjFile::initializeSymbols() {
Symbols.reserve(WasmObj->getNumberOfSymbols());
@@ -187,15 +192,23 @@
FunctionSymbols.resize(NumFunctionImports + WasmObj->functions().size());
GlobalSymbols.resize(NumGlobalImports + WasmObj->globals().size());
+ ArrayRef<WasmFunction> Funcs = WasmObj->functions();
+ ArrayRef<uint32_t> FuncTypes = WasmObj->functionTypes();
+ ArrayRef<WasmSignature> Types = WasmObj->types();
+ ArrayRef<WasmGlobal> Globals = WasmObj->globals();
+
+ for (const auto &C : WasmObj->comdats())
+ Symtab->addComdat(C, this);
+
+ FunctionSymbols.resize(NumFunctionImports + Funcs.size());
+ GlobalSymbols.resize(NumGlobalImports + Globals.size());
+
for (const WasmSegment &S : WasmObj->dataSegments()) {
InputSegment *Seg = make<InputSegment>(S, this);
Seg->copyRelocations(*DataSection);
Segments.emplace_back(Seg);
}
- ArrayRef<WasmFunction> Funcs = WasmObj->functions();
- ArrayRef<uint32_t> FuncTypes = WasmObj->functionTypes();
- ArrayRef<WasmSignature> Types = WasmObj->types();
for (size_t I = 0; I < Funcs.size(); ++I) {
const WasmFunction &Func = Funcs[I];
const WasmSignature &Sig = Types[FuncTypes[I]];
@@ -210,21 +223,35 @@
const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl());
Symbol *S;
switch (WasmSym.Type) {
+ case WasmSymbol::SymbolType::FUNCTION_EXPORT: {
+ InputFunction *Function = getFunction(WasmSym);
+ if (!isExcludedByComdat(Function)) {
+ S = createDefined(WasmSym, Symbol::Kind::DefinedFunctionKind, nullptr,
+ Function);
+ break;
+ } else {
+ Function->Discarded = true;
+ LLVM_FALLTHROUGH; // Exclude function, and add the symbol as undefined
+ }
+ }
case WasmSymbol::SymbolType::FUNCTION_IMPORT:
S = createUndefined(WasmSym, Symbol::Kind::UndefinedFunctionKind,
getFunctionSig(WasmSym));
break;
+ case WasmSymbol::SymbolType::GLOBAL_EXPORT: {
+ InputSegment *Segment = getSegment(WasmSym);
+ if (!isExcludedByComdat(Segment)) {
+ S = createDefined(WasmSym, Symbol::Kind::DefinedGlobalKind,
+ Segment, nullptr, getGlobalValue(WasmSym));
+ break;
+ } else {
+ Segment->Discarded = true;
+ LLVM_FALLTHROUGH; // Exclude global, and add the symbol as undefined
+ }
+ }
case WasmSymbol::SymbolType::GLOBAL_IMPORT:
S = createUndefined(WasmSym, Symbol::Kind::UndefinedGlobalKind);
break;
- case WasmSymbol::SymbolType::GLOBAL_EXPORT:
- S = createDefined(WasmSym, Symbol::Kind::DefinedGlobalKind,
- getSegment(WasmSym), nullptr, getGlobalValue(WasmSym));
- break;
- case WasmSymbol::SymbolType::FUNCTION_EXPORT:
- S = createDefined(WasmSym, Symbol::Kind::DefinedFunctionKind, nullptr,
- getFunction(WasmSym));
- break;
case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
// These are for debugging only, no need to create linker symbols for them
continue;