Skip to content

[WebAssembly] Add exnref type #93586

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lld/wasm/WriterUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
Expand Down
9 changes: 6 additions & 3 deletions llvm/include/llvm/BinaryFormat/Wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
};

Expand Down Expand Up @@ -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;
Expand Down
9 changes: 5 additions & 4 deletions llvm/include/llvm/CodeGen/ValueTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/IR/Intrinsics.td
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ def IIT_PPCF128 : IIT_VT<ppcf128, 52>;
def IIT_V3 : IIT_Vec<3, 53>;
def IIT_EXTERNREF : IIT_VT<externref, 54>;
def IIT_FUNCREF : IIT_VT<funcref, 55>;
def IIT_EXNREF: IIT_VT<exnref, 56>;
def IIT_I2 : IIT_Int<2, 57>;
def IIT_I4 : IIT_Int<4, 58>;
def IIT_AARCH64_SVCOUNT : IIT_VT<aarch64svcount, 59>;
Expand Down Expand Up @@ -581,6 +582,7 @@ def llvm_vararg_ty : LLVMType<isVoid>; // this means vararg here

def llvm_externref_ty : LLVMType<externref>;
def llvm_funcref_ty : LLVMType<funcref>;
def llvm_exnref_ty : LLVMType<exnref>;

//===----------------------------------------------------------------------===//

Expand Down
18 changes: 18 additions & 0 deletions llvm/include/llvm/IR/IntrinsicsWebAssembly.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -47,13 +52,19 @@ 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],
[IntrReadMem]>;
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 :
Expand All @@ -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,
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/ValueTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This causes a clang-format error, but this is in line with what's there, so won't fix it

case MVT::externref: return "externref";
case MVT::aarch64svcount:
return "aarch64svcount";
Expand Down
8 changes: 6 additions & 2 deletions llvm/lib/Object/WasmObjectFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also update the comment on line 180 above

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

return wasm::ValType(Code);
}
if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) {
Expand Down Expand Up @@ -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<GenericBinaryError>("invalid table element type",
object_error::parse_failed);
Expand Down Expand Up @@ -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<GenericBinaryError>("invalid table element type",
object_error::parse_failed);
Expand Down Expand Up @@ -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<GenericBinaryError>("invalid elem type",
object_error::parse_failed);
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/ObjectYAML/WasmYAML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ void ScalarEnumerationTraits<WasmYAML::ValueType>::enumeration(
ECase(V128);
ECase(FUNCREF);
ECase(EXTERNREF);
ECase(EXNREF);
ECase(OTHERREF);
#undef ECase
}
Expand Down Expand Up @@ -640,6 +641,7 @@ void ScalarEnumerationTraits<WasmYAML::TableType>::enumeration(
#define ECase(X) IO.enumCase(Type, #X, CONCAT(X));
ECase(FUNCREF);
ECase(EXTERNREF);
ECase(EXNREF);
ECase(OTHERREF);
#undef ECase
}
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,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;
Expand All @@ -377,6 +379,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;
Expand All @@ -399,6 +403,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;
Expand Down Expand Up @@ -489,6 +495,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;
Expand All @@ -511,6 +519,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;
Expand All @@ -533,6 +543,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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ std::optional<wasm::ValType> 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);
}

Expand All @@ -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);
}
Expand All @@ -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:
Expand Down Expand Up @@ -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");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -58,6 +59,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");
}
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

Expand All @@ -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");
}

Expand All @@ -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");
}

Expand All @@ -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");
}

Expand All @@ -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");
}

Expand Down
Loading
Loading