https://github.com/badumbatish created https://github.com/llvm/llvm-project/pull/148935
Landing support for nonnull_extern_ref in https://github.com/llvm/llvm-project/issues/136594. Unsure if more fixes are needed or split in another patch Implementation follows footstep of https://github.com/llvm/llvm-project/commit/890146b19206827bc48ee1ae1dc1534ff2ff18d7. Added test cases. >From 224712116275b58fade172096bfb512d9157691d Mon Sep 17 00:00:00 2001 From: Jasmine Tang <jjasm...@igalia.com> Date: Mon, 14 Jul 2025 18:31:07 -0700 Subject: [PATCH] Add scaffolding and drafting support for nonnull_extern_ref type --- clang/include/clang/AST/ASTContext.h | 3 ++ clang/include/clang/AST/Type.h | 6 +++ .../clang/Basic/WebAssemblyReferenceTypes.def | 2 + clang/lib/AST/ASTContext.cpp | 4 +- clang/lib/AST/Type.cpp | 13 ++++- clang/lib/CodeGen/CodeGenTypes.cpp | 3 ++ clang/lib/CodeGen/TargetInfo.h | 4 ++ clang/lib/CodeGen/Targets/WebAssembly.cpp | 3 ++ .../test/CodeGen/WebAssembly/wasm-externref.c | 47 +++++++++++++++++ clang/test/Sema/wasm-refs-and-tables.c | 51 +++++++++++++++++++ llvm/include/llvm/IR/IntrinsicsWebAssembly.td | 5 ++ llvm/include/llvm/IR/Type.h | 1 + llvm/lib/IR/Type.cpp | 7 +++ 13 files changed, 147 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 2b9cd035623cc..398e878dff90a 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1675,6 +1675,9 @@ class ASTContext : public RefCountedBase<ASTContext> { /// Return a WebAssembly externref type. QualType getWebAssemblyExternrefType() const; + /// Return a WebAssembly non null externref type. + QualType getWebAssemblyNonNullExternrefType() const; + /// Return the unique reference to a vector type of the specified /// element type and size. /// diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 21b97102db95a..3e35fa655c4d5 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1145,6 +1145,9 @@ class QualType { /// Returns true if it is a WebAssembly Externref Type. bool isWebAssemblyExternrefType() const; + /// Returns true if it is a WebAssembly non null Externref Type. + bool isWebAssemblyNonNullExternrefType() const; + /// Returns true if it is a WebAssembly Funcref Type. bool isWebAssemblyFuncrefType() const; @@ -2402,6 +2405,9 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { /// Check if this is a WebAssembly Externref Type. bool isWebAssemblyExternrefType() const; + /// Check if this is a WebAssembly non null Externref Type. + bool isWebAssemblyNonNullExternrefType() const; + /// Returns true if this is a WebAssembly table type: either an array of /// reference types, or a pointer to a reference type (which can only be /// created by array to pointer decay). diff --git a/clang/include/clang/Basic/WebAssemblyReferenceTypes.def b/clang/include/clang/Basic/WebAssemblyReferenceTypes.def index 7c83da15150ce..747eb4034f669 100644 --- a/clang/include/clang/Basic/WebAssemblyReferenceTypes.def +++ b/clang/include/clang/Basic/WebAssemblyReferenceTypes.def @@ -36,5 +36,7 @@ WASM_REF_TYPE("__externref_t", "externref_t", WasmExternRef, WasmExternRefTy, 10) +WASM_REF_TYPE("__non_null_externref_t", "non_null_externref_t", WasmNonNullExternRef, WasmNonNullExternRefTy, 10) + #undef WASM_TYPE #undef WASM_REF_TYPE diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 679812adcdf12..2322c5112eb73 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3550,6 +3550,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx, #define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id: #include "clang/Basic/AMDGPUTypes.def" case BuiltinType::WasmExternRef: + case BuiltinType::WasmNonNullExternRef: #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/RISCVVTypes.def" llvm_unreachable("not yet implemented"); @@ -4584,7 +4585,8 @@ ASTContext::getBuiltinVectorTypeInfo(const BuiltinType *Ty) const { QualType ASTContext::getWebAssemblyExternrefType() const { if (Target->getTriple().isWasm() && Target->hasFeature("reference-types")) { #define WASM_REF_TYPE(Name, MangledName, Id, SingletonId, AS) \ - if (BuiltinType::Id == BuiltinType::WasmExternRef) \ + if (BuiltinType::Id == BuiltinType::WasmExternRef || \ + BuiltinType::Id == BuiltinType::WasmNonNullExternRef) \ return SingletonId; #include "clang/Basic/WebAssemblyReferenceTypes.def" } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index e5a1ab2ff8906..b2302311ef291 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2553,6 +2553,12 @@ bool Type::isWebAssemblyExternrefType() const { return false; } +bool Type::isWebAssemblyNonNullExternrefType() const { + if (const auto *BT = getAs<BuiltinType>()) + return BT->getKind() == BuiltinType::WasmNonNullExternRef; + return false; +} + bool Type::isWebAssemblyTableType() const { if (const auto *ATy = dyn_cast<ArrayType>(this)) return ATy->getElementType().isWebAssemblyReferenceType(); @@ -2922,13 +2928,18 @@ bool QualType::hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD) { } bool QualType::isWebAssemblyReferenceType() const { - return isWebAssemblyExternrefType() || isWebAssemblyFuncrefType(); + return isWebAssemblyExternrefType() || isWebAssemblyNonNullExternrefType() || + isWebAssemblyFuncrefType(); } bool QualType::isWebAssemblyExternrefType() const { return getTypePtr()->isWebAssemblyExternrefType(); } +bool QualType::isWebAssemblyNonNullExternrefType() const { + return getTypePtr()->isWebAssemblyNonNullExternrefType(); +} + bool QualType::isWebAssemblyFuncrefType() const { return getTypePtr()->isFunctionPointerType() && getAddressSpace() == LangAS::wasm_funcref; diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index c98503e4bbd26..515a756c7a755 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -569,6 +569,9 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { case BuiltinType::Id: { \ if (BuiltinType::Id == BuiltinType::WasmExternRef) \ ResultType = CGM.getTargetCodeGenInfo().getWasmExternrefReferenceType(); \ + else if (BuiltinType::Id == BuiltinType::WasmNonNullExternRef) \ + ResultType = \ + CGM.getTargetCodeGenInfo().getWasmNonNullExternrefReferenceType(); \ else \ llvm_unreachable("Unexpected wasm reference builtin type!"); \ } break; diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index b4057d369f988..a416e4127ff13 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -418,6 +418,10 @@ class TargetCodeGenInfo { /// Return the WebAssembly externref reference type. virtual llvm::Type *getWasmExternrefReferenceType() const { return nullptr; } + /// Return the WebAssembly externref reference type. + virtual llvm::Type *getWasmNonNullExternrefReferenceType() const { + return nullptr; + } /// Return the WebAssembly funcref reference type. virtual llvm::Type *getWasmFuncrefReferenceType() const { return nullptr; } diff --git a/clang/lib/CodeGen/Targets/WebAssembly.cpp b/clang/lib/CodeGen/Targets/WebAssembly.cpp index 9217c78a540a3..054dd7c66455c 100644 --- a/clang/lib/CodeGen/Targets/WebAssembly.cpp +++ b/clang/lib/CodeGen/Targets/WebAssembly.cpp @@ -89,6 +89,9 @@ class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo { virtual llvm::Type *getWasmExternrefReferenceType() const override { return llvm::Type::getWasm_ExternrefTy(getABIInfo().getVMContext()); } + virtual llvm::Type *getWasmNonNullExternrefReferenceType() const override { + return llvm::Type::getWasm_NonNullExternrefTy(getABIInfo().getVMContext()); + } /// Return the WebAssembly funcref reference type. virtual llvm::Type *getWasmFuncrefReferenceType() const override { return llvm::Type::getWasm_FuncrefTy(getABIInfo().getVMContext()); diff --git a/clang/test/CodeGen/WebAssembly/wasm-externref.c b/clang/test/CodeGen/WebAssembly/wasm-externref.c index 788438bb4a86a..ae3b4b450eccc 100644 --- a/clang/test/CodeGen/WebAssembly/wasm-externref.c +++ b/clang/test/CodeGen/WebAssembly/wasm-externref.c @@ -2,8 +2,10 @@ // RUN: %clang_cc1 -triple wasm32-unknown-unknown -target-feature +reference-types -o - -emit-llvm %s | FileCheck %s typedef __externref_t externref_t; +typedef __non_null_externref_t nn_externref_t; void helper(externref_t); +void helper_2(nn_externref_t); // CHECK-LABEL: @handle( // CHECK-NEXT: entry: @@ -16,3 +18,48 @@ void helper(externref_t); void handle(externref_t obj) { helper(obj); } + + +// CHECK-LABEL: @handle_2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[OBJ_ADDR:%.*]] = alloca ptr addrspace(10), align 1 +// CHECK-NEXT: store ptr addrspace(10) [[OBJ:%.*]], ptr [[OBJ_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr addrspace(10), ptr [[OBJ_ADDR]], align 1 +// CHECK-NEXT: call void @helper_2(ptr addrspace(10) [[TMP0]]) +// CHECK-NEXT: ret void +// +void handle_2(nn_externref_t obj) { + helper_2(obj); +} + + +nn_externref_t socketpair_js_concat(nn_externref_t, nn_externref_t) +__attribute__((import_module("wasm:js-string"), import_name("concat"))); + +nn_externref_t get_string_ref(const char *s); +void print_string_ref(nn_externref_t); + +// CHECK-LABEL: @socketpair_example( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[STR1:%.*]] = alloca ptr addrspace(10), align 1 +// CHECK-NEXT: [[STR2:%.*]] = alloca ptr addrspace(10), align 1 +// CHECK-NEXT: [[RESULT:%.*]] = alloca ptr addrspace(10), align 1 +// CHECK-NEXT: [[CALL:%.*]] = call ptr addrspace(10) @get_string_ref(ptr noundef @.str) +// CHECK-NEXT: store ptr addrspace(10) [[CALL]], ptr [[STR1]], align 1 +// CHECK-NEXT: [[CALL1:%.*]] = call ptr addrspace(10) @get_string_ref(ptr noundef @.str.1) +// CHECK-NEXT: store ptr addrspace(10) [[CALL1]], ptr [[STR2]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr addrspace(10), ptr [[STR1]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr addrspace(10), ptr [[STR2]], align 1 +// CHECK-NEXT: [[CALL2:%.*]] = call ptr addrspace(10) @socketpair_js_concat(ptr addrspace(10) [[TMP0]], ptr addrspace(10) [[TMP1]]) +// CHECK-NEXT: store ptr addrspace(10) [[CALL2]], ptr [[RESULT]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr addrspace(10), ptr [[RESULT]], align 1 +// CHECK-NEXT: call void @print_string_ref(ptr addrspace(10) [[TMP2]]) +// CHECK-NEXT: ret void +// +void socketpair_example() { + nn_externref_t str1 = get_string_ref("Hello, "); + nn_externref_t str2 = get_string_ref("world!"); + nn_externref_t result = socketpair_js_concat(str1, str2); + print_string_ref(result); +} + diff --git a/clang/test/Sema/wasm-refs-and-tables.c b/clang/test/Sema/wasm-refs-and-tables.c index dd8536c52cd03..0237138ed9eda 100644 --- a/clang/test/Sema/wasm-refs-and-tables.c +++ b/clang/test/Sema/wasm-refs-and-tables.c @@ -9,6 +9,10 @@ __externref_t r1; extern __externref_t r2; static __externref_t r3; +__non_null_externref_t nn_r1; +extern __non_null_externref_t nn_r2; +static __non_null_externref_t nn_r3; + __externref_t *t1; // expected-error {{pointer to WebAssembly reference type is not allowed}} __externref_t **t2; // expected-error {{pointer to WebAssembly reference type is not allowed}} __externref_t ******t3; // expected-error {{pointer to WebAssembly reference type is not allowed}} @@ -19,10 +23,24 @@ __externref_t t7[0]; // expected-error {{WebAssembly table must be s static __externref_t t8[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}} static __externref_t (*t9)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}} +__non_null_externref_t *nn_t1; // expected-error {{pointer to WebAssembly reference type is not allowed}} +__non_null_externref_t **nn_t2; // expected-error {{pointer to WebAssembly reference type is not allowed}} +__non_null_externref_t ******nn_t3; // expected-error {{pointer to WebAssembly reference type is not allowed}} +static __non_null_externref_t nn_t4[3]; // expected-error {{only zero-length WebAssembly tables are currently supported}} +static __non_null_externref_t nn_t5[]; // expected-error {{only zero-length WebAssembly tables are currently supported}} +static __non_null_externref_t nn_t6[] = {0}; // expected-error {{only zero-length WebAssembly tables are currently supported}} +__non_null_externref_t nn_t7[0]; // expected-error {{WebAssembly table must be static}} +static __non_null_externref_t nn_t8[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}} +static __non_null_externref_t (*nn_t9)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}} + static __externref_t table[0]; static __externref_t other_table[0] = {}; static __externref_t another_table[] = {}; // expected-error {{only zero-length WebAssembly tables are currently supported}} +static __non_null_externref_t nn_table[0]; +static __non_null_externref_t nn_other_table[0] = {}; +static __non_null_externref_t nn_another_table[] = {}; // expected-error {{only zero-length WebAssembly tables are currently supported}} + struct s { __externref_t f1; // expected-error {{field has sizeless type '__externref_t'}} __externref_t f2[0]; // expected-error {{field has sizeless type '__externref_t'}} @@ -33,6 +51,17 @@ struct s { __externref_t (*f7)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}} }; + +struct nn_s { + __externref_t nn_f1; // expected-error {{field has sizeless type '__externref_t'}} + __externref_t nn_f2[0]; // expected-error {{field has sizeless type '__externref_t'}} + __externref_t nn_f3[]; // expected-error {{field has sizeless type '__externref_t'}} + __externref_t nn_f4[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}} + __externref_t *nn_f5; // expected-error {{pointer to WebAssembly reference type is not allowed}} + __externref_t ****nn_f6; // expected-error {{pointer to WebAssembly reference type is not allowed}} + __externref_t (*nn_f7)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}} +}; + union u { __externref_t f1; // expected-error {{field has sizeless type '__externref_t'}} __externref_t f2[0]; // expected-error {{field has sizeless type '__externref_t'}} @@ -43,16 +72,38 @@ union u { __externref_t (*f7)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}} }; + +union nn_u { + __externref_t nn_f1; // expected-error {{field has sizeless type '__externref_t'}} + __externref_t nn_f2[0]; // expected-error {{field has sizeless type '__externref_t'}} + __externref_t nn_f3[]; // expected-error {{field has sizeless type '__externref_t'}} + __externref_t nn_f4[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}} + __externref_t *nn_f5; // expected-error {{pointer to WebAssembly reference type is not allowed}} + __externref_t ****nn_f6; // expected-error {{pointer to WebAssembly reference type is not allowed}} + __externref_t (*f7)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}} +}; + void illegal_argument_1(__externref_t table[]); // expected-error {{cannot use WebAssembly table as a function parameter}} void illegal_argument_2(__externref_t table[0][0]); // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}} void illegal_argument_3(__externref_t *table); // expected-error {{pointer to WebAssembly reference type is not allowed}} void illegal_argument_4(__externref_t ***table); // expected-error {{pointer to WebAssembly reference type is not allowed}} void illegal_argument_5(__externref_t (*table)[0]); // expected-error {{cannot form a pointer to a WebAssembly table}} void illegal_argument_6(__externref_t table[0]); // expected-error {{cannot use WebAssembly table as a function parameter}} + +void illegal_nn_argument_1(__non_null_externref_t table[]); // expected-error {{cannot use WebAssembly table as a function parameter}} +void illegal_nn_argument_2(__non_null_externref_t table[0][0]); // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}} +void illegal_nn_argument_3(__non_null_externref_t *table); // expected-error {{pointer to WebAssembly reference type is not allowed}} +void illegal_nn_argument_4(__non_null_externref_t ***table); // expected-error {{pointer to WebAssembly reference type is not allowed}} +void illegal_nn_argument_5(__non_null_externref_t (*table)[0]); // expected-error {{cannot form a pointer to a WebAssembly table}} +void illegal_nn_argument_6(__non_null_externref_t table[0]); // expected-error {{cannot use WebAssembly table as a function parameter}} __externref_t *illegal_return_1(); // expected-error {{pointer to WebAssembly reference type is not allowed}} __externref_t ***illegal_return_2(); // expected-error {{pointer to WebAssembly reference type is not allowed}} __externref_t (*illegal_return_3())[0]; // expected-error {{cannot form a pointer to a WebAssembly table}} + +__non_null_externref_t *illegal_nn_return_1(); // expected-error {{pointer to WebAssembly reference type is not allowed}} +__non_null_externref_t ***illegal_nn_return_2(); // expected-error {{pointer to WebAssembly reference type is not allowed}} +__non_null_externref_t (*illegal_nn_return_3())[0]; // expected-error {{cannot form a pointer to a WebAssembly table}} void varargs(int, ...); typedef void (*__funcref funcref_t)(); diff --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td index f592ff287a0e3..93510e52af4d5 100644 --- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td @@ -29,6 +29,11 @@ def int_wasm_memory_grow : //===----------------------------------------------------------------------===// def int_wasm_ref_null_extern : DefaultAttrsIntrinsic<[llvm_externref_ty], [], [IntrNoMem]>; + +// TODO: Is this correct? +def int_wasm_ref_nonnull_extern + : DefaultAttrsIntrinsic<[llvm_externref_ty], [], [IntrNoMem]>; + def int_wasm_ref_null_func : DefaultAttrsIntrinsic<[llvm_funcref_ty], [], [IntrNoMem]>; def int_wasm_ref_null_exn: diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h index 74dd490729741..d488b1552240a 100644 --- a/llvm/include/llvm/IR/Type.h +++ b/llvm/include/llvm/IR/Type.h @@ -476,6 +476,7 @@ class Type { // Convenience methods for getting pointer types. // LLVM_ABI static Type *getWasm_ExternrefTy(LLVMContext &C); + LLVM_ABI static Type *getWasm_NonNullExternrefTy(LLVMContext &C); LLVM_ABI static Type *getWasm_FuncrefTy(LLVMContext &C); /// Return a pointer to the current type. This is equivalent to diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp index 5e1bf2863191c..75afb0989c111 100644 --- a/llvm/lib/IR/Type.cpp +++ b/llvm/lib/IR/Type.cpp @@ -308,6 +308,13 @@ Type *Type::getWasm_ExternrefTy(LLVMContext &C) { return Ty; } +Type *Type::getWasm_NonNullExternrefTy(LLVMContext &C) { + // opaque pointer in addrspace(10) + // TODO: Hey Jasmine, Is this correct? + static PointerType *Ty = PointerType::get(C, 10); + return Ty; +} + Type *Type::getWasm_FuncrefTy(LLVMContext &C) { // opaque pointer in addrspace(20) static PointerType *Ty = PointerType::get(C, 20); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits