Author: Demetrius Kanios Date: 2026-02-04T09:55:36-08:00 New Revision: 24c7a10730a0c8ddce16741e9996bf11fc6ef885
URL: https://github.com/llvm/llvm-project/commit/24c7a10730a0c8ddce16741e9996bf11fc6ef885 DIFF: https://github.com/llvm/llvm-project/commit/24c7a10730a0c8ddce16741e9996bf11fc6ef885.diff LOG: [Clang][WebAssembly] Fix WASM tables to allow `__funcref` function pointers (#178720) Allows __funcref pointers to be used as the element type for WASM tables in Clang (static, global, zero-length arrays of a reference type). Modifies `QualType::isWebAssemblyFuncrefType` to correctly look at the addrspace of the pointee, rather than the pointer type. Related: #140933 Added: clang/test/CodeGen/WebAssembly/builtins-table-externref.c clang/test/CodeGen/WebAssembly/builtins-table-funcref.c clang/test/Sema/wasm-funcref-table.c Modified: clang/lib/AST/Type.cpp clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp Removed: clang/test/CodeGen/WebAssembly/builtins-table.c ################################################################################ diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 53082bcf78f6a..dcdbb62f9d62b 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2947,7 +2947,8 @@ bool QualType::isWebAssemblyExternrefType() const { bool QualType::isWebAssemblyFuncrefType() const { return getTypePtr()->isFunctionPointerType() && - getAddressSpace() == LangAS::wasm_funcref; + (getTypePtr()->getPointeeType().getAddressSpace() == + LangAS::wasm_funcref); } QualType::PrimitiveDefaultInitializeKind diff --git a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp index 1a1889a4139d3..edaba6e5998fc 100644 --- a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp @@ -633,8 +633,8 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, Function *Callee; if (E->getArg(1)->getType().isWebAssemblyExternrefType()) Callee = CGM.getIntrinsic(Intrinsic::wasm_table_grow_externref); - else if (E->getArg(2)->getType().isWebAssemblyFuncrefType()) - Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_funcref); + else if (E->getArg(1)->getType().isWebAssemblyFuncrefType()) + Callee = CGM.getIntrinsic(Intrinsic::wasm_table_grow_funcref); else llvm_unreachable( "Unexpected reference type for __builtin_wasm_table_grow"); diff --git a/clang/test/CodeGen/WebAssembly/builtins-table.c b/clang/test/CodeGen/WebAssembly/builtins-table-externref.c similarity index 100% rename from clang/test/CodeGen/WebAssembly/builtins-table.c rename to clang/test/CodeGen/WebAssembly/builtins-table-externref.c diff --git a/clang/test/CodeGen/WebAssembly/builtins-table-funcref.c b/clang/test/CodeGen/WebAssembly/builtins-table-funcref.c new file mode 100644 index 0000000000000..b4f729669a795 --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/builtins-table-funcref.c @@ -0,0 +1,69 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature +// RUN: %clang_cc1 -triple wasm32 -target-feature +reference-types -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck %s +// REQUIRES: webassembly-registered-target + +typedef void (*__funcref funcref_t)(); +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]] +// +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-NEXT: entry: +// CHECK-NEXT: call void @llvm.wasm.table.set.funcref(ptr addrspace(1) @table, i32 [[INDEX]], ptr addrspace(20) [[REF]]) +// CHECK-NEXT: ret void +// +void test_builtin_wasm_table_set(int index, funcref_t ref) { + return __builtin_wasm_table_set(table, index, ref); +} + +// CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_size +// CHECK-SAME: () #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.wasm.table.size(ptr addrspace(1) @table) +// CHECK-NEXT: ret i32 [[TMP0]] +// +int test_builtin_wasm_table_size() { + return __builtin_wasm_table_size(table); +} + + +// CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_grow +// CHECK-SAME: (ptr addrspace(20) 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: ret i32 [[TMP0]] +// +int test_builtin_wasm_table_grow(funcref_t ref, int nelem) { + return __builtin_wasm_table_grow(table, ref, nelem); +} + +// CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_fill +// CHECK-SAME: (i32 noundef [[INDEX:%.*]], ptr addrspace(20) 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: ret void +// +void test_builtin_wasm_table_fill(int index, funcref_t ref, int nelem) { + __builtin_wasm_table_fill(table, index, ref, nelem); +} + +static funcref_t other_table[0]; + +// CHECK-LABEL: define {{[^@]+}}@test_table_copy +// CHECK-SAME: (i32 noundef [[DST_IDX:%.*]], i32 noundef [[SRC_IDX:%.*]], i32 noundef [[NELEM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @llvm.wasm.table.copy(ptr addrspace(1) @table, ptr addrspace(1) @other_table, i32 [[SRC_IDX]], i32 [[DST_IDX]], i32 [[NELEM]]) +// CHECK-NEXT: ret void +// +void test_table_copy(int dst_idx, int src_idx, int nelem) { + __builtin_wasm_table_copy(table, other_table, dst_idx, src_idx, nelem); +} diff --git a/clang/test/Sema/wasm-funcref-table.c b/clang/test/Sema/wasm-funcref-table.c new file mode 100644 index 0000000000000..9b4d53b8bbf08 --- /dev/null +++ b/clang/test/Sema/wasm-funcref-table.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple wasm32 -target-feature +reference-types -fsyntax-only -verify %s + +typedef void (*__funcref fn_funcref)(void); + +// Valid funcref table declaration (zero-length, static) +static fn_funcref valid_table[0]; // no error expected + +// Invalid: non-zero length +static fn_funcref bad_table[1]; // expected-error {{only zero-length WebAssembly tables are currently supported}} + +// Array subscript on funcref table should be rejected +void test_subscript(void) { + (void)valid_table[0]; // expected-error {{cannot subscript a WebAssembly table}} +} + +// Original reproducer from https://github.com/llvm/llvm-project/issues/140933 +// The declaration should be rejected (not static, non-zero length) +extern fn_funcref issue_table[1]; // expected-error {{WebAssembly table must be static}} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
