aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp')
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp170
1 files changed, 157 insertions, 13 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index 7f1c4bb40a4c..56829eb45e21 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -14,14 +14,16 @@
//===----------------------------------------------------------------------===//
#include "WebAssemblyAsmPrinter.h"
-#include "MCTargetDesc/WebAssemblyInstPrinter.h"
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "MCTargetDesc/WebAssemblyTargetStreamer.h"
#include "TargetInfo/WebAssemblyTargetInfo.h"
+#include "Utils/WebAssemblyTypeUtilities.h"
+#include "Utils/WebAssemblyUtilities.h"
#include "WebAssembly.h"
#include "WebAssemblyMCInstLower.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblyRegisterInfo.h"
+#include "WebAssemblyRuntimeLibcallSignatures.h"
#include "WebAssemblyTargetMachine.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
@@ -169,14 +171,126 @@ MCSymbolWasm *WebAssemblyAsmPrinter::getMCSymbolForFunction(
return WasmSym;
}
-void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) {
+void WebAssemblyAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
+ if (!WebAssembly::isWasmVarAddressSpace(GV->getAddressSpace())) {
+ AsmPrinter::emitGlobalVariable(GV);
+ return;
+ }
+
+ assert(!GV->isThreadLocal());
+
+ MCSymbolWasm *Sym = cast<MCSymbolWasm>(getSymbol(GV));
+
+ if (!Sym->getType()) {
+ const WebAssemblyTargetLowering &TLI = *Subtarget->getTargetLowering();
+ SmallVector<EVT, 1> VTs;
+ ComputeValueVTs(TLI, GV->getParent()->getDataLayout(), GV->getValueType(),
+ VTs);
+ if (VTs.size() != 1 ||
+ TLI.getNumRegisters(GV->getParent()->getContext(), VTs[0]) != 1)
+ report_fatal_error("Aggregate globals not yet implemented");
+ MVT VT = TLI.getRegisterType(GV->getParent()->getContext(), VTs[0]);
+ bool Mutable = true;
+ wasm::ValType Type = WebAssembly::toValType(VT);
+ Sym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
+ Sym->setGlobalType(wasm::WasmGlobalType{uint8_t(Type), Mutable});
+ }
+
+ emitVisibility(Sym, GV->getVisibility(), !GV->isDeclaration());
+ if (GV->hasInitializer()) {
+ assert(getSymbolPreferLocal(*GV) == Sym);
+ emitLinkage(GV, Sym);
+ getTargetStreamer()->emitGlobalType(Sym);
+ OutStreamer->emitLabel(Sym);
+ // TODO: Actually emit the initializer value. Otherwise the global has the
+ // default value for its type (0, ref.null, etc).
+ OutStreamer->AddBlankLine();
+ }
+}
+
+MCSymbol *WebAssemblyAsmPrinter::getOrCreateWasmSymbol(StringRef Name) {
+ auto *WasmSym = cast<MCSymbolWasm>(GetExternalSymbolSymbol(Name));
+
+ // May be called multiple times, so early out.
+ if (WasmSym->getType().hasValue())
+ return WasmSym;
+
+ const WebAssemblySubtarget &Subtarget = getSubtarget();
+
+ // Except for certain known symbols, all symbols used by CodeGen are
+ // functions. It's OK to hardcode knowledge of specific symbols here; this
+ // method is precisely there for fetching the signatures of known
+ // Clang-provided symbols.
+ if (Name == "__stack_pointer" || Name == "__tls_base" ||
+ Name == "__memory_base" || Name == "__table_base" ||
+ Name == "__tls_size" || Name == "__tls_align") {
+ bool Mutable =
+ Name == "__stack_pointer" || Name == "__tls_base";
+ WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
+ WasmSym->setGlobalType(wasm::WasmGlobalType{
+ uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64
+ : wasm::WASM_TYPE_I32),
+ Mutable});
+ return WasmSym;
+ }
+
+ SmallVector<wasm::ValType, 4> Returns;
+ SmallVector<wasm::ValType, 4> Params;
+ if (Name == "__cpp_exception") {
+ WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);
+ // We can't confirm its signature index for now because there can be
+ // imported exceptions. Set it to be 0 for now.
+ WasmSym->setTagType(
+ {wasm::WASM_TAG_ATTRIBUTE_EXCEPTION, /* SigIndex */ 0});
+ // We may have multiple C++ compilation units to be linked together, each of
+ // which defines the exception symbol. To resolve them, we declare them as
+ // weak.
+ WasmSym->setWeak(true);
+ WasmSym->setExternal(true);
+
+ // All C++ exceptions are assumed to have a single i32 (for wasm32) or i64
+ // (for wasm64) param type and void return type. The reaon is, all C++
+ // exception values are pointers, and to share the type section with
+ // functions, exceptions are assumed to have void return type.
+ Params.push_back(Subtarget.hasAddr64() ? wasm::ValType::I64
+ : wasm::ValType::I32);
+ } else { // Function symbols
+ WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
+ getLibcallSignature(Subtarget, Name, Returns, Params);
+ }
+ auto Signature = std::make_unique<wasm::WasmSignature>(std::move(Returns),
+ std::move(Params));
+ WasmSym->setSignature(Signature.get());
+ addSignature(std::move(Signature));
+
+ return WasmSym;
+}
+
+void WebAssemblyAsmPrinter::emitExternalDecls(const Module &M) {
+ if (signaturesEmitted)
+ return;
+ signaturesEmitted = true;
+
+ // Normally symbols for globals get discovered as the MI gets lowered,
+ // but we need to know about them ahead of time.
+ MachineModuleInfoWasm &MMIW = MMI->getObjFileInfo<MachineModuleInfoWasm>();
+ for (const auto &Name : MMIW.MachineSymbolsUsed) {
+ getOrCreateWasmSymbol(Name.getKey());
+ }
+
for (auto &It : OutContext.getSymbols()) {
- // Emit a .globaltype and .eventtype declaration.
+ // Emit .globaltype, .tagtype, or .tabletype declarations.
auto Sym = cast<MCSymbolWasm>(It.getValue());
- if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL)
- getTargetStreamer()->emitGlobalType(Sym);
- else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_EVENT)
- getTargetStreamer()->emitEventType(Sym);
+ if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL) {
+ // .globaltype already handled by emitGlobalVariable for defined
+ // variables; here we make sure the types of external wasm globals get
+ // written to the file.
+ if (Sym->isUndefined())
+ getTargetStreamer()->emitGlobalType(Sym);
+ } else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_TAG)
+ getTargetStreamer()->emitTagType(Sym);
+ else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_TABLE)
+ getTargetStreamer()->emitTableType(Sym);
}
DenseSet<MCSymbol *> InvokeSymbols;
@@ -241,14 +355,33 @@ void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) {
getTargetStreamer()->emitExportName(Sym, Name);
}
}
+}
+
+void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) {
+ emitExternalDecls(M);
+
+ // When a function's address is taken, a TABLE_INDEX relocation is emitted
+ // against the function symbol at the use site. However the relocation
+ // doesn't explicitly refer to the table. In the future we may want to
+ // define a new kind of reloc against both the function and the table, so
+ // that the linker can see that the function symbol keeps the table alive,
+ // but for now manually mark the table as live.
+ for (const auto &F : M) {
+ if (!F.isIntrinsic() && F.hasAddressTaken()) {
+ MCSymbolWasm *FunctionTable =
+ WebAssembly::getOrCreateFunctionTableSymbol(OutContext, Subtarget);
+ OutStreamer->emitSymbolAttribute(FunctionTable, MCSA_NoDeadStrip);
+ break;
+ }
+ }
for (const auto &G : M.globals()) {
- if (!G.hasInitializer() && G.hasExternalLinkage()) {
- if (G.getValueType()->isSized()) {
- uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());
- OutStreamer->emitELFSize(getSymbol(&G),
- MCConstantExpr::create(Size, OutContext));
- }
+ if (!G.hasInitializer() && G.hasExternalLinkage() &&
+ !WebAssembly::isWasmVarAddressSpace(G.getAddressSpace()) &&
+ G.getValueType()->isSized()) {
+ uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());
+ OutStreamer->emitELFSize(getSymbol(&G),
+ MCConstantExpr::create(Size, OutContext));
}
}
@@ -392,6 +525,17 @@ void WebAssemblyAsmPrinter::emitJumpTableInfo() {
// Nothing to do; jump tables are incorporated into the instruction stream.
}
+void WebAssemblyAsmPrinter::emitLinkage(const GlobalValue *GV, MCSymbol *Sym)
+ const {
+ AsmPrinter::emitLinkage(GV, Sym);
+ // This gets called before the function label and type are emitted.
+ // We use it to emit signatures of external functions.
+ // FIXME casts!
+ const_cast<WebAssemblyAsmPrinter *>(this)
+ ->emitExternalDecls(*MMI->getModule());
+}
+
+
void WebAssemblyAsmPrinter::emitFunctionBodyStart() {
const Function &F = MF->getFunction();
SmallVector<MVT, 1> ResultVTs;