diff --git a/lld/test/wasm/externref.s b/lld/test/wasm/externref.s new file mode 100644 --- /dev/null +++ b/lld/test/wasm/externref.s @@ -0,0 +1,44 @@ +# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -o %t.o %s +# RUN: wasm-ld %t.o -o %t.wasm +# RUN: obj2yaml %t.wasm | FileCheck %s + +# Tests use of externref type, including storing it in a global + +.globaltype my_global, externref + +.globl read_externref +read_externref: + .functype read_externref () -> (externref) + global.get my_global + end_function + +.globl write_externref +write_externref: + .functype write_externref (externref) -> () + local.get 0 + global.set my_global + end_function + +my_global: + +.globl _start +_start: + .functype _start () -> () + call read_externref + call write_externref + end_function + +# CHECK: - Type: GLOBAL +# CHECK-NEXT: Globals: +# CHECK-NEXT: - Index: 0 +# CHECK-NEXT: Type: I32 +# CHECK-NEXT: Mutable: true +# CHECK-NEXT: InitExpr: +# CHECK-NEXT: Opcode: I32_CONST +# CHECK-NEXT: Value: 66560 +# CHECK-NEXT: - Index: 1 +# CHECK-NEXT: Type: EXTERNREF +# CHECK-NEXT: Mutable: true +# CHECK-NEXT: InitExpr: +# CHECK-NEXT: Opcode: REF_NULL +# CHECK-NEXT: Type: EXTERNREF diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp --- a/lld/wasm/WriterUtils.cpp +++ b/lld/wasm/WriterUtils.cpp @@ -32,6 +32,8 @@ return "v128"; case ValType::EXNREF: return "exnref"; + case ValType::EXTERNREF: + return "externref"; } llvm_unreachable("Invalid wasm::ValType"); } @@ -155,6 +157,9 @@ case WASM_OPCODE_GLOBAL_GET: writeUleb128(os, initExpr.Value.Global, "literal (global index)"); break; + case WASM_OPCODE_REF_NULL: + writeValueType(os, ValType::EXTERNREF, "literal (externref type)"); + break; default: fatal("unknown opcode in init expr: " + Twine(initExpr.Opcode)); } diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -232,6 +232,7 @@ WASM_TYPE_V128 = 0x7B, WASM_TYPE_FUNCREF = 0x70, WASM_TYPE_EXNREF = 0x68, + WASM_TYPE_EXTERNREF = 0x6F, WASM_TYPE_FUNC = 0x60, WASM_TYPE_NORESULT = 0x40, // for blocks with no result values }; @@ -258,6 +259,7 @@ WASM_OPCODE_F32_CONST = 0x43, WASM_OPCODE_F64_CONST = 0x44, WASM_OPCODE_I32_ADD = 0x6a, + WASM_OPCODE_REF_NULL = 0xd0, }; // Opcodes used in synthetic functions. @@ -355,6 +357,7 @@ F64 = WASM_TYPE_F64, V128 = WASM_TYPE_V128, EXNREF = WASM_TYPE_EXNREF, + EXTERNREF = WASM_TYPE_EXTERNREF, }; struct WasmSignature { diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -833,6 +833,9 @@ case wasm::WASM_TYPE_F64: writeI64(0); break; + case wasm::WASM_TYPE_EXTERNREF: + writeValueType(wasm::ValType::EXTERNREF); + break; default: llvm_unreachable("unexpected type"); } @@ -1462,6 +1465,9 @@ case wasm::WASM_TYPE_F64: Global.InitExpr.Opcode = wasm::WASM_OPCODE_F64_CONST; break; + case wasm::WASM_TYPE_EXTERNREF: + Global.InitExpr.Opcode = wasm::WASM_OPCODE_REF_NULL; + break; default: llvm_unreachable("unexpected type"); } diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -184,6 +184,14 @@ case wasm::WASM_OPCODE_GLOBAL_GET: Expr.Value.Global = readULEB128(Ctx); break; + case wasm::WASM_OPCODE_REF_NULL: { + wasm::ValType Ty = static_cast(readULEB128(Ctx)); + if (Ty != wasm::ValType::EXTERNREF) { + return make_error("Invalid type for ref.null", + object_error::parse_failed); + } + break; + } default: return make_error("Invalid opcode in init_expr", object_error::parse_failed); diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp --- a/llvm/lib/ObjectYAML/WasmYAML.cpp +++ b/llvm/lib/ObjectYAML/WasmYAML.cpp @@ -433,6 +433,11 @@ case wasm::WASM_OPCODE_GLOBAL_GET: IO.mapRequired("Index", Expr.Value.Global); break; + case wasm::WASM_OPCODE_REF_NULL: { + WasmYAML::ValueType Ty = wasm::WASM_TYPE_EXTERNREF; + IO.mapRequired("Type", Ty); + break; + } } } @@ -559,6 +564,8 @@ ECase(F64); ECase(V128); ECase(FUNCREF); + ECase(EXNREF); + ECase(EXTERNREF); ECase(FUNC); #undef ECase } @@ -583,6 +590,7 @@ ECase(F64_CONST); ECase(F32_CONST); ECase(GLOBAL_GET); + ECase(REF_NULL); #undef ECase } diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -322,6 +322,8 @@ return wasm::ValType::V128; if (Type == "exnref") return wasm::ValType::EXNREF; + if (Type == "externref") + return wasm::ValType::EXTERNREF; return Optional(); } diff --git a/llvm/test/MC/WebAssembly/externref.s b/llvm/test/MC/WebAssembly/externref.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/WebAssembly/externref.s @@ -0,0 +1,36 @@ +# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj < %s | obj2yaml | FileCheck %s + +# Tests use of externref type, including storing it in a global + +.globaltype my_global, externref + +.globl read_externref +read_externref: + .functype read_externref () -> (externref) + global.get my_global + end_function + +.globl write_externref +write_externref: + .functype write_externref (externref) -> () + local.get 0 + global.set my_global + end_function + +.globl call_with_ref +call_with_ref: + .functype call_with_ref () -> () + call read_externref + call write_externref + end_function + +my_global: + +# CHECK: - Type: GLOBAL +# CHECK-NEXT: Globals: +# CHECK-NEXT: - Index: 0 +# CHECK-NEXT: Type: EXTERNREF +# CHECK-NEXT: Mutable: true +# CHECK-NEXT: InitExpr: +# CHECK-NEXT: Opcode: REF_NULL +# CHECK-NEXT: Type: EXTERNREF