Index: test/wasm/trace-symbol.ll =================================================================== --- /dev/null +++ test/wasm/trace-symbol.ll @@ -0,0 +1,23 @@ +; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o +; RUN: llc -filetype=obj -o %t.o %s +; RUN: wasm-ld -o %t.wasm %t.o %t.ret32.o -y ret32 -y _start 2>&1 | FileCheck %s -check-prefix=BOTH + +; check alias +; RUN: wasm-ld -o %t.wasm %t.o %t.ret32.o -trace-symbol=_start 2>&1 | FileCheck %s -check-prefixes=JUST-START + +target triple = "wasm32-unknown-unknown" + +declare i32 @ret32(float %arg) + +define void @_start() { +entry: + %call1 = call i32 @ret32(float 0.0) + ret void +} + +; BOTH: .o: definition of _start +; BOTH: .o: reference to ret32 +; BOTH: .ret32.o: definition of ret32 + +; JUST-START: .o: definition of _start +; JUST-START-NOT: ret32 Index: test/wasm/trace.test =================================================================== --- /dev/null +++ test/wasm/trace.test @@ -0,0 +1,8 @@ +RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.foo.o + +# Check -t +RUN: wasm-ld %t.foo.o -o out.wasm -t 2>&1 | FileCheck %s +CHECK: {{.*}}.foo.o + +# Check --trace alias +RUN: wasm-ld %t.foo.o -o out.wasm --trace 2>&1 | FileCheck %s Index: wasm/Config.h =================================================================== --- wasm/Config.h +++ wasm/Config.h @@ -38,6 +38,7 @@ bool StripAll; bool StripDebug; bool StackFirst; + bool Trace; uint32_t GlobalBase; uint32_t InitialMemory; uint32_t MaxMemory; Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -371,6 +371,7 @@ Config->StripAll = Args.hasArg(OPT_strip_all); Config->StripDebug = Args.hasArg(OPT_strip_debug); Config->StackFirst = Args.hasArg(OPT_stack_first); + Config->Trace = Args.hasArg(OPT_trace); Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir); Config->ThinLTOCachePolicy = CHECK( parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)), @@ -556,6 +557,10 @@ Config->AllowUndefined = true; } + // Handle --trace-symbol. + for (auto *Arg : Args.filtered(OPT_trace_symbol)) + Symtab->trace(Arg->getValue()); + if (!Config->Relocatable) createSyntheticSymbols(); Index: wasm/Options.td =================================================================== --- wasm/Options.td +++ wasm/Options.td @@ -93,6 +93,10 @@ def threads: F<"threads">, HelpText<"Run the linker multi-threaded">; +def trace: F<"trace">, HelpText<"Print the names of the input files">; + +defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">; + defm undefined: Eq<"undefined", "Force undefined symbol during linking">; def v: Flag<["-"], "v">, HelpText<"Display the version number">; @@ -160,6 +164,8 @@ def: Flag<["-"], "r">, Alias; def: Flag<["-"], "s">, Alias, HelpText<"Alias for --strip-all">; def: Flag<["-"], "S">, Alias, HelpText<"Alias for --strip-debug">; +def: Flag<["-"], "t">, Alias, HelpText<"Alias for --trace">; +def: JoinedOrSeparate<["-"], "y">, Alias, HelpText<"Alias for --trace-symbol">; def: JoinedOrSeparate<["-"], "u">, Alias; // LTO-related options. Index: wasm/SymbolTable.h =================================================================== --- wasm/SymbolTable.h +++ wasm/SymbolTable.h @@ -46,8 +46,11 @@ void reportRemainingUndefines(); ArrayRef getSymbols() const { return SymVector; } + Symbol *find(StringRef Name); + void trace(StringRef Name); + Symbol *addDefinedFunction(StringRef Name, uint32_t Flags, InputFile *File, InputFunction *Function); Symbol *addDefinedData(StringRef Name, uint32_t Flags, InputFile *File, @@ -76,8 +79,12 @@ private: std::pair insert(StringRef Name, InputFile *File); + std::pair insertName(StringRef Name); - llvm::DenseMap SymMap; + // Maps symbol names to index into the SymVector. -1 means that symbols + // is to not yet in the vector but it should have tracing enabled if it is + // ever added. + llvm::DenseMap SymMap; std::vector SymVector; llvm::DenseSet Comdats; Index: wasm/SymbolTable.cpp =================================================================== --- wasm/SymbolTable.cpp +++ wasm/SymbolTable.cpp @@ -28,6 +28,8 @@ void SymbolTable::addFile(InputFile *File) { log("Processing: " + toString(File)); + if (Config->Trace) + message(toString(File)); File->parse(); // LLVM bitcode file @@ -73,21 +75,42 @@ } Symbol *SymbolTable::find(StringRef Name) { - return SymMap.lookup(CachedHashStringRef(Name)); + auto It = SymMap.find(CachedHashStringRef(Name)); + if (It == SymMap.end() || It->second == -1) + return nullptr; + return SymVector[It->second]; } -std::pair SymbolTable::insert(StringRef Name, InputFile *File) { - bool Inserted = false; - Symbol *&Sym = SymMap[CachedHashStringRef(Name)]; - if (!Sym) { - Sym = reinterpret_cast(make()); - Sym->IsUsedInRegularObj = false; - SymVector.emplace_back(Sym); - Inserted = true; +std::pair SymbolTable::insertName(StringRef Name) { + bool Trace = false; + auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()}); + int &SymIndex = P.first->second; + bool IsNew = P.second; + if (SymIndex == -1) { + SymIndex = SymVector.size(); + Trace = true; + IsNew = true; } + + if (!IsNew) + return {SymVector[SymIndex], false}; + + Symbol *Sym = reinterpret_cast(make()); + Sym->IsUsedInRegularObj = false; + Sym->Traced = Trace; + SymVector.emplace_back(Sym); + return {Sym, true}; +} + +std::pair SymbolTable::insert(StringRef Name, InputFile *File) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insertName(Name); + if (!File || File->kind() == InputFile::ObjectKind) - Sym->IsUsedInRegularObj = true; - return {Sym, Inserted}; + S->IsUsedInRegularObj = true; + + return {S, WasInserted}; } static void reportTypeError(const Symbol *Existing, const InputFile *File, @@ -409,3 +432,9 @@ bool SymbolTable::addComdat(StringRef Name) { return Comdats.insert(CachedHashStringRef(Name)).second; } + +// Set a flag for --trace-symbol so that we can print out a log message +// if a new symbol with the same name is inserted into the symbol table. +void SymbolTable::trace(StringRef Name) { + SymMap.insert({CachedHashStringRef(Name), -1}); +} Index: wasm/Symbols.h =================================================================== --- wasm/Symbols.h +++ wasm/Symbols.h @@ -100,10 +100,14 @@ unsigned IsUsedInRegularObj : 1; unsigned ForceExport : 1; + // True if this symbol is specified by --trace-symbol option. + unsigned Traced : 1; + protected: Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F) - : IsUsedInRegularObj(false), ForceExport(false), Name(Name), - SymbolKind(K), Flags(Flags), File(F), Referenced(!Config->GcSections) {} + : IsUsedInRegularObj(false), ForceExport(false), Traced(false), + Name(Name), SymbolKind(K), Flags(Flags), File(F), + Referenced(!Config->GcSections) {} StringRef Name; Kind SymbolKind; @@ -402,6 +406,8 @@ alignas(SectionSymbol) char I[sizeof(SectionSymbol)]; }; +void printTraceSymbol(Symbol *Sym); + template T *replaceSymbol(Symbol *S, ArgT &&... Arg) { static_assert(std::is_trivially_destructible(), @@ -417,6 +423,13 @@ T *S2 = new (S) T(std::forward(Arg)...); S2->IsUsedInRegularObj = SymCopy.IsUsedInRegularObj; S2->ForceExport = SymCopy.ForceExport; + S2->Traced = SymCopy.Traced; + + // Print out a log message if --trace-symbol was specified. + // This is for debugging. + if (S2->Traced) + printTraceSymbol(S2); + return S2; } Index: wasm/Symbols.cpp =================================================================== --- wasm/Symbols.cpp +++ wasm/Symbols.cpp @@ -293,3 +293,16 @@ } llvm_unreachable("invalid symbol kind"); } + +// Print out a log message for --trace-symbol. +void lld::wasm::printTraceSymbol(Symbol *Sym) { + std::string S; + if (Sym->isUndefined()) + S = ": reference to "; + else if (Sym->isLazy()) + S = ": lazy definition of "; + else + S = ": definition of "; + + message(toString(Sym->getFile()) + S + Sym->getName()); +}