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<wasm::WasmSignature>();
+ 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<MCSymbolWasm>(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>(
+ WebAssemblyOperand::Symbol, Loc.getLoc(), Loc.getEndLoc(),
+ WebAssemblyOperand::SymOp{Expr}));
}
while (Lexer.isNot(AsmToken::EndOfStatement)) {
#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"
}
} 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<const MCSymbolRefExpr *>(Op.getExpr());
+ if (SRE->getKind() == MCSymbolRefExpr::VK_WASM_TYPEINDEX) {
+ auto &Sym = static_cast<const MCSymbolWasm &>(SRE->getSymbol());
+ O << WebAssembly::signatureToString(Sym.getSignature());
+ } else {
+ Op.getExpr()->print(O, &MAI);
+ }
}
}
// 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";
}
}
-const char *llvm::WebAssembly::typeToString(wasm::ValType Ty) {
+const char *WebAssembly::typeToString(wasm::ValType Ty) {
return anyTypeToString(static_cast<unsigned>(Ty));
}
+
+std::string WebAssembly::typeListToString(ArrayRef<wasm::ValType> 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;
+}
const char *typeToString(wasm::ValType Ty);
const char *anyTypeToString(unsigned Ty);
+std::string typeListToString(ArrayRef<wasm::ValType> List);
+std::string signatureToString(const wasm::WasmSignature *Sig);
+
} // end namespace WebAssembly
} // end namespace llvm
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";
}
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";
}
/// 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);
; 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
i64.const 1234
i32.call something2
i32.const 0
- call_indirect 0
+ call_indirect (i32, f64) -> ()
i32.const 1
i32.add
local.tee 0
# 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
foo2:
.functype foo2 () -> ()
- # CHECK: return_call_indirect 0 # encoding: [0x13,0x00,0x00]
- return_call_indirect 0
+ # CHECK: return_call_indirect (i32) -> (i32) # encoding: [0x13,
+ # CHECK-NEXT: fixup A - offset: 1, value: .Ltypeindex0@TYPEINDEX, kind: fixup_uleb128_i32
+ return_call_indirect (i32) -> (i32)
end_function
--- /dev/null
+# 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: ...
+