[llvm] 107c3a1 - [WebAssembly] Implement ref.null
Thomas Lively via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 3 10:46:31 PST 2020
Author: Andy Wingo
Date: 2020-11-03T10:46:23-08:00
New Revision: 107c3a12d627f12a23f138a00d6aabe9de7402f7
URL: https://github.com/llvm/llvm-project/commit/107c3a12d627f12a23f138a00d6aabe9de7402f7
DIFF: https://github.com/llvm/llvm-project/commit/107c3a12d627f12a23f138a00d6aabe9de7402f7.diff
LOG: [WebAssembly] Implement ref.null
This patch adds a new "heap type" operand kind to the WebAssembly MC
layer, used by ref.null. Currently the possible values are "extern" and
"func"; when typed function references come, though, this operand may be
a type index.
Note that the "heap type" production is still known as "refedtype" in
the draft proposal; changing its name in the spec is
ongoing (https://github.com/WebAssembly/reference-types/issues/123).
The register form of ref.null is still untested.
Differential Revision: https://reviews.llvm.org/D90608
Added:
llvm/test/MC/WebAssembly/reference-types.s
Modified:
llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td
llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 92e855972e8a..2920a49ba944 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -440,6 +440,13 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
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>(
@@ -482,6 +489,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
// proper nesting.
bool ExpectBlockType = false;
bool ExpectFuncType = false;
+ bool ExpectHeapType = false;
if (Name == "block") {
push(Block);
ExpectBlockType = true;
@@ -521,6 +529,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
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))) {
@@ -562,6 +572,15 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
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;
diff --git a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
index 8c93b59a7d37..1b7cc093f7ad 100644
--- a/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
+++ b/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
@@ -241,6 +241,28 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
}
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))
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index 86c894eb2076..0812ee0f461d 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -302,6 +302,29 @@ void WebAssemblyInstPrinter::printWebAssemblySignatureOperand(const MCInst *MI,
}
}
+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) {
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
index 1387a1928b3f..f40cef233ac5 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.h
@@ -48,6 +48,8 @@ class WebAssemblyInstPrinter final : public MCInstPrinter {
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);
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index 3e8cce488490..55bf5d14fdac 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -106,6 +106,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
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:
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
index 2dcd31204c3b..d6c3f74c496a 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
@@ -78,6 +78,8 @@ enum OperandType {
OPERAND_BRLIST,
/// 32-bit unsigned table number.
OPERAND_TABLE,
+ /// heap type immediate for ref.null.
+ OPERAND_HEAPTYPE,
};
} // end namespace WebAssembly
@@ -140,6 +142,13 @@ enum class BlockType : unsigned {
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;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index 94c1df338353..b57d6fdd943d 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -187,6 +187,11 @@ def Signature : Operand<i32> {
let PrintMethod = "printWebAssemblySignatureOperand";
}
+let OperandType = "OPERAND_HEAPTYPE" in
+def HeapType : Operand<i32> {
+ let PrintMethod = "printWebAssemblyHeapTypeOperand";
+}
+
let OperandType = "OPERAND_TYPEINDEX" in
def TypeIndex : Operand<i32>;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td
index 14d723750f07..32b0e712f8a6 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td
@@ -23,3 +23,15 @@ def : Pat<(select (i32 (setne I32:$cond, 0)), EXNREF:$lhs, EXNREF:$rhs),
(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]>;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index 7774a0d71be3..09d1b96d1797 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -271,6 +271,11 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
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());
diff --git a/llvm/test/MC/WebAssembly/reference-types.s b/llvm/test/MC/WebAssembly/reference-types.s
new file mode 100644
index 000000000000..cd4d767a3d96
--- /dev/null
+++ b/llvm/test/MC/WebAssembly/reference-types.s
@@ -0,0 +1,20 @@
+# 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
More information about the llvm-commits
mailing list