From a093a778ee8c1660896ab72bbbaaac6e62965216 Mon Sep 17 00:00:00 2001 From: Jasmine Tang Date: Tue, 22 Jul 2025 11:38:59 -0700 Subject: [PATCH 1/4] Precommit test for nonnull extern ref --- .../test/CodeGen/WebAssembly/wasm-externref.c | 47 +++++++++++ clang/test/Sema/wasm-refs-and-tables.c | 80 +++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/clang/test/CodeGen/WebAssembly/wasm-externref.c b/clang/test/CodeGen/WebAssembly/wasm-externref.c index 788438bb4a86a..1bc9f74f46074 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(11), align 1 +// CHECK-NEXT: store ptr addrspace(11) [[OBJ:%.*]], ptr [[OBJ_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr addrspace(11), ptr [[OBJ_ADDR]], align 1 +// CHECK-NEXT: call void @helper_2(ptr addrspace(11) [[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(11), align 1 +// CHECK-NEXT: [[STR2:%.*]] = alloca ptr addrspace(11), align 1 +// CHECK-NEXT: [[RESULT:%.*]] = alloca ptr addrspace(11), align 1 +// CHECK-NEXT: [[CALL:%.*]] = call ptr addrspace(11) @get_string_ref(ptr noundef @.str) +// CHECK-NEXT: store ptr addrspace(11) [[CALL]], ptr [[STR1]], align 1 +// CHECK-NEXT: [[CALL1:%.*]] = call ptr addrspace(11) @get_string_ref(ptr noundef @.str.1) +// CHECK-NEXT: store ptr addrspace(11) [[CALL1]], ptr [[STR2]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr addrspace(11), ptr [[STR1]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr addrspace(11), ptr [[STR2]], align 1 +// CHECK-NEXT: [[CALL2:%.*]] = call ptr addrspace(11) @socketpair_js_concat(ptr addrspace(11) [[TMP0]], ptr addrspace(11) [[TMP1]]) +// CHECK-NEXT: store ptr addrspace(11) [[CALL2]], ptr [[RESULT]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load ptr addrspace(11), ptr [[RESULT]], align 1 +// CHECK-NEXT: call void @print_string_ref(ptr addrspace(11) [[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..09ddbf5798f61 100644 --- a/clang/test/Sema/wasm-refs-and-tables.c +++ b/clang/test/Sema/wasm-refs-and-tables.c @@ -1,3 +1,4 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 // RUN: %clang_cc1 -fsyntax-only -verify=expected,conly -triple wasm32 -Wno-unused-value -target-feature +reference-types %s // RUN: %clang_cc1 -x c++ -std=c++17 -fsyntax-only -verify=expected,cpp -triple wasm32 -Wno-unused-value -target-feature +reference-types %s @@ -9,6 +10,10 @@ __externref_t r1; extern __externref_t r2; static __externref_t r3; +__non_null_externref_t nn_r1; // expected-error {{unknown type name '__non_null_externref_t'}} +extern __non_null_externref_t nn_r2; // expected-error {{unknown type name '__non_null_externref_t'}} +static __non_null_externref_t nn_r3; // expected-error {{unknown type name '__non_null_externref_t'}} + __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 +24,28 @@ __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 {{unknown type name '__non_null_externref_t'}} +__non_null_externref_t **nn_t2; // expected-error {{unknown type name '__non_null_externref_t'}} +__non_null_externref_t ******nn_t3; // expected-error {{unknown type name '__non_null_externref_t'}} +static __non_null_externref_t nn_t4[3]; // expected-error {{unknown type name '__non_null_externref_t'}} +static __non_null_externref_t nn_t5[]; // expected-error {{unknown type name '__non_null_externref_t'}} \ + // cpp-error {{definition of variable with array type needs an explicit size or an initializer}} +static __non_null_externref_t nn_t6[] = {0}; // expected-error {{unknown type name '__non_null_externref_t'}} +__non_null_externref_t nn_t7[0]; // expected-error {{unknown type name '__non_null_externref_t'}} +static __non_null_externref_t nn_t8[0][0]; // expected-error {{unknown type name '__non_null_externref_t'}} +static __non_null_externref_t (*nn_t9)[0]; // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit in}} \ + // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit in}} \ + // conly-error {{function cannot return array type 'int[0]'}} \ + // cpp-error {{unknown type name '__non_null_externref_t'}} + 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]; // expected-error {{unknown type name '__non_null_externref_t'}} +static __non_null_externref_t nn_other_table[0] = {}; // expected-error {{unknown type name '__non_null_externref_t'}} +static __non_null_externref_t nn_another_table[] = {}; // expected-error {{unknown type name '__non_null_externref_t'}} + 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 +56,19 @@ struct s { __externref_t (*f7)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}} }; + +struct nn_s { + __non_null_externref_t nn_f1; // expected-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t nn_f2[0]; // expected-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t nn_f3[]; // expected-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t nn_f4[0][0]; // expected-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t *nn_f5; // expected-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t ****nn_f6; // expected-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t (*nn_f7)[0]; // conly-error {{type name requires a specifier or qualifier}} \ + // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \ + // cpp-error {{unknown type name '__non_null_externref_t'}} +}; + 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,6 +79,19 @@ union u { __externref_t (*f7)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}} }; + +union nn_u { + __non_null_externref_t nn_f1; // expected-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t nn_f2[0]; // expected-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t nn_f3[]; // expected-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t nn_f4[0][0]; // expected-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t *nn_f5; // expected-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t ****nn_f6; // expected-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t (*f7)[0]; // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \ + // conly-error {{type name requires a specifier or qualifier}} \ + // cpp-error {{unknown type name '__non_null_externref_t'}} +}; + 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}} @@ -50,10 +99,28 @@ void illegal_argument_4(__externref_t ***table); // expected-error {{pointer 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 {{unknown type name '__non_null_externref_t'}} +void illegal_nn_argument_2(__non_null_externref_t table[0][0]); // expected-error {{unknown type name '__non_null_externref_t'}} +void illegal_nn_argument_3(__non_null_externref_t *table); // expected-error {{unknown type name '__non_null_externref_t'}} +void illegal_nn_argument_4(__non_null_externref_t ***table); // expected-error {{unknown type name '__non_null_externref_t'}} +void illegal_nn_argument_5(__non_null_externref_t (*table)[0]); // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit in}} \ + // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit in}} \ + // conly-error {{function cannot return array type 'int[0]'}} \ + // cpp-error {{variable has incomplete type 'void'}} \ + // cpp-error {{use of undeclared identifier '__non_null_externref_t'}} +void illegal_nn_argument_6(__non_null_externref_t table[0]); // expected-error {{unknown type name '__non_null_externref_t'}} + __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 {{unknown type name '__non_null_externref_t'}} +__non_null_externref_t ***illegal_nn_return_2(); // expected-error {{unknown type name '__non_null_externref_t'}} +__non_null_externref_t (*illegal_nn_return_3())[0]; // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit in}} \ + // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit in}} \ + // conly-error {{function cannot return array type 'int[0]'}} \ + // cpp-error {{unknown type name '__non_null_externref_t'}} + void varargs(int, ...); typedef void (*__funcref funcref_t)(); typedef void (*__funcref __funcref funcref_fail_t)(); // expected-warning {{attribute '__funcref' is already applied}} @@ -133,3 +200,16 @@ void foo() { void *ret_void_ptr() { return table; // expected-error {{cannot return a WebAssembly table}} } + +// checks all related assignment from extern ref to non null extern ref and vice versa +void externref_assignment(__externref_t er, __non_null_externref_t nn_er) { // expected-error {{unknown type name '__non_null_externref_t'}} + __externref_t asg_1 = er; + __externref_t asg_2 = nn_er; + + __non_null_externref_t nn_asg_1 = er; // conly-error {{expected ';' after expression}} \ + // conly-error {{use of undeclared identifier 'nn_asg_1'}} \ + // cpp-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t nn_asg_2 = nn_er; // conly-error {{expected ';' after expression}} \ + // conly-error {{use of undeclared identifier 'nn_asg_2'}} \ + // cpp-error {{unknown type name '__non_null_externref_t'}} +} From d57b88fa7be3981dc2a9b9d2307447333ecb24f5 Mon Sep 17 00:00:00 2001 From: Jasmine Tang Date: Tue, 22 Jul 2025 11:39:08 -0700 Subject: [PATCH 2/4] ok --- 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 + clang/lib/Sema/SemaDecl.cpp | 5 + clang/lib/Sema/SemaExpr.cpp | 5 + clang/test/Sema/wasm-refs-and-tables.c | 117 ++++++++---------- llvm/include/llvm/CodeGen/ValueTypes.td | 1 + llvm/include/llvm/IR/Intrinsics.td | 1 + llvm/include/llvm/IR/IntrinsicsWebAssembly.td | 5 + llvm/include/llvm/IR/Type.h | 1 + llvm/lib/IR/Type.cpp | 6 + 16 files changed, 110 insertions(+), 69 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 { /// 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()) + return BT->getKind() == BuiltinType::WasmNonNullExternRef; + return false; +} + bool Type::isWebAssemblyTableType() const { if (const auto *ATy = dyn_cast(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/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 11cbda412667f..bb41c30e0eeae 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -13643,6 +13643,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { return; } + if (VDecl->getType().isWebAssemblyExternrefType() && Init->getType()->isWebAssemblyNonNullExternrefType()) { + VDecl->setInit(Init); + return; + } + // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. if (VDecl->getType()->isUndeducedType()) { if (Init->containsErrors()) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 01df1913339d9..a3bf2db4bb6c7 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -9638,6 +9638,11 @@ AssignConvertType Sema::CheckAssignmentConstraints(QualType LHSType, return AssignConvertType::Compatible; } + if (LHSType->isWebAssemblyExternrefType() && RHSType->isWebAssemblyNonNullExternrefType()) { + Kind = CK_NoOp; + return AssignConvertType::Compatible; + } + return AssignConvertType::Incompatible; } diff --git a/clang/test/Sema/wasm-refs-and-tables.c b/clang/test/Sema/wasm-refs-and-tables.c index 09ddbf5798f61..2c5b8307998b1 100644 --- a/clang/test/Sema/wasm-refs-and-tables.c +++ b/clang/test/Sema/wasm-refs-and-tables.c @@ -1,4 +1,3 @@ -// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 // RUN: %clang_cc1 -fsyntax-only -verify=expected,conly -triple wasm32 -Wno-unused-value -target-feature +reference-types %s // RUN: %clang_cc1 -x c++ -std=c++17 -fsyntax-only -verify=expected,cpp -triple wasm32 -Wno-unused-value -target-feature +reference-types %s @@ -10,9 +9,9 @@ __externref_t r1; extern __externref_t r2; static __externref_t r3; -__non_null_externref_t nn_r1; // expected-error {{unknown type name '__non_null_externref_t'}} -extern __non_null_externref_t nn_r2; // expected-error {{unknown type name '__non_null_externref_t'}} -static __non_null_externref_t nn_r3; // expected-error {{unknown type name '__non_null_externref_t'}} +__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}} @@ -24,27 +23,23 @@ __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 {{unknown type name '__non_null_externref_t'}} -__non_null_externref_t **nn_t2; // expected-error {{unknown type name '__non_null_externref_t'}} -__non_null_externref_t ******nn_t3; // expected-error {{unknown type name '__non_null_externref_t'}} -static __non_null_externref_t nn_t4[3]; // expected-error {{unknown type name '__non_null_externref_t'}} -static __non_null_externref_t nn_t5[]; // expected-error {{unknown type name '__non_null_externref_t'}} \ - // cpp-error {{definition of variable with array type needs an explicit size or an initializer}} -static __non_null_externref_t nn_t6[] = {0}; // expected-error {{unknown type name '__non_null_externref_t'}} -__non_null_externref_t nn_t7[0]; // expected-error {{unknown type name '__non_null_externref_t'}} -static __non_null_externref_t nn_t8[0][0]; // expected-error {{unknown type name '__non_null_externref_t'}} -static __non_null_externref_t (*nn_t9)[0]; // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit in}} \ - // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit in}} \ - // conly-error {{function cannot return array type 'int[0]'}} \ - // cpp-error {{unknown type name '__non_null_externref_t'}} +__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]; // expected-error {{unknown type name '__non_null_externref_t'}} -static __non_null_externref_t nn_other_table[0] = {}; // expected-error {{unknown type name '__non_null_externref_t'}} -static __non_null_externref_t nn_another_table[] = {}; // expected-error {{unknown type name '__non_null_externref_t'}} +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'}} @@ -58,15 +53,13 @@ struct s { struct nn_s { - __non_null_externref_t nn_f1; // expected-error {{unknown type name '__non_null_externref_t'}} - __non_null_externref_t nn_f2[0]; // expected-error {{unknown type name '__non_null_externref_t'}} - __non_null_externref_t nn_f3[]; // expected-error {{unknown type name '__non_null_externref_t'}} - __non_null_externref_t nn_f4[0][0]; // expected-error {{unknown type name '__non_null_externref_t'}} - __non_null_externref_t *nn_f5; // expected-error {{unknown type name '__non_null_externref_t'}} - __non_null_externref_t ****nn_f6; // expected-error {{unknown type name '__non_null_externref_t'}} - __non_null_externref_t (*nn_f7)[0]; // conly-error {{type name requires a specifier or qualifier}} \ - // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \ - // cpp-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t nn_f1; // expected-error {{field has sizeless type '__non_null_externref_t'}} + __non_null_externref_t nn_f2[0]; // expected-error {{field has sizeless type '__non_null_externref_t'}} + __non_null_externref_t nn_f3[]; // expected-error {{field has sizeless type '__non_null_externref_t'}} + __non_null_externref_t nn_f4[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}} + __non_null_externref_t *nn_f5; // expected-error {{pointer to WebAssembly reference type is not allowed}} + __non_null_externref_t ****nn_f6; // expected-error {{pointer to WebAssembly reference type is not allowed}} + __non_null_externref_t (*nn_f7)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}} }; union u { @@ -81,15 +74,13 @@ union u { union nn_u { - __non_null_externref_t nn_f1; // expected-error {{unknown type name '__non_null_externref_t'}} - __non_null_externref_t nn_f2[0]; // expected-error {{unknown type name '__non_null_externref_t'}} - __non_null_externref_t nn_f3[]; // expected-error {{unknown type name '__non_null_externref_t'}} - __non_null_externref_t nn_f4[0][0]; // expected-error {{unknown type name '__non_null_externref_t'}} - __non_null_externref_t *nn_f5; // expected-error {{unknown type name '__non_null_externref_t'}} - __non_null_externref_t ****nn_f6; // expected-error {{unknown type name '__non_null_externref_t'}} - __non_null_externref_t (*f7)[0]; // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int}} \ - // conly-error {{type name requires a specifier or qualifier}} \ - // cpp-error {{unknown type name '__non_null_externref_t'}} + __non_null_externref_t nn_f1; // expected-error {{field has sizeless type '__non_null_externref_t'}} + __non_null_externref_t nn_f2[0]; // expected-error {{field has sizeless type '__non_null_externref_t'}} + __non_null_externref_t nn_f3[]; // expected-error {{field has sizeless type '__non_null_externref_t'}} + __non_null_externref_t nn_f4[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are not allowed}} + __non_null_externref_t *nn_f5; // expected-error {{pointer to WebAssembly reference type is not allowed}} + __non_null_externref_t ****nn_f6; // expected-error {{pointer to WebAssembly reference type is not allowed}} + __non_null_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}} @@ -98,28 +89,21 @@ void illegal_argument_3(__externref_t *table); // expected-error {{pointer 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 {{unknown type name '__non_null_externref_t'}} -void illegal_nn_argument_2(__non_null_externref_t table[0][0]); // expected-error {{unknown type name '__non_null_externref_t'}} -void illegal_nn_argument_3(__non_null_externref_t *table); // expected-error {{unknown type name '__non_null_externref_t'}} -void illegal_nn_argument_4(__non_null_externref_t ***table); // expected-error {{unknown type name '__non_null_externref_t'}} -void illegal_nn_argument_5(__non_null_externref_t (*table)[0]); // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit in}} \ - // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit in}} \ - // conly-error {{function cannot return array type 'int[0]'}} \ - // cpp-error {{variable has incomplete type 'void'}} \ - // cpp-error {{use of undeclared identifier '__non_null_externref_t'}} -void illegal_nn_argument_6(__non_null_externref_t table[0]); // expected-error {{unknown type name '__non_null_externref_t'}} + +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 {{unknown type name '__non_null_externref_t'}} -__non_null_externref_t ***illegal_nn_return_2(); // expected-error {{unknown type name '__non_null_externref_t'}} -__non_null_externref_t (*illegal_nn_return_3())[0]; // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit in}} \ - // conly-error {{type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit in}} \ - // conly-error {{function cannot return array type 'int[0]'}} \ - // cpp-error {{unknown type name '__non_null_externref_t'}} + +__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)(); @@ -201,15 +185,14 @@ void *ret_void_ptr() { return table; // expected-error {{cannot return a WebAssembly table}} } -// checks all related assignment from extern ref to non null extern ref and vice versa -void externref_assignment(__externref_t er, __non_null_externref_t nn_er) { // expected-error {{unknown type name '__non_null_externref_t'}} - __externref_t asg_1 = er; - __externref_t asg_2 = nn_er; - - __non_null_externref_t nn_asg_1 = er; // conly-error {{expected ';' after expression}} \ - // conly-error {{use of undeclared identifier 'nn_asg_1'}} \ - // cpp-error {{unknown type name '__non_null_externref_t'}} - __non_null_externref_t nn_asg_2 = nn_er; // conly-error {{expected ';' after expression}} \ - // conly-error {{use of undeclared identifier 'nn_asg_2'}} \ - // cpp-error {{unknown type name '__non_null_externref_t'}} +// checks all related assignment from extern ref to non null extern ref and vice versa +void externref_assignment(__externref_t er, __non_null_externref_t nn_er) { + __externref_t asg_1 = er; + __externref_t asg_2 = nn_er; + + __non_null_externref_t nn_asg_1 = er; // conly-error {{initializing '__non_null_externref_t' with an expression of incompatible type '__externref_t'}} \ + // cpp-error {{cannot initialize a variable of type '__non_null_externref_t' with an lvalue of type '__externref_t'}} + __non_null_externref_t nn_asg_2 = nn_er; + + } diff --git a/llvm/include/llvm/CodeGen/ValueTypes.td b/llvm/include/llvm/CodeGen/ValueTypes.td index 4551e7e4b9b60..42df9fc580de8 100644 --- a/llvm/include/llvm/CodeGen/ValueTypes.td +++ b/llvm/include/llvm/CodeGen/ValueTypes.td @@ -330,6 +330,7 @@ def untyped : ValueType<8, 231> { // Produces an untyped value } def funcref : ValueType<0, 232>; // WebAssembly's funcref type def externref : ValueType<0, 233>; // WebAssembly's externref type +def externref_nn : ValueType<0, 242>; // WebAssembly's nonnull externref type def exnref : ValueType<0, 234>; // WebAssembly's exnref type def x86amx : ValueType<8192, 235>; // X86 AMX value def i64x8 : ValueType<512, 236>; // 8 Consecutive GPRs (AArch64) diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index bd6f94ac1286c..feb83d8d0291c 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -616,6 +616,7 @@ def llvm_v16f64_ty : LLVMType; // 16 x double def llvm_vararg_ty : LLVMType; // this means vararg here def llvm_externref_ty : LLVMType; +def llvm_externref_nn_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 f592ff287a0e3..bc0f79ab4bd70 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_nn_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..9ed41f1e45ad5 100644 --- a/llvm/lib/IR/Type.cpp +++ b/llvm/lib/IR/Type.cpp @@ -308,6 +308,12 @@ Type *Type::getWasm_ExternrefTy(LLVMContext &C) { return Ty; } +Type *Type::getWasm_NonNullExternrefTy(LLVMContext &C) { + // opaque pointer in addrspace(11) + static PointerType *Ty = PointerType::get(C, 11); + return Ty; +} + Type *Type::getWasm_FuncrefTy(LLVMContext &C) { // opaque pointer in addrspace(20) static PointerType *Ty = PointerType::get(C, 20); From 2380d3e23698f64bf84e975e94ee1654154e5a11 Mon Sep 17 00:00:00 2001 From: Jasmine Tang Date: Tue, 22 Jul 2025 13:12:28 -0700 Subject: [PATCH 3/4] Reformatted changes --- clang/lib/Sema/SemaDecl.cpp | 3 ++- clang/lib/Sema/SemaExpr.cpp | 3 ++- llvm/include/llvm/IR/Intrinsics.td | 2 +- llvm/include/llvm/IR/IntrinsicsWebAssembly.td | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index bb41c30e0eeae..807a385b83fe0 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -13643,7 +13643,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { return; } - if (VDecl->getType().isWebAssemblyExternrefType() && Init->getType()->isWebAssemblyNonNullExternrefType()) { + if (VDecl->getType().isWebAssemblyExternrefType() && + Init->getType()->isWebAssemblyNonNullExternrefType()) { VDecl->setInit(Init); return; } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index a3bf2db4bb6c7..da38a5a5ff056 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -9638,7 +9638,8 @@ AssignConvertType Sema::CheckAssignmentConstraints(QualType LHSType, return AssignConvertType::Compatible; } - if (LHSType->isWebAssemblyExternrefType() && RHSType->isWebAssemblyNonNullExternrefType()) { + if (LHSType->isWebAssemblyExternrefType() && + RHSType->isWebAssemblyNonNullExternrefType()) { Kind = CK_NoOp; return AssignConvertType::Compatible; } diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index feb83d8d0291c..fe4d20dba7484 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -616,7 +616,7 @@ def llvm_v16f64_ty : LLVMType; // 16 x double def llvm_vararg_ty : LLVMType; // this means vararg here def llvm_externref_ty : LLVMType; -def llvm_externref_nn_ty : LLVMType; +def llvm_externref_nn_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 bc0f79ab4bd70..1e910d418066c 100644 --- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td @@ -32,7 +32,7 @@ def int_wasm_ref_null_extern : // TODO: Is this correct? def int_wasm_ref_nonnull_extern - : DefaultAttrsIntrinsic<[llvm_externref_nn_ty], [], [IntrNoMem]>; + : DefaultAttrsIntrinsic<[llvm_externref_nn_ty], [], [IntrNoMem]>; def int_wasm_ref_null_func : DefaultAttrsIntrinsic<[llvm_funcref_ty], [], [IntrNoMem]>; From d48916c1cdc5793736faedcc244e3a48344f7f70 Mon Sep 17 00:00:00 2001 From: Jasmine Tang Date: Tue, 22 Jul 2025 14:57:26 -0700 Subject: [PATCH 4/4] Put AS 11 for nn extern ref --- clang/include/clang/Basic/WebAssemblyReferenceTypes.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/WebAssemblyReferenceTypes.def b/clang/include/clang/Basic/WebAssemblyReferenceTypes.def index 747eb4034f669..296bc45cff4c9 100644 --- a/clang/include/clang/Basic/WebAssemblyReferenceTypes.def +++ b/clang/include/clang/Basic/WebAssemblyReferenceTypes.def @@ -36,7 +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) +WASM_REF_TYPE("__non_null_externref_t", "non_null_externref_t", WasmNonNullExternRef, WasmNonNullExternRefTy, 11) #undef WASM_TYPE #undef WASM_REF_TYPE