Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lld / wasm / Symbols.cpp
blob2adf72b6965ca858e13c1c12228dc7489e415f77
1 //===- Symbols.cpp --------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "Symbols.h"
10 #include "Config.h"
11 #include "InputChunks.h"
12 #include "InputElement.h"
13 #include "InputFiles.h"
14 #include "OutputSections.h"
15 #include "OutputSegment.h"
16 #include "lld/Common/ErrorHandler.h"
17 #include "lld/Common/Memory.h"
18 #include "llvm/Demangle/Demangle.h"
20 #define DEBUG_TYPE "lld"
22 using namespace llvm;
23 using namespace llvm::object;
24 using namespace llvm::wasm;
25 using namespace lld::wasm;
27 namespace lld {
28 std::string toString(const wasm::Symbol &sym) {
29 return maybeDemangleSymbol(sym.getName());
32 std::string maybeDemangleSymbol(StringRef name) {
33 // WebAssembly requires caller and callee signatures to match, so we mangle
34 // `main` in the case where we need to pass it arguments.
35 if (name == "__main_argc_argv")
36 return "main";
37 if (wasm::config->demangle)
38 return demangle(name);
39 return name.str();
42 std::string toString(wasm::Symbol::Kind kind) {
43 switch (kind) {
44 case wasm::Symbol::DefinedFunctionKind:
45 return "DefinedFunction";
46 case wasm::Symbol::DefinedDataKind:
47 return "DefinedData";
48 case wasm::Symbol::DefinedGlobalKind:
49 return "DefinedGlobal";
50 case wasm::Symbol::DefinedTableKind:
51 return "DefinedTable";
52 case wasm::Symbol::DefinedTagKind:
53 return "DefinedTag";
54 case wasm::Symbol::UndefinedFunctionKind:
55 return "UndefinedFunction";
56 case wasm::Symbol::UndefinedDataKind:
57 return "UndefinedData";
58 case wasm::Symbol::UndefinedGlobalKind:
59 return "UndefinedGlobal";
60 case wasm::Symbol::UndefinedTableKind:
61 return "UndefinedTable";
62 case wasm::Symbol::UndefinedTagKind:
63 return "UndefinedTag";
64 case wasm::Symbol::LazyKind:
65 return "LazyKind";
66 case wasm::Symbol::SectionKind:
67 return "SectionKind";
68 case wasm::Symbol::OutputSectionKind:
69 return "OutputSectionKind";
71 llvm_unreachable("invalid symbol kind");
74 namespace wasm {
75 DefinedFunction *WasmSym::callCtors;
76 DefinedFunction *WasmSym::callDtors;
77 DefinedFunction *WasmSym::initMemory;
78 DefinedFunction *WasmSym::applyDataRelocs;
79 DefinedFunction *WasmSym::applyGlobalRelocs;
80 DefinedFunction *WasmSym::applyTLSRelocs;
81 DefinedFunction *WasmSym::applyGlobalTLSRelocs;
82 DefinedFunction *WasmSym::initTLS;
83 DefinedFunction *WasmSym::startFunction;
84 DefinedData *WasmSym::dsoHandle;
85 DefinedData *WasmSym::dataEnd;
86 DefinedData *WasmSym::globalBase;
87 DefinedData *WasmSym::heapBase;
88 DefinedData *WasmSym::heapEnd;
89 DefinedData *WasmSym::initMemoryFlag;
90 GlobalSymbol *WasmSym::stackPointer;
91 DefinedData *WasmSym::stackLow;
92 DefinedData *WasmSym::stackHigh;
93 GlobalSymbol *WasmSym::tlsBase;
94 GlobalSymbol *WasmSym::tlsSize;
95 GlobalSymbol *WasmSym::tlsAlign;
96 UndefinedGlobal *WasmSym::tableBase;
97 DefinedData *WasmSym::definedTableBase;
98 UndefinedGlobal *WasmSym::tableBase32;
99 DefinedData *WasmSym::definedTableBase32;
100 UndefinedGlobal *WasmSym::memoryBase;
101 DefinedData *WasmSym::definedMemoryBase;
102 TableSymbol *WasmSym::indirectFunctionTable;
104 WasmSymbolType Symbol::getWasmType() const {
105 if (isa<FunctionSymbol>(this))
106 return WASM_SYMBOL_TYPE_FUNCTION;
107 if (isa<DataSymbol>(this))
108 return WASM_SYMBOL_TYPE_DATA;
109 if (isa<GlobalSymbol>(this))
110 return WASM_SYMBOL_TYPE_GLOBAL;
111 if (isa<TagSymbol>(this))
112 return WASM_SYMBOL_TYPE_TAG;
113 if (isa<TableSymbol>(this))
114 return WASM_SYMBOL_TYPE_TABLE;
115 if (isa<SectionSymbol>(this) || isa<OutputSectionSymbol>(this))
116 return WASM_SYMBOL_TYPE_SECTION;
117 llvm_unreachable("invalid symbol kind");
120 const WasmSignature *Symbol::getSignature() const {
121 if (auto* f = dyn_cast<FunctionSymbol>(this))
122 return f->signature;
123 if (auto *t = dyn_cast<TagSymbol>(this))
124 return t->signature;
125 if (auto *l = dyn_cast<LazySymbol>(this))
126 return l->signature;
127 return nullptr;
130 InputChunk *Symbol::getChunk() const {
131 if (auto *f = dyn_cast<DefinedFunction>(this))
132 return f->function;
133 if (auto *f = dyn_cast<UndefinedFunction>(this))
134 if (f->stubFunction)
135 return f->stubFunction->function;
136 if (auto *d = dyn_cast<DefinedData>(this))
137 return d->segment;
138 return nullptr;
141 bool Symbol::isDiscarded() const {
142 if (InputChunk *c = getChunk())
143 return c->discarded;
144 return false;
147 bool Symbol::isLive() const {
148 if (auto *g = dyn_cast<DefinedGlobal>(this))
149 return g->global->live;
150 if (auto *t = dyn_cast<DefinedTag>(this))
151 return t->tag->live;
152 if (auto *t = dyn_cast<DefinedTable>(this))
153 return t->table->live;
154 if (InputChunk *c = getChunk())
155 return c->live;
156 return referenced;
159 void Symbol::markLive() {
160 assert(!isDiscarded());
161 referenced = true;
162 if (file != nullptr && isDefined())
163 file->markLive();
164 if (auto *g = dyn_cast<DefinedGlobal>(this))
165 g->global->live = true;
166 if (auto *t = dyn_cast<DefinedTag>(this))
167 t->tag->live = true;
168 if (auto *t = dyn_cast<DefinedTable>(this))
169 t->table->live = true;
170 if (InputChunk *c = getChunk()) {
171 // Usually, a whole chunk is marked as live or dead, but in mergeable
172 // (splittable) sections, each piece of data has independent liveness bit.
173 // So we explicitly tell it which offset is in use.
174 if (auto *d = dyn_cast<DefinedData>(this)) {
175 if (auto *ms = dyn_cast<MergeInputChunk>(c)) {
176 ms->getSectionPiece(d->value)->live = true;
179 c->live = true;
183 uint32_t Symbol::getOutputSymbolIndex() const {
184 assert(outputSymbolIndex != INVALID_INDEX);
185 return outputSymbolIndex;
188 void Symbol::setOutputSymbolIndex(uint32_t index) {
189 LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name << " -> " << index
190 << "\n");
191 assert(outputSymbolIndex == INVALID_INDEX);
192 outputSymbolIndex = index;
195 void Symbol::setGOTIndex(uint32_t index) {
196 LLVM_DEBUG(dbgs() << "setGOTIndex " << name << " -> " << index << "\n");
197 assert(gotIndex == INVALID_INDEX);
198 gotIndex = index;
201 bool Symbol::isWeak() const {
202 return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
205 bool Symbol::isLocal() const {
206 return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
209 bool Symbol::isHidden() const {
210 return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
213 bool Symbol::isTLS() const { return flags & WASM_SYMBOL_TLS; }
215 void Symbol::setHidden(bool isHidden) {
216 LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n");
217 flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
218 if (isHidden)
219 flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
220 else
221 flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;
224 bool Symbol::isImported() const {
225 return isUndefined() && (importName.has_value() || forceImport);
228 bool Symbol::isExported() const {
229 if (!isDefined() || isLocal())
230 return false;
232 // Shared libraries must export all weakly defined symbols
233 // in case they contain the version that will be chosen by
234 // the dynamic linker.
235 if (config->shared && isLive() && isWeak() && !isHidden())
236 return true;
238 if (config->exportAll || (config->exportDynamic && !isHidden()))
239 return true;
241 return isExportedExplicit();
244 bool Symbol::isExportedExplicit() const {
245 return forceExport || flags & WASM_SYMBOL_EXPORTED;
248 bool Symbol::isNoStrip() const {
249 return flags & WASM_SYMBOL_NO_STRIP;
252 uint32_t FunctionSymbol::getFunctionIndex() const {
253 if (const auto *u = dyn_cast<UndefinedFunction>(this))
254 if (u->stubFunction)
255 return u->stubFunction->getFunctionIndex();
256 if (functionIndex != INVALID_INDEX)
257 return functionIndex;
258 auto *f = cast<DefinedFunction>(this);
259 return f->function->getFunctionIndex();
262 void FunctionSymbol::setFunctionIndex(uint32_t index) {
263 LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n");
264 assert(functionIndex == INVALID_INDEX);
265 functionIndex = index;
268 bool FunctionSymbol::hasFunctionIndex() const {
269 if (auto *f = dyn_cast<DefinedFunction>(this))
270 return f->function->hasFunctionIndex();
271 return functionIndex != INVALID_INDEX;
274 uint32_t FunctionSymbol::getTableIndex() const {
275 if (auto *f = dyn_cast<DefinedFunction>(this))
276 return f->function->getTableIndex();
277 assert(tableIndex != INVALID_INDEX);
278 return tableIndex;
281 bool FunctionSymbol::hasTableIndex() const {
282 if (auto *f = dyn_cast<DefinedFunction>(this))
283 return f->function->hasTableIndex();
284 return tableIndex != INVALID_INDEX;
287 void FunctionSymbol::setTableIndex(uint32_t index) {
288 // For imports, we set the table index here on the Symbol; for defined
289 // functions we set the index on the InputFunction so that we don't export
290 // the same thing twice (keeps the table size down).
291 if (auto *f = dyn_cast<DefinedFunction>(this)) {
292 f->function->setTableIndex(index);
293 return;
295 LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n");
296 assert(tableIndex == INVALID_INDEX);
297 tableIndex = index;
300 DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f,
301 InputFunction *function)
302 : FunctionSymbol(name, DefinedFunctionKind, flags, f,
303 function ? &function->signature : nullptr),
304 function(function) {}
306 uint32_t DefinedFunction::getExportedFunctionIndex() const {
307 return function->getFunctionIndex();
310 uint64_t DefinedData::getVA() const {
311 LLVM_DEBUG(dbgs() << "getVA: " << getName() << "\n");
312 // In the shared memory case, TLS symbols are relative to the start of the TLS
313 // output segment (__tls_base). When building without shared memory, TLS
314 // symbols absolute, just like non-TLS.
315 if (isTLS() && config->sharedMemory)
316 return getOutputSegmentOffset();
317 if (segment)
318 return segment->getVA(value);
319 return value;
322 void DefinedData::setVA(uint64_t value_) {
323 LLVM_DEBUG(dbgs() << "setVA " << name << " -> " << value_ << "\n");
324 assert(!segment);
325 value = value_;
328 uint64_t DefinedData::getOutputSegmentOffset() const {
329 LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
330 return segment->getChunkOffset(value);
333 uint64_t DefinedData::getOutputSegmentIndex() const {
334 LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
335 return segment->outputSeg->index;
338 uint32_t GlobalSymbol::getGlobalIndex() const {
339 if (auto *f = dyn_cast<DefinedGlobal>(this))
340 return f->global->getAssignedIndex();
341 assert(globalIndex != INVALID_INDEX);
342 return globalIndex;
345 void GlobalSymbol::setGlobalIndex(uint32_t index) {
346 LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n");
347 assert(globalIndex == INVALID_INDEX);
348 globalIndex = index;
351 bool GlobalSymbol::hasGlobalIndex() const {
352 if (auto *f = dyn_cast<DefinedGlobal>(this))
353 return f->global->hasAssignedIndex();
354 return globalIndex != INVALID_INDEX;
357 DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,
358 InputGlobal *global)
359 : GlobalSymbol(name, DefinedGlobalKind, flags, file,
360 global ? &global->getType() : nullptr),
361 global(global) {}
363 uint32_t TagSymbol::getTagIndex() const {
364 if (auto *f = dyn_cast<DefinedTag>(this))
365 return f->tag->getAssignedIndex();
366 assert(tagIndex != INVALID_INDEX);
367 return tagIndex;
370 void TagSymbol::setTagIndex(uint32_t index) {
371 LLVM_DEBUG(dbgs() << "setTagIndex " << name << " -> " << index << "\n");
372 assert(tagIndex == INVALID_INDEX);
373 tagIndex = index;
376 bool TagSymbol::hasTagIndex() const {
377 if (auto *f = dyn_cast<DefinedTag>(this))
378 return f->tag->hasAssignedIndex();
379 return tagIndex != INVALID_INDEX;
382 DefinedTag::DefinedTag(StringRef name, uint32_t flags, InputFile *file,
383 InputTag *tag)
384 : TagSymbol(name, DefinedTagKind, flags, file,
385 tag ? &tag->signature : nullptr),
386 tag(tag) {}
388 void TableSymbol::setLimits(const WasmLimits &limits) {
389 if (auto *t = dyn_cast<DefinedTable>(this))
390 t->table->setLimits(limits);
391 auto *newType = make<WasmTableType>(*tableType);
392 newType->Limits = limits;
393 tableType = newType;
396 uint32_t TableSymbol::getTableNumber() const {
397 if (const auto *t = dyn_cast<DefinedTable>(this))
398 return t->table->getAssignedIndex();
399 assert(tableNumber != INVALID_INDEX);
400 return tableNumber;
403 void TableSymbol::setTableNumber(uint32_t number) {
404 if (const auto *t = dyn_cast<DefinedTable>(this))
405 return t->table->assignIndex(number);
406 LLVM_DEBUG(dbgs() << "setTableNumber " << name << " -> " << number << "\n");
407 assert(tableNumber == INVALID_INDEX);
408 tableNumber = number;
411 bool TableSymbol::hasTableNumber() const {
412 if (const auto *t = dyn_cast<DefinedTable>(this))
413 return t->table->hasAssignedIndex();
414 return tableNumber != INVALID_INDEX;
417 DefinedTable::DefinedTable(StringRef name, uint32_t flags, InputFile *file,
418 InputTable *table)
419 : TableSymbol(name, DefinedTableKind, flags, file,
420 table ? &table->getType() : nullptr),
421 table(table) {}
423 const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const {
424 assert(section->outputSec && section->outputSec->sectionSym);
425 return section->outputSec->sectionSym;
428 void LazySymbol::fetch() { cast<ArchiveFile>(file)->addMember(&archiveSymbol); }
430 void LazySymbol::setWeak() {
431 flags |= (flags & ~WASM_SYMBOL_BINDING_MASK) | WASM_SYMBOL_BINDING_WEAK;
434 MemoryBufferRef LazySymbol::getMemberBuffer() {
435 Archive::Child c =
436 CHECK(archiveSymbol.getMember(),
437 "could not get the member for symbol " + toString(*this));
439 return CHECK(c.getMemoryBufferRef(),
440 "could not get the buffer for the member defining symbol " +
441 toString(*this));
444 void printTraceSymbolUndefined(StringRef name, const InputFile* file) {
445 message(toString(file) + ": reference to " + name);
448 // Print out a log message for --trace-symbol.
449 void printTraceSymbol(Symbol *sym) {
450 // Undefined symbols are traced via printTraceSymbolUndefined
451 if (sym->isUndefined())
452 return;
454 std::string s;
455 if (sym->isLazy())
456 s = ": lazy definition of ";
457 else
458 s = ": definition of ";
460 message(toString(sym->getFile()) + s + sym->getName());
463 const char *defaultModule = "env";
464 const char *functionTableName = "__indirect_function_table";
465 const char *memoryName = "memory";
467 } // namespace wasm
468 } // namespace lld