diff options
| author | Simon Pilgrim <llvm-dev@redking.me.uk> | 2020-11-20 12:02:57 +0000 |
|---|---|---|
| committer | Simon Pilgrim <llvm-dev@redking.me.uk> | 2020-11-20 12:03:28 +0000 |
| commit | 822c5c50849a1f762c920d59baaa6a6edbb657ee (patch) | |
| tree | 36db0c3f1a8cef2fa3cd8a1ff6960419c35f4fea /clang/test/CodeGen/WebAssembly | |
| parent | 2f1fe9a3a60d6f18998c5f3b7e643d4cbaa4e65d (diff) | |
[clang][CodeGen] Move WebAssembly specific tests to WebAssembly subtarget folder
Minor cleanup to move more target specific tests out of the root codegen test folder
Diffstat (limited to 'clang/test/CodeGen/WebAssembly')
| -rw-r--r-- | clang/test/CodeGen/WebAssembly/wasm-arguments.c | 140 | ||||
| -rw-r--r-- | clang/test/CodeGen/WebAssembly/wasm-call-main.c | 13 | ||||
| -rw-r--r-- | clang/test/CodeGen/WebAssembly/wasm-export-name.c | 13 | ||||
| -rw-r--r-- | clang/test/CodeGen/WebAssembly/wasm-import-module.c | 11 | ||||
| -rw-r--r-- | clang/test/CodeGen/WebAssembly/wasm-import-name.c | 11 | ||||
| -rw-r--r-- | clang/test/CodeGen/WebAssembly/wasm-main.c | 9 | ||||
| -rw-r--r-- | clang/test/CodeGen/WebAssembly/wasm-main_argc_argv.c | 9 | ||||
| -rw-r--r-- | clang/test/CodeGen/WebAssembly/wasm-regparm.c | 4 | ||||
| -rw-r--r-- | clang/test/CodeGen/WebAssembly/wasm-varargs.c | 140 |
9 files changed, 350 insertions, 0 deletions
diff --git a/clang/test/CodeGen/WebAssembly/wasm-arguments.c b/clang/test/CodeGen/WebAssembly/wasm-arguments.c new file mode 100644 index 000000000000..13700b50b5bd --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/wasm-arguments.c @@ -0,0 +1,140 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown %s -emit-llvm -o - \ +// RUN: | FileCheck %s -check-prefix=WEBASSEMBLY32 +// RUN: %clang_cc1 -triple wasm64-unknown-unknown %s -emit-llvm -o - \ +// RUN: | FileCheck %s -check-prefix=WEBASSEMBLY64 +// RUN: %clang_cc1 -triple wasm32-unknown-unknown %s -target-abi experimental-mv -emit-llvm -o - \ +// RUN: | FileCheck %s -check-prefix=EXPERIMENTAL-MV + +// Basic argument/attribute and return tests for WebAssembly + +// WEBASSEMBLY32: define void @misc_args(i32 %i, i32 %j, i64 %k, double %l, fp128 %m) +// WEBASSEMBLY64: define void @misc_args(i32 %i, i64 %j, i64 %k, double %l, fp128 %m) +void misc_args(int i, long j, long long k, double l, long double m) {} + +typedef struct { + int aa; + int bb; +} s1; + +// Structs should be passed byval and not split up. +// WEBASSEMBLY32: define void @struct_arg(%struct.s1* byval(%struct.s1) align 4 %i) +// WEBASSEMBLY64: define void @struct_arg(%struct.s1* byval(%struct.s1) align 4 %i) + +// Except in the experimental multivalue ABI, where structs are passed in args +// EXPERIMENTAL-MV: define void @struct_arg(i32 %i.0, i32 %i.1) +void struct_arg(s1 i) {} + +// Structs should be returned sret and not simplified by the frontend. +// WEBASSEMBLY32: define void @struct_ret(%struct.s1* noalias sret(%struct.s1) align 4 %agg.result) +// WEBASSEMBLY32: ret void +// WEBASSEMBLY64: define void @struct_ret(%struct.s1* noalias sret(%struct.s1) align 4 %agg.result) +// WEBASSEMBLY64: ret void + +// Except with the experimental multivalue ABI, which returns structs by value +// EXPERIMENTAL-MV: define %struct.s1 @struct_ret() +// EXPERIMENTAL-MV: ret %struct.s1 %0 +s1 struct_ret() { + s1 foo; + return foo; +} + +typedef struct { + int cc; +} s2; + +// Single-element structs should be passed as the one element. +// WEBASSEMBLY32: define void @single_elem_arg(i32 %i.coerce) +// WEBASSEMBLY64: define void @single_elem_arg(i32 %i.coerce) +// EXPERIMENTAL-MV: define void @single_elem_arg(i32 %i.coerce) +void single_elem_arg(s2 i) {} + +// Single-element structs should be passed as the one element. +// WEBASSEMBLY32: define i32 @single_elem_ret() +// WEBASSEMBLY32: ret i32 +// WEBASSEMBLY64: define i32 @single_elem_ret() +// EXPERIMENTAL-MV: define i32 @single_elem_ret() +s2 single_elem_ret() { + s2 foo; + return foo; +} + +// WEBASSEMBLY32: define void @long_long_arg(i64 %i) +// WEBASSEMBLY64: define void @long_long_arg(i64 %i) +void long_long_arg(long long i) {} + +// i8/i16 should be signext, i32 and higher should not. +// WEBASSEMBLY32: define void @char_short_arg(i8 signext %a, i16 signext %b) +// WEBASSEMBLY64: define void @char_short_arg(i8 signext %a, i16 signext %b) +void char_short_arg(char a, short b) {} + +// WEBASSEMBLY32: define void @uchar_ushort_arg(i8 zeroext %a, i16 zeroext %b) +// WEBASSEMBLY64: define void @uchar_ushort_arg(i8 zeroext %a, i16 zeroext %b) +void uchar_ushort_arg(unsigned char a, unsigned short b) {} + +enum my_enum { + ENUM1, + ENUM2, + ENUM3, +}; + +// Enums should be treated as the underlying i32. +// WEBASSEMBLY32: define void @enum_arg(i32 %a) +// WEBASSEMBLY64: define void @enum_arg(i32 %a) +void enum_arg(enum my_enum a) {} + +enum my_big_enum { + ENUM4 = 0xFFFFFFFFFFFFFFFF, +}; + +// Big enums should be treated as the underlying i64. +// WEBASSEMBLY32: define void @big_enum_arg(i64 %a) +// WEBASSEMBLY64: define void @big_enum_arg(i64 %a) +void big_enum_arg(enum my_big_enum a) {} + +union simple_union { + int a; + char b; +}; + +// Unions should be passed as byval structs. +// WEBASSEMBLY32: define void @union_arg(%union.simple_union* byval(%union.simple_union) align 4 %s) +// WEBASSEMBLY64: define void @union_arg(%union.simple_union* byval(%union.simple_union) align 4 %s) +// EXPERIMENTAL-MV: define void @union_arg(i32 %s.0) +void union_arg(union simple_union s) {} + +// Unions should be returned sret and not simplified by the frontend. +// WEBASSEMBLY32: define void @union_ret(%union.simple_union* noalias sret(%union.simple_union) align 4 %agg.result) +// WEBASSEMBLY32: ret void +// WEBASSEMBLY64: define void @union_ret(%union.simple_union* noalias sret(%union.simple_union) align 4 %agg.result) +// WEBASSEMBLY64: ret void + +// The experimental multivalue ABI returns them by value, though. +// EXPERIMENTAL-MV: define %union.simple_union @union_ret() +// EXPERIMENTAL-MV: ret %union.simple_union %0 +union simple_union union_ret() { + union simple_union bar; + return bar; +} + +typedef struct { + int b4 : 4; + int b3 : 3; + int b8 : 8; +} bitfield1; + +// Bitfields should be passed as byval structs. +// WEBASSEMBLY32: define void @bitfield_arg(%struct.bitfield1* byval(%struct.bitfield1) align 4 %bf1) +// WEBASSEMBLY64: define void @bitfield_arg(%struct.bitfield1* byval(%struct.bitfield1) align 4 %bf1) +// EXPERIMENTAL-MV: define void @bitfield_arg(%struct.bitfield1* byval(%struct.bitfield1) align 4 %bf1) +void bitfield_arg(bitfield1 bf1) {} + +// And returned via sret pointers. +// WEBASSEMBLY32: define void @bitfield_ret(%struct.bitfield1* noalias sret(%struct.bitfield1) align 4 %agg.result) +// WEBASSEMBLY64: define void @bitfield_ret(%struct.bitfield1* noalias sret(%struct.bitfield1) align 4 %agg.result) + +// Except, of course, in the experimental multivalue ABI +// EXPERIMENTAL-MV: define %struct.bitfield1 @bitfield_ret() +bitfield1 bitfield_ret() { + bitfield1 baz; + return baz; +} diff --git a/clang/test/CodeGen/WebAssembly/wasm-call-main.c b/clang/test/CodeGen/WebAssembly/wasm-call-main.c new file mode 100644 index 000000000000..f22ba651c9b1 --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/wasm-call-main.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm %s | FileCheck %s + +// Mangle argc/argv main even when it's not defined in this TU. + +#include <stddef.h> + +int main(int argc, char *argv[]); + +int foo(void) { + return main(0, NULL); +} + +// CHECK: call i32 @__main_argc_argv( diff --git a/clang/test/CodeGen/WebAssembly/wasm-export-name.c b/clang/test/CodeGen/WebAssembly/wasm-export-name.c new file mode 100644 index 000000000000..f2556155dd4c --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/wasm-export-name.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm -o - %s | FileCheck %s + +int __attribute__((export_name("bar"))) foo(void); + +int foo(void) { + return 43; +} + +// CHECK: @llvm.used = appending global [1 x i8*] [i8* bitcast (i32 ()* @foo to i8*)] + +// CHECK: define i32 @foo() [[A:#[0-9]+]] + +// CHECK: attributes [[A]] = {{{.*}} "wasm-export-name"="bar" {{.*}}} diff --git a/clang/test/CodeGen/WebAssembly/wasm-import-module.c b/clang/test/CodeGen/WebAssembly/wasm-import-module.c new file mode 100644 index 000000000000..866a3a459949 --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/wasm-import-module.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm -o - %s | FileCheck %s + +void __attribute__((import_module("bar"))) foo(void); + +void call(void) { + foo(); +} + +// CHECK: declare void @foo() [[A:#[0-9]+]] + +// CHECK: attributes [[A]] = {{{.*}} "wasm-import-module"="bar" {{.*}}} diff --git a/clang/test/CodeGen/WebAssembly/wasm-import-name.c b/clang/test/CodeGen/WebAssembly/wasm-import-name.c new file mode 100644 index 000000000000..7c3b094b9e43 --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/wasm-import-name.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm -o - %s | FileCheck %s + +void __attribute__((import_name("bar"))) foo(void); + +void call(void) { + foo(); +} + +// CHECK: declare void @foo() [[A:#[0-9]+]] + +// CHECK: attributes [[A]] = {{{.*}} "wasm-import-name"="bar" {{.*}}} diff --git a/clang/test/CodeGen/WebAssembly/wasm-main.c b/clang/test/CodeGen/WebAssembly/wasm-main.c new file mode 100644 index 000000000000..33dbdac2a5ba --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/wasm-main.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm %s | FileCheck %s + +// Don't mangle the no-arg form of main. + +int main(void) { + return 0; +} + +// CHECK-LABEL: define i32 @main() diff --git a/clang/test/CodeGen/WebAssembly/wasm-main_argc_argv.c b/clang/test/CodeGen/WebAssembly/wasm-main_argc_argv.c new file mode 100644 index 000000000000..194afc2fd5af --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/wasm-main_argc_argv.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm %s | FileCheck %s + +// Mangle the argc/argv form of main. + +int main(int argc, char **argv) { + return 0; +} + +// CHECK-LABEL: define i32 @__main_argc_argv(i32 %argc, i8** %argv) diff --git a/clang/test/CodeGen/WebAssembly/wasm-regparm.c b/clang/test/CodeGen/WebAssembly/wasm-regparm.c new file mode 100644 index 000000000000..66037d92b4f7 --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/wasm-regparm.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown %s -fsyntax-only -verify +// RUN: %clang_cc1 -triple wasm64-unknown-unknown %s -fsyntax-only -verify + +void __attribute__((regparm(2))) fc_f1(int i, int j, int k) {} // expected-error{{'regparm' is not valid on this platform}} diff --git a/clang/test/CodeGen/WebAssembly/wasm-varargs.c b/clang/test/CodeGen/WebAssembly/wasm-varargs.c new file mode 100644 index 000000000000..00808c9ad3be --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/wasm-varargs.c @@ -0,0 +1,140 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown -o - -emit-llvm %s | FileCheck %s + +#include <stdarg.h> + +int test_i32(char *fmt, ...) { + va_list va; + + va_start(va, fmt); + int v = va_arg(va, int); + va_end(va); + + return v; +} + +// CHECK-LABEL: define i32 @test_i32(i8*{{.*}} %fmt, ...) {{.*}} { +// CHECK: [[FMT_ADDR:%[^,=]+]] = alloca i8*, align 4 +// CHECK: [[VA:%[^,=]+]] = alloca i8*, align 4 +// CHECK: [[V:%[^,=]+]] = alloca i32, align 4 +// CHECK: store i8* %fmt, i8** [[FMT_ADDR]], align 4 +// CHECK: [[VA1:%[^,=]+]] = bitcast i8** [[VA]] to i8* +// CHECK: call void @llvm.va_start(i8* [[VA1]]) +// CHECK: [[ARGP_CUR:%[^,=]+]] = load i8*, i8** [[VA]], align 4 +// CHECK: [[ARGP_NEXT:%[^,=]+]] = getelementptr inbounds i8, i8* [[ARGP_CUR]], i32 4 +// CHECK: store i8* [[ARGP_NEXT]], i8** [[VA]], align 4 +// CHECK: [[R3:%[^,=]+]] = bitcast i8* [[ARGP_CUR]] to i32* +// CHECK: [[R4:%[^,=]+]] = load i32, i32* [[R3]], align 4 +// CHECK: store i32 [[R4]], i32* [[V]], align 4 +// CHECK: [[VA2:%[^,=]+]] = bitcast i8** [[VA]] to i8* +// CHECK: call void @llvm.va_end(i8* [[VA2]]) +// CHECK: [[R5:%[^,=]+]] = load i32, i32* [[V]], align 4 +// CHECK: ret i32 [[R5]] +// CHECK: } + +long long test_i64(char *fmt, ...) { + va_list va; + + va_start(va, fmt); + long long v = va_arg(va, long long); + va_end(va); + + return v; +} + +// CHECK-LABEL: define i64 @test_i64(i8*{{.*}} %fmt, ...) {{.*}} { +// CHECK: [[FMT_ADDR:%[^,=]+]] = alloca i8*, align 4 +// CHECK: [[VA:%[^,=]+]] = alloca i8*, align 4 +// CHECK: [[V:%[^,=]+]] = alloca i64, align 8 +// CHECK: store i8* %fmt, i8** [[FMT_ADDR]], align 4 +// CHECK: [[VA1:%[^,=]+]] = bitcast i8** [[VA]] to i8* +// CHECK: call void @llvm.va_start(i8* [[VA1]]) +// CHECK: [[ARGP_CUR:%[^,=]+]] = load i8*, i8** [[VA]], align 4 +// CHECK: [[R0:%[^,=]+]] = ptrtoint i8* [[ARGP_CUR]] to i32 +// CHECK: [[R1:%[^,=]+]] = add i32 [[R0]], 7 +// CHECK: [[R2:%[^,=]+]] = and i32 [[R1]], -8 +// CHECK: [[ARGP_CUR_ALIGNED:%[^,=]+]] = inttoptr i32 [[R2]] to i8* +// CHECK: [[ARGP_NEXT:%[^,=]+]] = getelementptr inbounds i8, i8* [[ARGP_CUR_ALIGNED]], i32 8 +// CHECK: store i8* [[ARGP_NEXT]], i8** [[VA]], align 4 +// CHECK: [[R3:%[^,=]+]] = bitcast i8* [[ARGP_CUR_ALIGNED]] to i64* +// CHECK: [[R4:%[^,=]+]] = load i64, i64* [[R3]], align 8 +// CHECK: store i64 [[R4]], i64* [[V]], align 8 +// CHECK: [[VA2:%[^,=]+]] = bitcast i8** [[VA]] to i8* +// CHECK: call void @llvm.va_end(i8* [[VA2]]) +// CHECK: [[R5:%[^,=]+]] = load i64, i64* [[V]], align 8 +// CHECK: ret i64 [[R5]] +// CHECK: } + +struct S { + int x; + int y; + int z; +}; + +struct S test_struct(char *fmt, ...) { + va_list va; + + va_start(va, fmt); + struct S v = va_arg(va, struct S); + va_end(va); + + return v; +} + +// CHECK: define void @test_struct([[STRUCT_S:%[^,=]+]]*{{.*}} noalias sret({{.*}}) align 4 [[AGG_RESULT:%.*]], i8*{{.*}} %fmt, ...) {{.*}} { +// CHECK: [[FMT_ADDR:%[^,=]+]] = alloca i8*, align 4 +// CHECK-NEXT: [[VA:%[^,=]+]] = alloca i8*, align 4 +// CHECK-NEXT: store i8* %fmt, i8** [[FMT_ADDR]], align 4 +// CHECK-NEXT: [[VA1:%[^,=]+]] = bitcast i8** [[VA]] to i8* +// CHECK-NEXT: call void @llvm.va_start(i8* [[VA1]]) +// CHECK-NEXT: [[ARGP_CUR:%[^,=]+]] = load i8*, i8** [[VA]], align 4 +// CHECK-NEXT: [[ARGP_NEXT:%[^,=]+]] = getelementptr inbounds i8, i8* [[ARGP_CUR]], i32 4 +// CHECK-NEXT: store i8* [[ARGP_NEXT]], i8** [[VA]], align 4 +// CHECK-NEXT: [[R3:%[^,=]+]] = bitcast i8* [[ARGP_CUR]] to [[STRUCT_S]]** +// CHECK-NEXT: [[R4:%[^,=]+]] = load [[STRUCT_S]]*, [[STRUCT_S]]** [[R3]], align 4 +// CHECK-NEXT: [[R5:%[^,=]+]] = bitcast [[STRUCT_S]]* [[AGG_RESULT]] to i8* +// CHECK-NEXT: [[R6:%[^,=]+]] = bitcast [[STRUCT_S]]* [[R4]] to i8* +// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[R5]], i8* align 4 [[R6]], i32 12, i1 false) +// CHECK-NEXT: [[VA2:%[^,=]+]] = bitcast i8** [[VA]] to i8* +// CHECK-NEXT: call void @llvm.va_end(i8* [[VA2]]) +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +struct Z {}; + +struct S test_empty_struct(char *fmt, ...) { + va_list va; + + va_start(va, fmt); + struct Z u = va_arg(va, struct Z); + struct S v = va_arg(va, struct S); + va_end(va); + + return v; +} + +// CHECK: define void @test_empty_struct([[STRUCT_S:%[^,=]+]]*{{.*}} noalias sret([[STRUCT_S]]) align 4 [[AGG_RESULT:%.*]], i8*{{.*}} %fmt, ...) {{.*}} { +// CHECK: [[FMT_ADDR:%[^,=]+]] = alloca i8*, align 4 +// CHECK-NEXT: [[VA:%[^,=]+]] = alloca i8*, align 4 +// CHECK-NEXT: [[U:%[^,=]+]] = alloca [[STRUCT_Z:%[^,=]+]], align 1 +// CHECK-NEXT: store i8* %fmt, i8** [[FMT_ADDR]], align 4 +// CHECK-NEXT: [[VA1:%[^,=]+]] = bitcast i8** [[VA]] to i8* +// CHECK-NEXT: call void @llvm.va_start(i8* [[VA1]]) +// CHECK-NEXT: [[ARGP_CUR:%[^,=]+]] = load i8*, i8** [[VA]], align 4 +// CHECK-NEXT: [[ARGP_NEXT:%[^,=]+]] = getelementptr inbounds i8, i8* [[ARGP_CUR]], i32 0 +// CHECK-NEXT: store i8* [[ARGP_NEXT]], i8** [[VA]], align 4 +// CHECK-NEXT: [[R0:%[^,=]+]] = bitcast i8* [[ARGP_CUR]] to [[STRUCT_Z]]* +// CHECK-NEXT: [[R1:%[^,=]+]] = bitcast [[STRUCT_Z]]* [[U]] to i8* +// CHECK-NEXT: [[R2:%[^,=]+]] = bitcast [[STRUCT_Z]]* [[R0]] to i8* +// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 [[R1]], i8* align 4 [[R2]], i32 0, i1 false) +// CHECK-NEXT: [[ARGP_CUR2:%[^,=]+]] = load i8*, i8** [[VA]], align 4 +// CHECK-NEXT: [[ARGP_NEXT2:%[^,=]+]] = getelementptr inbounds i8, i8* [[ARGP_CUR2]], i32 4 +// CHECK-NEXT: store i8* [[ARGP_NEXT2]], i8** [[VA]], align 4 +// CHECK-NEXT: [[R3:%[^,=]+]] = bitcast i8* [[ARGP_CUR2]] to [[STRUCT_S]]** +// CHECK-NEXT: [[R4:%[^,=]+]] = load [[STRUCT_S]]*, [[STRUCT_S]]** [[R3]], align 4 +// CHECK-NEXT: [[R5:%[^,=]+]] = bitcast [[STRUCT_S]]* [[AGG_RESULT]] to i8* +// CHECK-NEXT: [[R6:%[^,=]+]] = bitcast [[STRUCT_S]]* [[R4]] to i8* +// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[R5]], i8* align 4 [[R6]], i32 12, i1 false) +// CHECK-NEXT: [[VA2:%[^,=]+]] = bitcast i8** [[VA]] to i8* +// CHECK-NEXT: call void @llvm.va_end(i8* [[VA2]]) +// CHECK-NEXT: ret void +// CHECK-NEXT: } |
