[WebAssembly][Clang] Add __builtin_wasm_ref_is_null_extern (#139580)
I also fixed __builtin_wasm_ref_null_extern() to generate a diagnostic
when it gets an argument. It seems like `SemaRef.checkArgCount()` has a
bug that makes it unable to check for 0 args.
diff --git a/clang/include/clang/Basic/BuiltinsWebAssembly.def b/clang/include/clang/Basic/BuiltinsWebAssembly.def
index ab48036..e2afcc0 100644
--- a/clang/include/clang/Basic/BuiltinsWebAssembly.def
+++ b/clang/include/clang/Basic/BuiltinsWebAssembly.def
@@ -192,6 +192,7 @@
// in which case the argument spec (second argument) is unused.
TARGET_BUILTIN(__builtin_wasm_ref_null_extern, "i", "nct", "reference-types")
+TARGET_BUILTIN(__builtin_wasm_ref_is_null_extern, "ii", "nct", "reference-types")
// A funcref represented as a function pointer with the funcref attribute
// attached to the type, therefore SemaChecking will check for the right
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d6afd5a..87c2f57 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13012,6 +13012,8 @@
"multi-dimensional arrays of WebAssembly references are not allowed">;
def err_wasm_builtin_arg_must_be_table_type : Error <
"%ordinal0 argument must be a WebAssembly table">;
+def err_wasm_builtin_arg_must_be_externref_type : Error <
+ "%ordinal0 argument must be an externref">;
def err_wasm_builtin_arg_must_match_table_element_type : Error <
"%ordinal0 argument must match the element type of the WebAssembly table in the %ordinal1 argument">;
def err_wasm_builtin_arg_must_be_integer_type : Error <
diff --git a/clang/include/clang/Sema/SemaWasm.h b/clang/include/clang/Sema/SemaWasm.h
index 8841fdf..2123e07 100644
--- a/clang/include/clang/Sema/SemaWasm.h
+++ b/clang/include/clang/Sema/SemaWasm.h
@@ -29,6 +29,7 @@
CallExpr *TheCall);
bool BuiltinWasmRefNullExtern(CallExpr *TheCall);
+ bool BuiltinWasmRefIsNullExtern(CallExpr *TheCall);
bool BuiltinWasmRefNullFunc(CallExpr *TheCall);
bool BuiltinWasmTableGet(CallExpr *TheCall);
bool BuiltinWasmTableSet(CallExpr *TheCall);
diff --git a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
index 698f432..b7fd70e 100644
--- a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
@@ -209,6 +209,11 @@
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_extern);
return Builder.CreateCall(Callee);
}
+ case WebAssembly::BI__builtin_wasm_ref_is_null_extern: {
+ Value *Src = EmitScalarExpr(E->getArg(0));
+ Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_is_null_extern);
+ return Builder.CreateCall(Callee, {Src});
+ }
case WebAssembly::BI__builtin_wasm_ref_null_func: {
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_func);
return Builder.CreateCall(Callee);
diff --git a/clang/lib/Sema/SemaWasm.cpp b/clang/lib/Sema/SemaWasm.cpp
index 3362e1d..6faea24 100644
--- a/clang/lib/Sema/SemaWasm.cpp
+++ b/clang/lib/Sema/SemaWasm.cpp
@@ -54,12 +54,27 @@
bool SemaWasm::BuiltinWasmRefNullExtern(CallExpr *TheCall) {
if (SemaRef.checkArgCount(TheCall, /*DesiredArgCount=*/0))
return true;
-
TheCall->setType(getASTContext().getWebAssemblyExternrefType());
return false;
}
+bool SemaWasm::BuiltinWasmRefIsNullExtern(CallExpr *TheCall) {
+ if (SemaRef.checkArgCount(TheCall, 1)) {
+ return true;
+ }
+
+ Expr *ArgExpr = TheCall->getArg(0);
+ if (!ArgExpr->getType().isWebAssemblyExternrefType()) {
+ SemaRef.Diag(ArgExpr->getBeginLoc(),
+ diag::err_wasm_builtin_arg_must_be_externref_type)
+ << 1 << ArgExpr->getSourceRange();
+ return true;
+ }
+
+ return false;
+}
+
bool SemaWasm::BuiltinWasmRefNullFunc(CallExpr *TheCall) {
ASTContext &Context = getASTContext();
if (SemaRef.checkArgCount(TheCall, /*DesiredArgCount=*/0))
@@ -220,6 +235,8 @@
return BuiltinWasmRefNullExtern(TheCall);
case WebAssembly::BI__builtin_wasm_ref_null_func:
return BuiltinWasmRefNullFunc(TheCall);
+ case WebAssembly::BI__builtin_wasm_ref_is_null_extern:
+ return BuiltinWasmRefIsNullExtern(TheCall);
case WebAssembly::BI__builtin_wasm_table_get:
return BuiltinWasmTableGet(TheCall);
case WebAssembly::BI__builtin_wasm_table_set:
diff --git a/clang/test/CodeGen/builtins-wasm.c b/clang/test/CodeGen/builtins-wasm.c
index 263cfd3..4a44a9a 100644
--- a/clang/test/CodeGen/builtins-wasm.c
+++ b/clang/test/CodeGen/builtins-wasm.c
@@ -741,6 +741,12 @@
// WEBASSEMBLY-NEXT: ret
}
+int externref_is_null(__externref_t arg) {
+ return __builtin_wasm_ref_is_null_extern(arg);
+ // WEBASSEMBLY: tail call i32 @llvm.wasm.ref.is_null.extern(ptr addrspace(10) %arg)
+ // WEBASSEMBLY-NEXT: ret
+}
+
void *tp (void) {
return __builtin_thread_pointer ();
// WEBASSEMBLY: call {{.*}} @llvm.thread.pointer()
diff --git a/clang/test/Sema/builtins-wasm.c b/clang/test/Sema/builtins-wasm.c
index 1aae365..31e5291 100644
--- a/clang/test/Sema/builtins-wasm.c
+++ b/clang/test/Sema/builtins-wasm.c
@@ -8,6 +8,9 @@
void test_ref_null() {
funcref_t func = __builtin_wasm_ref_null_func(0); // expected-error {{too many arguments to function call, expected 0, have 1}}
__externref_t ref = __builtin_wasm_ref_null_extern(0); // expected-error {{too many arguments to function call, expected 0, have 1}}
+ __builtin_wasm_ref_is_null_extern(ref, 1); // expected-error {{too many arguments to function call, expected 1, have 2}}
+ __builtin_wasm_ref_is_null_extern(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+ __builtin_wasm_ref_is_null_extern(1); // expected-error {{1st argument must be an externref}}
}
void test_table_size(__externref_t ref, void *ptr, int arr[]) {