[clang] [llvm] [WebAssembly] Add support for nonnull_extern_ref type (PR #148935)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 15 12:20:41 PDT 2025
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 <jjasmine at 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);
More information about the llvm-commits
mailing list