Skip to content

Commit 60e2c93

Browse files
committed
Reject struct/union param/return type in Sema with multivalue abi
1 parent 2739332 commit 60e2c93

File tree

6 files changed

+115
-71
lines changed

6 files changed

+115
-71
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13234,9 +13234,9 @@ def err_wasm_builtin_arg_must_match_table_element_type : Error <
1323413234
"%ordinal0 argument must match the element type of the WebAssembly table in the %ordinal1 argument">;
1323513235
def err_wasm_builtin_arg_must_be_integer_type : Error <
1323613236
"%ordinal0 argument must be an integer">;
13237-
def err_wasm_builtin_test_fp_sig_cannot_include_reference_type
13238-
: Error<"not supported for "
13239-
"function pointers with a reference type %select{return "
13237+
def err_wasm_builtin_test_fp_sig_cannot_include_struct_or_union
13238+
: Error<"not supported with the multivalue ABI for "
13239+
"function pointers with a struct/union as %select{return "
1324013240
"value|parameter}0">;
1324113241

1324213242
// OpenACC diagnostics.

clang/include/clang/Sema/SemaWasm.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ class SemaWasm : public SemaBase {
3737
bool BuiltinWasmTableGrow(CallExpr *TheCall);
3838
bool BuiltinWasmTableFill(CallExpr *TheCall);
3939
bool BuiltinWasmTableCopy(CallExpr *TheCall);
40-
bool BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall);
40+
bool BuiltinWasmTestFunctionPointerSignature(const TargetInfo &TI,
41+
CallExpr *TheCall);
4142

4243
WebAssemblyImportNameAttr *
4344
mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL);

clang/lib/Sema/SemaWasm.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "clang/Basic/AddressSpaces.h"
1818
#include "clang/Basic/DiagnosticSema.h"
1919
#include "clang/Basic/TargetBuiltins.h"
20+
#include "clang/Basic/TargetInfo.h"
2021
#include "clang/Sema/Attr.h"
2122
#include "clang/Sema/Sema.h"
2223

@@ -227,7 +228,8 @@ bool SemaWasm::BuiltinWasmTableCopy(CallExpr *TheCall) {
227228
return false;
228229
}
229230

230-
bool SemaWasm::BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall) {
231+
bool SemaWasm::BuiltinWasmTestFunctionPointerSignature(const TargetInfo &TI,
232+
CallExpr *TheCall) {
231233
if (SemaRef.checkArgCount(TheCall, 1))
232234
return true;
233235

@@ -250,9 +252,31 @@ bool SemaWasm::BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall) {
250252
<< ArgType << FuncPtrArg->getSourceRange();
251253
}
252254

255+
if (TI.getABI() == "experimental-mv") {
256+
auto isStructOrUnion = [](QualType T) {
257+
return T->isUnionType() || T->isStructureType();
258+
};
259+
if (isStructOrUnion(FuncTy->getReturnType())) {
260+
return Diag(
261+
FuncPtrArg->getBeginLoc(),
262+
diag::
263+
err_wasm_builtin_test_fp_sig_cannot_include_struct_or_union)
264+
<< 0 << FuncTy->getReturnType() << FuncPtrArg->getSourceRange();
265+
}
266+
auto NParams = FuncTy->getNumParams();
267+
for (unsigned I = 0; I < NParams; I++) {
268+
if (isStructOrUnion(FuncTy->getParamType(I))) {
269+
return Diag(
270+
FuncPtrArg->getBeginLoc(),
271+
diag::
272+
err_wasm_builtin_test_fp_sig_cannot_include_struct_or_union)
273+
<< 1 << FuncPtrArg->getSourceRange();
274+
}
275+
}
276+
}
277+
253278
// Set return type to int (the result of the test)
254279
TheCall->setType(getASTContext().IntTy);
255-
256280
return false;
257281
}
258282

@@ -279,7 +303,7 @@ bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI,
279303
case WebAssembly::BI__builtin_wasm_table_copy:
280304
return BuiltinWasmTableCopy(TheCall);
281305
case WebAssembly::BI__builtin_wasm_test_function_pointer_signature:
282-
return BuiltinWasmTestFunctionPointerSignature(TheCall);
306+
return BuiltinWasmTestFunctionPointerSignature(TI, TheCall);
283307
}
284308

285309
return false;
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// RUN: %clang_cc1 -triple wasm32-unknown-unknown -target-feature +gc -O3 -emit-llvm -DSINGLE_VALUE -o - %s | FileCheck %s -check-prefixes WEBASSEMBLY,WEBASSEMBLY-SV
2+
// RUN: %clang_cc1 -triple wasm64-unknown-unknown -target-feature +gc -O3 -emit-llvm -DSINGLE_VALUE -o - %s | FileCheck %s -check-prefixes WEBASSEMBLY,WEBASSEMBLY-SV
3+
// RUN: %clang_cc1 -triple wasm64-unknown-unknown -target-feature +gc -target-abi experimental-mv -O3 -emit-llvm -o - %s 2>&1 | FileCheck %s -check-prefixes WEBASSEMBLY
4+
// RUN: not %clang_cc1 -triple wasm64-unknown-unknown -O3 -emit-llvm -o - %s 2>&1 | FileCheck %s -check-prefixes MISSING-GC
5+
6+
void use(int);
7+
8+
typedef void (*Fvoid)(void);
9+
void test_function_pointer_signature_void(Fvoid func) {
10+
// MISSING-GC: error: '__builtin_wasm_test_function_pointer_signature' needs target feature gc
11+
// WEBASSEMBLY: %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, token poison)
12+
use(__builtin_wasm_test_function_pointer_signature(func));
13+
}
14+
15+
typedef float (*Ffloats)(float, double, int);
16+
void test_function_pointer_signature_floats(Ffloats func) {
17+
// WEBASSEMBLY: %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, float poison, token poison, float poison, double poison, i32 poison)
18+
use(__builtin_wasm_test_function_pointer_signature(func));
19+
}
20+
21+
typedef void (*Fpointers)(Fvoid, Ffloats, void*, int*, int***, char[5]);
22+
void test_function_pointer_signature_pointers(Fpointers func) {
23+
// WEBASSEMBLY: %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, token poison, ptr poison, ptr poison, ptr poison, ptr poison, ptr poison, ptr poison)
24+
use(__builtin_wasm_test_function_pointer_signature(func));
25+
}
26+
27+
typedef void (*FVarArgs)(int, ...);
28+
void test_function_pointer_signature_varargs(FVarArgs func) {
29+
// WEBASSEMBLY: %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, token poison, i32 poison, ptr poison)
30+
use(__builtin_wasm_test_function_pointer_signature(func));
31+
}
32+
33+
typedef __externref_t (*FExternRef)(__externref_t, __externref_t);
34+
void test_function_pointer_externref(FExternRef func) {
35+
// 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)
36+
use(__builtin_wasm_test_function_pointer_signature(func));
37+
}
38+
39+
typedef __funcref Fpointers (*FFuncRef)(__funcref Fvoid, __funcref Ffloats);
40+
void test_function_pointer_funcref(FFuncRef func) {
41+
// 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)
42+
use(__builtin_wasm_test_function_pointer_signature(func));
43+
}
44+
45+
#ifdef SINGLE_VALUE
46+
// Some tests that we get struct ABIs correct. There is no special code in
47+
// __builtin_wasm_test_function_pointer_signature for this, it gets handled by
48+
// the normal type lowering code.
49+
// Single element structs are unboxed, multi element structs are passed on
50+
// stack.
51+
typedef struct {double x;} (*Fstructs1)(struct {double x;}, struct {float x;}, struct {double x; float y;});
52+
void test_function_pointer_structs1(Fstructs1 func) {
53+
// WEBASSEMBLY-SV: %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, double poison, token poison, double poison, float poison, ptr poison)
54+
use(__builtin_wasm_test_function_pointer_signature(func));
55+
}
56+
57+
// Two element return struct ==> return ptr on stack
58+
typedef struct {double x; double y;} (*Fstructs2)(void);
59+
void test_function_pointer_structs2(Fstructs2 func) {
60+
// WEBASSEMBLY-SV: %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, token poison, ptr poison)
61+
use(__builtin_wasm_test_function_pointer_signature(func));
62+
}
63+
64+
// Return union ==> return ptr on stack, one element union => unboxed
65+
typedef union {double x; float y;} (*FUnions)(union {double x; float y;}, union {double x;});
66+
void test_function_pointer_unions(FUnions func) {
67+
// WEBASSEMBLY-SV: %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, token poison, ptr poison, ptr poison, double poison)
68+
use(__builtin_wasm_test_function_pointer_signature(func));
69+
}
70+
#endif

clang/test/CodeGen/builtins-wasm.c

Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -751,67 +751,3 @@ void *tp (void) {
751751
return __builtin_thread_pointer ();
752752
// WEBASSEMBLY: call {{.*}} @llvm.thread.pointer.p0()
753753
}
754-
755-
756-
void use(int);
757-
758-
typedef void (*Fvoid)(void);
759-
void test_function_pointer_signature_void(Fvoid func) {
760-
// WEBASSEMBLY: %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, token poison)
761-
use(__builtin_wasm_test_function_pointer_signature(func));
762-
}
763-
764-
typedef float (*Ffloats)(float, double, int);
765-
void test_function_pointer_signature_floats(Ffloats func) {
766-
// WEBASSEMBLY: %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, float poison, token poison, float poison, double poison, i32 poison)
767-
use(__builtin_wasm_test_function_pointer_signature(func));
768-
}
769-
770-
typedef void (*Fpointers)(Fvoid, Ffloats, void*, int*, int***, char[5]);
771-
void test_function_pointer_signature_pointers(Fpointers func) {
772-
// WEBASSEMBLY: %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, token poison, ptr poison, ptr poison, ptr poison, ptr poison, ptr poison, ptr poison)
773-
use(__builtin_wasm_test_function_pointer_signature(func));
774-
}
775-
776-
typedef void (*FVarArgs)(int, ...);
777-
void test_function_pointer_signature_varargs(FVarArgs func) {
778-
// WEBASSEMBLY: %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, token poison, i32 poison, ptr poison)
779-
use(__builtin_wasm_test_function_pointer_signature(func));
780-
}
781-
782-
typedef __externref_t (*FExternRef)(__externref_t, __externref_t);
783-
void test_function_pointer_externref(FExternRef func) {
784-
// 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)
785-
use(__builtin_wasm_test_function_pointer_signature(func));
786-
}
787-
788-
typedef __funcref Fpointers (*FFuncRef)(__funcref Fvoid, __funcref Ffloats);
789-
void test_function_pointer_funcref(FFuncRef func) {
790-
// 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)
791-
use(__builtin_wasm_test_function_pointer_signature(func));
792-
}
793-
794-
// Some tests that we get struct ABIs correct. There is no special code in
795-
// __builtin_wasm_test_function_pointer_signature for this, it gets handled by
796-
// the normal type lowering code.
797-
// Single element structs are unboxed, multi element structs are passed on
798-
// stack.
799-
typedef struct {double x;} (*Fstructs1)(struct {double x;}, struct {float x;}, struct {double x; float y;});
800-
void test_function_pointer_structs1(Fstructs1 func) {
801-
// WEBASSEMBLY: %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, double poison, token poison, double poison, float poison, ptr poison)
802-
use(__builtin_wasm_test_function_pointer_signature(func));
803-
}
804-
805-
// Two element return struct ==> return ptr on stack
806-
typedef struct {double x; double y;} (*Fstructs2)(void);
807-
void test_function_pointer_structs2(Fstructs2 func) {
808-
// WEBASSEMBLY: %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, token poison, ptr poison)
809-
use(__builtin_wasm_test_function_pointer_signature(func));
810-
}
811-
812-
// Return union ==> return ptr on stack, one element union => unboxed
813-
typedef union {double x; float y;} (*FUnions)(union {double x; float y;}, union {double x;});
814-
void test_function_pointer_unions(FUnions func) {
815-
// WEBASSEMBLY: %0 = tail call i32 (ptr, ...) @llvm.wasm.ref.test.func(ptr %func, token poison, ptr poison, ptr poison, double poison)
816-
use(__builtin_wasm_test_function_pointer_signature(func));
817-
}

clang/test/Sema/builtins-wasm.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify -triple wasm32 -target-feature +reference-types %s
2+
// RUN: %clang_cc1 -fsyntax-only -verify -triple wasm32 -target-abi experimental-mv -DMULTIVALUE -target-feature +reference-types %s
23

34
#define EXPR_HAS_TYPE(expr, type) _Generic((expr), type : 1, default : 0)
45

@@ -57,6 +58,8 @@ void test_table_copy(int dst_idx, int src_idx, int nelem) {
5758

5859
typedef void (*F1)(void);
5960
typedef int (*F2)(int);
61+
typedef void (*F3)(struct {int x; double y;});
62+
typedef struct {int x; double y;} (*F4)(void);
6063

6164
void test_function_pointer_signature() {
6265
// Test argument count validation
@@ -73,4 +76,14 @@ void test_function_pointer_signature() {
7376

7477
// Test return type
7578
_Static_assert(EXPR_HAS_TYPE(__builtin_wasm_test_function_pointer_signature((F1)0), int), "");
79+
80+
#ifdef MULTIVALUE
81+
// Test that struct arguments and returns are rejected with multivalue abi
82+
(void)__builtin_wasm_test_function_pointer_signature((F3)0); // expected-error {{not supported with the multivalue ABI for function pointers with a struct/union as parameter}}
83+
(void)__builtin_wasm_test_function_pointer_signature((F4)0); // expected-error {{not supported with the multivalue ABI for function pointers with a struct/union as return value}}
84+
#else
85+
// with default abi they are fine
86+
(void)__builtin_wasm_test_function_pointer_signature((F3)0);
87+
(void)__builtin_wasm_test_function_pointer_signature((F4)0);
88+
#endif
7689
}

0 commit comments

Comments
 (0)