llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-selectiondag

Author: Hood Chatham (hoodmane)

<details>
<summary>Changes</summary>

Originally #<!-- -->71540 by Paolo Matos, I picked it up and finished it.

Model WebAssembly externref and funcref as target("wasm.externref") / 
target("wasm.funcref") TargetExtTypes instead of pointers in non-integral 
address spaces 10 and 20.

The entire WebAssemblyLowerRefTypesIntPtrConv can be removed.

This breaks the GlobalISel handling for reference types, I just disabled 
GlobalISel handling for functions that use them.

I added intrinsics for `wasm.ptr.to_funcref` and `wasm.funcref.to_ptr`. 
ptr.to_funcref does a table.get from the indirect function pointer table. As a 
special case, 0 is converted to the null funcref rather than doing table.get on 
0. `wasm.funcref.to_ptr` is only handled when we call it immediately, otherwise 
it will fail to lower. We could dynamically put the funcref into the table to 
make it work but that would require a stack of spilled funcrefs and isn't worth 
the effort.

In the process of looking into this, I noticed that clang used to allow casting 
from funcref to function pointer but if the cast result escaped it would hit 
`Cannot select: FUNCREF_TO_PTR` in the backend. I added a diagnostic that says 
"a funcref can only be converted to a pointer to be directly called" to make 
this a little cleaner.

cc @<!-- -->QuantumSegfault

---

Patch is 98.62 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/203165.diff


57 Files Affected:

- (modified) clang/lib/CodeGen/CGCall.cpp (+13) 
- (modified) clang/lib/CodeGen/CGExprScalar.cpp (+38-3) 
- (modified) clang/lib/CodeGen/CodeGenTypes.cpp (+6) 
- (modified) clang/test/CodeGen/WebAssembly/builtins-table-externref.c (+14-14) 
- (modified) clang/test/CodeGen/WebAssembly/builtins-table-funcref.c (+8-8) 
- (modified) clang/test/CodeGen/WebAssembly/builtins-test-fp-sig.c (+2-2) 
- (modified) clang/test/CodeGen/WebAssembly/wasm-externref.c (+4-4) 
- (added) clang/test/CodeGen/WebAssembly/wasm-funcref-to-ptr-error.c (+22) 
- (modified) clang/test/CodeGen/WebAssembly/wasm-funcref.c (+49-20) 
- (modified) clang/test/CodeGen/builtins-wasm.c (+2-2) 
- (modified) llvm/include/llvm/IR/Intrinsics.h (+2) 
- (modified) llvm/include/llvm/IR/IntrinsicsWebAssembly.td (+11) 
- (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp (+20-3) 
- (modified) llvm/lib/CodeGen/ValueTypes.cpp (+4) 
- (modified) llvm/lib/IR/Intrinsics.cpp (+14-3) 
- (modified) llvm/lib/IR/Type.cpp (+8-4) 
- (modified) llvm/lib/Target/WebAssembly/CMakeLists.txt (-1) 
- (modified) llvm/lib/Target/WebAssembly/GISel/WebAssemblyCallLowering.cpp 
(+32-21) 
- (modified) llvm/lib/Target/WebAssembly/Utils/WasmAddressSpaces.h (+1-5) 
- (modified) llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h 
(+4-6) 
- (modified) llvm/lib/Target/WebAssembly/WebAssembly.h (-2) 
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp (+21) 
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp (+25-25) 
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h (-3) 
- (removed) llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp 
(-85) 
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyRefTypeMem2Local.cpp (+2) 
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp (-2) 
- (modified) llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/args.ll 
(+3-21) 
- (modified) 
llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/call-basics.ll (+6-50) 
- (modified) 
llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/ret-basics.ll (+3-27) 
- (added) llvm/test/CodeGen/WebAssembly/GlobalISel/reference-types-fallback.ll 
(+40) 
- (modified) llvm/test/CodeGen/WebAssembly/externref-globalget.ll (+1-1) 
- (modified) llvm/test/CodeGen/WebAssembly/externref-globalset.ll (+1-1) 
- (modified) llvm/test/CodeGen/WebAssembly/externref-inttoptr.ll (+3-9) 
- (modified) llvm/test/CodeGen/WebAssembly/externref-ptrtoint.ll (+3-8) 
- (modified) llvm/test/CodeGen/WebAssembly/externref-tableget.ll (+1-1) 
- (modified) llvm/test/CodeGen/WebAssembly/externref-tableset.ll (+1-1) 
- (modified) llvm/test/CodeGen/WebAssembly/externref-unsized-load.ll (+1-1) 
- (modified) llvm/test/CodeGen/WebAssembly/externref-unsized-store.ll (+1-1) 
- (modified) llvm/test/CodeGen/WebAssembly/funcref-call.ll (+7-3) 
- (modified) llvm/test/CodeGen/WebAssembly/funcref-globalget.ll (+1-1) 
- (modified) llvm/test/CodeGen/WebAssembly/funcref-globalset.ll (+1-1) 
- (added) llvm/test/CodeGen/WebAssembly/funcref-ptr-conversion.ll (+28) 
- (modified) llvm/test/CodeGen/WebAssembly/funcref-table_call.ll (+4-2) 
- (modified) llvm/test/CodeGen/WebAssembly/funcref-tableget.ll (+1-1) 
- (modified) llvm/test/CodeGen/WebAssembly/funcref-tableset.ll (+1-1) 
- (added) llvm/test/CodeGen/WebAssembly/funcref-to-ptr-error.ll (+32) 
- (modified) llvm/test/CodeGen/WebAssembly/ref-null.ll (+2-2) 
- (modified) llvm/test/CodeGen/WebAssembly/ref-test-func.ll (+137-64) 
- (modified) llvm/test/CodeGen/WebAssembly/ref-type-mem2local.ll (+22-22) 
- (modified) llvm/test/CodeGen/WebAssembly/select-reftype.ll (+12-12) 
- (modified) llvm/test/CodeGen/WebAssembly/table-copy.ll (+1-1) 
- (modified) llvm/test/CodeGen/WebAssembly/table-fill.ll (+1-1) 
- (modified) llvm/test/CodeGen/WebAssembly/table-grow.ll (+1-1) 
- (modified) llvm/test/CodeGen/WebAssembly/table-size.ll (+1-1) 
- (modified) llvm/test/CodeGen/WebAssembly/table-types.ll (+2-2) 
- (modified) llvm/utils/gn/secondary/llvm/lib/Target/WebAssembly/BUILD.gn (-1) 


``````````diff
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 40cc275d40273..3b91a210248ff 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -49,6 +49,7 @@
 #include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/IntrinsicsWebAssembly.h"
 #include "llvm/IR/Type.h"
 #include "llvm/Transforms/Utils/Local.h"
 #include <optional>
@@ -5972,6 +5973,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo 
&CallInfo,
   const CGCallee &ConcreteCallee = Callee.prepareConcreteCallee(*this);
   llvm::Value *CalleePtr = ConcreteCallee.getFunctionPointer();
 
+  // A WebAssembly funcref is an opaque reference type and llvm only accepts
+  // function pointers as the call target. To make an indirect call through a
+  // reference type, first use the llvm.wasm.funcref.to_ptr intrinsic to make a
+  // fake function pointer to it. The backend lowers the resulting indirect 
call
+  // to a table.set into a single element dummy table + call_indirect 0.
+  if (auto *TET = dyn_cast<llvm::TargetExtType>(CalleePtr->getType());
+      TET && TET->getName() == "wasm.funcref") {
+    llvm::Function *ToPtr =
+        CGM.getIntrinsic(llvm::Intrinsic::wasm_funcref_to_ptr);
+    CalleePtr = Builder.CreateCall(ToPtr, {CalleePtr});
+  }
+
   // If we're using inalloca, set up that argument.
   if (ArgMemory.isValid()) {
     llvm::Value *Arg = ArgMemory.getPointer();
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index 3a3dff7bec347..cb167d2b8f449 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -47,6 +47,7 @@
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/IntrinsicsPowerPC.h"
+#include "llvm/IR/IntrinsicsWebAssembly.h"
 #include "llvm/IR/MatrixBuilder.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/TypeSize.h"
@@ -2839,6 +2840,41 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
     return CGF.authPointerToPointerCast(Result, E->getType(), DestTy);
   }
   case CK_AddressSpaceConversion: {
+    llvm::Type *DestLTy = ConvertType(DestTy);
+    // WebAssembly reference types are opaque target extension types so an
+    // "address space conversion" involving them is not a real pointer cast.
+    auto IsWasmFuncref = [](llvm::Type *T) {
+      auto *TET = dyn_cast<llvm::TargetExtType>(T);
+      return TET && TET->getName() == "wasm.funcref";
+    };
+    bool SrcIsFuncref = IsWasmFuncref(ConvertType(E->getType()));
+    bool DestIsFuncref = IsWasmFuncref(DestLTy);
+    if (SrcIsFuncref && DestIsFuncref) {
+      // funcref -> funcref (e.g. between differently-typed funcrefs) is the
+      // identity on the opaque reference value.
+      return Visit(E);
+    }
+    if (SrcIsFuncref && !DestIsFuncref) {
+      // funcref -> pointer: recover the underlying function pointer.
+      llvm::Function *ToPtr =
+          CGF.CGM.getIntrinsic(llvm::Intrinsic::wasm_funcref_to_ptr);
+      return CGF.Builder.CreateCall(ToPtr, {Visit(E)});
+    }
+    if (!SrcIsFuncref && DestIsFuncref) {
+      // A null function pointer converts to a null funcref (ref.null func),
+      // rather than a table lookup at index 0.
+      Expr::EvalResult NullResult;
+      if (E->EvaluateAsRValue(NullResult, CGF.getContext()) &&
+          NullResult.Val.isNullPointer()) {
+        if (NullResult.HasSideEffects)
+          Visit(E);
+        return llvm::Constant::getNullValue(DestLTy);
+      }
+      // pointer -> funcref: do a table.get from the indirect function table.
+      llvm::Function *ToFuncref =
+          CGF.CGM.getIntrinsic(llvm::Intrinsic::wasm_ptr_to_funcref);
+      return CGF.Builder.CreateCall(ToFuncref, {Visit(E)});
+    }
     Expr::EvalResult Result;
     if (E->EvaluateAsRValue(Result, CGF.getContext()) &&
         Result.Val.isNullPointer()) {
@@ -2847,12 +2883,11 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
       // eliminate the useless instructions emitted during translating E.
       if (Result.HasSideEffects)
         Visit(E);
-      return CGF.CGM.getNullPointer(cast<llvm::PointerType>(
-          ConvertType(DestTy)), DestTy);
+      return CGF.CGM.getNullPointer(cast<llvm::PointerType>(DestLTy), DestTy);
     }
     // Since target may map different address spaces in AST to the same address
     // space, an address space conversion may end up as a bitcast.
-    return CGF.performAddrSpaceCast(Visit(E), ConvertType(DestTy));
+    return CGF.performAddrSpaceCast(Visit(E), DestLTy);
   }
   case CK_AtomicToNonAtomic:
   case CK_NonAtomicToAtomic:
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp 
b/clang/lib/CodeGen/CodeGenTypes.cpp
index b28a0eb82f302..70c1d4f6a6ba9 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -645,6 +645,12 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
   case Type::Pointer: {
     const PointerType *PTy = cast<PointerType>(Ty);
     QualType ETy = PTy->getPointeeType();
+    // A WebAssembly funcref is represented as the opaque reference type
+    // target("wasm.funcref").
+    if (ETy.getAddressSpace() == LangAS::wasm_funcref) {
+      ResultType = CGM.getTargetCodeGenInfo().getWasmFuncrefReferenceType();
+      break;
+    }
     unsigned AS = getTargetAddressSpace(ETy);
     ResultType = llvm::PointerType::get(getLLVMContext(), AS);
     break;
diff --git a/clang/test/CodeGen/WebAssembly/builtins-table-externref.c 
b/clang/test/CodeGen/WebAssembly/builtins-table-externref.c
index 7600a53ba3aa2..454fc31a5f53f 100644
--- a/clang/test/CodeGen/WebAssembly/builtins-table-externref.c
+++ b/clang/test/CodeGen/WebAssembly/builtins-table-externref.c
@@ -8,8 +8,8 @@ static const __externref_t const_table[0];
 // CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_get
 // CHECK-SAME: (i32 noundef [[INDEX:%.*]]) #[[ATTR0:[0-9]+]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[TMP0:%.*]] = call ptr addrspace(10) 
@llvm.wasm.table.get.externref(ptr addrspace(1) @table, i32 [[INDEX]])
-// CHECK-NEXT:    ret ptr addrspace(10) [[TMP0]]
+// CHECK-NEXT:    [[TMP0:%.*]] = call target("wasm.externref") 
@llvm.wasm.table.get.externref(ptr addrspace(1) @table, i32 [[INDEX]])
+// CHECK-NEXT:    ret target("wasm.externref") [[TMP0]]
 //
 __externref_t test_builtin_wasm_table_get(int index) {
   return __builtin_wasm_table_get(table, index);
@@ -18,18 +18,18 @@ __externref_t test_builtin_wasm_table_get(int index) {
 // CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_get_const
 // CHECK-SAME: (i32 noundef [[INDEX:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[TMP0:%.*]] = call ptr addrspace(10) 
@llvm.wasm.table.get.externref(ptr addrspace(1) @table, i32 [[INDEX]])
-// CHECK-NEXT:    ret ptr addrspace(10) [[TMP0]]
+// CHECK-NEXT:    [[TMP0:%.*]] = call target("wasm.externref") 
@llvm.wasm.table.get.externref(ptr addrspace(1) @table, i32 [[INDEX]])
+// CHECK-NEXT:    ret target("wasm.externref") [[TMP0]]
 //
 __externref_t test_builtin_wasm_table_get_const(const int index) {
   return __builtin_wasm_table_get(table, index);
 }
 
 // CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_set
-// CHECK-SAME: (i32 noundef [[INDEX:%.*]], ptr addrspace(10) [[REF:%.*]]) 
#[[ATTR0]] {
+// CHECK-SAME: (i32 noundef [[INDEX:%.*]], target("wasm.externref") 
[[REF:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    call void @llvm.wasm.table.set.externref(ptr addrspace(1) 
@const_table, i32 [[INDEX]], ptr addrspace(10) [[REF]])
-// CHECK-NEXT:    call void @llvm.wasm.table.set.externref(ptr addrspace(1) 
@table, i32 [[INDEX]], ptr addrspace(10) [[REF]])
+// CHECK-NEXT:    call void @llvm.wasm.table.set.externref(ptr addrspace(1) 
@const_table, i32 [[INDEX]], target("wasm.externref") [[REF]])
+// CHECK-NEXT:    call void @llvm.wasm.table.set.externref(ptr addrspace(1) 
@table, i32 [[INDEX]], target("wasm.externref") [[REF]])
 // CHECK-NEXT:    ret void
 //
 void test_builtin_wasm_table_set(const int index, __externref_t ref) {
@@ -38,10 +38,10 @@ void test_builtin_wasm_table_set(const int index, 
__externref_t ref) {
 }
 
 // CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_set_const
-// CHECK-SAME: (i32 noundef [[INDEX:%.*]], ptr addrspace(10) [[REF:%.*]]) 
#[[ATTR0]] {
+// CHECK-SAME: (i32 noundef [[INDEX:%.*]], target("wasm.externref") 
[[REF:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    call void @llvm.wasm.table.set.externref(ptr addrspace(1) 
@table, i32 [[INDEX]], ptr addrspace(10) [[REF]])
-// CHECK-NEXT:    call void @llvm.wasm.table.set.externref(ptr addrspace(1) 
@const_table, i32 [[INDEX]], ptr addrspace(10) [[REF]])
+// CHECK-NEXT:    call void @llvm.wasm.table.set.externref(ptr addrspace(1) 
@table, i32 [[INDEX]], target("wasm.externref") [[REF]])
+// CHECK-NEXT:    call void @llvm.wasm.table.set.externref(ptr addrspace(1) 
@const_table, i32 [[INDEX]], target("wasm.externref") [[REF]])
 // CHECK-NEXT:    ret void
 //
 void test_builtin_wasm_table_set_const(const int index, const __externref_t 
ref) {
@@ -60,9 +60,9 @@ int test_builtin_wasm_table_size() {
 }
 
 // CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_grow
-// CHECK-SAME: (ptr addrspace(10) [[REF:%.*]], i32 noundef [[NELEM:%.*]]) 
#[[ATTR0]] {
+// CHECK-SAME: (target("wasm.externref") [[REF:%.*]], i32 noundef 
[[NELEM:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.wasm.table.grow.externref(ptr 
addrspace(1) @table, ptr addrspace(10) [[REF]], i32 [[NELEM]])
+// CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.wasm.table.grow.externref(ptr 
addrspace(1) @table, target("wasm.externref") [[REF]], i32 [[NELEM]])
 // CHECK-NEXT:    ret i32 [[TMP0]]
 //
 int test_builtin_wasm_table_grow(__externref_t ref, int nelem) {
@@ -70,9 +70,9 @@ int test_builtin_wasm_table_grow(__externref_t ref, int 
nelem) {
 }
 
 // CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_fill
-// CHECK-SAME: (i32 noundef [[INDEX:%.*]], ptr addrspace(10) [[REF:%.*]], i32 
noundef [[NELEM:%.*]]) #[[ATTR0]] {
+// CHECK-SAME: (i32 noundef [[INDEX:%.*]], target("wasm.externref") 
[[REF:%.*]], i32 noundef [[NELEM:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    call void @llvm.wasm.table.fill.externref(ptr addrspace(1) 
@table, i32 [[INDEX]], ptr addrspace(10) [[REF]], i32 [[NELEM]])
+// CHECK-NEXT:    call void @llvm.wasm.table.fill.externref(ptr addrspace(1) 
@table, i32 [[INDEX]], target("wasm.externref") [[REF]], i32 [[NELEM]])
 // CHECK-NEXT:    ret void
 //
 void test_builtin_wasm_table_fill(int index, __externref_t ref, int nelem) {
diff --git a/clang/test/CodeGen/WebAssembly/builtins-table-funcref.c 
b/clang/test/CodeGen/WebAssembly/builtins-table-funcref.c
index b4f729669a795..f80e9b10c4941 100644
--- a/clang/test/CodeGen/WebAssembly/builtins-table-funcref.c
+++ b/clang/test/CodeGen/WebAssembly/builtins-table-funcref.c
@@ -8,17 +8,17 @@ static funcref_t table[0];
 // CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_get
 // CHECK-SAME: (i32 noundef [[INDEX:%.*]]) #[[ATTR0:[0-9]+]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[TMP0:%.*]] = call ptr addrspace(20) 
@llvm.wasm.table.get.funcref(ptr addrspace(1) @table, i32 [[INDEX]])
-// CHECK-NEXT:    ret ptr addrspace(20) [[TMP0]]
+// CHECK-NEXT:    [[TMP0:%.*]] = call target("wasm.funcref") 
@llvm.wasm.table.get.funcref(ptr addrspace(1) @table, i32 [[INDEX]])
+// CHECK-NEXT:    ret target("wasm.funcref") [[TMP0]]
 //
 funcref_t test_builtin_wasm_table_get(int index) {
   return __builtin_wasm_table_get(table, index);
 }
 
 // CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_set
-// CHECK-SAME: (i32 noundef [[INDEX:%.*]], ptr addrspace(20) noundef 
[[REF:%.*]]) #[[ATTR0]] {
+// CHECK-SAME: (i32 noundef [[INDEX:%.*]], target("wasm.funcref") noundef 
[[REF:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    call void @llvm.wasm.table.set.funcref(ptr addrspace(1) 
@table, i32 [[INDEX]], ptr addrspace(20) [[REF]])
+// CHECK-NEXT:    call void @llvm.wasm.table.set.funcref(ptr addrspace(1) 
@table, i32 [[INDEX]], target("wasm.funcref") [[REF]])
 // CHECK-NEXT:    ret void
 //
 void test_builtin_wasm_table_set(int index, funcref_t ref) {
@@ -37,9 +37,9 @@ int test_builtin_wasm_table_size() {
 
 
 // CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_grow
-// CHECK-SAME: (ptr addrspace(20) noundef [[REF:%.*]], i32 noundef 
[[NELEM:%.*]]) #[[ATTR0]] {
+// CHECK-SAME: (target("wasm.funcref") noundef [[REF:%.*]], i32 noundef 
[[NELEM:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.wasm.table.grow.funcref(ptr 
addrspace(1) @table, ptr addrspace(20) [[REF]], i32 [[NELEM]])
+// CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.wasm.table.grow.funcref(ptr 
addrspace(1) @table, target("wasm.funcref") [[REF]], i32 [[NELEM]])
 // CHECK-NEXT:    ret i32 [[TMP0]]
 //
 int test_builtin_wasm_table_grow(funcref_t ref, int nelem) {
@@ -47,9 +47,9 @@ int test_builtin_wasm_table_grow(funcref_t ref, int nelem) {
 }
 
 // CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_fill
-// CHECK-SAME: (i32 noundef [[INDEX:%.*]], ptr addrspace(20) noundef 
[[REF:%.*]], i32 noundef [[NELEM:%.*]]) #[[ATTR0]] {
+// CHECK-SAME: (i32 noundef [[INDEX:%.*]], target("wasm.funcref") noundef 
[[REF:%.*]], i32 noundef [[NELEM:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    call void @llvm.wasm.table.fill.funcref(ptr addrspace(1) 
@table, i32 [[INDEX]], ptr addrspace(20) [[REF]], i32 [[NELEM]])
+// CHECK-NEXT:    call void @llvm.wasm.table.fill.funcref(ptr addrspace(1) 
@table, i32 [[INDEX]], target("wasm.funcref") [[REF]], i32 [[NELEM]])
 // CHECK-NEXT:    ret void
 //
 void test_builtin_wasm_table_fill(int index, funcref_t ref, int nelem) {
diff --git a/clang/test/CodeGen/WebAssembly/builtins-test-fp-sig.c 
b/clang/test/CodeGen/WebAssembly/builtins-test-fp-sig.c
index 88447f7fa232d..c8825028e1789 100644
--- a/clang/test/CodeGen/WebAssembly/builtins-test-fp-sig.c
+++ b/clang/test/CodeGen/WebAssembly/builtins-test-fp-sig.c
@@ -32,13 +32,13 @@ void test_function_pointer_signature_varargs(FVarArgs func) 
{
 
 typedef __externref_t (*FExternRef)(__externref_t, __externref_t);
 void test_function_pointer_externref(FExternRef func) {
-  // WEBASSEMBLY:  %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, ptr addrspace(10) poison, token poison, ptr addrspace(10) poison, ptr 
addrspace(10) poison)
+  // WEBASSEMBLY:  %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, target("wasm.externref") poison, token poison, target("wasm.externref") 
poison, target("wasm.externref") poison)
   use(__builtin_wasm_test_function_pointer_signature(func));
 }
 
 typedef __funcref Fpointers (*FFuncRef)(__funcref Fvoid, __funcref Ffloats);
 void test_function_pointer_funcref(FFuncRef func) {
-  // WEBASSEMBLY:  %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, ptr addrspace(20) poison, token poison, ptr addrspace(20) poison, ptr 
addrspace(20) poison)
+  // WEBASSEMBLY:  %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr 
%func, target("wasm.funcref") poison, token poison, target("wasm.funcref") 
poison, target("wasm.funcref") poison)
   use(__builtin_wasm_test_function_pointer_signature(func));
 }
 
diff --git a/clang/test/CodeGen/WebAssembly/wasm-externref.c 
b/clang/test/CodeGen/WebAssembly/wasm-externref.c
index 788438bb4a86a..d226c51b7fd4e 100644
--- a/clang/test/CodeGen/WebAssembly/wasm-externref.c
+++ b/clang/test/CodeGen/WebAssembly/wasm-externref.c
@@ -7,10 +7,10 @@ void helper(externref_t);
 
 // CHECK-LABEL: @handle(
 // 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(ptr addrspace(10) [[TMP0]])
+// CHECK-NEXT:    [[OBJ_ADDR:%.*]] = alloca target("wasm.externref"), align 1
+// CHECK-NEXT:    store target("wasm.externref") [[OBJ:%.*]], ptr 
[[OBJ_ADDR]], align 1
+// CHECK-NEXT:    [[TMP0:%.*]] = load target("wasm.externref"), ptr 
[[OBJ_ADDR]], align 1
+// CHECK-NEXT:    call void @helper(target("wasm.externref") [[TMP0]])
 // CHECK-NEXT:    ret void
 //
 void handle(externref_t obj) {
diff --git a/clang/test/CodeGen/WebAssembly/wasm-funcref-to-ptr-error.c 
b/clang/test/CodeGen/WebAssembly/wasm-funcref-to-ptr-error.c
new file mode 100644
index 0000000000000..7923196f7478e
--- /dev/null
+++ b/clang/test/CodeGen/WebAssembly/wasm-funcref-to-ptr-error.c
@@ -0,0 +1,22 @@
+// RUN: not %clang_cc1 -triple wasm32 -target-feature +reference-types -S -o 
/dev/null %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple wasm64 -target-feature +reference-types -S -o 
/dev/null %s 2>&1 | FileCheck %s
+
+// A WebAssembly funcref is an opaque reference type. Converting one to a plain
+// function pointer is only meaningful when the result is immediately called
+// (which lowers to a table.set + call_indirect through the funcref call 
table).
+// If the resulting pointer escapes (is stored, returned, or passed along), the
+// conversion is not representable and is diagnosed rather than crashing the
+// backend.
+
+typedef void (*__funcref funcref_t)(void);
+typedef void (*fn_t)(void);
+
+// CHECK: error: a funcref can only be converted to a pointer to be directly 
called; the resulting pointer cannot otherwise be used
+void store_funcref_as_ptr(funcref_t f, fn_t *out) {
+  *out = (fn_t)f;
+}
+
+// CHECK: error: a funcref can only be converted to a pointer to be directly 
called; the resulting pointer cannot otherwise be used
+fn_t return_funcref_as_ptr(funcref_t f) {
+  return (fn_t)f;
+}
diff --git a/clang/test/CodeGen/WebAssembly/wasm-funcref.c 
b/clang/test/CodeGen/WebAssembly/wasm-funcref.c
index f01af0db321dd..63e9099b08a15 100644
--- a/clang/test/CodeGen/WebAssembly/wasm-funcref.c
+++ b/clang/test/CodeGen/WebAssembly/wasm-funcref.c
@@ -8,8 +8,8 @@ typedef int (*fn_t)(int);
 // Null funcref builtin call
 // CHECK-LABEL: @get_null(
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[TMP0:%.*]] = call ptr addrspace(20) 
@llvm.wasm.ref.null.func()
-// CHECK-NEXT:    ret ptr addrspace(20) [[TMP0]]
+// CHECK-NEXT:    [[TMP0:%.*]] = call target("wasm.funcref") 
@llvm.wasm.ref.null.func()
+// CHECK-NEXT:    ret target("wasm.funcref") [[TMP0]]
 //
 funcref_t get_null() {
   return __builtin_wasm_ref_null_func();
@@ -19,8 +19,8 @@ funcref_t get_null() {
 // default return value for builtin is a funcref with function type () -> ().
 // CHECK-LABEL: @get_null_ii(
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[TMP0:%.*]] = call ptr addrspace(20) 
@llvm.wasm.ref.null.func()
-// CHECK-NEXT:    ret ptr addrspace(20) [[TMP0]]
+// CHECK-NEXT:    [[TMP0:%.*]] = call target("wasm.funcref") 
@llvm.wasm.ref.null.func()
+// CHECK-NEXT:    ret target("wasm.funcref") [[TMP0]]
 //
 fn_funcref_t get_null_ii() {
   return (fn_funcref_t) __builtin_wasm_ref_null_func();
@@ -29,10 +29,10 @@ fn_funcref_t get_null_ii() {
 // Identity function for funcref.
 // CHECK-LABEL: @identity(
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[FN_ADDR:%.*]] = alloca ptr addrspace(20), align 4
-// CHECK-NEXT:    store ptr addrspace(20) [[FN:%.*]], ptr [[FN_ADDR]], align 4
-// CHECK-NEXT:    [[TMP0:%.*]] = load ptr addrspace(20), ptr [[FN_ADDR]], 
align 4
-// CHECK-NEXT:    ret ptr addrspace(20) [[TMP0]]
+// CHECK-NEXT:    [[FN_ADDR:%.*]] = alloca target("wasm.funcref"), align 4
+// CHECK-NEXT:    store target("wasm.funcref") [[FN:%.*]], ptr [[FN_ADDR]], 
align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load target("wasm.funcref"), ptr [[FN_ADDR]], 
align 4
+// CHECK-NEXT:    ret target("wasm.funcref") [[TMP0]]
 //
 funcref_t identity(funcref_t fn) {
   return fn;
@@ -43,10 +43,10 @@ void helper(funcref_t);
 // Pass funcref ref as an argument to a helper function.
 // CHECK-LABEL: @handle(
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[FN_ADDR:%.*]] = alloca ptr addrspace(20), align 4
-// CHECK-NEXT:    store ptr addrspace(20) [[FN:%.*]], ptr [[FN_ADDR]], align 4
-// CHECK-NEXT:    [[TMP0:%.*]] = load ptr addrspace(20), ptr [[FN_ADDR]], 
align 4
-// CHECK-NEXT:    call void @helper(ptr addrspace(20) noundef [[TMP0]])
+// CHECK-NEXT:    [[FN_ADDR:%.*]] = alloca target("wasm.funcref"), align 4
+// CHECK-NEXT:    store target("wasm.funcref") [[FN:%.*]], ptr [[FN_ADDR]], 
align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load target("wasm.funcref"), ptr [[...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/203165
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to