diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h --- a/llvm/include/llvm/MC/MCContext.h +++ b/llvm/include/llvm/MC/MCContext.h @@ -446,6 +446,16 @@ /// inline assembly. void registerInlineAsmLabel(MCSymbol *Sym); + /// getOrCreateWasmFunctionTableSymbol - Gets or creates a symbol denoting a + /// WebAssembly table holding elements of type funcref. + MCSymbol *getOrCreateWasmFunctionTableSymbol(StringRef TableName); + + /// getOrCreateWasmDefaultFunctionTableSymbol - By default, all WebAssembly + /// functions that can be called indirectly are put into a single well-known + /// function table, conventionally called __indirect_function_table. This + /// table's definition is synthesized by the linker. + MCSymbol *getOrCreateWasmDefaultFunctionTableSymbol(); + /// @} /// \name Section Management diff --git a/llvm/include/llvm/MC/MCSymbolWasm.h b/llvm/include/llvm/MC/MCSymbolWasm.h --- a/llvm/include/llvm/MC/MCSymbolWasm.h +++ b/llvm/include/llvm/MC/MCSymbolWasm.h @@ -96,6 +96,15 @@ StringRef getExportName() const { return ExportName.getValue(); } void setExportName(StringRef Name) { ExportName = Name; } + bool isFunctionTable() const { + return isTable() && hasTableType() && + getTableType() == wasm::ValType::FUNCREF; + } + void setFunctionTable() { + setType(wasm::WASM_SYMBOL_TYPE_TABLE); + setTableType(wasm::ValType::FUNCREF); + } + void setUsedInGOT() const { IsUsedInGOT = true; } bool isUsedInGOT() const { return IsUsedInGOT; } @@ -111,8 +120,9 @@ } void setGlobalType(wasm::WasmGlobalType GT) { GlobalType = GT; } - const wasm::ValType &getTableType() const { - assert(TableType.hasValue()); + bool hasTableType() const { return TableType.hasValue(); } + wasm::ValType getTableType() const { + assert(hasTableType()); return TableType.getValue(); } void setTableType(wasm::ValType TT) { TableType = TT; } diff --git a/llvm/include/llvm/MC/MCWasmStreamer.h b/llvm/include/llvm/MC/MCWasmStreamer.h --- a/llvm/include/llvm/MC/MCWasmStreamer.h +++ b/llvm/include/llvm/MC/MCWasmStreamer.h @@ -59,8 +59,6 @@ SMLoc Loc = SMLoc()) override; void emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment = 0) override; - void emitValueImpl(const MCExpr *Value, unsigned Size, - SMLoc Loc = SMLoc()) override; void emitIdent(StringRef IdentString) override; diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h --- a/llvm/include/llvm/Object/Wasm.h +++ b/llvm/include/llvm/Object/Wasm.h @@ -299,6 +299,7 @@ uint32_t DataSection = 0; uint32_t EventSection = 0; uint32_t GlobalSection = 0; + uint32_t TableSection = 0; }; class WasmSectionOrderChecker { diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp --- a/llvm/lib/MC/MCContext.cpp +++ b/llvm/lib/MC/MCContext.cpp @@ -301,6 +301,24 @@ InlineAsmUsedLabelNames[Sym->getName()] = Sym; } +MCSymbol *MCContext::getOrCreateWasmFunctionTableSymbol(StringRef TableName) { + if (auto Sym = cast_or_null(Symbols.lookup(TableName))) { + if (!Sym->isFunctionTable()) + reportError(SMLoc(), "symbol is not a wasm funcref table"); + return Sym; + } + auto Sym = cast(getOrCreateSymbol(TableName)); + Sym->setFunctionTable(); + return Sym; +} + +MCSymbol *MCContext::getOrCreateWasmDefaultFunctionTableSymbol() { + auto Sym = getOrCreateWasmFunctionTableSymbol("__indirect_function_table"); + // The default function table is synthesized by the linker. + Sym->setUndefined(); + return Sym; +} + MCSymbolXCOFF * MCContext::createXCOFFSymbolImpl(const StringMapEntry *Name, bool IsTemporary) { diff --git a/llvm/lib/MC/MCWasmStreamer.cpp b/llvm/lib/MC/MCWasmStreamer.cpp --- a/llvm/lib/MC/MCWasmStreamer.cpp +++ b/llvm/lib/MC/MCWasmStreamer.cpp @@ -148,11 +148,6 @@ llvm_unreachable("Local common symbols are not yet implemented for Wasm"); } -void MCWasmStreamer::emitValueImpl(const MCExpr *Value, unsigned Size, - SMLoc Loc) { - MCObjectStreamer::emitValueImpl(Value, Size, Loc); -} - void MCWasmStreamer::emitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -40,8 +40,8 @@ namespace { -// Went we ceate the indirect function table we start at 1, so that there is -// and emtpy slot at 0 and therefore calling a null function pointer will trap. +// When we create the indirect function table we start at 1, so that there is +// and empty slot at 0 and therefore calling a null function pointer will trap. static const uint32_t InitialTableOffset = 1; // For patching purposes, we need to remember where each section starts, both @@ -218,9 +218,7 @@ SmallVector DataSegments; unsigned NumFunctionImports = 0; unsigned NumGlobalImports = 0; - // NumTableImports is initialized to 1 to account for the hardcoded import of - // __indirect_function_table - unsigned NumTableImports = 1; + unsigned NumTableImports = 0; unsigned NumEventImports = 0; uint32_t SectionCount = 0; @@ -270,7 +268,7 @@ SectionFunctions.clear(); NumFunctionImports = 0; NumGlobalImports = 0; - NumTableImports = 1; + NumTableImports = 0; MCObjectWriter::reset(); } @@ -496,6 +494,17 @@ SymA = cast(SectionSymbol); } + if (Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB || + Type == wasm::R_WASM_TABLE_INDEX_SLEB || + Type == wasm::R_WASM_TABLE_INDEX_SLEB64 || + Type == wasm::R_WASM_TABLE_INDEX_I32 || + Type == wasm::R_WASM_TABLE_INDEX_I64) { + // TABLE_INDEX relocs implicitly use the default indirect function table. + auto BaseSym = Ctx.getOrCreateWasmDefaultFunctionTableSymbol(); + BaseSym->setUsedInReloc(); + Asm.registerSymbol(*BaseSym); + } + // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be // against a named symbol. if (Type != wasm::R_WASM_TYPE_INDEX_LEB) { @@ -1196,16 +1205,6 @@ : wasm::WASM_LIMITS_FLAG_NONE; Imports.push_back(MemImport); - // For now, always emit the table section, since indirect calls are not - // valid without it. In the future, we could perhaps be more clever and omit - // it if there are no indirect calls. - wasm::WasmImport TableImport; - TableImport.Module = "env"; - TableImport.Field = "__indirect_function_table"; - TableImport.Kind = wasm::WASM_EXTERNAL_TABLE; - TableImport.Table.ElemType = wasm::WASM_TYPE_FUNCREF; - Imports.push_back(TableImport); - // Populate SignatureIndices, and Imports and WasmIndices for undefined // symbols. This must be done before populating WasmIndices for defined // symbols. @@ -1264,6 +1263,22 @@ Imports.push_back(Import); assert(WasmIndices.count(&WS) == 0); WasmIndices[&WS] = NumEventImports++; + } else if (WS.isTable()) { + if (WS.isWeak()) + report_fatal_error("undefined table symbol cannot be weak"); + + wasm::WasmImport Import; + Import.Module = WS.getImportModule(); + Import.Field = WS.getImportName(); + Import.Kind = wasm::WASM_EXTERNAL_TABLE; + Import.Table.Index = NumTableImports; + wasm::ValType ElemType = WS.getTableType(); + Import.Table.ElemType = uint8_t(ElemType); + // FIXME: ? + Import.Table.Limits = {wasm::WASM_LIMITS_FLAG_NONE, 0, 0}; + Imports.push_back(Import); + assert(WasmIndices.count(&WS) == 0); + WasmIndices[&WS] = NumTableImports++; } } } diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -484,9 +484,11 @@ std::vector ImportedGlobals; std::vector ImportedFunctions; std::vector ImportedEvents; + std::vector ImportedTables; ImportedGlobals.reserve(Imports.size()); ImportedFunctions.reserve(Imports.size()); ImportedEvents.reserve(Imports.size()); + ImportedTables.reserve(Imports.size()); for (auto &I : Imports) { if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION) ImportedFunctions.emplace_back(&I); @@ -494,6 +496,8 @@ ImportedGlobals.emplace_back(&I); else if (I.Kind == wasm::WASM_EXTERNAL_EVENT) ImportedEvents.emplace_back(&I); + else if (I.Kind == wasm::WASM_EXTERNAL_TABLE) + ImportedTables.emplace_back(&I); } while (Count--) { @@ -562,7 +566,6 @@ Info.Name = Import.Field; } GlobalType = &Import.Global; - Info.ImportName = Import.Field; if (!Import.Module.empty()) { Info.ImportModule = Import.Module; } @@ -585,8 +588,18 @@ wasm::WasmTable &Table = Tables[TableIndex]; TableType = Table.ElemType; } else { - return make_error("undefined table symbol", - object_error::parse_failed); + wasm::WasmImport &Import = *ImportedTables[Info.ElementIndex]; + if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) { + Info.Name = readString(Ctx); + Info.ImportName = Import.Field; + } else { + Info.Name = Import.Field; + } + TableType = Import.Table.ElemType; + // FIXME: Parse limits here too. + if (!Import.Module.empty()) { + Info.ImportModule = Import.Module; + } } break; @@ -1038,6 +1051,7 @@ } Error WasmObjectFile::parseTableSection(ReadContext &Ctx) { + TableSection = Sections.size(); uint32_t Count = readVaruint32(Ctx); Tables.reserve(Count); while (Count--) { @@ -1492,6 +1506,8 @@ return Sym.Info.ElementIndex; case wasm::WASM_SYMBOL_TYPE_EVENT: return EventSection; + case wasm::WASM_SYMBOL_TYPE_TABLE: + return TableSection; default: llvm_unreachable("Unknown WasmSymbol::SymbolType"); } diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -490,6 +490,7 @@ bool ExpectBlockType = false; bool ExpectFuncType = false; bool ExpectHeapType = false; + bool ExpectFunctionTable = false; if (Name == "block") { push(Block); ExpectBlockType = true; @@ -529,6 +530,7 @@ return true; } else if (Name == "call_indirect" || Name == "return_call_indirect") { ExpectFuncType = true; + ExpectFunctionTable = true; } else if (Name == "ref.null") { ExpectHeapType = true; } @@ -544,7 +546,7 @@ 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(Sym); @@ -556,6 +558,16 @@ Operands.push_back(std::make_unique( 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)) { @@ -581,8 +593,15 @@ WebAssemblyOperand::Integer, Id.getLoc(), Id.getEndLoc(), WebAssemblyOperand::IntOp{static_cast(HeapType)})); Parser.Lex(); + } else if (ExpectFunctionTable) { + auto *Sym = + getContext().getOrCreateWasmFunctionTableSymbol(Id.getString()); + auto *Val = MCSymbolRefExpr::create(Sym, getContext()); + Operands.push_back(std::make_unique( + WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(), + WebAssemblyOperand::SymOp{Val})); + Parser.Lex(); } else { - // Assume this identifier is a label. const MCExpr *Val; SMLoc End; if (Parser.parseExpression(Val, End)) diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp @@ -68,7 +68,8 @@ 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, table, and flags arguments when printing for tests + ++I; ++I; continue; } diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -387,6 +387,16 @@ } } +inline bool isRetCallIndirect(unsigned Opc) { + switch (Opc) { + case WebAssembly::RET_CALL_INDIRECT: + case WebAssembly::RET_CALL_INDIRECT_S: + return true; + default: + return false; + } +} + inline bool isBrTable(const MachineInstr &MI) { switch (MI.getOpcode()) { case WebAssembly::BR_TABLE_I32: diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -15,10 +15,12 @@ #include "MCTargetDesc/WebAssemblyTargetStreamer.h" #include "MCTargetDesc/WebAssemblyInstPrinter.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssemblyUtilities.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbolWasm.h" +#include "llvm/MC/MCWasmStreamer.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -26,6 +26,7 @@ #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" @@ -867,8 +868,12 @@ if (IsDirect) { MIB.addGlobalAddress(Func); } else { - // Add placeholders for the type index and immediate flags + // Placehoder for the type index. MIB.addImm(0); + // The table into which this call_indirect indexes. + auto &Context = MF->getMMI().getContext(); + MIB.addSym(Context.getOrCreateWasmDefaultFunctionTableSymbol()); + // Placeholder for immediate flags. MIB.addImm(0); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -472,9 +472,13 @@ for (auto Def : CallResults.defs()) MIB.add(Def); - // Add placeholders for the type index and immediate flags if (IsIndirect) { + // Placehoder for the type index. MIB.addImm(0); + // The table into which this call_indirect indexes. + auto &Context = MF.getContext(); + MIB.addSym(Context.getOrCreateWasmDefaultFunctionTableSymbol()); + // Placeholder for immediate flags. MIB.addImm(0); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td @@ -48,6 +48,9 @@ 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 @@ 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, i32imm:$flags, variable_ops), + (outs), + (ins TypeIndex:$type, table32_op:$table, i32imm:$flags), + [], + "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 @@ 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, i32imm:$flags, variable_ops), + (outs), (ins TypeIndex:$type, table32_op:$table, i32imm:$flags), [], + "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 --- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -158,6 +158,8 @@ 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); @@ -256,7 +258,7 @@ // return_call_indirect instructions have the return type of the // caller - if (MI->getOpcode() == WebAssembly::RET_CALL_INDIRECT) + if (WebAssembly::isRetCallIndirect(MI->getOpcode())) getFunctionReturns(MI, Returns); MCOp = lowerTypeIndexOperand(std::move(Returns), std::move(Params)); diff --git a/llvm/test/CodeGen/WebAssembly/function-pointer64.ll b/llvm/test/CodeGen/WebAssembly/function-pointer64.ll --- a/llvm/test/CodeGen/WebAssembly/function-pointer64.ll +++ b/llvm/test/CodeGen/WebAssembly/function-pointer64.ll @@ -34,7 +34,7 @@ ; 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) -> (), __indirect_function_table ; CHECK: .functype test () -> () ; CHECK-NEXT: i64.const bar @@ -50,7 +50,7 @@ ; YAML: - Type: CODE ; YAML: - Type: R_WASM_TABLE_INDEX_SLEB64 ; YAML-NEXT: Index: 0 -; YAML-NEXT: Offset: 0x00000016 +; YAML-NEXT: Offset: 0x0000001B ; 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 --- a/llvm/test/CodeGen/WebAssembly/multivalue.ll +++ b/llvm/test/CodeGen/WebAssembly/multivalue.ll @@ -57,7 +57,7 @@ ; 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), __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/assembler-binary.ll b/llvm/test/MC/WebAssembly/assembler-binary.ll --- a/llvm/test/MC/WebAssembly/assembler-binary.ll +++ b/llvm/test/MC/WebAssembly/assembler-binary.ll @@ -52,14 +52,6 @@ ; CHECK-NEXT: Memory: ; CHECK-NEXT: Initial: 0x00000000 ; CHECK-NEXT: - Module: env -; CHECK-NEXT: Field: __indirect_function_table -; CHECK-NEXT: Kind: TABLE -; CHECK-NEXT: Table: -; CHECK-NEXT: Index: 0 -; CHECK-NEXT: ElemType: FUNCREF -; CHECK-NEXT: Limits: -; CHECK-NEXT: Initial: 0x00000000 -; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: bar ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 1 diff --git a/llvm/test/MC/WebAssembly/basic-assembly.s b/llvm/test/MC/WebAssembly/basic-assembly.s --- a/llvm/test/MC/WebAssembly/basic-assembly.s +++ b/llvm/test/MC/WebAssembly/basic-assembly.s @@ -39,7 +39,7 @@ i64.const 1234 call something2 i32.const 0 - call_indirect (i32, f64) -> () + call_indirect (i32, f64) -> (), __indirect_function_table i32.const 1 i32.add local.tee 0 @@ -159,7 +159,7 @@ # 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 --- /dev/null +++ b/llvm/test/MC/WebAssembly/call-indirect-relocs.s @@ -0,0 +1,26 @@ +# RUN: llvm-mc -triple=wasm32-unknown-unknown < %s | FileCheck %s +# not yet: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -o %t.o < %s | obj2yaml | FileCheck -check-prefix=CHECK-OBJ %s + +test0: + .functype test0 () -> () + i32.const 42 + f64.const 2.5 + i32.const 0 + call_indirect (i32, f64) -> (), __indirect_function_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) -> (), __indirect_function_table +# CHECK-NEXT: end_function + +# CHECK: .tabletype empty_fref_table, funcref +# CHECK: empty_fref_table: diff --git a/llvm/test/MC/WebAssembly/comdat.ll b/llvm/test/MC/WebAssembly/comdat.ll --- a/llvm/test/MC/WebAssembly/comdat.ll +++ b/llvm/test/MC/WebAssembly/comdat.ll @@ -39,14 +39,6 @@ ; CHECK-NEXT: Memory: ; CHECK-NEXT: Initial: 0x00000001 ; CHECK-NEXT: - Module: env -; CHECK-NEXT: Field: __indirect_function_table -; CHECK-NEXT: Kind: TABLE -; CHECK-NEXT: Table: -; CHECK-NEXT: Index: 0 -; CHECK-NEXT: ElemType: FUNCREF -; CHECK-NEXT: Limits: -; CHECK-NEXT: Initial: 0x00000000 -; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: funcImport ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 0 diff --git a/llvm/test/MC/WebAssembly/custom-sections.ll b/llvm/test/MC/WebAssembly/custom-sections.ll --- a/llvm/test/MC/WebAssembly/custom-sections.ll +++ b/llvm/test/MC/WebAssembly/custom-sections.ll @@ -15,18 +15,18 @@ ; CHECK: Section { ; CHECK: Type: CUSTOM (0x0) ; CHECK: Size: 3 -; CHECK: Offset: 72 +; CHECK: Offset: 38 ; CHECK: Name: red ; CHECK: } ; CHECK: Section { ; CHECK: Type: CUSTOM (0x0) ; CHECK: Size: 6 -; CHECK: Offset: 85 +; CHECK: Offset: 51 ; CHECK: Name: green ; CHECK: } ; CHECK: Section { ; CHECK: Type: CUSTOM (0x0) ; CHECK: Size: 25 -; CHECK: Offset: 118 +; CHECK: Offset: 84 ; CHECK: Name: producers ; CHECK: } diff --git a/llvm/test/MC/WebAssembly/data-section.s b/llvm/test/MC/WebAssembly/data-section.s --- a/llvm/test/MC/WebAssembly/data-section.s +++ b/llvm/test/MC/WebAssembly/data-section.s @@ -45,14 +45,6 @@ # BIN-NEXT: Kind: MEMORY # BIN-NEXT: Memory: # BIN-NEXT: Initial: 0x00000001 -# BIN-NEXT: - Module: env -# BIN-NEXT: Field: __indirect_function_table -# BIN-NEXT: Kind: TABLE -# BIN-NEXT: Table: -# BIN-NEXT: Index: 0 -# BIN-NEXT: ElemType: FUNCREF -# BIN-NEXT: Limits: -# BIN-NEXT: Initial: 0x00000000 # BIN-NEXT: - Type: FUNCTION # BIN-NEXT: FunctionTypes: [ 0 ] # BIN-NEXT: - Type: DATACOUNT diff --git a/llvm/test/MC/WebAssembly/debug-info.ll b/llvm/test/MC/WebAssembly/debug-info.ll --- a/llvm/test/MC/WebAssembly/debug-info.ll +++ b/llvm/test/MC/WebAssembly/debug-info.ll @@ -11,33 +11,33 @@ ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: IMPORT (0x2) -; CHECK-NEXT: Size: 81 +; CHECK-NEXT: Size: 47 ; CHECK-NEXT: Offset: 18 ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: FUNCTION (0x3) ; CHECK-NEXT: Size: 2 -; CHECK-NEXT: Offset: 105 +; CHECK-NEXT: Offset: 71 ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: ELEM (0x9) ; CHECK-NEXT: Size: 7 -; CHECK-NEXT: Offset: 113 +; CHECK-NEXT: Offset: 79 ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: DATACOUNT (0xC) ; CHECK-NEXT: Size: 1 -; CHECK-NEXT: Offset: 126 +; CHECK-NEXT: Offset: 92 ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CODE (0xA) ; CHECK-NEXT: Size: 4 -; CHECK-NEXT: Offset: 133 +; CHECK-NEXT: Offset: 99 ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: DATA (0xB) ; CHECK-NEXT: Size: 19 -; CHECK-NEXT: Offset: 143 +; CHECK-NEXT: Offset: 109 ; CHECK-NEXT: Segments [ ; CHECK-NEXT: Segment { ; CHECK-NEXT: Name: .data.foo @@ -54,79 +54,79 @@ ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 86 -; CHECK-NEXT: Offset: 168 +; CHECK-NEXT: Offset: 134 ; CHECK-NEXT: Name: .debug_abbrev ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 114 -; CHECK-NEXT: Offset: 274 +; CHECK-NEXT: Offset: 240 ; CHECK-NEXT: Name: .debug_info ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 121 -; CHECK-NEXT: Offset: 406 +; CHECK-NEXT: Offset: 372 ; CHECK-NEXT: Name: .debug_str ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 42 -; CHECK-NEXT: Offset: 544 +; CHECK-NEXT: Offset: 510 ; CHECK-NEXT: Name: .debug_pubnames ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 26 -; CHECK-NEXT: Offset: 608 +; CHECK-NEXT: Offset: 574 ; CHECK-NEXT: Name: .debug_pubtypes ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 57 -; CHECK-NEXT: Offset: 656 +; CHECK-NEXT: Offset: 622 ; CHECK-NEXT: Name: .debug_line ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 91 -; CHECK-NEXT: Offset: 731 +; CHECK-NEXT: Offset: 697 ; CHECK-NEXT: Name: linking ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 9 -; CHECK-NEXT: Offset: 836 +; CHECK-NEXT: Offset: 802 ; CHECK-NEXT: Name: reloc.DATA ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 61 -; CHECK-NEXT: Offset: 862 +; CHECK-NEXT: Offset: 828 ; CHECK-NEXT: Name: reloc..debug_info ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 6 -; CHECK-NEXT: Offset: 947 +; CHECK-NEXT: Offset: 913 ; CHECK-NEXT: Name: reloc..debug_pubnames ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 6 -; CHECK-NEXT: Offset: 981 +; CHECK-NEXT: Offset: 947 ; CHECK-NEXT: Name: reloc..debug_pubtypes ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 6 -; CHECK-NEXT: Offset: 1015 +; CHECK-NEXT: Offset: 981 ; CHECK-NEXT: Name: reloc..debug_line ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) ; CHECK-NEXT: Size: 77 -; CHECK-NEXT: Offset: 1045 +; CHECK-NEXT: Offset: 1011 ; CHECK-NEXT: Name: producers ; CHECK-NEXT: } ; CHECK-NEXT:] @@ -219,7 +219,6 @@ ; CHECK-NEXT: Flags [ (0x10) ; CHECK-NEXT: UNDEFINED (0x10) ; CHECK-NEXT: ] -; CHECK-NEXT: ImportName: __stack_pointer ; CHECK-NEXT: ImportModule: env ; CHECK-NEXT: ElementIndex: 0x0 ; CHECK-NEXT: } diff --git a/llvm/test/MC/WebAssembly/event-section.ll b/llvm/test/MC/WebAssembly/event-section.ll --- a/llvm/test/MC/WebAssembly/event-section.ll +++ b/llvm/test/MC/WebAssembly/event-section.ll @@ -56,4 +56,4 @@ ; SEC: Type: EVENT (0xD) ; SEC-NEXT: Size: 3 -; SEC-NEXT: Offset: 97 +; SEC-NEXT: Offset: 63 diff --git a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll --- a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll +++ b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll @@ -27,14 +27,6 @@ ; CHECK-NEXT: Memory: ; CHECK-NEXT: Initial: 0x00000001 ; CHECK-NEXT: - Module: env -; CHECK-NEXT: Field: __indirect_function_table -; CHECK-NEXT: Kind: TABLE -; CHECK-NEXT: Table: -; CHECK-NEXT: Index: 0 -; CHECK-NEXT: ElemType: FUNCREF -; CHECK-NEXT: Limits: -; CHECK-NEXT: Initial: 0x00000002 -; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: func3 ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 1 diff --git a/llvm/test/MC/WebAssembly/tail-call-encodings.s b/llvm/test/MC/WebAssembly/tail-call-encodings.s --- a/llvm/test/MC/WebAssembly/tail-call-encodings.s +++ b/llvm/test/MC/WebAssembly/tail-call-encodings.s @@ -16,8 +16,8 @@ foo2: .functype foo2 () -> () - # CHECK: return_call_indirect (i32) -> (i32) # encoding: [0x13, + # CHECK: return_call_indirect (i32) -> (i32), __indirect_function_table # encoding: [0x13, # CHECK-NEXT: fixup A - offset: 1, value: .Ltypeindex0@TYPEINDEX, kind: fixup_uleb128_i32 - return_call_indirect (i32) -> (i32) + return_call_indirect (i32) -> (i32), __indirect_function_table end_function diff --git a/llvm/test/MC/WebAssembly/type-index.s b/llvm/test/MC/WebAssembly/type-index.s --- a/llvm/test/MC/WebAssembly/type-index.s +++ b/llvm/test/MC/WebAssembly/type-index.s @@ -6,7 +6,7 @@ test0: .functype test0 (i32) -> (i32) - call_indirect (f64) -> (f64) + call_indirect (f64) -> (f64), __indirect_function_table end_function # CHECK: .text diff --git a/llvm/test/MC/WebAssembly/wasm64.s b/llvm/test/MC/WebAssembly/wasm64.s --- a/llvm/test/MC/WebAssembly/wasm64.s +++ b/llvm/test/MC/WebAssembly/wasm64.s @@ -150,14 +150,6 @@ # BIN-NEXT: Flags: [ IS_64 ] # BIN-NEXT: Initial: 0x00000001 # BIN-NEXT: - Module: env -# BIN-NEXT: Field: __indirect_function_table -# BIN-NEXT: Kind: TABLE -# BIN-NEXT: Table: -# BIN-NEXT: Index: 0 -# BIN-NEXT: ElemType: FUNCREF -# BIN-NEXT: Limits: -# BIN-NEXT: Initial: 0x00000000 -# BIN-NEXT: - Module: env # BIN-NEXT: Field: myglob64 # BIN-NEXT: Kind: GLOBAL # BIN-NEXT: GlobalType: I64 diff --git a/llvm/test/MC/WebAssembly/weak-alias.s b/llvm/test/MC/WebAssembly/weak-alias.s --- a/llvm/test/MC/WebAssembly/weak-alias.s +++ b/llvm/test/MC/WebAssembly/weak-alias.s @@ -32,7 +32,7 @@ .functype call_direct_ptr () -> (i32) i32.const 0 i32.load direct_address - call_indirect () -> (i32) + call_indirect () -> (i32), __indirect_function_table end_function call_alias_ptr: @@ -41,7 +41,7 @@ .functype call_alias_ptr () -> (i32) i32.const 0 i32.load alias_address - call_indirect () -> (i32) + call_indirect () -> (i32), __indirect_function_table end_function .section .data.bar,"",@