From 5a7c331aa4cae9f20dbfc058258901fb4d789c55 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Sat, 25 May 2024 00:46:11 +0000 Subject: [PATCH 1/3] [WebAssembly] Add exnref type This adds (back) the exnref type restored in the new EH proposal adopted in Oct 2023 CG meeting: https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md:x --- lld/wasm/WriterUtils.cpp | 2 ++ llvm/include/llvm/BinaryFormat/Wasm.h | 9 ++++--- llvm/include/llvm/CodeGen/ValueTypes.td | 9 ++++--- llvm/include/llvm/IR/Intrinsics.td | 2 ++ llvm/include/llvm/IR/IntrinsicsWebAssembly.td | 18 +++++++++++++ llvm/lib/CodeGen/ValueTypes.cpp | 1 + llvm/lib/Object/WasmObjectFile.cpp | 4 +++ llvm/lib/ObjectYAML/WasmYAML.cpp | 2 ++ .../MCTargetDesc/WebAssemblyMCTargetDesc.h | 12 +++++++++ .../WebAssemblyMCTypeUtilities.cpp | 6 +++++ .../MCTargetDesc/WebAssemblyMCTypeUtilities.h | 4 ++- .../Utils/WebAssemblyTypeUtilities.cpp | 3 +++ .../WebAssembly/WebAssemblyAsmPrinter.cpp | 2 ++ .../WebAssembly/WebAssemblyExplicitLocals.cpp | 10 +++++++ .../WebAssembly/WebAssemblyFastISel.cpp | 16 ++++++++++++ .../WebAssembly/WebAssemblyISelLowering.cpp | 3 +++ .../WebAssembly/WebAssemblyInstrInfo.td | 3 +++ .../Target/WebAssembly/WebAssemblyInstrRef.td | 8 +++--- .../WebAssembly/WebAssemblyInstrTable.td | 2 ++ .../WebAssembly/WebAssemblyRegStackify.cpp | 2 ++ .../WebAssembly/WebAssemblyRegisterInfo.td | 2 ++ .../WebAssembly/WebAssemblyUtilities.cpp | 2 ++ .../test/CodeGen/WebAssembly/reg-argument.mir | 11 ++++++++ llvm/test/CodeGen/WebAssembly/reg-copy.mir | 11 ++++++++ llvm/test/MC/WebAssembly/basic-assembly.s | 21 +++++++++------ llvm/test/MC/WebAssembly/reference-types.s | 26 +++++++++++++++++-- .../test/MC/WebAssembly/type-checker-errors.s | 16 ++++++++++++ llvm/utils/TableGen/Common/CodeGenTarget.cpp | 1 + 28 files changed, 187 insertions(+), 21 deletions(-) diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp index cdd2c42f939ef..c6a1592012e64 100644 --- a/lld/wasm/WriterUtils.cpp +++ b/lld/wasm/WriterUtils.cpp @@ -35,6 +35,8 @@ std::string toString(ValType type) { return "funcref"; case ValType::EXTERNREF: return "externref"; + case ValType::EXNREF: + return "exnref"; case ValType::OTHERREF: return "otherref"; } diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index 38ef8e37df91d..d8aa899080097 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -58,15 +58,16 @@ enum : unsigned { WASM_TYPE_V128 = 0x7B, WASM_TYPE_NULLFUNCREF = 0x73, WASM_TYPE_NULLEXTERNREF = 0x72, + WASM_TYPE_NULLEXNREF= 0x74, WASM_TYPE_NULLREF = 0x71, WASM_TYPE_FUNCREF = 0x70, WASM_TYPE_EXTERNREF = 0x6F, + WASM_TYPE_EXNREF = 0x69, WASM_TYPE_ANYREF = 0x6E, WASM_TYPE_EQREF = 0x6D, WASM_TYPE_I31REF = 0x6C, WASM_TYPE_STRUCTREF = 0x6B, WASM_TYPE_ARRAYREF = 0x6A, - WASM_TYPE_EXNREF = 0x69, WASM_TYPE_NONNULLABLE = 0x64, WASM_TYPE_NULLABLE = 0x63, WASM_TYPE_FUNC = 0x60, @@ -261,8 +262,9 @@ enum class ValType { V128 = WASM_TYPE_V128, FUNCREF = WASM_TYPE_FUNCREF, EXTERNREF = WASM_TYPE_EXTERNREF, + EXNREF = WASM_TYPE_EXNREF, // Unmodeled value types include ref types with heap types other than - // func or extern, and type-specialized funcrefs + // func, extern or exn, and type-specialized funcrefs OTHERREF = 0xff, }; @@ -410,7 +412,8 @@ struct WasmDataSegment { // 1) Does not model passive or declarative segments (Segment will end up with // an Offset field of i32.const 0) // 2) Does not model init exprs (Segment will get an empty Functions list) -// 2) Does not model types other than basic funcref/externref (see ValType) +// 3) Does not model types other than basic funcref/externref/exnref (see +// ValType) struct WasmElemSegment { uint32_t Flags; uint32_t TableNumber; diff --git a/llvm/include/llvm/CodeGen/ValueTypes.td b/llvm/include/llvm/CodeGen/ValueTypes.td index 900b30d9b0249..6ae283b9c5a85 100644 --- a/llvm/include/llvm/CodeGen/ValueTypes.td +++ b/llvm/include/llvm/CodeGen/ValueTypes.td @@ -280,11 +280,12 @@ def untyped : ValueType<8, 193> { // Produces an untyped value } def funcref : ValueType<0, 194>; // WebAssembly's funcref type def externref : ValueType<0, 195>; // WebAssembly's externref type -def x86amx : ValueType<8192, 196>; // X86 AMX value -def i64x8 : ValueType<512, 197>; // 8 Consecutive GPRs (AArch64) +def exnref : ValueType<0, 196>; // WebAssembly's exnref type +def x86amx : ValueType<8192, 197>; // X86 AMX value +def i64x8 : ValueType<512, 198>; // 8 Consecutive GPRs (AArch64) def aarch64svcount - : ValueType<16, 198>; // AArch64 predicate-as-counter -def spirvbuiltin : ValueType<0, 199>; // SPIR-V's builtin type + : ValueType<16, 199>; // AArch64 predicate-as-counter +def spirvbuiltin : ValueType<0, 200>; // SPIR-V's builtin type def token : ValueType<0, 248>; // TokenTy def MetadataVT : ValueType<0, 249> { // Metadata diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index 3019f68083d42..c3ac53837444e 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -316,6 +316,7 @@ def IIT_PPCF128 : IIT_VT; def IIT_V3 : IIT_Vec<3, 53>; def IIT_EXTERNREF : IIT_VT; def IIT_FUNCREF : IIT_VT; +def IIT_EXNREF: IIT_VT; def IIT_I2 : IIT_Int<2, 57>; def IIT_I4 : IIT_Int<4, 58>; def IIT_AARCH64_SVCOUNT : IIT_VT; @@ -581,6 +582,7 @@ def llvm_vararg_ty : LLVMType; // this means vararg here def llvm_externref_ty : LLVMType; def llvm_funcref_ty : LLVMType; +def llvm_exnref_ty : LLVMType; //===----------------------------------------------------------------------===// diff --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td index 572d334ac9552..373a816f476a3 100644 --- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td @@ -31,12 +31,17 @@ def int_wasm_ref_null_extern : DefaultAttrsIntrinsic<[llvm_externref_ty], [], [IntrNoMem]>; def int_wasm_ref_null_func : DefaultAttrsIntrinsic<[llvm_funcref_ty], [], [IntrNoMem]>; +def int_wasm_ref_null_exn: + DefaultAttrsIntrinsic<[llvm_exnref_ty], [], [IntrNoMem]>; def int_wasm_ref_is_null_extern : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_externref_ty], [IntrNoMem], "llvm.wasm.ref.is_null.extern">; def int_wasm_ref_is_null_func : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_funcref_ty], [IntrNoMem], "llvm.wasm.ref.is_null.func">; +def int_wasm_ref_is_null_exn : + DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_exnref_ty], [IntrNoMem], + "llvm.wasm.ref.is_null.exn">; //===----------------------------------------------------------------------===// // Table intrinsics @@ -47,6 +52,9 @@ def int_wasm_table_set_externref : def int_wasm_table_set_funcref : DefaultAttrsIntrinsic<[], [llvm_table_ty, llvm_i32_ty, llvm_funcref_ty], [IntrWriteMem]>; +def int_wasm_table_set_exnref : + DefaultAttrsIntrinsic<[], [llvm_table_ty, llvm_i32_ty, llvm_exnref_ty], + [IntrWriteMem]>; def int_wasm_table_get_externref : DefaultAttrsIntrinsic<[llvm_externref_ty], [llvm_table_ty, llvm_i32_ty], @@ -54,6 +62,9 @@ def int_wasm_table_get_externref : def int_wasm_table_get_funcref : DefaultAttrsIntrinsic<[llvm_funcref_ty], [llvm_table_ty, llvm_i32_ty], [IntrReadMem]>; +def int_wasm_table_get_exnref : + DefaultAttrsIntrinsic<[llvm_exnref_ty], [llvm_table_ty, llvm_i32_ty], + [IntrReadMem]>; // Query the current table size, and increase the current table size. def int_wasm_table_size : @@ -68,6 +79,9 @@ def int_wasm_table_grow_externref : def int_wasm_table_grow_funcref : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_table_ty, llvm_funcref_ty, llvm_i32_ty], []>; +def int_wasm_table_grow_exnref : + DefaultAttrsIntrinsic<[llvm_i32_ty], + [llvm_table_ty, llvm_exnref_ty, llvm_i32_ty], []>; def int_wasm_table_fill_externref : DefaultAttrsIntrinsic<[], [llvm_table_ty, llvm_i32_ty, llvm_externref_ty, @@ -76,6 +90,10 @@ def int_wasm_table_fill_funcref : DefaultAttrsIntrinsic<[], [llvm_table_ty, llvm_i32_ty, llvm_funcref_ty, llvm_i32_ty], []>; +def int_wasm_table_fill_exnref : + DefaultAttrsIntrinsic<[], + [llvm_table_ty, llvm_i32_ty, llvm_exnref_ty, + llvm_i32_ty], []>; //===----------------------------------------------------------------------===// // Trapping float-to-int conversions diff --git a/llvm/lib/CodeGen/ValueTypes.cpp b/llvm/lib/CodeGen/ValueTypes.cpp index 58db686ec7d57..078894d5ac4ed 100644 --- a/llvm/lib/CodeGen/ValueTypes.cpp +++ b/llvm/lib/CodeGen/ValueTypes.cpp @@ -181,6 +181,7 @@ std::string EVT::getEVTString() const { case MVT::Metadata: return "Metadata"; case MVT::Untyped: return "Untyped"; case MVT::funcref: return "funcref"; + case MVT::exnref: return "exnref"; case MVT::externref: return "externref"; case MVT::aarch64svcount: return "aarch64svcount"; diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 6507a0e5950eb..872a1214d4f0e 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -187,6 +187,7 @@ static wasm::ValType parseValType(WasmObjectFile::ReadContext &Ctx, case wasm::WASM_TYPE_V128: case wasm::WASM_TYPE_FUNCREF: case wasm::WASM_TYPE_EXTERNREF: + case wasm::WASM_TYPE_EXNREF: return wasm::ValType(Code); } if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) { @@ -1288,6 +1289,7 @@ Error WasmObjectFile::parseImportSection(ReadContext &Ctx) { auto ElemType = Im.Table.ElemType; if (ElemType != wasm::ValType::FUNCREF && ElemType != wasm::ValType::EXTERNREF && + ElemType != wasm::ValType::EXNREF && ElemType != wasm::ValType::OTHERREF) return make_error("invalid table element type", object_error::parse_failed); @@ -1346,6 +1348,7 @@ Error WasmObjectFile::parseTableSection(ReadContext &Ctx) { auto ElemType = Tables.back().Type.ElemType; if (ElemType != wasm::ValType::FUNCREF && ElemType != wasm::ValType::EXTERNREF && + ElemType != wasm::ValType::EXNREF && ElemType != wasm::ValType::OTHERREF) { return make_error("invalid table element type", object_error::parse_failed); @@ -1680,6 +1683,7 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) { Segment.ElemKind = parseValType(Ctx, ElemKind); if (Segment.ElemKind != wasm::ValType::FUNCREF && Segment.ElemKind != wasm::ValType::EXTERNREF && + Segment.ElemKind != wasm::ValType::EXNREF && Segment.ElemKind != wasm::ValType::OTHERREF) { return make_error("invalid elem type", object_error::parse_failed); diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp index 544a91d03dce0..7ad338f65706d 100644 --- a/llvm/lib/ObjectYAML/WasmYAML.cpp +++ b/llvm/lib/ObjectYAML/WasmYAML.cpp @@ -606,6 +606,7 @@ void ScalarEnumerationTraits::enumeration( ECase(V128); ECase(FUNCREF); ECase(EXTERNREF); + ECase(EXNREF); ECase(OTHERREF); #undef ECase } @@ -640,6 +641,7 @@ void ScalarEnumerationTraits::enumeration( #define ECase(X) IO.enumCase(Type, #X, CONCAT(X)); ECase(FUNCREF); ECase(EXTERNREF); + ECase(EXNREF); ECase(OTHERREF); #undef ECase } diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index d4e9fb057c44d..c1859a28488e1 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -353,6 +353,8 @@ inline bool isArgument(unsigned Opc) { case WebAssembly::ARGUMENT_funcref_S: case WebAssembly::ARGUMENT_externref: case WebAssembly::ARGUMENT_externref_S: + case WebAssembly::ARGUMENT_exnref: + case WebAssembly::ARGUMENT_exnref_S: return true; default: return false; @@ -375,6 +377,8 @@ inline bool isCopy(unsigned Opc) { case WebAssembly::COPY_FUNCREF_S: case WebAssembly::COPY_EXTERNREF: case WebAssembly::COPY_EXTERNREF_S: + case WebAssembly::COPY_EXNREF: + case WebAssembly::COPY_EXNREF_S: return true; default: return false; @@ -397,6 +401,8 @@ inline bool isTee(unsigned Opc) { case WebAssembly::TEE_FUNCREF_S: case WebAssembly::TEE_EXTERNREF: case WebAssembly::TEE_EXTERNREF_S: + case WebAssembly::TEE_EXNREF: + case WebAssembly::TEE_EXNREF_S: return true; default: return false; @@ -487,6 +493,8 @@ inline bool isLocalGet(unsigned Opc) { case WebAssembly::LOCAL_GET_FUNCREF_S: case WebAssembly::LOCAL_GET_EXTERNREF: case WebAssembly::LOCAL_GET_EXTERNREF_S: + case WebAssembly::LOCAL_GET_EXNREF: + case WebAssembly::LOCAL_GET_EXNREF_S: return true; default: return false; @@ -509,6 +517,8 @@ inline bool isLocalSet(unsigned Opc) { case WebAssembly::LOCAL_SET_FUNCREF_S: case WebAssembly::LOCAL_SET_EXTERNREF: case WebAssembly::LOCAL_SET_EXTERNREF_S: + case WebAssembly::LOCAL_SET_EXNREF: + case WebAssembly::LOCAL_SET_EXNREF_S: return true; default: return false; @@ -531,6 +541,8 @@ inline bool isLocalTee(unsigned Opc) { case WebAssembly::LOCAL_TEE_FUNCREF_S: case WebAssembly::LOCAL_TEE_EXTERNREF: case WebAssembly::LOCAL_TEE_EXTERNREF_S: + case WebAssembly::LOCAL_TEE_EXNREF: + case WebAssembly::LOCAL_TEE_EXNREF_S: return true; default: return false; diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTypeUtilities.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTypeUtilities.cpp index 8ea02bd2ad1ff..d9c8e22bbbaf5 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTypeUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTypeUtilities.cpp @@ -27,6 +27,7 @@ std::optional WebAssembly::parseType(StringRef Type) { wasm::ValType::V128) .Case("funcref", wasm::ValType::FUNCREF) .Case("externref", wasm::ValType::EXTERNREF) + .Case("exnref", wasm::ValType::EXNREF) .Default(std::nullopt); } @@ -40,6 +41,7 @@ WebAssembly::BlockType WebAssembly::parseBlockType(StringRef Type) { .Case("v128", WebAssembly::BlockType::V128) .Case("funcref", WebAssembly::BlockType::Funcref) .Case("externref", WebAssembly::BlockType::Externref) + .Case("exnref", WebAssembly::BlockType::Exnref) .Case("void", WebAssembly::BlockType::Void) .Default(WebAssembly::BlockType::Invalid); } @@ -62,6 +64,8 @@ const char *WebAssembly::anyTypeToString(unsigned Type) { return "funcref"; case wasm::WASM_TYPE_EXTERNREF: return "externref"; + case wasm::WASM_TYPE_EXNREF: + return "exnref"; case wasm::WASM_TYPE_FUNC: return "func"; case wasm::WASM_TYPE_NORESULT: @@ -110,6 +114,8 @@ wasm::ValType WebAssembly::regClassToValType(unsigned RC) { return wasm::ValType::FUNCREF; case WebAssembly::EXTERNREFRegClassID: return wasm::ValType::EXTERNREF; + case WebAssembly::EXNREFRegClassID: + return wasm::ValType::EXNREF; default: llvm_unreachable("unexpected type"); } diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTypeUtilities.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTypeUtilities.h index 486cf264d13e2..063ee4dba9068 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTypeUtilities.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTypeUtilities.h @@ -32,6 +32,7 @@ enum class BlockType : unsigned { V128 = unsigned(wasm::ValType::V128), Externref = unsigned(wasm::ValType::EXTERNREF), Funcref = unsigned(wasm::ValType::FUNCREF), + Exnref = unsigned(wasm::ValType::EXNREF), // Multivalue blocks (and other non-void blocks) are only emitted when the // blocks will never be exited and are at the ends of functions (see // WebAssemblyCFGStackify::fixEndsAtEndOfFunction). They also are never made @@ -41,7 +42,8 @@ enum class BlockType : unsigned { }; inline bool isRefType(wasm::ValType Type) { - return Type == wasm::ValType::EXTERNREF || Type == wasm::ValType::FUNCREF; + return Type == wasm::ValType::EXTERNREF || Type == wasm::ValType::FUNCREF || + Type == wasm::ValType::EXNREF; } // Convert ValType or a list/signature of ValTypes to a string. diff --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp index fac2e0d935f5a..6e5905c301ad5 100644 --- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp @@ -33,6 +33,7 @@ MVT WebAssembly::parseMVT(StringRef Type) { .Case("v2i64", MVT::v2i64) .Case("funcref", MVT::funcref) .Case("externref", MVT::externref) + .Case("exnref", MVT::exnref) .Default(MVT::INVALID_SIMPLE_VALUE_TYPE); } @@ -57,6 +58,8 @@ wasm::ValType WebAssembly::toValType(MVT Type) { return wasm::ValType::FUNCREF; case MVT::externref: return wasm::ValType::EXTERNREF; + case MVT::exnref: + return wasm::ValType::EXNREF; default: llvm_unreachable("unexpected type"); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 3524abba8990a..958705d7c51a0 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -125,6 +125,8 @@ static char getInvokeSig(wasm::ValType VT) { return 'F'; case wasm::ValType::EXTERNREF: return 'X'; + case wasm::ValType::EXNREF: + return 'E'; default: llvm_unreachable("Unhandled wasm::ValType enum"); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp index 0159c44a79b76..3c6a29311a10e 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp @@ -100,6 +100,8 @@ static unsigned getDropOpcode(const TargetRegisterClass *RC) { return WebAssembly::DROP_FUNCREF; if (RC == &WebAssembly::EXTERNREFRegClass) return WebAssembly::DROP_EXTERNREF; + if (RC == &WebAssembly::EXNREFRegClass) + return WebAssembly::DROP_EXNREF; llvm_unreachable("Unexpected register class"); } @@ -119,6 +121,8 @@ static unsigned getLocalGetOpcode(const TargetRegisterClass *RC) { return WebAssembly::LOCAL_GET_FUNCREF; if (RC == &WebAssembly::EXTERNREFRegClass) return WebAssembly::LOCAL_GET_EXTERNREF; + if (RC == &WebAssembly::EXNREFRegClass) + return WebAssembly::LOCAL_GET_EXNREF; llvm_unreachable("Unexpected register class"); } @@ -138,6 +142,8 @@ static unsigned getLocalSetOpcode(const TargetRegisterClass *RC) { return WebAssembly::LOCAL_SET_FUNCREF; if (RC == &WebAssembly::EXTERNREFRegClass) return WebAssembly::LOCAL_SET_EXTERNREF; + if (RC == &WebAssembly::EXNREFRegClass) + return WebAssembly::LOCAL_SET_EXNREF; llvm_unreachable("Unexpected register class"); } @@ -157,6 +163,8 @@ static unsigned getLocalTeeOpcode(const TargetRegisterClass *RC) { return WebAssembly::LOCAL_TEE_FUNCREF; if (RC == &WebAssembly::EXTERNREFRegClass) return WebAssembly::LOCAL_TEE_EXTERNREF; + if (RC == &WebAssembly::EXNREFRegClass) + return WebAssembly::LOCAL_TEE_EXNREF; llvm_unreachable("Unexpected register class"); } @@ -176,6 +184,8 @@ static MVT typeForRegClass(const TargetRegisterClass *RC) { return MVT::funcref; if (RC == &WebAssembly::EXTERNREFRegClass) return MVT::externref; + if (RC == &WebAssembly::EXNREFRegClass) + return MVT::exnref; llvm_unreachable("unrecognized register class"); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp index 1c62290704fe4..708e259d1a4cd 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -137,6 +137,10 @@ class WebAssemblyFastISel final : public FastISel { if (Subtarget->hasReferenceTypes()) return VT; break; + case MVT::exnref: + if (Subtarget->hasReferenceTypes() && Subtarget->hasExceptionHandling()) + return VT; + break; case MVT::f16: return MVT::f32; case MVT::v16i8: @@ -717,6 +721,10 @@ bool WebAssemblyFastISel::fastLowerArguments() { Opc = WebAssembly::ARGUMENT_externref; RC = &WebAssembly::EXTERNREFRegClass; break; + case MVT::exnref: + Opc = WebAssembly::ARGUMENT_exnref; + RC = &WebAssembly::EXNREFRegClass; + break; default: return false; } @@ -821,6 +829,9 @@ bool WebAssemblyFastISel::selectCall(const Instruction *I) { case MVT::externref: ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass); break; + case MVT::exnref: + ResultReg = createResultReg(&WebAssembly::EXNREFRegClass); + break; default: return false; } @@ -960,6 +971,10 @@ bool WebAssemblyFastISel::selectSelect(const Instruction *I) { Opc = WebAssembly::SELECT_EXTERNREF; RC = &WebAssembly::EXTERNREFRegClass; break; + case MVT::exnref: + Opc = WebAssembly::SELECT_EXNREF; + RC = &WebAssembly::EXNREFRegClass; + break; default: return false; } @@ -1367,6 +1382,7 @@ bool WebAssemblyFastISel::selectRet(const Instruction *I) { case MVT::v2f64: case MVT::funcref: case MVT::externref: + case MVT::exnref: break; default: return false; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index 527bb4c9fbea6..aeb6831c7f3b8 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -73,6 +73,9 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering( if (Subtarget->hasReferenceTypes()) { addRegisterClass(MVT::externref, &WebAssembly::EXTERNREFRegClass); addRegisterClass(MVT::funcref, &WebAssembly::FUNCREFRegClass); + if (Subtarget->hasExceptionHandling()) { + addRegisterClass(MVT::exnref, &WebAssembly::EXNREFRegClass); + } } // Compute derived properties from the register classes. computeRegisterProperties(Subtarget->getRegisterInfo()); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td index c1a5a45395e87..3d37eb2fa27bc 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -292,6 +292,7 @@ defm "": ARGUMENT; defm "": ARGUMENT; defm "": ARGUMENT; defm "": ARGUMENT; +defm "": ARGUMENT; // local.get and local.set are not generated by instruction selection; they // are implied by virtual register uses and defs. @@ -375,6 +376,8 @@ defm "" : LOCAL; defm "" : LOCAL, Requires<[HasSIMD128]>; defm "" : LOCAL, Requires<[HasReferenceTypes]>; defm "" : LOCAL, Requires<[HasReferenceTypes]>; +defm "" : LOCAL, + Requires<[HasReferenceTypes, HasExceptionHandling]>; let isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1 in { defm CONST_I32 : I<(outs I32:$res), (ins i32imm_op:$imm), diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td index 608963d588635..2654a09387fd4 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td @@ -17,8 +17,9 @@ multiclass REF_I { [(set rc:$dst, (!cast("int_wasm_ref_null_" # ht)))], "ref.null_" # ht # "$dst", "ref.null_" # ht, - !cond(!eq(ht, "func") : 0xd070, - !eq(ht, "extern") : 0xd06f)>, + !cond(!eq(ht, "func") : 0xd070, + !eq(ht, "extern") : 0xd06f, + !eq(ht, "exn") : 0xd069)>, Requires<[HasReferenceTypes]>; defm SELECT_#rc: I<(outs rc:$dst), (ins rc:$lhs, rc:$rhs, I32:$cond), (outs), (ins), @@ -37,8 +38,9 @@ multiclass REF_I { defm "" : REF_I; defm "" : REF_I; +defm "" : REF_I; -foreach rc = [FUNCREF, EXTERNREF] in { +foreach rc = [FUNCREF, EXTERNREF, EXNREF] in { def : Pat<(select (i32 (setne I32:$cond, 0)), rc:$lhs, rc:$rhs), (!cast("SELECT_"#rc) rc:$lhs, rc:$rhs, I32:$cond)>; def : Pat<(select (i32 (seteq I32:$cond, 0)), rc:$lhs, rc:$rhs), diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td index 069ce5e3bc94a..02f0ab8577c3d 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td @@ -64,6 +64,8 @@ multiclass TABLE { defm "" : TABLE, Requires<[HasReferenceTypes]>; defm "" : TABLE, Requires<[HasReferenceTypes]>; +defm "" : TABLE, + Requires<[HasReferenceTypes, HasExceptionHandling]>; def : Pat<(WebAssemblyTableSet mcsym:$table, i32:$idx, funcref:$r), (TABLE_SET_FUNCREF mcsym:$table, i32:$idx, funcref:$r)>, diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index ef174e1716ef1..d4edb6bf18d93 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -504,6 +504,8 @@ static unsigned getTeeOpcode(const TargetRegisterClass *RC) { return WebAssembly::TEE_EXTERNREF; if (RC == &WebAssembly::FUNCREFRegClass) return WebAssembly::TEE_FUNCREF; + if (RC == &WebAssembly::EXNREFRegClass) + return WebAssembly::TEE_EXNREF; llvm_unreachable("Unexpected register class"); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td index ba2936b492a9a..38a276319c41d 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td @@ -45,6 +45,7 @@ def V128_0: WebAssemblyReg<"%v128">; def FUNCREF_0 : WebAssemblyReg<"%funcref.0">; def EXTERNREF_0 : WebAssemblyReg<"%externref.0">; +def EXNREF_0 : WebAssemblyReg<"%exnref.0">; // The value stack "register". This is an opaque entity which serves to order // uses and defs that must remain in LIFO order. @@ -67,3 +68,4 @@ def V128 : WebAssemblyRegClass<[v4f32, v2f64, v2i64, v4i32, v16i8, v8i16], 128, (add V128_0)>; def FUNCREF : WebAssemblyRegClass<[funcref], 0, (add FUNCREF_0)>; def EXTERNREF : WebAssemblyRegClass<[externref], 0, (add EXTERNREF_0)>; +def EXNREF : WebAssemblyRegClass<[exnref], 0, (add EXNREF_0)>; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index 60e872549f87d..5e7279808cce6 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -175,6 +175,8 @@ unsigned WebAssembly::getCopyOpcodeForRegClass(const TargetRegisterClass *RC) { return WebAssembly::COPY_FUNCREF; case WebAssembly::EXTERNREFRegClassID: return WebAssembly::COPY_EXTERNREF; + case WebAssembly::EXNREFRegClassID: + return WebAssembly::COPY_EXNREF; default: llvm_unreachable("Unexpected register class"); } diff --git a/llvm/test/CodeGen/WebAssembly/reg-argument.mir b/llvm/test/CodeGen/WebAssembly/reg-argument.mir index 23e66dfc71fa1..a549990bdb0a2 100644 --- a/llvm/test/CodeGen/WebAssembly/reg-argument.mir +++ b/llvm/test/CodeGen/WebAssembly/reg-argument.mir @@ -68,3 +68,14 @@ body: | %1:externref = ARGUMENT_externref 0, implicit $arguments RETURN implicit-def $arguments ... +--- +name: argument_exnref +# CHECK-LABEL: argument_exnref +body: | + ; CHECK-LABEL: bb.0: + ; CHECK-NEXT: %1:exnref = ARGUMENT_exnref 0 + bb.0: + %0:i32 = CONST_I32 0, implicit-def $arguments + %1:exnref = ARGUMENT_exnref 0, implicit $arguments + RETURN implicit-def $arguments +... diff --git a/llvm/test/CodeGen/WebAssembly/reg-copy.mir b/llvm/test/CodeGen/WebAssembly/reg-copy.mir index 31a5bfa63a4ea..763fe42d07b61 100644 --- a/llvm/test/CodeGen/WebAssembly/reg-copy.mir +++ b/llvm/test/CodeGen/WebAssembly/reg-copy.mir @@ -77,3 +77,14 @@ body: | %0:externref = COPY %1:externref RETURN implicit-def $arguments ... +--- +name: copy_exnref +# CHECK-LABEL: copy_exnref +body: | + ; CHECK-LABEL: bb.0: + ; CHECK-NEXT: %0:exnref = COPY_EXNREF %1:exnref + ; CHECK-NEXT: RETURN + bb.0: + %0:exnref = COPY %1:exnref + RETURN implicit-def $arguments +... diff --git a/llvm/test/MC/WebAssembly/basic-assembly.s b/llvm/test/MC/WebAssembly/basic-assembly.s index 769cd7edfa8a3..ac358c1b5c7a5 100644 --- a/llvm/test/MC/WebAssembly/basic-assembly.s +++ b/llvm/test/MC/WebAssembly/basic-assembly.s @@ -146,12 +146,14 @@ test0: .ident "clang version 9.0.0 (trunk 364502) (llvm/trunk 364571)" -.tabletype empty_eref_table, externref -empty_eref_table: +.tabletype empty_externref_table, externref +empty_externref_table: -.tabletype empty_fref_table, funcref -empty_fref_table: +.tabletype empty_funcref_table, funcref +empty_funcref_table: +.tabletype empty_exnref_table, exnref +empty_exnref_table: # CHECK: .text # CHECK: .globaltype __stack_pointer, i32 @@ -283,8 +285,11 @@ empty_fref_table: # CHECK-NEXT: .p2align 2 # CHECK-NEXT: .int32 test0 -# CHECK: .tabletype empty_eref_table, externref -# CHECK-NEXT: empty_eref_table: +# CHECK: .tabletype empty_externref_table, externref +# CHECK-NEXT: empty_externref_table: -# CHECK: .tabletype empty_fref_table, funcref -# CHECK-NEXT: empty_fref_table: +# CHECK: .tabletype empty_funcref_table, funcref +# CHECK-NEXT: empty_funcref_table: + +# CHECK: .tabletype empty_exnref_table, exnref +# CHECK-NEXT: empty_exnref_table: diff --git a/llvm/test/MC/WebAssembly/reference-types.s b/llvm/test/MC/WebAssembly/reference-types.s index ab3e3ee6b155b..2f8bfba68dcea 100644 --- a/llvm/test/MC/WebAssembly/reference-types.s +++ b/llvm/test/MC/WebAssembly/reference-types.s @@ -4,22 +4,27 @@ # CHECK-LABEL:ref_is_null: # CHECK: ref.is_null # encoding: [0xd1] ref_is_null: - .functype ref_is_null () -> (i32, i32) + .functype ref_is_null () -> (i32, i32, i32) ref.null_extern ref.is_null ref.null_func ref.is_null + ref.null_exn + ref.is_null end_function # CHECK-LABEL: ref_null_test: # CHECK: ref.null_func # encoding: [0xd0,0x70] # CHECK: ref.null_extern # encoding: [0xd0,0x6f] +# CHECK: ref.null_exn # encoding: [0xd0,0x69] ref_null_test: .functype ref_null_test () -> () ref.null_func drop ref.null_extern drop + ref.null_exn + drop end_function # CHECK-LABEL: ref_sig_test_funcref: @@ -36,9 +41,17 @@ ref_sig_test_externref: local.get 0 end_function +# CHECK-LABEL: ref_sig_test_exnref: +# CHECK-NEXT: .functype ref_sig_test_exnref (exnref) -> (exnref) +ref_sig_test_exnref: + .functype ref_sig_test_exnref (exnref) -> (exnref) + local.get 0 + end_function + # CHECK-LABEL: ref_select_test: # CHECK: funcref.select # encoding: [0x1b] # CHECK: externref.select # encoding: [0x1b] +# CHECK: exnref.select # encoding: [0x1b] ref_select_test: .functype ref_select_test () -> () ref.null_func @@ -51,15 +64,24 @@ ref_select_test: i32.const 0 externref.select drop + ref.null_exn + ref.null_exn + i32.const 0 + exnref.select + drop end_function # CHECK-LABEL: ref_block_test: # CHECK: block funcref # CHECK: block externref +# CHECK: block exnref ref_block_test: - .functype ref_block_test () -> (externref, funcref) + .functype ref_block_test () -> (exnref, externref, funcref) block funcref block externref + block exnref + ref.null_exn + end_block ref.null_extern end_block ref.null_func diff --git a/llvm/test/MC/WebAssembly/type-checker-errors.s b/llvm/test/MC/WebAssembly/type-checker-errors.s index 5e28d117501e9..d2841250137a8 100644 --- a/llvm/test/MC/WebAssembly/type-checker-errors.s +++ b/llvm/test/MC/WebAssembly/type-checker-errors.s @@ -215,6 +215,22 @@ table_fill_type_mismatch_3: table.fill valid_table end_function +table_fill_type_mismatch_4: + .functype table_fill_type_mismatch_4 () -> () + ref.null_exn + i32.const 1 +# CHECK: [[@LINE+1]]:3: error: popped exnref, expected externref + table.fill valid_table + end_function + +table_fill_type_mismatch_5: + .functype table_fill_type_mismatch_5 () -> () + ref.null_exn + i32.const 1 +# CHECK: [[@LINE+1]]:3: error: popped exnref, expected externref + table.fill valid_table + end_function + table_grow_non_exist_table: .functype table_grow_non_exist_table (externref, i32) -> (i32) local.get 0 diff --git a/llvm/utils/TableGen/Common/CodeGenTarget.cpp b/llvm/utils/TableGen/Common/CodeGenTarget.cpp index e1cf33e7f62ff..52d1dde587903 100644 --- a/llvm/utils/TableGen/Common/CodeGenTarget.cpp +++ b/llvm/utils/TableGen/Common/CodeGenTarget.cpp @@ -269,6 +269,7 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) { case MVT::Untyped: return "MVT::Untyped"; case MVT::funcref: return "MVT::funcref"; case MVT::externref: return "MVT::externref"; + case MVT::exnref: return "MVT::exnref"; default: llvm_unreachable("ILLEGAL VALUE TYPE!"); } // clang-format on From 10d37817e4af60e0cf76527d577b1071b1a30127 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Tue, 28 May 2024 18:34:12 +0000 Subject: [PATCH 2/3] Fix comment --- llvm/lib/Object/WasmObjectFile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 872a1214d4f0e..23381955c60a8 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -177,8 +177,8 @@ static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) { static wasm::ValType parseValType(WasmObjectFile::ReadContext &Ctx, uint32_t Code) { - // only directly encoded FUNCREF/EXTERNREF are supported - // (not ref null func or ref null extern) + // only directly encoded FUNCREF/EXTERNREF/EXNREF are supported + // (not ref null func, ref null extern, or ref null exn) switch (Code) { case wasm::WASM_TYPE_I32: case wasm::WASM_TYPE_I64: From ea3ee65684e69c56fc2c6d151875c4f71f35f31f Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Tue, 28 May 2024 18:48:16 +0000 Subject: [PATCH 3/3] clang-format --- llvm/include/llvm/BinaryFormat/Wasm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index d8aa899080097..acf89885af6fd 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -58,7 +58,7 @@ enum : unsigned { WASM_TYPE_V128 = 0x7B, WASM_TYPE_NULLFUNCREF = 0x73, WASM_TYPE_NULLEXTERNREF = 0x72, - WASM_TYPE_NULLEXNREF= 0x74, + WASM_TYPE_NULLEXNREF = 0x74, WASM_TYPE_NULLREF = 0x71, WASM_TYPE_FUNCREF = 0x70, WASM_TYPE_EXTERNREF = 0x6F,