Index: lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp =================================================================== --- lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -492,6 +492,27 @@ CurrentState = EndFunction; if (pop(Name, Function) || ensureEmptyNestingStack()) return true; + } else if (Name == "call_indirect" || Name == "return_call_indirect") { + // This has a special TYPEINDEX operand which in text we + // represent as a signature, such that we can re-build this signature, + // attach it to an anonymous symbol, which is what WasmObjectWriter + // expects to be able to recreate the actual unique-ified type indices. + auto Loc = Parser.getTok(); + auto Signature = make_unique(); + if (parseSignature(Signature.get())) + return true; + auto &Ctx = getStreamer().getContext(); + // The "true" here will cause this to be a nameless symbol. + MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true); + auto *WasmSym = cast(Sym); + WasmSym->setSignature(Signature.get()); + addSignature(std::move(Signature)); + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); + const MCExpr *Expr = MCSymbolRefExpr::create( + WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx); + Operands.push_back(make_unique( + WebAssemblyOperand::Symbol, Loc.getLoc(), Loc.getEndLoc(), + WebAssemblyOperand::SymOp{Expr})); } while (Lexer.isNot(AsmToken::EndOfStatement)) { Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h @@ -58,6 +58,9 @@ const char *typeToString(wasm::ValType Ty); const char *anyTypeToString(unsigned Ty); +std::string typeListToString(ArrayRef List); +std::string signatureToString(const wasm::WasmSignature *Sig); + } // end namespace WebAssembly } // end namespace llvm Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp @@ -15,6 +15,7 @@ #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" +#include "WebAssemblyUtilities.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/CodeGen/TargetRegisterInfo.h" @@ -232,7 +233,16 @@ } } else { assert(Op.isExpr() && "unknown operand kind in printOperand"); - Op.getExpr()->print(O, &MAI); + // call_indirect instructions have a TYPEINDEX operand that we print + // as a signature here, such that the assembler can recover this + // information. + auto SRE = static_cast(Op.getExpr()); + if (SRE->getKind() == MCSymbolRefExpr::VK_WASM_TYPEINDEX) { + auto &Sym = static_cast(SRE->getSymbol()); + O << WebAssembly::signatureToString(Sym.getSignature()); + } else { + Op.getExpr()->print(O, &MAI); + } } } @@ -266,7 +276,7 @@ // We have various enums representing a subset of these types, use this // function to convert any of them to text. -const char *llvm::WebAssembly::anyTypeToString(unsigned Ty) { +const char *WebAssembly::anyTypeToString(unsigned Ty) { switch (Ty) { case wasm::WASM_TYPE_I32: return "i32"; @@ -291,6 +301,24 @@ } } -const char *llvm::WebAssembly::typeToString(wasm::ValType Ty) { +const char *WebAssembly::typeToString(wasm::ValType Ty) { return anyTypeToString(static_cast(Ty)); } + +std::string WebAssembly::typeListToString(ArrayRef List) { + std::string S; + for (auto &Ty : List) { + if (&Ty != &List[0]) S += ", "; + S += WebAssembly::typeToString(Ty); + } + return S; +} + +std::string WebAssembly::signatureToString(const wasm::WasmSignature *Sig) { + std::string S("("); + S += typeListToString(Sig->Params); + S += ") -> ("; + S += typeListToString(Sig->Returns); + S += ")"; + return S; +} Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h @@ -56,9 +56,6 @@ /// This part is for ascii assembly output class WebAssemblyTargetAsmStreamer final : public WebAssemblyTargetStreamer { formatted_raw_ostream &OS; - void emitSignature(const wasm::WasmSignature *Sig); - void emitParamList(const wasm::WasmSignature *Sig); - void emitReturnList(const wasm::WasmSignature *Sig); public: WebAssemblyTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -60,39 +60,10 @@ void WebAssemblyTargetAsmStreamer::emitEndFunc() { OS << "\t.endfunc\n"; } -void WebAssemblyTargetAsmStreamer::emitSignature( - const wasm::WasmSignature *Sig) { - OS << "("; - emitParamList(Sig); - OS << ") -> ("; - emitReturnList(Sig); - OS << ")"; -} - -void WebAssemblyTargetAsmStreamer::emitParamList( - const wasm::WasmSignature *Sig) { - auto &Params = Sig->Params; - for (auto &Ty : Params) { - if (&Ty != &Params[0]) - OS << ", "; - OS << WebAssembly::typeToString(Ty); - } -} - -void WebAssemblyTargetAsmStreamer::emitReturnList( - const wasm::WasmSignature *Sig) { - auto &Returns = Sig->Returns; - for (auto &Ty : Returns) { - if (&Ty != &Returns[0]) - OS << ", "; - OS << WebAssembly::typeToString(Ty); - } -} - void WebAssemblyTargetAsmStreamer::emitFunctionType(const MCSymbolWasm *Sym) { assert(Sym->isFunction()); OS << "\t.functype\t" << Sym->getName() << " "; - emitSignature(Sym->getSignature()); + OS << WebAssembly::signatureToString(Sym->getSignature()); OS << "\n"; } @@ -107,7 +78,7 @@ void WebAssemblyTargetAsmStreamer::emitEventType(const MCSymbolWasm *Sym) { assert(Sym->isEvent()); OS << "\t.eventtype\t" << Sym->getName() << " "; - emitParamList(Sym->getSignature()); + OS << WebAssembly::typeListToString(Sym->getSignature()->Params); OS << "\n"; } Index: test/CodeGen/WebAssembly/reg-stackify.ll =================================================================== --- test/CodeGen/WebAssembly/reg-stackify.ll +++ test/CodeGen/WebAssembly/reg-stackify.ll @@ -655,7 +655,7 @@ ; NOREGS-NEXT: local.tee 0 ; NOREGS: i32.load 0 ; NOREGS-NEXT: i32.load 0 -; NOREGS-NEXT: i32.call_indirect +; NOREGS-NEXT: i32.call_indirect (i32, i32) -> (i32) %class.call_indirect = type { i32 (...)** } define i32 @call_indirect_stackify(%class.call_indirect** %objptr, i32 %arg) { %obj = load %class.call_indirect*, %class.call_indirect** %objptr Index: test/MC/WebAssembly/basic-assembly.s =================================================================== --- test/MC/WebAssembly/basic-assembly.s +++ test/MC/WebAssembly/basic-assembly.s @@ -34,7 +34,7 @@ i64.const 1234 i32.call something2 i32.const 0 - call_indirect 0 + call_indirect (i32, f64) -> () i32.const 1 i32.add local.tee 0 @@ -138,7 +138,7 @@ # CHECK-NEXT: i64.const 1234 # CHECK-NEXT: i32.call something2 # CHECK-NEXT: i32.const 0 -# CHECK-NEXT: call_indirect 0 +# CHECK-NEXT: call_indirect (i32, f64) -> () # CHECK-NEXT: i32.const 1 # CHECK-NEXT: i32.add # CHECK-NEXT: local.tee 0 Index: test/MC/WebAssembly/type-index.s =================================================================== --- /dev/null +++ test/MC/WebAssembly/type-index.s @@ -0,0 +1,67 @@ +# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+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 + +# Minimal test for type indices in call_indirect. + +test0: + .functype test0 (i32) -> (i32) + call_indirect (f64) -> (f64) + end_function + +# CHECK: .text +# CHECK-LABEL: test0: +# CHECK-NEXT: .functype test0 (i32) -> (i32) +# CHECK-NEXT: call_indirect (f64) -> (f64) +# CHECK-NEXT: end_function + +# BIN: --- !WASM +# BIN-NEXT: FileHeader: +# BIN-NEXT: Version: 0x00000001 +# BIN-NEXT: Sections: +# BIN-NEXT: - Type: TYPE +# BIN-NEXT: Signatures: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: ReturnType: I32 +# BIN-NEXT: ParamTypes: +# BIN-NEXT: - I32 +# BIN-NEXT: - Index: 1 +# BIN-NEXT: ReturnType: F64 +# BIN-NEXT: ParamTypes: +# BIN-NEXT: - F64 +# 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: 0x00000000 +# BIN-NEXT: - Module: env +# BIN-NEXT: Field: __indirect_function_table +# BIN-NEXT: Kind: TABLE +# BIN-NEXT: Table: +# BIN-NEXT: ElemType: FUNCREF +# BIN-NEXT: Limits: +# BIN-NEXT: Initial: 0x00000000 +# BIN-NEXT: - Type: FUNCTION +# BIN-NEXT: FunctionTypes: [ 0 ] +# BIN-NEXT: - Type: CODE +# BIN-NEXT: Relocations: +# BIN-NEXT: - Type: R_WASM_TYPE_INDEX_LEB +# BIN-NEXT: Index: 1 +# BIN-NEXT: Offset: 0x00000004 +# BIN-NEXT: Functions: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: Locals: [] +# BIN-NEXT: Body: 118180808000000B +# 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: ... +