1 // RUN: %clang_cc1 -triple arm64_32-apple-ios7.0 -target-abi darwinpcs -emit-llvm -o - -O1 -ffreestanding %s | FileCheck %s
2 
3 #include <stdarg.h>
4 
5 typedef struct {
6   int a;
7 } OneInt;
8 
9 // No realignment should be needed here: slot size is 4 bytes.
test_int(OneInt input,va_list * mylist)10 int test_int(OneInt input, va_list *mylist) {
11 // CHECK-LABEL: define i32 @test_int(i32 %input
12 // CHECK: [[START:%.*]] = load i8*, i8** %mylist
13 // CHECK: [[NEXT:%.*]] = getelementptr inbounds i8, i8* [[START]], i32 4
14 // CHECK: store i8* [[NEXT]], i8** %mylist
15 
16 // CHECK: [[ADDR_I32:%.*]] = bitcast i8* [[START]] to i32*
17 // CHECK: [[RES:%.*]] = load i32, i32* [[ADDR_I32]]
18 // CHECK: ret i32 [[RES]]
19 
20   return va_arg(*mylist, OneInt).a;
21 }
22 
23 
24 typedef struct {
25   long long a;
26 } OneLongLong;
27 
28 // Minimum slot size is 4 bytes, so address needs rounding up to multiple of 8.
test_longlong(OneLongLong input,va_list * mylist)29 long long test_longlong(OneLongLong input, va_list *mylist) {
30 // CHECK-LABEL: define i64 @test_longlong(i64 %input
31 // CHECK: [[STARTPTR:%.*]] = bitcast i8** %mylist to i32*
32 // CHECK: [[START:%.*]] = load i32, i32* [[STARTPTR]]
33 
34 // CHECK: [[ALIGN_TMP:%.*]] = add i32 [[START]], 7
35 // CHECK: [[ALIGNED:%.*]] = and i32 [[ALIGN_TMP]], -8
36 // CHECK: [[ALIGNED_ADDR:%.*]] = inttoptr i32 [[ALIGNED]] to i8*
37 // CHECK: [[NEXT:%.*]] = getelementptr inbounds i8, i8* [[ALIGNED_ADDR]], i32 8
38 // CHECK: store i8* [[NEXT]], i8** %mylist
39 
40 // CHECK: [[ADDR_STRUCT:%.*]] = inttoptr i32 [[ALIGNED]] to %struct.OneLongLong*
41 // CHECK: [[ADDR_I64:%.*]] = getelementptr inbounds %struct.OneLongLong, %struct.OneLongLong* [[ADDR_STRUCT]], i32 0, i32 0
42 // CHECK: [[RES:%.*]] = load i64, i64* [[ADDR_I64]]
43 // CHECK: ret i64 [[RES]]
44 
45   return va_arg(*mylist, OneLongLong).a;
46 }
47 
48 
49 typedef struct {
50   float arr[4];
51 } HFA;
52 
53 // HFAs take priority over passing large structs indirectly.
test_hfa(va_list * mylist)54 float test_hfa(va_list *mylist) {
55 // CHECK-LABEL: define float @test_hfa
56 // CHECK: [[START:%.*]] = load i8*, i8** %mylist
57 
58 // CHECK: [[NEXT:%.*]] = getelementptr inbounds i8, i8* [[START]], i32 16
59 // CHECK: store i8* [[NEXT]], i8** %mylist
60 
61 // CHECK: [[ADDR_FLOAT:%.*]] = bitcast i8* [[START]] to float*
62 // CHECK: [[RES:%.*]] = load float, float* [[ADDR_FLOAT]]
63 // CHECK: ret float [[RES]]
64 
65   return va_arg(*mylist, HFA).arr[0];
66 }
67 
68 // armv7k does not return HFAs normally for variadic functions, so we must match
69 // that.
test_hfa_return(int n,...)70 HFA test_hfa_return(int n, ...) {
71 // CHECK-LABEL: define [2 x i64] @test_hfa_return
72   HFA h = {0};
73   return h;
74 }
75 
76 typedef struct {
77   long long a, b;
78   char c;
79 } BigStruct;
80 
81 // Structs bigger than 16 bytes are passed indirectly: a pointer is placed on
82 // the stack.
test_bigstruct(BigStruct input,va_list * mylist)83 long long test_bigstruct(BigStruct input, va_list *mylist) {
84 // CHECK-LABEL: define i64 @test_bigstruct(%struct.BigStruct*
85 // CHECK: [[START:%.*]] = load i8*, i8** %mylist
86 // CHECK: [[NEXT:%.*]] = getelementptr inbounds i8, i8* [[START]], i32 4
87 // CHECK: store i8* [[NEXT]], i8** %mylist
88 
89 // CHECK: [[INT_PTR:%.*]] = bitcast i8* [[START]] to %struct.BigStruct**
90 // CHECK: [[ADDR:%.*]] = load %struct.BigStruct*, %struct.BigStruct** [[INT_PTR]]
91 // CHECK: [[ADDR_I64:%.*]] = getelementptr inbounds %struct.BigStruct, %struct.BigStruct* [[ADDR]], i32 0, i32 0
92 // CHECK: [[RES:%.*]] = load i64, i64* [[ADDR_I64]]
93 // CHECK: ret i64 [[RES]]
94 
95   return va_arg(*mylist, BigStruct).a;
96 }
97 
98 typedef struct {
99   short arr[3];
100 } ThreeShorts;
101 
102 // Slot sizes are 4-bytes on arm64_32, so structs with less than 32-bit
103 // alignment must be passed via "[N x i32]" to be correctly allocated in the
104 // backend.
test_threeshorts(ThreeShorts input,va_list * mylist)105 short test_threeshorts(ThreeShorts input, va_list *mylist) {
106 // CHECK-LABEL: define signext i16 @test_threeshorts([2 x i32] %input
107 
108 // CHECK: [[START:%.*]] = load i8*, i8** %mylist
109 // CHECK: [[NEXT:%.*]] = getelementptr inbounds i8, i8* [[START]], i32 8
110 // CHECK: store i8* [[NEXT]], i8** %mylist
111 
112 // CHECK: [[ADDR_I32:%.*]] = bitcast i8* [[START]] to i16*
113 // CHECK: [[RES:%.*]] = load i16, i16* [[ADDR_I32]]
114 // CHECK: ret i16 [[RES]]
115 
116   return va_arg(*mylist, ThreeShorts).arr[0];
117 }
118