Index: include/llvm/MC/MCSymbol.h =================================================================== --- include/llvm/MC/MCSymbol.h +++ include/llvm/MC/MCSymbol.h @@ -208,6 +208,13 @@ return getNameEntryPtr()->first(); } + void setUnNamed() const { + // We don't own the name, it is allocated after the StringMapEntry and + // deleted with it. + getNameEntryPtr() = nullptr; + FragmentAndHasName.setInt(0); + } + bool isRegistered() const { return IsRegistered; } void setIsRegistered(bool Value) const { IsRegistered = Value; } Index: lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp =================================================================== --- lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -490,6 +490,15 @@ SMLoc End; if (Parser.parseExpression(Val, End)) return error("Cannot parse symbol: ", Lexer.getTok()); + // If this is a TYPE_INDEX symbol, have to ensure it is unnamed, + // since that is what WasmObjectWriter expects. + if (Val->getKind() == MCExpr::SymbolRef) { + auto SR = static_cast(Val); + if (SR->getKind() == MCSymbolRefExpr::VK_WASM_TYPEINDEX) { + auto &Sym = SR->getSymbol(); + if (!Sym.isDefined()) Sym.setUnNamed(); + } + } Operands.push_back(make_unique( WebAssemblyOperand::Symbol, Id.getLoc(), Id.getEndLoc(), WebAssemblyOperand::SymOp{Val})); 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" @@ -46,6 +47,22 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS, StringRef Annot, const MCSubtargetInfo &STI) { + // call_indirect instructions have a TYPEINDEX operand represented as + // an undefined symbol in assembly, that needs to have the correct signature, + // which we attach by emitting a .functype here. + if (WebAssembly::isCallIndirect(MI->getOpcode())) { + auto O = MI->getOperand(0); + // Ignore register based instructions. + if (O.isExpr() && MI->getNumOperands() == 2) { + auto SRE = static_cast(O.getExpr()); + if (SRE->getKind() == MCSymbolRefExpr::VK_WASM_TYPEINDEX) { + auto &Sym = static_cast(SRE->getSymbol()); + OS << "\t.functype\t" << Sym.getName() << " "; + OS << WebAssembly::signatureToString(Sym.getSignature()) << "\n"; + } + } + } + // Print the instruction (this uses the AsmStrings from the .td files). printInstruction(MI, OS); @@ -266,7 +283,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 +308,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,8 @@ ; NOREGS-NEXT: local.tee 0 ; NOREGS: i32.load 0 ; NOREGS-NEXT: i32.load 0 -; NOREGS-NEXT: i32.call_indirect +; NOREGS-NEXT: .functype .Ltypeindex0 (i32, i32) -> (i32) +; NOREGS-NEXT: i32.call_indirect .Ltypeindex0@TYPEINDEX %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/type-index.s =================================================================== --- /dev/null +++ test/MC/WebAssembly/type-index.s @@ -0,0 +1,72 @@ +# 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) + .functype .Ltype_index0 (f64) -> (f64) + call_indirect .Ltype_index0@TYPEINDEX + end_function + +# CHECK: .text +# CHECK-LABEL: test0: +# CHECK-NEXT: .functype test0 (i32) -> (i32) +# CHECK-NEXT: .functype .Ltype_index0 (f64) -> (f64) +# FIXME: This is a consequence of the assembler removing the symbol, +# which is clearly not desirable in an assembler round-trip. +# CHECK-NEXT: .functype (f64) -> (f64) +# CHECK-NEXT: call_indirect ""@TYPEINDEX +# 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: ... +