return false;
}
+ WebAssembly::HeapType parseHeapType(StringRef Id) {
+ return StringSwitch<WebAssembly::HeapType>(Id)
+ .Case("extern", WebAssembly::HeapType::Externref)
+ .Case("func", WebAssembly::HeapType::Funcref)
+ .Default(WebAssembly::HeapType::Invalid);
+ }
+
void addBlockTypeOperand(OperandVector &Operands, SMLoc NameLoc,
WebAssembly::BlockType BT) {
Operands.push_back(std::make_unique<WebAssemblyOperand>(
// proper nesting.
bool ExpectBlockType = false;
bool ExpectFuncType = false;
+ bool ExpectHeapType = false;
if (Name == "block") {
push(Block);
ExpectBlockType = true;
return true;
} else if (Name == "call_indirect" || Name == "return_call_indirect") {
ExpectFuncType = true;
+ } else if (Name == "ref.null") {
+ ExpectHeapType = true;
}
if (ExpectFuncType || (ExpectBlockType && Lexer.is(AsmToken::LParen))) {
return error("Unknown block type: ", Id);
addBlockTypeOperand(Operands, NameLoc, BT);
Parser.Lex();
+ } else if (ExpectHeapType) {
+ auto HeapType = parseHeapType(Id.getString());
+ if (HeapType == WebAssembly::HeapType::Invalid) {
+ return error("Expected a heap type: ", Id);
+ }
+ Operands.push_back(std::make_unique<WebAssemblyOperand>(
+ WebAssemblyOperand::Integer, Id.getLoc(), Id.getEndLoc(),
+ WebAssemblyOperand::IntOp{static_cast<int64_t>(HeapType)}));
+ Parser.Lex();
} else {
// Assume this identifier is a label.
const MCExpr *Val;
}
break;
}
+ // heap_type operands, for e.g. ref.null:
+ case WebAssembly::OPERAND_HEAPTYPE: {
+ int64_t Val;
+ uint64_t PrevSize = Size;
+ if (!nextLEB(Val, Bytes, Size, true))
+ return MCDisassembler::Fail;
+ if (Val < 0 && Size == PrevSize + 1) {
+ // The HeapType encoding is like BlockType, in that encodings that
+ // decode as negative values indicate ValTypes. In practice we expect
+ // either wasm::ValType::EXTERNREF or wasm::ValType::FUNCREF here.
+ //
+ // The positive SLEB values are reserved for future expansion and are
+ // expected to be type indices in the typed function references
+ // proposal, and should disassemble as MCSymbolRefExpr as in BlockType
+ // above.
+ MI.addOperand(MCOperand::createImm(Val & 0x7f));
+ } else {
+ MI.addOperand(
+ MCOperand::createImm(int64_t(WebAssembly::HeapType::Invalid)));
+ }
+ break;
+ }
// FP operands.
case WebAssembly::OPERAND_F32IMM: {
if (!parseImmediate<float>(MI, Size, Bytes))
}
}
+void WebAssemblyInstPrinter::printWebAssemblyHeapTypeOperand(const MCInst *MI,
+ unsigned OpNo,
+ raw_ostream &O) {
+ const MCOperand &Op = MI->getOperand(OpNo);
+ if (Op.isImm()) {
+ switch (Op.getImm()) {
+ case long(wasm::ValType::EXTERNREF):
+ O << "extern";
+ break;
+ case long(wasm::ValType::FUNCREF):
+ O << "func";
+ break;
+ default:
+ O << "unsupported_heap_type_value";
+ break;
+ }
+ } else {
+ // Typed function references and other subtypes of funcref and externref
+ // currently unimplemented.
+ O << "unsupported_heap_type_operand";
+ }
+}
+
// We have various enums representing a subset of these types, use this
// function to convert any of them to text.
const char *WebAssembly::anyTypeToString(unsigned Ty) {
raw_ostream &O);
void printWebAssemblySignatureOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O);
+ void printWebAssemblyHeapTypeOperand(const MCInst *MI, unsigned OpNo,
+ raw_ostream &O);
// Autogenerated by tblgen.
void printInstruction(const MCInst *MI, uint64_t Address, raw_ostream &O);
encodeSLEB128(int64_t(MO.getImm()), OS);
break;
case WebAssembly::OPERAND_SIGNATURE:
+ case WebAssembly::OPERAND_HEAPTYPE:
OS << uint8_t(MO.getImm());
break;
case WebAssembly::OPERAND_VEC_I8IMM:
OPERAND_BRLIST,
/// 32-bit unsigned table number.
OPERAND_TABLE,
+ /// heap type immediate for ref.null.
+ OPERAND_HEAPTYPE,
};
} // end namespace WebAssembly
Multivalue = 0xffff,
};
+/// Used as immediate MachineOperands for heap types, e.g. for ref.null.
+enum class HeapType : unsigned {
+ Invalid = 0x00,
+ Externref = unsigned(wasm::ValType::EXTERNREF),
+ Funcref = unsigned(wasm::ValType::FUNCREF),
+};
+
/// Instruction opcodes emitted via means other than CodeGen.
static const unsigned Nop = 0x01;
static const unsigned End = 0x0b;
let PrintMethod = "printWebAssemblySignatureOperand";
}
+let OperandType = "OPERAND_HEAPTYPE" in
+def HeapType : Operand<i32> {
+ let PrintMethod = "printWebAssemblyHeapTypeOperand";
+}
+
let OperandType = "OPERAND_TYPEINDEX" in
def TypeIndex : Operand<i32>;
(SELECT_EXNREF EXNREF:$lhs, EXNREF:$rhs, I32:$cond)>;
def : Pat<(select (i32 (seteq I32:$cond, 0)), EXNREF:$lhs, EXNREF:$rhs),
(SELECT_EXNREF EXNREF:$rhs, EXNREF:$lhs, I32:$cond)>;
+
+multiclass REF<WebAssemblyRegClass rt> {
+ defm REF_NULL_#rt : I<(outs rt:$res), (ins HeapType:$heaptype),
+ (outs), (ins HeapType:$heaptype),
+ [],
+ "ref.null\t$res, $heaptype",
+ "ref.null\t$heaptype",
+ 0xd0>;
+}
+
+defm "" : REF<FUNCREF>, Requires<[HasReferenceTypes]>;
+defm "" : REF<EXTERNREF>, Requires<[HasReferenceTypes]>;
SmallVector<wasm::ValType, 4>());
break;
}
+ } else if (Info.OperandType == WebAssembly::OPERAND_HEAPTYPE) {
+ auto HT = static_cast<WebAssembly::HeapType>(MO.getImm());
+ assert(HT != WebAssembly::HeapType::Invalid);
+ // With typed function references, this will need a case for type
+ // index operands. Otherwise, fall through.
}
}
MCOp = MCOperand::createImm(MO.getImm());
--- /dev/null
+# RUN: llvm-mc -show-encoding -triple=wasm32-unknown-unknown -mattr=+reference-types < %s | FileCheck %s
+# RUN: llvm-mc -show-encoding -triple=wasm64-unknown-unknown -mattr=+reference-types < %s | FileCheck %s
+
+# CHECK: ref_null_externref:
+# CHECK-NEXT: .functype ref_null_externref () -> (externref)
+# CHECK: ref.null extern # encoding: [0xd0,0x6f]
+# CHECK-NEXT: end_function
+ref_null_externref:
+ .functype ref_null_externref () -> (externref)
+ ref.null extern
+ end_function
+
+# CHECK: ref_null_funcref:
+# CHECK-NEXT: .functype ref_null_funcref () -> (funcref)
+# CHECK: ref.null func # encoding: [0xd0,0x70]
+# CHECK-NEXT: end_function
+ref_null_funcref:
+ .functype ref_null_funcref () -> (funcref)
+ ref.null func
+ end_function