238 lines · cpp
1// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-abi darwinpcs -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,DARWIN2// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - -x c %s | FileCheck %s --check-prefixes=CHECK,C,AAPCS3// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CXX,AAPCS4 5// Empty structs are ignored for PCS purposes on Darwin and in C mode elsewhere.6// In C++ mode on ELF they consume a register slot though. Functions are7// slightly bigger than minimal to make confirmation against actual GCC8// behaviour easier.9 10#if __cplusplus11#define EXTERNC extern "C"12#else13#define EXTERNC14#endif15 16struct Empty {};17 18// DARWIN: define{{.*}} i32 @empty_arg(i32 noundef %a)19// C: define{{.*}} i32 @empty_arg(i32 noundef %a)20// CXX: define{{.*}} i32 @empty_arg(i64 %e.coerce, i32 noundef %a)21EXTERNC int empty_arg(struct Empty e, int a) {22 return a;23}24 25// CXX: define{{.*}} i32 @empty_align8_arg(i64 %a.coerce, i32 noundef %b)26struct EmptyAlign8 { int __attribute__((aligned(8))) : 0; };27EXTERNC int empty_align8_arg(struct EmptyAlign8 a, int b) {28 return b;29}30 31// CXX: define{{.*}} i32 @empty_align16_arg(i128 %a.coerce, i32 noundef %b)32struct EmptyAlign16 { long long int __attribute__((aligned(16))) : 0; };33EXTERNC int empty_align16_arg(struct EmptyAlign16 a, int b) {34 return b;35}36 37// CXX: define{{.*}} i32 @empty_align32_arg(ptr dead_on_return noundef %a, i32 noundef %b)38struct EmptyAlign32 { long long int __attribute__((aligned(32))) : 0; };39EXTERNC int empty_align32_arg(struct EmptyAlign32 a, int b) {40 return b;41}42 43// DARWIN: define{{.*}} void @empty_ret()44// C: define{{.*}} void @empty_ret()45// CXX: define{{.*}} void @empty_ret()46EXTERNC struct Empty empty_ret(void) {47 struct Empty e;48 return e;49}50 51// However, what counts as "empty" is a baroque mess. This is super-empty, it's52// ignored even in C++ mode. It also has sizeof == 0, violating C++, but that's53// legacy for you:54 55struct SuperEmpty {56 int arr[0];57};58 59// DARWIN: define{{.*}} i32 @super_empty_arg(i32 noundef %a)60// C: define{{.*}} i32 @super_empty_arg(i32 noundef %a)61// CXX: define{{.*}} i32 @super_empty_arg(i32 noundef %a)62EXTERNC int super_empty_arg(struct SuperEmpty e, int a) {63 return a;64}65 66// This is also not empty, and non-standard. We previously considered it to67// consume a register slot, but GCC does not, so we match that.68 69struct SortOfEmpty {70 struct SuperEmpty e;71};72 73// DARWIN: define{{.*}} i32 @sort_of_empty_arg(i32 noundef %a)74// C: define{{.*}} i32 @sort_of_empty_arg(i32 noundef %a)75// CXX: define{{.*}} i32 @sort_of_empty_arg(i32 noundef %a)76EXTERNC int sort_of_empty_arg(struct SortOfEmpty e, int a) {77 return a;78}79 80// DARWIN: define{{.*}} void @sort_of_empty_ret()81// C: define{{.*}} void @sort_of_empty_ret()82// CXX: define{{.*}} void @sort_of_empty_ret()83EXTERNC struct SortOfEmpty sort_of_empty_ret(void) {84 struct SortOfEmpty e;85 return e;86}87 88#include <stdarg.h>89 90// va_arg matches the above rules, consuming an incoming argument in cases91// where one would be passed, and not doing so when the argument should be92// ignored.93 94EXTERNC struct Empty empty_arg_variadic(int a, ...) {95// CHECK-LABEL: @empty_arg_variadic(96// DARWIN-NOT: {{ getelementptr }}97// C-NOT: {{ getelementptr }}98// CXX: %new_reg_offs = add i32 %gr_offs, 899// CXX: %new_stack = getelementptr inbounds i8, ptr %stack, i64 8100 va_list vl;101 va_start(vl, a);102 struct Empty b = va_arg(vl, struct Empty);103 va_end(vl);104 return b;105}106 107EXTERNC struct SuperEmpty super_empty_arg_variadic(int a, ...) {108// CHECK-LABEL: @super_empty_arg_variadic(109// DARWIN-NOT: {{ getelementptr }}110// C-NOT: {{ getelementptr }}111// CXX-NOT: {{ getelementptr }}112 va_list vl;113 va_start(vl, a);114 struct SuperEmpty b = va_arg(vl, struct SuperEmpty);115 va_end(vl);116 return b;117}118 119EXTERNC struct SortOfEmpty sort_of_empty_arg_variadic(int a, ...) {120// CHECK-LABEL: @sort_of_empty_arg_variadic(121// DARWIN: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i64 0122// C-NOT: {{ getelementptr }}123// CXX-NOT: {{ getelementptr }}124 va_list vl;125 va_start(vl, a);126 struct SortOfEmpty b = va_arg(vl, struct SortOfEmpty);127 va_end(vl);128 return b;129}130 131// Base case, nothing interesting.132struct S {133 long x, y;134};135 136// CHECK-LABEL: @g_S(137// CHECK: call void @f_S(i64 noundef 1, [2 x i64] {{.*}})138// CHECK: call void @fm_S(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, [2 x i64] {{.*}})139EXTERNC void f_S(long, struct S);140EXTERNC void fm_S(long, long, long, long, long, struct S);141EXTERNC void g_S() {142 struct S s = {6, 7};143 f_S(1, s);144 fm_S(1, 2, 3, 4, 5, s);145}146 147// Aligned struct passed according to its natural alignment.148struct __attribute__((aligned(16))) S16 {149 long x, y;150};151 152// CHECK-LABEL: @g_S16(153// DARWIN: call void @f_S16(i64 noundef 1, i128 {{.*}})154// AAPCS: call void @f_S16(i64 noundef 1, [2 x i64] {{.*}})155// DARWIN: call void @fm_S16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}})156// AAPCS: call void @fm_S16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, [2 x i64] {{.*}})157EXTERNC void f_S16(long, struct S16);158EXTERNC void fm_S16(long, long, long, long, long, struct S16);159EXTERNC void g_S16() {160 struct S16 s = {6, 7};161 f_S16(1, s);162 fm_S16(1, 2, 3, 4, 5, s);163}164 165// Aligned struct with increased natural alignment through an aligned field.166struct SF16 {167 __attribute__((aligned(16))) long x;168 long y;169};170 171// CHECK-LABEL: @g_SF16(172// DARWIN: call void @f_SF16(i64 noundef 1, i128 {{.*}})173// AAPCS: call void @f_SF16(i64 noundef 1, i128 {{.*}})174// DARWIN: call void @fm_SF16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}})175// AAPCS: call void @fm_SF16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}})176EXTERNC void f_SF16(long, struct SF16);177EXTERNC void fm_SF16(long, long, long, long, long, struct SF16);178EXTERNC void g_SF16() {179 struct SF16 s = {6, 7};180 f_SF16(1, s);181 fm_SF16(1, 2, 3, 4, 5, s);182}183 184#ifdef __cplusplus185// Aligned struct with increased natural alignment through an aligned base class.186struct SB16 : S16 {};187 188// DARWIN-LABEL: @g_SB16(189// CXX-LABEL: @g_SB16(190// DARWIN: call void @f_SB16(i64 noundef 1, i128 {{.*}})191// CXX: call void @f_SB16(i64 noundef 1, i128 {{.*}})192// DARWIN: call void @fm_SB16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}})193// CXX: call void @fm_SB16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}})194EXTERNC void f_SB16(long, struct SB16);195EXTERNC void fm_SB16(long, long, long, long, long, struct SB16);196EXTERNC void g_SB16() {197 struct SB16 s = {6, 7};198 f_SB16(1, s);199 fm_SB16(1, 2, 3, 4, 5, s);200}201#endif202 203// Packed structure.204struct __attribute__((packed)) SP {205 int x;206 long y;207};208 209// CHECK-LABEL: @g_SP(210// CHECK: call void @f_SP(i32 noundef 1, [2 x i64] {{.*}})211// CHECK: call void @fm_SP(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [2 x i64] {{.*}})212EXTERNC void f_SP(int, struct SP);213EXTERNC void fm_SP(int, int, int, int, int, struct SP);214EXTERNC void g_SP() {215 struct SP s = {6, 7};216 f_SP(1, s);217 fm_SP(1, 2, 3, 4, 5, s);218}219 220// Packed structure, overaligned, same as above.221struct __attribute__((packed, aligned(16))) SP16 {222 int x;223 long y;224};225 226// CHECK-LABEL: @g_SP16(227// DARWIN: call void @f_SP16(i32 noundef 1, i128 {{.*}})228// AAPCS: call void @f_SP16(i32 noundef 1, [2 x i64] {{.*}})229// DARWIN: call void @fm_SP16(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, i128 {{.*}})230// AAPCS: call void @fm_SP16(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [2 x i64] {{.*}})231EXTERNC void f_SP16(int, struct SP16);232EXTERNC void fm_SP16(int, int, int, int, int, struct SP16);233EXTERNC void g_SP16() {234 struct SP16 s = {6, 7};235 f_SP16(1, s);236 fm_SP16(1, 2, 3, 4, 5, s);237}238