[WebAssembly] Define __funcref_call_table in generated asm and objects (#180900)
Currently, calls into funcref (`call addrspace(20)`) are lowered into a store of the ref into a special single-element `__funcref_call_table`, a call_indirect into said table, then a store of null into it. It functions just fine when `-filetype=asm` (default), but when emitting an object file directly from llc it fails with `LLVM ERROR: undefined table symbol cannot be weak` This fixes said error by "defining" it during `WebAssemblyAsmPrinter`, and ensuring it is definitely emitted as weak (so duplicate tables in multiple objects are merged into a single one).
This commit is contained in:
parent
fc20c57067
commit
d79df25b12
2 changed files with 34 additions and 0 deletions
|
|
@ -333,6 +333,39 @@ void WebAssemblyAsmPrinter::emitDecls(const Module &M) {
|
|||
emitSymbolType(Sym);
|
||||
}
|
||||
|
||||
// We handle `__funcref_call_table` specially here.
|
||||
//
|
||||
// Unlike most table symbols, which are attached to a `GlobalVariable`
|
||||
// this one is a directly created, freestanding MCSymbol, much like
|
||||
// `__indirect_function_table`. However, given that the table is always
|
||||
// identical (single element, default initialized), we declare it
|
||||
// weak in each object, and define it here rather than in the linker.
|
||||
//
|
||||
// TODO: consider moving this definition elsewhere, or doing away with
|
||||
// the table entirely (in favor of `call_ref` exclusively).
|
||||
{
|
||||
StringRef Name = "__funcref_call_table";
|
||||
auto *Sym = static_cast<MCSymbolWasm *>(OutContext.lookupSymbol(Name));
|
||||
if (Sym) {
|
||||
if (!Sym->isFunctionTable())
|
||||
OutContext.reportError(SMLoc(), "symbol is not a wasm funcref table");
|
||||
|
||||
// symbol is declared weak in `getOrCreateFuncrefCallTableSymbol`
|
||||
assert(Sym->isWeak());
|
||||
OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
|
||||
|
||||
// Make sure we haven't already emitted it for whatever reason.
|
||||
assert(!Sym->isDefined());
|
||||
|
||||
// Actually define the symbol.
|
||||
// Confusingly enough, `emitLabel` is what "defines" a MCSymbol.
|
||||
// Provides it a fragment, so that it `!isUndefined`
|
||||
OutStreamer->emitLabel(Sym);
|
||||
// No initializer needed. Default ref.null is good
|
||||
OutStreamer->addBlankLine();
|
||||
}
|
||||
}
|
||||
|
||||
DenseSet<MCSymbol *> InvokeSymbols;
|
||||
for (const auto &F : M) {
|
||||
if (F.isIntrinsic())
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -fast-isel=0 -mattr=+reference-types | FileCheck %s
|
||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown --filetype=obj
|
||||
|
||||
; Use -fast-isel-abort=3 (never fall back to SelectionDAG) to make sure that the
|
||||
; funcref call is selected by FastISel
|
||||
|
|
|
|||
Loading…
Reference in a new issue