[llvm] 861dbe1 - [WebAssembly] call_indirect issues table number relocs
Andy Wingo via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 22 01:17:09 PST 2021
Author: Andy Wingo
Date: 2021-02-22T10:13:36+01:00
New Revision: 861dbe1a021e6439af837b72b219fb9c449a57ae
URL: https://github.com/llvm/llvm-project/commit/861dbe1a021e6439af837b72b219fb9c449a57ae
DIFF: https://github.com/llvm/llvm-project/commit/861dbe1a021e6439af837b72b219fb9c449a57ae.diff
LOG: [WebAssembly] call_indirect issues table number relocs
If the reference-types feature is enabled, call_indirect will explicitly
reference its corresponding function table via `TABLE_NUMBER`
relocations against a table symbol.
Also, as before, address-taken functions can also cause the function
table to be created, only with reference-types they additionally cause a
symbol table entry to be emitted.
We abuse the used-in-reloc flag on symbols to indicate which tables
should end up in the symbol table. We do this because unfortunately
older wasm-ld will carp if it see a table symbol.
Differential Revision: https://reviews.llvm.org/D90948
Added:
llvm/test/MC/WebAssembly/call-indirect-relocs.s
Modified:
lld/test/wasm/compress-relocs.ll
llvm/include/llvm/MC/MCSymbolWasm.h
llvm/lib/MC/WasmObjectWriter.cpp
llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h
llvm/test/CodeGen/WebAssembly/function-pointer64.ll
llvm/test/CodeGen/WebAssembly/multivalue.ll
llvm/test/MC/WebAssembly/basic-assembly.s
llvm/test/MC/WebAssembly/function-alias.ll
llvm/test/MC/WebAssembly/reloc-code.ll
llvm/test/MC/WebAssembly/reloc-pic.s
llvm/test/MC/WebAssembly/tail-call-encodings.s
llvm/test/MC/WebAssembly/type-index.s
llvm/test/MC/WebAssembly/weak-alias.s
Removed:
################################################################################
diff --git a/lld/test/wasm/compress-relocs.ll b/lld/test/wasm/compress-relocs.ll
index 4d4ac4b705ee..f1faab754cb7 100644
--- a/lld/test/wasm/compress-relocs.ll
+++ b/lld/test/wasm/compress-relocs.ll
@@ -1,5 +1,5 @@
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/call-indirect.s -o %t2.o
+; RUN: llvm-mc -mattr=+reference-types -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/call-indirect.s -o %t2.o
; RUN: wasm-ld --export-dynamic -o %t.wasm %t2.o %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
; RUN: wasm-ld --export-dynamic -O2 -o %t-opt.wasm %t2.o %t.o
@@ -22,5 +22,5 @@ entry:
; ERROR: wasm-ld: error: --compress-relocations is incompatible with output debug information. Please pass --strip-debug or --strip-all
-; CHECK: Body: 410028028088808000118080808000001A410028028488808000118180808000001A0B
+; CHECK: Body: 41002802808880800011808080800080808080001A41002802848880800011818080800080808080001A0B
; COMPRESS: Body: 4100280280081100001A4100280284081101001A0B
diff --git a/llvm/include/llvm/MC/MCSymbolWasm.h b/llvm/include/llvm/MC/MCSymbolWasm.h
index dbb1cb04fc5d..49d57919f6f3 100644
--- a/llvm/include/llvm/MC/MCSymbolWasm.h
+++ b/llvm/include/llvm/MC/MCSymbolWasm.h
@@ -18,6 +18,7 @@ class MCSymbolWasm : public MCSymbol {
bool IsWeak = false;
bool IsHidden = false;
bool IsComdat = false;
+ bool OmitFromLinkingSection = false;
mutable bool IsUsedInInitArray = false;
mutable bool IsUsedInGOT = false;
Optional<StringRef> ImportModule;
@@ -75,6 +76,12 @@ class MCSymbolWasm : public MCSymbol {
bool isComdat() const { return IsComdat; }
void setComdat(bool isComdat) { IsComdat = isComdat; }
+ // wasm-ld understands a finite set of symbol types. This flag allows the
+ // compiler to avoid emitting symbol table entries that would confuse the
+ // linker, unless the user specifically requests the feature.
+ bool omitFromLinkingSection() const { return OmitFromLinkingSection; }
+ void setOmitFromLinkingSection() { OmitFromLinkingSection = true; }
+
bool hasImportModule() const { return ImportModule.hasValue(); }
StringRef getImportModule() const {
if (ImportModule.hasValue())
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index d16be49c92e6..b2c8c022b5c8 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -405,12 +405,17 @@ void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
const MCAsmLayout &Layout) {
- // As a stopgap measure until call_indirect instructions start explicitly
- // referencing the indirect function table via TABLE_NUMBER relocs, ensure
- // that the indirect function table import makes it to the output if anything
- // in the compilation unit has caused it to be present.
- if (auto *Sym = Asm.getContext().lookupSymbol("__indirect_function_table"))
- Asm.registerSymbol(*Sym);
+ // Some compilation units require the indirect function table to be present
+ // but don't explicitly reference it. This is the case for call_indirect
+ // without the reference-types feature, and also function bitcasts in all
+ // cases. In those cases the __indirect_function_table has the
+ // WASM_SYMBOL_NO_STRIP attribute. Here we make sure this symbol makes it to
+ // the assembler, if needed.
+ if (auto *Sym = Asm.getContext().lookupSymbol("__indirect_function_table")) {
+ const auto *WasmSym = static_cast<const MCSymbolWasm *>(Sym);
+ if (WasmSym->isNoStrip())
+ Asm.registerSymbol(*Sym);
+ }
// Build a map of sections to the function that defines them, for use
// in recordRelocation.
@@ -509,21 +514,18 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
Type == wasm::R_WASM_TABLE_INDEX_I32 ||
Type == wasm::R_WASM_TABLE_INDEX_I64) {
// TABLE_INDEX relocs implicitly use the default indirect function table.
+ // We require the function table to have already been defined.
auto TableName = "__indirect_function_table";
MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(TableName));
- if (Sym) {
- if (!Sym->isFunctionTable())
- Ctx.reportError(
- Fixup.getLoc(),
- "symbol '__indirect_function_table' is not a function table");
+ if (!Sym || !Sym->isFunctionTable()) {
+ Ctx.reportError(
+ Fixup.getLoc(),
+ "symbol '__indirect_function_table' is not a function table");
} else {
- Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(TableName));
- Sym->setFunctionTable();
- // The default function table is synthesized by the linker.
- Sym->setUndefined();
+ // Ensure that __indirect_function_table reaches the output.
+ Sym->setNoStrip();
+ Asm.registerSymbol(*Sym);
}
- Sym->setUsedInReloc();
- Asm.registerSymbol(*Sym);
}
// Relocation other than R_WASM_TYPE_INDEX_LEB are required to be
@@ -1211,6 +1213,9 @@ static bool isInSymtab(const MCSymbolWasm &Sym) {
if (Sym.isSection())
return false;
+ if (Sym.omitFromLinkingSection())
+ return false;
+
return true;
}
@@ -1674,10 +1679,6 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
WS.setIndex(InvalidIndex);
continue;
}
- if (WS.isTable() && WS.getName() == "__indirect_function_table") {
- // For the moment, don't emit table symbols -- wasm-ld can't handle them.
- continue;
- }
LLVM_DEBUG(dbgs() << "adding to symtab: " << WS << "\n");
uint32_t Flags = 0;
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 9a2ae0100b50..cd0f9dc32ec4 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -171,9 +171,6 @@ struct WebAssemblyOperand : public MCParsedAsmOperand {
static MCSymbolWasm *GetOrCreateFunctionTableSymbol(MCContext &Ctx,
const StringRef &Name) {
- // FIXME: Duplicates functionality from
- // MC/WasmObjectWriter::recordRelocation, as well as WebAssemblyCodegen's
- // WebAssembly:getOrCreateFunctionTableSymbol.
MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
if (Sym) {
if (!Sym->isFunctionTable())
@@ -223,6 +220,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
};
std::vector<NestingType> NestingStack;
+ MCSymbolWasm *DefaultFunctionTable = nullptr;
MCSymbol *LastFunctionLabel = nullptr;
public:
@@ -233,6 +231,15 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
}
+ void Initialize(MCAsmParser &Parser) override {
+ MCAsmParserExtension::Initialize(Parser);
+
+ DefaultFunctionTable = GetOrCreateFunctionTableSymbol(
+ getContext(), "__indirect_function_table");
+ if (!STI->checkFeatures("+reference-types"))
+ DefaultFunctionTable->setOmitFromLinkingSection();
+ }
+
#define GET_ASSEMBLER_HEADER
#include "WebAssemblyGenAsmMatcher.inc"
@@ -480,6 +487,39 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)}));
}
+ bool addFunctionTableOperand(OperandVector &Operands, MCSymbolWasm *Sym,
+ SMLoc StartLoc, SMLoc EndLoc) {
+ const auto *Val = MCSymbolRefExpr::create(Sym, getContext());
+ Operands.push_back(std::make_unique<WebAssemblyOperand>(
+ WebAssemblyOperand::Symbol, StartLoc, EndLoc,
+ WebAssemblyOperand::SymOp{Val}));
+ return false;
+ }
+
+ bool addFunctionTableOperand(OperandVector &Operands, StringRef TableName,
+ SMLoc StartLoc, SMLoc EndLoc) {
+ return addFunctionTableOperand(
+ Operands, GetOrCreateFunctionTableSymbol(getContext(), TableName),
+ StartLoc, EndLoc);
+ }
+
+ bool addDefaultFunctionTableOperand(OperandVector &Operands, SMLoc StartLoc,
+ SMLoc EndLoc) {
+ if (STI->checkFeatures("+reference-types")) {
+ return addFunctionTableOperand(Operands, DefaultFunctionTable, StartLoc,
+ EndLoc);
+ } else {
+ // For the MVP there is at most one table whose number is 0, but we can't
+ // write a table symbol or issue relocations. Instead we just ensure the
+ // table is live and write a zero.
+ getStreamer().emitSymbolAttribute(DefaultFunctionTable, MCSA_NoDeadStrip);
+ Operands.push_back(std::make_unique<WebAssemblyOperand>(
+ WebAssemblyOperand::Integer, StartLoc, EndLoc,
+ WebAssemblyOperand::IntOp{0}));
+ return false;
+ }
+ }
+
bool ParseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override {
// Note: Name does NOT point into the sourcecode, but to a local, so
@@ -516,6 +556,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
bool ExpectBlockType = false;
bool ExpectFuncType = false;
bool ExpectHeapType = false;
+ bool ExpectFunctionTable = false;
if (Name == "block") {
push(Block);
ExpectBlockType = true;
@@ -562,15 +603,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
return true;
} else if (Name == "call_indirect" || Name == "return_call_indirect") {
ExpectFuncType = true;
- // Ensure that the object file has a __indirect_function_table import, as
- // we call_indirect against it.
- auto &Ctx = getStreamer().getContext();
- MCSymbolWasm *Sym =
- GetOrCreateFunctionTableSymbol(Ctx, "__indirect_function_table");
- // Until call_indirect emits TABLE_NUMBER relocs against this symbol, mark
- // it as NO_STRIP so as to ensure that the indirect function table makes
- // it to linked output.
- Sym->setNoStrip();
+ ExpectFunctionTable = true;
} else if (Name == "ref.null") {
ExpectHeapType = true;
}
@@ -586,7 +619,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
return true;
// Got signature as block type, don't need more
ExpectBlockType = false;
- auto &Ctx = getStreamer().getContext();
+ auto &Ctx = getContext();
// The "true" here will cause this to be a nameless symbol.
MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true);
auto *WasmSym = cast<MCSymbolWasm>(Sym);
@@ -598,6 +631,16 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
Operands.push_back(std::make_unique<WebAssemblyOperand>(
WebAssemblyOperand::Symbol, Loc.getLoc(), Loc.getEndLoc(),
WebAssemblyOperand::SymOp{Expr}));
+
+ // Allow additional operands after the signature, notably for
+ // call_indirect against a named table.
+ if (Lexer.isNot(AsmToken::EndOfStatement)) {
+ if (expect(AsmToken::Comma, ","))
+ return true;
+ if (Lexer.is(AsmToken::EndOfStatement)) {
+ return error("Unexpected trailing comma");
+ }
+ }
}
while (Lexer.isNot(AsmToken::EndOfStatement)) {
@@ -623,6 +666,11 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
WebAssemblyOperand::Integer, Id.getLoc(), Id.getEndLoc(),
WebAssemblyOperand::IntOp{static_cast<int64_t>(HeapType)}));
Parser.Lex();
+ } else if (ExpectFunctionTable) {
+ if (addFunctionTableOperand(Operands, Id.getString(), Id.getLoc(),
+ Id.getEndLoc()))
+ return true;
+ Parser.Lex();
} else {
// Assume this identifier is a label.
const MCExpr *Val;
@@ -689,6 +737,12 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
// Support blocks with no operands as default to void.
addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void);
}
+ if (ExpectFunctionTable && Operands.size() == 2) {
+ // If call_indirect doesn't specify a target table, supply one.
+ if (addDefaultFunctionTableOperand(Operands, NameLoc,
+ SMLoc::getFromPointer(Name.end())))
+ return true;
+ }
Parser.Lex();
return false;
}
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index 39b95da94e7c..f1afefd2c7c5 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -68,7 +68,7 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
for (auto I = Start, E = MI->getNumOperands(); I < E; ++I) {
if (MI->getOpcode() == WebAssembly::CALL_INDIRECT &&
I - Start == NumVariadicDefs) {
- // Skip type and flags arguments when printing for tests
+ // Skip type and table arguments when printing for tests.
++I;
continue;
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index 7f1c4bb40a4c..bef6d585a6fc 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -23,6 +23,7 @@
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblyRegisterInfo.h"
#include "WebAssemblyTargetMachine.h"
+#include "WebAssemblyUtilities.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/Wasm.h"
@@ -171,19 +172,25 @@ MCSymbolWasm *WebAssemblyAsmPrinter::getMCSymbolForFunction(
void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) {
for (auto &It : OutContext.getSymbols()) {
- // Emit a .globaltype and .eventtype declaration.
+ // Emit .globaltype, .eventtype, 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);
+ else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_TABLE)
+ getTargetStreamer()->emitTableType(Sym);
}
DenseSet<MCSymbol *> InvokeSymbols;
+ bool HasAddressTakenFunction = false;
for (const auto &F : M) {
if (F.isIntrinsic())
continue;
+ if (F.hasAddressTaken())
+ HasAddressTakenFunction = true;
+
// Emit function type info for all undefined functions
if (F.isDeclarationForLinker()) {
SmallVector<MVT, 4> Results;
@@ -242,6 +249,18 @@ void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &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.
+ if (HasAddressTakenFunction) {
+ MCSymbolWasm *FunctionTable =
+ WebAssembly::getOrCreateFunctionTableSymbol(OutContext, Subtarget);
+ OutStreamer->emitSymbolAttribute(FunctionTable, MCSA_NoDeadStrip);
+ }
+
for (const auto &G : M.globals()) {
if (!G.hasInitializer() && G.hasExternalLinkage()) {
if (G.getValueType()->isSized()) {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
index 509f2be8de59..d60c1624ff16 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
@@ -869,19 +869,20 @@ bool WebAssemblyFastISel::selectCall(const Instruction *I) {
if (IsDirect) {
MIB.addGlobalAddress(Func);
} else {
- // Add placeholders for the type index and immediate flags
+ // Placehoder for the type index.
MIB.addImm(0);
- MIB.addImm(0);
-
- // Ensure that the object file has a __indirect_function_table import, as we
- // call_indirect against it.
- MCSymbolWasm *Sym = WebAssembly::getOrCreateFunctionTableSymbol(
- MF->getMMI().getContext(), "__indirect_function_table");
- // Until call_indirect emits TABLE_NUMBER relocs against this symbol, mark
- // it as NO_STRIP so as to ensure that the indirect function table makes it
- // to linked output.
- Sym->setNoStrip();
-
+ // The table into which this call_indirect indexes.
+ MCSymbolWasm *Table = WebAssembly::getOrCreateFunctionTableSymbol(
+ MF->getMMI().getContext(), Subtarget);
+ if (Subtarget->hasReferenceTypes()) {
+ MIB.addSym(Table);
+ } else {
+ // Otherwise for the MVP there is at most one table whose number is 0, but
+ // we can't write a table symbol or issue relocations. Instead we just
+ // ensure the table is live.
+ Table->setNoStrip();
+ MIB.addImm(0);
+ }
// See if we must truncate the function pointer.
// CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers
// as 64-bit for uniformity with other pointer types.
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index d8680fae0c93..a515a5f4aef2 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -426,9 +426,10 @@ static MachineBasicBlock *LowerFPToInt(MachineInstr &MI, DebugLoc DL,
return DoneMBB;
}
-static MachineBasicBlock *LowerCallResults(MachineInstr &CallResults,
- DebugLoc DL, MachineBasicBlock *BB,
- const TargetInstrInfo &TII) {
+static MachineBasicBlock *
+LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB,
+ const WebAssemblySubtarget *Subtarget,
+ const TargetInstrInfo &TII) {
MachineInstr &CallParams = *CallResults.getPrevNode();
assert(CallParams.getOpcode() == WebAssembly::CALL_PARAMS);
assert(CallResults.getOpcode() == WebAssembly::CALL_RESULTS ||
@@ -476,19 +477,21 @@ static MachineBasicBlock *LowerCallResults(MachineInstr &CallResults,
for (auto Def : CallResults.defs())
MIB.add(Def);
- // Add placeholders for the type index and immediate flags
if (IsIndirect) {
+ // Placeholder for the type index.
MIB.addImm(0);
- MIB.addImm(0);
-
- // Ensure that the object file has a __indirect_function_table import, as we
- // call_indirect against it.
- MCSymbolWasm *Sym = WebAssembly::getOrCreateFunctionTableSymbol(
- MF.getContext(), "__indirect_function_table");
- // Until call_indirect emits TABLE_NUMBER relocs against this symbol, mark
- // it as NO_STRIP so as to ensure that the indirect function table makes it
- // to linked output.
- Sym->setNoStrip();
+ // The table into which this call_indirect indexes.
+ MCSymbolWasm *Table =
+ WebAssembly::getOrCreateFunctionTableSymbol(MF.getContext(), Subtarget);
+ if (Subtarget->hasReferenceTypes()) {
+ MIB.addSym(Table);
+ } else {
+ // For the MVP there is at most one table whose number is 0, but we can't
+ // write a table symbol or issue relocations. Instead we just ensure the
+ // table is live and write a zero.
+ Table->setNoStrip();
+ MIB.addImm(0);
+ }
}
for (auto Use : CallParams.uses())
@@ -535,7 +538,7 @@ MachineBasicBlock *WebAssemblyTargetLowering::EmitInstrWithCustomInserter(
WebAssembly::I64_TRUNC_U_F64);
case WebAssembly::CALL_RESULTS:
case WebAssembly::RET_CALL_RESULTS:
- return LowerCallResults(MI, DL, BB, TII);
+ return LowerCallResults(MI, DL, BB, Subtarget, TII);
}
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
index b997c1c16fcb..6a123f8f4030 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
@@ -48,6 +48,9 @@ defm RET_CALL_RESULTS :
I<(outs), (ins variable_ops), (outs), (ins), [],
"return_call_results", "return_call_results", -1>;
+// Note that instructions with variable_ops have custom printers in
+// WebAssemblyInstPrinter.cpp.
+
let variadicOpsAreDefs = 1 in
defm CALL :
I<(outs), (ins function32_op:$callee, variable_ops),
@@ -56,9 +59,12 @@ defm CALL :
let variadicOpsAreDefs = 1 in
defm CALL_INDIRECT :
- I<(outs), (ins TypeIndex:$type, i32imm:$flags, variable_ops),
- (outs), (ins TypeIndex:$type, i32imm:$flags), [],
- "call_indirect", "call_indirect\t$type", 0x11>;
+ I<(outs),
+ (ins TypeIndex:$type, table32_op:$table, variable_ops),
+ (outs),
+ (ins TypeIndex:$type, table32_op:$table),
+ [],
+ "call_indirect", "call_indirect\t$type, $table", 0x11>;
let isReturn = 1, isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in
defm RET_CALL :
@@ -69,9 +75,9 @@ defm RET_CALL :
let isReturn = 1 in
defm RET_CALL_INDIRECT :
- I<(outs), (ins TypeIndex:$type, i32imm:$flags, variable_ops),
- (outs), (ins TypeIndex:$type, i32imm:$flags), [],
- "return_call_indirect\t", "return_call_indirect\t$type",
+ I<(outs), (ins TypeIndex:$type, table32_op:$table, variable_ops),
+ (outs), (ins TypeIndex:$type, table32_op:$table), [],
+ "return_call_indirect\t", "return_call_indirect\t$type, $table",
0x13>,
Requires<[HasTailCall]>;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index 280fbf9d4dbb..95f2744a84b0 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -161,6 +161,8 @@ MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
report_fatal_error("Global indexes with offsets not supported");
if (WasmSym->isEvent())
report_fatal_error("Event indexes with offsets not supported");
+ if (WasmSym->isTable())
+ report_fatal_error("Table indexes with offsets not supported");
Expr = MCBinaryExpr::createAdd(
Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
index f8fb57d8a461..32f77c05cc88 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
@@ -98,11 +98,9 @@ const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) {
}
}
-MCSymbolWasm *
-WebAssembly::getOrCreateFunctionTableSymbol(MCContext &Ctx,
- const StringRef &Name) {
- // FIXME: Duplicates functionality from
- // MC/WasmObjectWriter::recordRelocation.
+MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol(
+ MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
+ StringRef Name = "__indirect_function_table";
MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
if (Sym) {
if (!Sym->isFunctionTable())
@@ -113,6 +111,9 @@ WebAssembly::getOrCreateFunctionTableSymbol(MCContext &Ctx,
// The default function table is synthesized by the linker.
Sym->setUndefined();
}
+ // MVP object files can't have symtab entries for tables.
+ if (!Subtarget->hasReferenceTypes())
+ Sym->setOmitFromLinkingSection();
return Sym;
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h
index 41ad7869cf46..1398d7d9dfc2 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h
@@ -24,6 +24,7 @@ class MCContext;
class MCSymbolWasm;
class StringRef;
class WebAssemblyFunctionInfo;
+class WebAssemblySubtarget;
namespace WebAssembly {
@@ -41,10 +42,11 @@ extern const char *const PersonalityWrapperFn;
/// instruction.
const MachineOperand &getCalleeOp(const MachineInstr &MI);
-/// Returns the operand number of a callee, assuming the argument is a call
-/// instruction.
-MCSymbolWasm *getOrCreateFunctionTableSymbol(MCContext &Ctx,
- const StringRef &Name);
+/// Returns the __indirect_function_table, for use in call_indirect and in
+/// function bitcasts.
+MCSymbolWasm *
+getOrCreateFunctionTableSymbol(MCContext &Ctx,
+ const WebAssemblySubtarget *Subtarget);
/// Find a catch instruction from an EH pad. Returns null if no catch
/// instruction found or the catch is in an invalid location.
diff --git a/llvm/test/CodeGen/WebAssembly/function-pointer64.ll b/llvm/test/CodeGen/WebAssembly/function-pointer64.ll
index 6b279cfb6ec0..dd739d67e14c 100644
--- a/llvm/test/CodeGen/WebAssembly/function-pointer64.ll
+++ b/llvm/test/CodeGen/WebAssembly/function-pointer64.ll
@@ -1,4 +1,5 @@
; RUN: llc < %s -asm-verbose=false -O2 | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -mattr=+reference-types -O2 | FileCheck --check-prefix=REF %s
; RUN: llc < %s -asm-verbose=false -O2 --filetype=obj | obj2yaml | FileCheck --check-prefix=YAML %s
; This tests pointer features that may codegen
diff erently in wasm64.
@@ -34,14 +35,16 @@ entry:
; CHECK-NEXT: i32.const 1
; CHECK-NEXT: local.get 0
; CHECK-NEXT: i32.wrap_i64
-; CHECK-NEXT: call_indirect (i32) -> ()
+; CHECK-NEXT: call_indirect (i32) -> (), 0
+; REF: call_indirect (i32) -> (), __indirect_function_table
; CHECK: .functype test () -> ()
; CHECK-NEXT: i64.const bar
; CHECK-NEXT: call foo
-; Check we're emitting a 64-bit reloc for `i64.const bar` and the global.
+; Check we're emitting a 64-bit relocs for the call_indirect, the
+; `i64.const bar` reference in code, and the global.
; YAML: Memory:
; YAML-NEXT: Flags: [ IS_64 ]
@@ -51,6 +54,9 @@ entry:
; YAML: - Type: R_WASM_TABLE_INDEX_SLEB64
; YAML-NEXT: Index: 0
; YAML-NEXT: Offset: 0x16
+; YAML: - Type: R_WASM_TABLE_INDEX_SLEB64
+; YAML-NEXT: Index: 0
+; YAML-NEXT: Offset: 0x29
; YAML: - Type: DATA
; YAML: - Type: R_WASM_TABLE_INDEX_I64
diff --git a/llvm/test/CodeGen/WebAssembly/multivalue.ll b/llvm/test/CodeGen/WebAssembly/multivalue.ll
index d5dfcacb6a2b..a57e2cf7fddf 100644
--- a/llvm/test/CodeGen/WebAssembly/multivalue.ll
+++ b/llvm/test/CodeGen/WebAssembly/multivalue.ll
@@ -1,4 +1,5 @@
; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -mattr=+multivalue,+tail-call | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -mattr=+reference-types,+multivalue,+tail-call | FileCheck --check-prefix REF %s
; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+multivalue,+tail-call | FileCheck %s --check-prefix REGS
; RUN: llc < %s --filetype=obj -mattr=+multivalue,+tail-call | obj2yaml | FileCheck %s --check-prefix OBJ
@@ -57,7 +58,8 @@ define %pair @pair_call_return() {
; CHECK-LABEL: pair_call_indirect:
; CHECK-NEXT: .functype pair_call_indirect (i32) -> (i32, i64)
; CHECK-NEXT: local.get 0{{$}}
-; CHECK-NEXT: call_indirect () -> (i32, i64){{$}}
+; CHECK-NEXT: call_indirect () -> (i32, i64), 0{{$}}
+; REF: call_indirect () -> (i32, i64), __indirect_function_table{{$}}
; CHECK-NEXT: end_function{{$}}
; REGS: call_indirect $push{{[0-9]+}}=, $push{{[0-9]+}}=, $0{{$}}
define %pair @pair_call_indirect(%pair()* %f) {
diff --git a/llvm/test/MC/WebAssembly/basic-assembly.s b/llvm/test/MC/WebAssembly/basic-assembly.s
index 5da08d6781ab..dcfd9addb061 100644
--- a/llvm/test/MC/WebAssembly/basic-assembly.s
+++ b/llvm/test/MC/WebAssembly/basic-assembly.s
@@ -1,6 +1,6 @@
-# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+atomics,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types,atomics,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s
# Check that it converts to .o without errors, but don't check any output:
-# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+atomics,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling -o %t.o < %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+reference-types,+atomics,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling -o %t.o < %s
empty_func:
@@ -156,7 +156,7 @@ empty_fref_table:
# CHECK-NEXT: i64.const 1234
# CHECK-NEXT: call something2
# CHECK-NEXT: i32.const 0
-# CHECK-NEXT: call_indirect (i32, f64) -> ()
+# CHECK-NEXT: call_indirect (i32, f64) -> (), __indirect_function_table
# CHECK-NEXT: i32.const 1
# CHECK-NEXT: i32.add
# CHECK-NEXT: local.tee 0
diff --git a/llvm/test/MC/WebAssembly/call-indirect-relocs.s b/llvm/test/MC/WebAssembly/call-indirect-relocs.s
new file mode 100644
index 000000000000..4244fbf3abea
--- /dev/null
+++ b/llvm/test/MC/WebAssembly/call-indirect-relocs.s
@@ -0,0 +1,83 @@
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types < %s | FileCheck --check-prefix=CHECK %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types -filetype=obj < %s | obj2yaml | FileCheck -check-prefix=BIN %s
+
+test0:
+ .functype test0 () -> ()
+ i32.const 42
+ f64.const 2.5
+ i32.const 0
+ call_indirect (i32, f64) -> (), empty_fref_table
+ end_function
+
+.tabletype empty_fref_table, funcref
+empty_fref_table:
+
+
+# CHECK: .text
+# CHECK-LABEL: test0:
+# CHECK-NEXT: .functype test0 () -> ()
+# CHECK-NEXT: i32.const 42
+# CHECK-NEXT: f64.const 0x1.4p1
+# CHECK-NEXT: i32.const 0
+# CHECK-NEXT: call_indirect (i32, f64) -> (), empty_fref_table
+# CHECK-NEXT: end_function
+
+# CHECK: .tabletype empty_fref_table, funcref
+# CHECK: empty_fref_table:
+
+# BIN: --- !WASM
+# BIN-NEXT: FileHeader:
+# BIN-NEXT: Version: 0x1
+# BIN-NEXT: Sections:
+# BIN-NEXT: - Type: TYPE
+# BIN-NEXT: Signatures:
+# BIN-NEXT: - Index: 0
+# BIN-NEXT: ParamTypes: []
+# BIN-NEXT: ReturnTypes: []
+# BIN-NEXT: - Index: 1
+# BIN-NEXT: ParamTypes:
+# BIN-NEXT: - I32
+# BIN-NEXT: - F64
+# BIN-NEXT: ReturnTypes: []
+# BIN-NEXT: - Type: IMPORT
+# BIN-NEXT: Imports:
+# BIN-NEXT: - Module: env
+# BIN-NEXT: Field: __linear_memory
+# BIN-NEXT: Kind: MEMORY
+# BIN-NEXT: Memory:
+# BIN-NEXT: Initial: 0x0
+# BIN-NEXT: - Type: FUNCTION
+# BIN-NEXT: FunctionTypes: [ 0 ]
+# BIN-NEXT: - Type: TABLE
+# BIN-NEXT: Tables:
+# BIN-NEXT: - Index: 0
+# BIN-NEXT: ElemType: FUNCREF
+# BIN-NEXT: Limits:
+# BIN-NEXT: Initial: 0x0
+# BIN-NEXT: - Type: CODE
+# BIN-NEXT: Relocations:
+# BIN-NEXT: - Type: R_WASM_TYPE_INDEX_LEB
+# BIN-NEXT: Index: 1
+# BIN-NEXT: Offset: 0x11
+# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
+# BIN-NEXT: Index: 1
+# BIN-NEXT: Offset: 0x16
+# BIN-NEXT: Functions:
+# BIN-NEXT: - Index: 0
+# BIN-NEXT: Locals: []
+# BIN-NEXT: Body: 412A440000000000000440410011818080800080808080000B
+# BIN-NEXT: - Type: CUSTOM
+# BIN-NEXT: Name: linking
+# BIN-NEXT: Version: 2
+# BIN-NEXT: SymbolTable:
+# BIN-NEXT: - Index: 0
+# BIN-NEXT: Kind: FUNCTION
+# BIN-NEXT: Name: test0
+# BIN-NEXT: Flags: [ BINDING_LOCAL ]
+# BIN-NEXT: Function: 0
+# BIN-NEXT: - Index: 1
+# BIN-NEXT: Kind: TABLE
+# BIN-NEXT: Name: empty_fref_table
+# BIN-NEXT: Flags: [ BINDING_LOCAL ]
+# BIN-NEXT: Table: 0
+# BIN-NEXT: ...
diff --git a/llvm/test/MC/WebAssembly/function-alias.ll b/llvm/test/MC/WebAssembly/function-alias.ll
index ec571083344b..83923475fae7 100644
--- a/llvm/test/MC/WebAssembly/function-alias.ll
+++ b/llvm/test/MC/WebAssembly/function-alias.ll
@@ -1,4 +1,5 @@
; RUN: llc -filetype=obj %s -o - | llvm-readobj --symbols - | FileCheck %s
+; RUN: llc -filetype=obj %s -mattr=+reference-types -o - | llvm-readobj --symbols - | FileCheck --check-prefix=REF %s
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-unknown-wasm"
@@ -42,3 +43,44 @@ define i8* @func() {
; CHECK-NEXT: ElementIndex: 0x0
; CHECK-NEXT: }
; CHECK-NEXT: ]
+
+; REF: Symbols [
+; REF-NEXT: Symbol {
+; REF-NEXT: Name: func
+; REF-NEXT: Type: FUNCTION (0x0)
+; REF-NEXT: Flags [ (0x0)
+; REF-NEXT: ]
+; REF-NEXT: ElementIndex: 0x0
+; REF-NEXT: }
+; REF-NEXT: Symbol {
+; REF-NEXT: Name: bar2
+; REF-NEXT: Type: FUNCTION (0x0)
+; REF-NEXT: Flags [ (0x0)
+; REF-NEXT: ]
+; REF-NEXT: ElementIndex: 0x0
+; REF-NEXT: }
+; REF-NEXT: Symbol {
+; REF-NEXT: Name: foo
+; REF-NEXT: Type: FUNCTION (0x0)
+; REF-NEXT: Flags [ (0x0)
+; REF-NEXT: ]
+; REF-NEXT: ElementIndex: 0x0
+; REF-NEXT: }
+; REF-NEXT: Symbol {
+; REF-NEXT: Name: bar
+; REF-NEXT: Type: FUNCTION (0x0)
+; REF-NEXT: Flags [ (0x0)
+; REF-NEXT: ]
+; REF-NEXT: ElementIndex: 0x0
+; REF-NEXT: }
+; REF-NEXT: Symbol {
+; REF-NEXT: Name: __indirect_function_table
+; REF-NEXT: Type: TABLE (0x5)
+; REF-NEXT: Flags [ (0x90)
+; REF-NEXT: NO_STRIP (0x80)
+; REF-NEXT: UNDEFINED (0x10)
+; REF-NEXT: ]
+; REF-NEXT: ImportModule: env
+; REF-NEXT: ElementIndex: 0x0
+; REF-NEXT: }
+; REF-NEXT: ]
diff --git a/llvm/test/MC/WebAssembly/reloc-code.ll b/llvm/test/MC/WebAssembly/reloc-code.ll
index 0aafeabec5ca..e80fbcf80cd3 100644
--- a/llvm/test/MC/WebAssembly/reloc-code.ll
+++ b/llvm/test/MC/WebAssembly/reloc-code.ll
@@ -1,4 +1,5 @@
; RUN: llc -filetype=obj %s -o - | llvm-readobj -r --expand-relocs - | FileCheck %s
+; RUN: llc -filetype=obj -mattr=+reference-types %s -o - | llvm-readobj -r --expand-relocs - | FileCheck --check-prefix=REF %s
target triple = "wasm32-unknown-unknown"
@@ -59,3 +60,51 @@ entry:
; CHECK-NEXT: }
; CHECK-NEXT: }
; CHECK-NEXT: ]
+
+; REF: Format: WASM
+; REF: Relocations [
+; REF-NEXT: Section (5) CODE {
+; REF-NEXT: Relocation {
+; REF-NEXT: Type: R_WASM_MEMORY_ADDR_LEB (3)
+; REF-NEXT: Offset: 0x9
+; REF-NEXT: Symbol: b
+; REF-NEXT: Addend: 0
+; REF-NEXT: }
+; REF-NEXT: Relocation {
+; REF-NEXT: Type: R_WASM_MEMORY_ADDR_LEB (3)
+; REF-NEXT: Offset: 0x14
+; REF-NEXT: Symbol: a
+; REF-NEXT: Addend: 0
+; REF-NEXT: }
+; REF-NEXT: Relocation {
+; REF-NEXT: Type: R_WASM_TYPE_INDEX_LEB (6)
+; REF-NEXT: Offset: 0x1A
+; REF-NEXT: Index: 0x1
+; REF-NEXT: }
+; REF-NEXT: Relocation {
+; REF-NEXT: Type: R_WASM_TABLE_NUMBER_LEB (20)
+; REF-NEXT: Offset: 0x1F
+; REF-NEXT: Symbol: __indirect_function_table
+; REF-NEXT: }
+; REF-NEXT: Relocation {
+; REF-NEXT: Type: R_WASM_TYPE_INDEX_LEB (6)
+; REF-NEXT: Offset: 0x28
+; REF-NEXT: Index: 0x0
+; REF-NEXT: }
+; REF-NEXT: Relocation {
+; REF-NEXT: Type: R_WASM_TABLE_NUMBER_LEB (20)
+; REF-NEXT: Offset: 0x2D
+; REF-NEXT: Symbol: __indirect_function_table
+; REF-NEXT: }
+; REF-NEXT: Relocation {
+; REF-NEXT: Type: R_WASM_FUNCTION_INDEX_LEB (0)
+; REF-NEXT: Offset: 0x35
+; REF-NEXT: Symbol: c
+; REF-NEXT: }
+; REF-NEXT: Relocation {
+; REF-NEXT: Type: R_WASM_FUNCTION_INDEX_LEB (0)
+; REF-NEXT: Offset: 0x3C
+; REF-NEXT: Symbol: d
+; REF-NEXT: }
+; REF-NEXT: }
+; REF-NEXT: ]
diff --git a/llvm/test/MC/WebAssembly/reloc-pic.s b/llvm/test/MC/WebAssembly/reloc-pic.s
index b7995ebf97fa..477b2cb8ac5e 100644
--- a/llvm/test/MC/WebAssembly/reloc-pic.s
+++ b/llvm/test/MC/WebAssembly/reloc-pic.s
@@ -1,4 +1,5 @@
# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj < %s | obj2yaml | FileCheck %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types -filetype=obj < %s | obj2yaml | FileCheck --check-prefix=REF %s
# Verify that @GOT relocation entryes result in R_WASM_GLOBAL_INDEX_LEB against
# against the corrsponding function or data symbol and that the corresponding
@@ -190,6 +191,11 @@ hidden_func:
# CHECK-NEXT: Name: hidden_func
# CHECK-NEXT: Flags: [ BINDING_LOCAL ]
# CHECK-NEXT: Function: 5
+# REF: - Index: 10
+# REF-NEXT: Kind: TABLE
+# REF-NEXT: Name: __indirect_function_table
+# REF-NEXT: Flags: [ UNDEFINED, NO_STRIP ]
+# REF-NEXT: Table: 0
# CHECK-NEXT: SegmentInfo:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: Name: .rodata.hidden_data
diff --git a/llvm/test/MC/WebAssembly/tail-call-encodings.s b/llvm/test/MC/WebAssembly/tail-call-encodings.s
index 405e6337f5fa..20bfb2e84a24 100644
--- a/llvm/test/MC/WebAssembly/tail-call-encodings.s
+++ b/llvm/test/MC/WebAssembly/tail-call-encodings.s
@@ -1,4 +1,5 @@
# RUN: llvm-mc -show-encoding -triple=wasm32-unknown-unknown -mattr=+tail-call < %s | FileCheck %s
+# RUN: llvm-mc -show-encoding -triple=wasm32-unknown-unknown -mattr=+reference-types,+tail-call < %s | FileCheck --check-prefix=REF %s
bar1:
.functype bar1 () -> ()
@@ -16,7 +17,8 @@ foo1:
foo2:
.functype foo2 () -> ()
- # CHECK: return_call_indirect (i32) -> (i32) # encoding: [0x13,
+ # REF: return_call_indirect (i32) -> (i32), __indirect_function_table # encoding: [0x13,
+ # CHECK: return_call_indirect (i32) -> (i32), 0 # encoding: [0x13,
# CHECK-NEXT: fixup A - offset: 1, value: .Ltypeindex0 at TYPEINDEX, kind: fixup_uleb128_i32
return_call_indirect (i32) -> (i32)
diff --git a/llvm/test/MC/WebAssembly/type-index.s b/llvm/test/MC/WebAssembly/type-index.s
index 298e5e2f9de3..dd6581b826f5 100644
--- a/llvm/test/MC/WebAssembly/type-index.s
+++ b/llvm/test/MC/WebAssembly/type-index.s
@@ -1,8 +1,8 @@
-# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s
# Check that it converts to .o without errors:
-# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | obj2yaml | FileCheck -check-prefix=BIN %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+reference-types,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | obj2yaml | FileCheck -check-prefix=BIN %s
-# Minimal test for type indices in call_indirect.
+# Minimal test for type indices and table references in call_indirect.
test0:
.functype test0 (i32) -> (i32)
@@ -53,10 +53,13 @@ test0:
# BIN-NEXT: - Type: R_WASM_TYPE_INDEX_LEB
# BIN-NEXT: Index: 1
# BIN-NEXT: Offset: 0x4
+# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
+# BIN-NEXT: Index: 1
+# BIN-NEXT: Offset: 0x9
# BIN-NEXT: Functions:
# BIN-NEXT: - Index: 0
# BIN-NEXT: Locals: []
-# BIN-NEXT: Body: 118180808000000B
+# BIN-NEXT: Body: 11818080800080808080000B
# BIN-NEXT: - Type: CUSTOM
# BIN-NEXT: Name: linking
# BIN-NEXT: Version: 2
@@ -66,4 +69,9 @@ test0:
# BIN-NEXT: Name: test0
# BIN-NEXT: Flags: [ BINDING_LOCAL ]
# BIN-NEXT: Function: 0
+# BIN-NEXT: - Index: 1
+# BIN-NEXT: Kind: TABLE
+# BIN-NEXT: Name: __indirect_function_table
+# BIN-NEXT: Flags: [ UNDEFINED ]
+# BIN-NEXT: Table: 0
# BIN-NEXT: ...
diff --git a/llvm/test/MC/WebAssembly/weak-alias.s b/llvm/test/MC/WebAssembly/weak-alias.s
index 4590e0020382..48bfc0b7a58d 100644
--- a/llvm/test/MC/WebAssembly/weak-alias.s
+++ b/llvm/test/MC/WebAssembly/weak-alias.s
@@ -1,5 +1,5 @@
-# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -o %t.o < %s
-# RUN: obj2yaml %t.o | FileCheck %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj < %s | obj2yaml | FileCheck --check-prefix=CHECK %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types -filetype=obj < %s | obj2yaml | FileCheck --check-prefix=REF %s
# 'foo_alias()' is weak alias of function 'foo()'
# 'bar_alias' is weak alias of global variable 'bar'
@@ -78,7 +78,7 @@ alias_address:
# CHECK: - Type: TYPE
# CHECK-NEXT: Signatures:
# CHECK-NEXT: - Index: 0
-# CHECK-NEXT: ParamTypes:
+# CHECK-NEXT: ParamTypes: []
# CHECK-NEXT: ReturnTypes:
# CHECK-NEXT: - I32
# CHECK-NEXT: - Type: IMPORT
@@ -128,19 +128,19 @@ alias_address:
# CHECK-NEXT: Offset: 0x37
# CHECK-NEXT: Functions:
# CHECK-NEXT: - Index: 0
-# CHECK-NEXT: Locals:
+# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 41000B
# CHECK-NEXT: - Index: 1
-# CHECK-NEXT: Locals:
+# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 1080808080000B
# CHECK-NEXT: - Index: 2
-# CHECK-NEXT: Locals:
+# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 1080808080000B
# CHECK-NEXT: - Index: 3
-# CHECK-NEXT: Locals:
+# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 410028028880808000118080808000000B
# CHECK-NEXT: - Index: 4
-# CHECK-NEXT: Locals:
+# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 410028029080808000118080808000000B
# CHECK-NEXT: - Type: DATA
# CHECK-NEXT: Relocations:
@@ -231,17 +231,195 @@ alias_address:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: Name: .data.bar
# CHECK-NEXT: Alignment: 3
-# CHECK-NEXT: Flags: [ ]
+# CHECK-NEXT: Flags: [ ]
# CHECK-NEXT: - Index: 1
# CHECK-NEXT: Name: .data.direct_address
# CHECK-NEXT: Alignment: 3
-# CHECK-NEXT: Flags: [ ]
+# CHECK-NEXT: Flags: [ ]
# CHECK-NEXT: - Index: 2
# CHECK-NEXT: Name: .data.alias_address
# CHECK-NEXT: Alignment: 3
-# CHECK-NEXT: Flags: [ ]
+# CHECK-NEXT: Flags: [ ]
# CHECK-NEXT: ...
+# REF: - Type: TYPE
+# REF-NEXT: Signatures:
+# REF-NEXT: - Index: 0
+# REF-NEXT: ParamTypes: []
+# REF-NEXT: ReturnTypes:
+# REF-NEXT: - I32
+# REF-NEXT: - Type: IMPORT
+# REF-NEXT: Imports:
+# REF-NEXT: - Module: env
+# REF-NEXT: Field: __linear_memory
+# REF-NEXT: Kind: MEMORY
+# REF-NEXT: Memory:
+# REF-NEXT: Initial: 0x1
+# REF-NEXT: - Module: env
+# REF-NEXT: Field: __indirect_function_table
+# REF-NEXT: Kind: TABLE
+# REF-NEXT: Table:
+# REF-NEXT: Index: 0
+# REF-NEXT: ElemType: FUNCREF
+# REF-NEXT: Limits:
+# REF-NEXT: Initial: 0x1
+# REF-NEXT: - Type: FUNCTION
+# REF-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0 ]
+# REF-NEXT: - Type: ELEM
+# REF-NEXT: Segments:
+# REF-NEXT: - Offset:
+# REF-NEXT: Opcode: I32_CONST
+# REF-NEXT: Value: 1
+# REF-NEXT: Functions: [ 0 ]
+# REF-NEXT: - Type: DATACOUNT
+# REF-NEXT: Count: 3
+# REF-NEXT: - Type: CODE
+# REF-NEXT: Relocations:
+# REF-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB
+# REF-NEXT: Index: 0
+# REF-NEXT: Offset: 0x9
+# REF-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB
+# REF-NEXT: Index: 3
+# REF-NEXT: Offset: 0x12
+# REF-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB
+# REF-NEXT: Index: 5
+# REF-NEXT: Offset: 0x1E
+# REF-NEXT: - Type: R_WASM_TYPE_INDEX_LEB
+# REF-NEXT: Index: 0
+# REF-NEXT: Offset: 0x24
+# REF-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
+# REF-NEXT: Index: 6
+# REF-NEXT: Offset: 0x29
+# REF-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB
+# REF-NEXT: Index: 8
+# REF-NEXT: Offset: 0x35
+# REF-NEXT: - Type: R_WASM_TYPE_INDEX_LEB
+# REF-NEXT: Index: 0
+# REF-NEXT: Offset: 0x3B
+# REF-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
+# REF-NEXT: Index: 6
+# REF-NEXT: Offset: 0x40
+# REF-NEXT: Functions:
+# REF-NEXT: - Index: 0
+# REF-NEXT: Locals: []
+# REF-NEXT: Body: 41000B
+# REF-NEXT: - Index: 1
+# REF-NEXT: Locals: []
+# REF-NEXT: Body: 1080808080000B
+# REF-NEXT: - Index: 2
+# REF-NEXT: Locals: []
+# REF-NEXT: Body: 1080808080000B
+# REF-NEXT: - Index: 3
+# REF-NEXT: Locals: []
+# REF-NEXT: Body: 41002802888080800011808080800080808080000B
+# REF-NEXT: - Index: 4
+# REF-NEXT: Locals: []
+# REF-NEXT: Body: 41002802908080800011808080800080808080000B
+# REF-NEXT: - Type: DATA
+# REF-NEXT: Relocations:
+# REF-NEXT: - Type: R_WASM_TABLE_INDEX_I32
+# REF-NEXT: Index: 0
+# REF-NEXT: Offset: 0x13
+# REF-NEXT: - Type: R_WASM_TABLE_INDEX_I32
+# REF-NEXT: Index: 3
+# REF-NEXT: Offset: 0x20
+# REF-NEXT: Segments:
+# REF-NEXT: - SectionOffset: 6
+# REF-NEXT: InitFlags: 0
+# REF-NEXT: Offset:
+# REF-NEXT: Opcode: I32_CONST
+# REF-NEXT: Value: 0
+# REF-NEXT: Content: '0700000000000000'
+# REF-NEXT: - SectionOffset: 19
+# REF-NEXT: InitFlags: 0
+# REF-NEXT: Offset:
+# REF-NEXT: Opcode: I32_CONST
+# REF-NEXT: Value: 8
+# REF-NEXT: Content: '0100000000000000'
+# REF-NEXT: - SectionOffset: 32
+# REF-NEXT: InitFlags: 0
+# REF-NEXT: Offset:
+# REF-NEXT: Opcode: I32_CONST
+# REF-NEXT: Value: 16
+# REF-NEXT: Content: '0100000000000000'
+# REF-NEXT: - Type: CUSTOM
+# REF-NEXT: Name: linking
+# REF-NEXT: Version: 2
+# REF-NEXT: SymbolTable:
+# REF-NEXT: - Index: 0
+# REF-NEXT: Kind: FUNCTION
+# REF-NEXT: Name: foo
+# REF-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+# REF-NEXT: Function: 0
+# REF-NEXT: - Index: 1
+# REF-NEXT: Kind: FUNCTION
+# REF-NEXT: Name: call_direct
+# REF-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+# REF-NEXT: Function: 1
+# REF-NEXT: - Index: 2
+# REF-NEXT: Kind: FUNCTION
+# REF-NEXT: Name: call_alias
+# REF-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+# REF-NEXT: Function: 2
+# REF-NEXT: - Index: 3
+# REF-NEXT: Kind: FUNCTION
+# REF-NEXT: Name: foo_alias
+# REF-NEXT: Flags: [ BINDING_WEAK, VISIBILITY_HIDDEN, NO_STRIP ]
+# REF-NEXT: Function: 0
+# REF-NEXT: - Index: 4
+# REF-NEXT: Kind: FUNCTION
+# REF-NEXT: Name: call_direct_ptr
+# REF-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+# REF-NEXT: Function: 3
+# REF-NEXT: - Index: 5
+# REF-NEXT: Kind: DATA
+# REF-NEXT: Name: direct_address
+# REF-NEXT: Flags: [ ]
+# REF-NEXT: Segment: 1
+# REF-NEXT: Size: 4
+# REF-NEXT: - Index: 6
+# REF-NEXT: Kind: TABLE
+# REF-NEXT: Name: __indirect_function_table
+# REF-NEXT: Flags: [ UNDEFINED, NO_STRIP ]
+# REF-NEXT: Table: 0
+# REF-NEXT: - Index: 7
+# REF-NEXT: Kind: FUNCTION
+# REF-NEXT: Name: call_alias_ptr
+# REF-NEXT: Flags: [ VISIBILITY_HIDDEN ]
+# REF-NEXT: Function: 4
+# REF-NEXT: - Index: 8
+# REF-NEXT: Kind: DATA
+# REF-NEXT: Name: alias_address
+# REF-NEXT: Flags: [ ]
+# REF-NEXT: Segment: 2
+# REF-NEXT: Size: 4
+# REF-NEXT: - Index: 9
+# REF-NEXT: Kind: DATA
+# REF-NEXT: Name: bar
+# REF-NEXT: Flags: [ ]
+# REF-NEXT: Segment: 0
+# REF-NEXT: Size: 4
+# REF-NEXT: - Index: 10
+# REF-NEXT: Kind: DATA
+# REF-NEXT: Name: bar_alias
+# REF-NEXT: Flags: [ BINDING_WEAK, VISIBILITY_HIDDEN, NO_STRIP ]
+# REF-NEXT: Segment: 0
+# REF-NEXT: Size: 4
+# REF-NEXT: SegmentInfo:
+# REF-NEXT: - Index: 0
+# REF-NEXT: Name: .data.bar
+# REF-NEXT: Alignment: 3
+# REF-NEXT: Flags: [ ]
+# REF-NEXT: - Index: 1
+# REF-NEXT: Name: .data.direct_address
+# REF-NEXT: Alignment: 3
+# REF-NEXT: Flags: [ ]
+# REF-NEXT: - Index: 2
+# REF-NEXT: Name: .data.alias_address
+# REF-NEXT: Alignment: 3
+# REF-NEXT: Flags: [ ]
+# REF-NEXT: ...
+
# CHECK-SYMS: SYMBOL TABLE:
# CHECK-SYMS-NEXT: 00000001 g F CODE .hidden foo
# CHECK-SYMS-NEXT: 00000006 g F CODE .hidden call_direct
More information about the llvm-commits
mailing list