summaryrefslogtreecommitdiffstats
path: root/clang/test
diff options
context:
space:
mode:
authorTim Northover <tnorthover@apple.com>2017-05-05 22:36:06 +0000
committerTim Northover <tnorthover@apple.com>2017-05-05 22:36:06 +0000
commit23bcad226c564944d2155b027b9c9fe8a2591d05 (patch)
tree8119cddf0382e65ed1af0ec1ff2f662521389d96 /clang/test
parentce03732ec85296f942ee6644596056ce5e577f89 (diff)
downloadbcm5719-llvm-23bcad226c564944d2155b027b9c9fe8a2591d05.tar.gz
bcm5719-llvm-23bcad226c564944d2155b027b9c9fe8a2591d05.zip
AArch64: fix weird edge case in ABI.
It turns out there are some sort-of-but-not-quite empty structs that break all the rules. For example: struct SuperEmpty { int arr[0]; }; struct SortOfEmpty { struct SuperEmpty e; }; Both of these have sizeof == 0, even in C++ mode, for GCC compatibility. The first one also doesn't occupy a register when passed by value in GNU C++ mode, unlike everything else. On Darwin, we want to ignore the lot (and especially don't want to try to use an i0 as we were). llvm-svn: 302313
Diffstat (limited to 'clang/test')
-rw-r--r--clang/test/CodeGen/aarch64-args.cpp67
1 files changed, 67 insertions, 0 deletions
diff --git a/clang/test/CodeGen/aarch64-args.cpp b/clang/test/CodeGen/aarch64-args.cpp
new file mode 100644
index 00000000000..40977362726
--- /dev/null
+++ b/clang/test/CodeGen/aarch64-args.cpp
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-abi darwinpcs -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - -x c %s | FileCheck %s --check-prefix=CHECK-GNU-C
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-GNU-CXX
+
+// Empty structs are ignored for PCS purposes on Darwin and in C mode elsewhere.
+// In C++ mode on ELF they consume a register slot though. Functions are
+// slightly bigger than minimal to make confirmation against actual GCC
+// behaviour easier.
+
+#if __cplusplus
+#define EXTERNC extern "C"
+#else
+#define EXTERNC
+#endif
+
+struct Empty {};
+
+// CHECK: define i32 @empty_arg(i32 %a)
+// CHECK-GNU-C: define i32 @empty_arg(i32 %a)
+// CHECK-GNU-CXX: define i32 @empty_arg(i8 %e.coerce, i32 %a)
+EXTERNC int empty_arg(struct Empty e, int a) {
+ return a;
+}
+
+// CHECK: define void @empty_ret()
+// CHECK-GNU-C: define void @empty_ret()
+// CHECK-GNU-CXX: define void @empty_ret()
+EXTERNC struct Empty empty_ret() {
+ struct Empty e;
+ return e;
+}
+
+// However, what counts as "empty" is a baroque mess. This is super-empty, it's
+// ignored even in C++ mode. It also has sizeof == 0, violating C++, but that's
+// legacy for you:
+
+struct SuperEmpty {
+ int arr[0];
+};
+
+// CHECK: define i32 @super_empty_arg(i32 %a)
+// CHECK-GNU-C: define i32 @super_empty_arg(i32 %a)
+// CHECK-GNU-CXX: define i32 @super_empty_arg(i32 %a)
+EXTERNC int super_empty_arg(struct SuperEmpty e, int a) {
+ return a;
+}
+
+// This is not empty. It has 0 size but consumes a register slot for GCC.
+
+struct SortOfEmpty {
+ struct SuperEmpty e;
+};
+
+// CHECK: define i32 @sort_of_empty_arg(i32 %a)
+// CHECK-GNU-C: define i32 @sort_of_empty_arg(i32 %a)
+// CHECK-GNU-CXX: define i32 @sort_of_empty_arg(i8 %e.coerce, i32 %a)
+EXTERNC int sort_of_empty_arg(struct Empty e, int a) {
+ return a;
+}
+
+// CHECK: define void @sort_of_empty_ret()
+// CHECK-GNU-C: define void @sort_of_empty_ret()
+// CHECK-GNU-CXX: define void @sort_of_empty_ret()
+EXTERNC struct SortOfEmpty sort_of_empty_ret() {
+ struct SortOfEmpty e;
+ return e;
+}
OpenPOWER on IntegriCloud