[WebAssembly] Implement --trace and --trace-symbol
Differential Revision: https://reviews.llvm.org/D57725
git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@353264 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/wasm/trace-symbol.ll b/test/wasm/trace-symbol.ll
new file mode 100644
index 0000000..649b425
--- /dev/null
+++ b/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
diff --git a/test/wasm/trace.test b/test/wasm/trace.test
new file mode 100644
index 0000000..bf74bd4
--- /dev/null
+++ b/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
diff --git a/wasm/Config.h b/wasm/Config.h
index 3897ef6..c5f22eb 100644
--- a/wasm/Config.h
+++ b/wasm/Config.h
@@ -38,6 +38,7 @@
bool StripAll;
bool StripDebug;
bool StackFirst;
+ bool Trace;
uint32_t GlobalBase;
uint32_t InitialMemory;
uint32_t MaxMemory;
diff --git a/wasm/Driver.cpp b/wasm/Driver.cpp
index 860d9f5..396f30a 100644
--- a/wasm/Driver.cpp
+++ b/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();
diff --git a/wasm/Options.td b/wasm/Options.td
index 3ed55b4..591d624 100644
--- a/wasm/Options.td
+++ b/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<relocatable>;
def: Flag<["-"], "s">, Alias<strip_all>, HelpText<"Alias for --strip-all">;
def: Flag<["-"], "S">, Alias<strip_debug>, HelpText<"Alias for --strip-debug">;
+def: Flag<["-"], "t">, Alias<trace>, HelpText<"Alias for --trace">;
+def: JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>, HelpText<"Alias for --trace-symbol">;
def: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
// LTO-related options.
diff --git a/wasm/SymbolTable.cpp b/wasm/SymbolTable.cpp
index e45dc6b..79e85d5 100644
--- a/wasm/SymbolTable.cpp
+++ b/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<Symbol *, bool> 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<Symbol *>(make<SymbolUnion>());
+ Sym->IsUsedInRegularObj = false;
+ Sym->Traced = Trace;
+ SymVector.emplace_back(Sym);
+ return {Sym, true};
}
std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, InputFile *File) {
- bool Inserted = false;
- Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
- if (!Sym) {
- Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
- Sym->IsUsedInRegularObj = false;
- SymVector.emplace_back(Sym);
- Inserted = true;
- }
+ 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});
+}
diff --git a/wasm/SymbolTable.h b/wasm/SymbolTable.h
index f0bdd6c..ed5c0ca 100644
--- a/wasm/SymbolTable.h
+++ b/wasm/SymbolTable.h
@@ -46,8 +46,11 @@
void reportRemainingUndefines();
ArrayRef<Symbol *> 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<Symbol *, bool> insert(StringRef Name, InputFile *File);
+ std::pair<Symbol *, bool> insertName(StringRef Name);
- llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> 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<llvm::CachedHashStringRef, int> SymMap;
std::vector<Symbol *> SymVector;
llvm::DenseSet<llvm::CachedHashStringRef> Comdats;
diff --git a/wasm/Symbols.cpp b/wasm/Symbols.cpp
index 0c3c0e0..4721e35 100644
--- a/wasm/Symbols.cpp
+++ b/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());
+}
diff --git a/wasm/Symbols.h b/wasm/Symbols.h
index 652d0a9..535948c 100644
--- a/wasm/Symbols.h
+++ b/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 <typename T, typename... ArgT>
T *replaceSymbol(Symbol *S, ArgT &&... Arg) {
static_assert(std::is_trivially_destructible<T>(),
@@ -417,6 +423,13 @@
T *S2 = new (S) T(std::forward<ArgT>(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;
}