[WebAssembly] Implement --trace and --trace-symbol
Differential Revision: https://reviews.llvm.org/D57725 llvm-svn: 353264
This commit is contained in:
parent
c1950aa183
commit
1f3f774f10
|
@ -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
|
|
@ -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
|
|
@ -38,6 +38,7 @@ struct Configuration {
|
||||||
bool StripAll;
|
bool StripAll;
|
||||||
bool StripDebug;
|
bool StripDebug;
|
||||||
bool StackFirst;
|
bool StackFirst;
|
||||||
|
bool Trace;
|
||||||
uint32_t GlobalBase;
|
uint32_t GlobalBase;
|
||||||
uint32_t InitialMemory;
|
uint32_t InitialMemory;
|
||||||
uint32_t MaxMemory;
|
uint32_t MaxMemory;
|
||||||
|
|
|
@ -371,6 +371,7 @@ static void setConfigs(opt::InputArgList &Args) {
|
||||||
Config->StripAll = Args.hasArg(OPT_strip_all);
|
Config->StripAll = Args.hasArg(OPT_strip_all);
|
||||||
Config->StripDebug = Args.hasArg(OPT_strip_debug);
|
Config->StripDebug = Args.hasArg(OPT_strip_debug);
|
||||||
Config->StackFirst = Args.hasArg(OPT_stack_first);
|
Config->StackFirst = Args.hasArg(OPT_stack_first);
|
||||||
|
Config->Trace = Args.hasArg(OPT_trace);
|
||||||
Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir);
|
Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir);
|
||||||
Config->ThinLTOCachePolicy = CHECK(
|
Config->ThinLTOCachePolicy = CHECK(
|
||||||
parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)),
|
parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)),
|
||||||
|
@ -556,6 +557,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
||||||
Config->AllowUndefined = true;
|
Config->AllowUndefined = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle --trace-symbol.
|
||||||
|
for (auto *Arg : Args.filtered(OPT_trace_symbol))
|
||||||
|
Symtab->trace(Arg->getValue());
|
||||||
|
|
||||||
if (!Config->Relocatable)
|
if (!Config->Relocatable)
|
||||||
createSyntheticSymbols();
|
createSyntheticSymbols();
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,10 @@ def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
|
||||||
|
|
||||||
def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
|
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">;
|
defm undefined: Eq<"undefined", "Force undefined symbol during linking">;
|
||||||
|
|
||||||
def v: Flag<["-"], "v">, HelpText<"Display the version number">;
|
def v: Flag<["-"], "v">, HelpText<"Display the version number">;
|
||||||
|
@ -160,6 +164,8 @@ def: Flag<["-"], "m">, Alias<max_memory>;
|
||||||
def: Flag<["-"], "r">, Alias<relocatable>;
|
def: Flag<["-"], "r">, Alias<relocatable>;
|
||||||
def: Flag<["-"], "s">, Alias<strip_all>, HelpText<"Alias for --strip-all">;
|
def: Flag<["-"], "s">, Alias<strip_all>, HelpText<"Alias for --strip-all">;
|
||||||
def: Flag<["-"], "S">, Alias<strip_debug>, HelpText<"Alias for --strip-debug">;
|
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>;
|
def: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
|
||||||
|
|
||||||
// LTO-related options.
|
// LTO-related options.
|
||||||
|
|
|
@ -28,6 +28,8 @@ SymbolTable *lld::wasm::Symtab;
|
||||||
|
|
||||||
void SymbolTable::addFile(InputFile *File) {
|
void SymbolTable::addFile(InputFile *File) {
|
||||||
log("Processing: " + toString(File));
|
log("Processing: " + toString(File));
|
||||||
|
if (Config->Trace)
|
||||||
|
message(toString(File));
|
||||||
File->parse();
|
File->parse();
|
||||||
|
|
||||||
// LLVM bitcode file
|
// LLVM bitcode file
|
||||||
|
@ -73,21 +75,42 @@ void SymbolTable::reportRemainingUndefines() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol *SymbolTable::find(StringRef Name) {
|
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) {
|
std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, InputFile *File) {
|
||||||
bool Inserted = false;
|
Symbol *S;
|
||||||
Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
|
bool WasInserted;
|
||||||
if (!Sym) {
|
std::tie(S, WasInserted) = insertName(Name);
|
||||||
Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
|
|
||||||
Sym->IsUsedInRegularObj = false;
|
|
||||||
SymVector.emplace_back(Sym);
|
|
||||||
Inserted = true;
|
|
||||||
}
|
|
||||||
if (!File || File->kind() == InputFile::ObjectKind)
|
if (!File || File->kind() == InputFile::ObjectKind)
|
||||||
Sym->IsUsedInRegularObj = true;
|
S->IsUsedInRegularObj = true;
|
||||||
return {Sym, Inserted};
|
|
||||||
|
return {S, WasInserted};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reportTypeError(const Symbol *Existing, const InputFile *File,
|
static void reportTypeError(const Symbol *Existing, const InputFile *File,
|
||||||
|
@ -409,3 +432,9 @@ void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
|
||||||
bool SymbolTable::addComdat(StringRef Name) {
|
bool SymbolTable::addComdat(StringRef Name) {
|
||||||
return Comdats.insert(CachedHashStringRef(Name)).second;
|
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});
|
||||||
|
}
|
||||||
|
|
|
@ -46,8 +46,11 @@ public:
|
||||||
void reportRemainingUndefines();
|
void reportRemainingUndefines();
|
||||||
|
|
||||||
ArrayRef<Symbol *> getSymbols() const { return SymVector; }
|
ArrayRef<Symbol *> getSymbols() const { return SymVector; }
|
||||||
|
|
||||||
Symbol *find(StringRef Name);
|
Symbol *find(StringRef Name);
|
||||||
|
|
||||||
|
void trace(StringRef Name);
|
||||||
|
|
||||||
Symbol *addDefinedFunction(StringRef Name, uint32_t Flags, InputFile *File,
|
Symbol *addDefinedFunction(StringRef Name, uint32_t Flags, InputFile *File,
|
||||||
InputFunction *Function);
|
InputFunction *Function);
|
||||||
Symbol *addDefinedData(StringRef Name, uint32_t Flags, InputFile *File,
|
Symbol *addDefinedData(StringRef Name, uint32_t Flags, InputFile *File,
|
||||||
|
@ -76,8 +79,12 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::pair<Symbol *, bool> insert(StringRef Name, InputFile *File);
|
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;
|
std::vector<Symbol *> SymVector;
|
||||||
|
|
||||||
llvm::DenseSet<llvm::CachedHashStringRef> Comdats;
|
llvm::DenseSet<llvm::CachedHashStringRef> Comdats;
|
||||||
|
|
|
@ -293,3 +293,16 @@ std::string lld::toString(wasm::Symbol::Kind Kind) {
|
||||||
}
|
}
|
||||||
llvm_unreachable("invalid symbol kind");
|
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());
|
||||||
|
}
|
||||||
|
|
|
@ -100,10 +100,14 @@ public:
|
||||||
unsigned IsUsedInRegularObj : 1;
|
unsigned IsUsedInRegularObj : 1;
|
||||||
unsigned ForceExport : 1;
|
unsigned ForceExport : 1;
|
||||||
|
|
||||||
|
// True if this symbol is specified by --trace-symbol option.
|
||||||
|
unsigned Traced : 1;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
|
Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
|
||||||
: IsUsedInRegularObj(false), ForceExport(false), Name(Name),
|
: IsUsedInRegularObj(false), ForceExport(false), Traced(false),
|
||||||
SymbolKind(K), Flags(Flags), File(F), Referenced(!Config->GcSections) {}
|
Name(Name), SymbolKind(K), Flags(Flags), File(F),
|
||||||
|
Referenced(!Config->GcSections) {}
|
||||||
|
|
||||||
StringRef Name;
|
StringRef Name;
|
||||||
Kind SymbolKind;
|
Kind SymbolKind;
|
||||||
|
@ -402,6 +406,8 @@ union SymbolUnion {
|
||||||
alignas(SectionSymbol) char I[sizeof(SectionSymbol)];
|
alignas(SectionSymbol) char I[sizeof(SectionSymbol)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void printTraceSymbol(Symbol *Sym);
|
||||||
|
|
||||||
template <typename T, typename... ArgT>
|
template <typename T, typename... ArgT>
|
||||||
T *replaceSymbol(Symbol *S, ArgT &&... Arg) {
|
T *replaceSymbol(Symbol *S, ArgT &&... Arg) {
|
||||||
static_assert(std::is_trivially_destructible<T>(),
|
static_assert(std::is_trivially_destructible<T>(),
|
||||||
|
@ -417,6 +423,13 @@ T *replaceSymbol(Symbol *S, ArgT &&... Arg) {
|
||||||
T *S2 = new (S) T(std::forward<ArgT>(Arg)...);
|
T *S2 = new (S) T(std::forward<ArgT>(Arg)...);
|
||||||
S2->IsUsedInRegularObj = SymCopy.IsUsedInRegularObj;
|
S2->IsUsedInRegularObj = SymCopy.IsUsedInRegularObj;
|
||||||
S2->ForceExport = SymCopy.ForceExport;
|
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;
|
return S2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue