summaryrefslogtreecommitdiff
path: root/clang/test/CodeGen/WebAssembly
diff options
context:
space:
mode:
authorSimon Pilgrim <llvm-dev@redking.me.uk>2020-11-20 12:02:57 +0000
committerSimon Pilgrim <llvm-dev@redking.me.uk>2020-11-20 12:03:28 +0000
commit822c5c50849a1f762c920d59baaa6a6edbb657ee (patch)
tree36db0c3f1a8cef2fa3cd8a1ff6960419c35f4fea /clang/test/CodeGen/WebAssembly
parent2f1fe9a3a60d6f18998c5f3b7e643d4cbaa4e65d (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.c140
-rw-r--r--clang/test/CodeGen/WebAssembly/wasm-call-main.c13
-rw-r--r--clang/test/CodeGen/WebAssembly/wasm-export-name.c13
-rw-r--r--clang/test/CodeGen/WebAssembly/wasm-import-module.c11
-rw-r--r--clang/test/CodeGen/WebAssembly/wasm-import-name.c11
-rw-r--r--clang/test/CodeGen/WebAssembly/wasm-main.c9
-rw-r--r--clang/test/CodeGen/WebAssembly/wasm-main_argc_argv.c9
-rw-r--r--clang/test/CodeGen/WebAssembly/wasm-regparm.c4
-rw-r--r--clang/test/CodeGen/WebAssembly/wasm-varargs.c140
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: }