132 lines · cpp
1// RUN: %clang_cc1 -triple armv7a-linux-gnueabi -emit-llvm -o - -x c %s | FileCheck %s --check-prefixes=CHECK,C2// RUN: %clang_cc1 -triple armv7a-linux-gnueabi -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CXX3// RUN: %clang_cc1 -triple armv7a-linux-gnueabi -emit-llvm -o - %s -fclang-abi-compat=19 | FileCheck %s --check-prefixes=CHECK,CXXCLANG194// RUN: %clang_cc1 -triple thumbv7k-apple-watchos2.0 -target-abi aapcs16 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,WATCHOS5 6// Empty structs are ignored for PCS purposes on WatchOS and in C mode7// elsewhere. In C++ mode they consume a register slot though. Functions are8// slightly bigger than minimal to make confirmation against actual GCC9// behaviour easier.10 11#if __cplusplus12#define EXTERNC extern "C"13#else14#define EXTERNC15#endif16 17struct Empty {};18 19// C: define{{.*}} i32 @empty_arg(i32 noundef %a)20// CXX: define{{.*}} i32 @empty_arg(i8 %e.coerce, i32 noundef %a)21// CXXCLANG19: define{{.*}} i32 @empty_arg(i32 noundef %a)22// WATCHOS: define{{.*}} i32 @empty_arg(i32 noundef %a)23EXTERNC int empty_arg(struct Empty e, int a) {24 return a;25}26 27// C: define{{.*}} void @empty_ret()28// CXX: define{{.*}} void @empty_ret()29// CXXCLANG19: define{{.*}} void @empty_ret()30// WATCHOS: define{{.*}} void @empty_ret()31EXTERNC struct Empty empty_ret(void) {32 struct Empty e;33 return e;34}35 36// However, what counts as "empty" is a baroque mess. This is super-empty, it's37// ignored even in C++ mode. It also has sizeof == 0, violating C++, but that's38// legacy for you:39 40struct SuperEmpty {41 int arr[0];42};43 44// C: define{{.*}} i32 @super_empty_arg(i32 noundef %a)45// CXX: define{{.*}} i32 @super_empty_arg(i32 noundef %a)46// CXXCLANG19: define{{.*}} i32 @super_empty_arg(i32 noundef %a)47// WATCHOS: define{{.*}} i32 @super_empty_arg(i32 noundef %a)48EXTERNC int super_empty_arg(struct SuperEmpty e, int a) {49 return a;50}51 52struct SortOfEmpty {53 struct SuperEmpty e;54};55 56// C: define{{.*}} i32 @sort_of_empty_arg(i32 noundef %a)57// CXX: define{{.*}} i32 @sort_of_empty_arg(i8 %e.coerce, i32 noundef %a)58// CXXCLANG19: define{{.*}} i32 @sort_of_empty_arg(i32 noundef %a)59// WATCHOS: define{{.*}} i32 @sort_of_empty_arg(i32 noundef %a)60EXTERNC int sort_of_empty_arg(struct Empty e, int a) {61 return a;62}63 64// C: define{{.*}} void @sort_of_empty_ret()65// CXX: define{{.*}} void @sort_of_empty_ret()66// CXXCLANG19: define{{.*}} void @sort_of_empty_ret()67// WATCHOS: define{{.*}} void @sort_of_empty_ret()68EXTERNC struct SortOfEmpty sort_of_empty_ret(void) {69 struct SortOfEmpty e;70 return e;71}72 73#include <stdarg.h>74 75// va_arg matches the above rules, consuming an incoming argument in cases76// where one would be passed, and not doing so when the argument should be77// ignored.78 79EXTERNC int empty_arg_variadic(int a, ...) {80// CHECK-LABEL: @empty_arg_variadic(81// C: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 482// C-NOT: {{ getelementptr }}83// CXX: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 484// CXX: %argp.next2 = getelementptr inbounds i8, ptr %argp.cur1, i32 485// CXXCLANG19: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 486// CXXCLANG19-NOT: {{ getelementptr }}87// WATCHOS: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 488// WATCHOS-NOT: {{ getelementptr }}89 va_list vl;90 va_start(vl, a);91 struct Empty b = va_arg(vl, struct Empty);92 int c = va_arg(vl, int);93 va_end(vl);94 return c;95}96 97EXTERNC int super_empty_arg_variadic(int a, ...) {98// CHECK-LABEL: @super_empty_arg_variadic(99// C: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4100// C-NOT: {{ getelementptr }}101// CXX: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4102// CXX-NOT: {{ getelementptr }}103// CXXCLANG19: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4104// CXXCLANG19-NOT: {{ getelementptr }}105// WATCHOS: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4106// WATCHOS-NOT: {{ getelementptr }}107 va_list vl;108 va_start(vl, a);109 struct SuperEmpty b = va_arg(vl, struct SuperEmpty);110 int c = va_arg(vl, int);111 va_end(vl);112 return c;113}114 115EXTERNC int sort_of_empty_arg_variadic(int a, ...) {116// CHECK-LABEL: @sort_of_empty_arg_variadic(117// C: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4118// C-NOT: {{ getelementptr }}119// CXX: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4120// CXX-NOT: {{ getelementptr }}121// CXXCLANG19: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4122// CXXCLANG19-NOT: {{ getelementptr }}123// WATCHOS: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i32 4124// WATCHOS-NOT: {{ getelementptr }}125 va_list vl;126 va_start(vl, a);127 struct SortOfEmpty b = va_arg(vl, struct SortOfEmpty);128 int c = va_arg(vl, int);129 va_end(vl);130 return c;131}132