1 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --filter "^define |^entry:" --version 2
2 // RUN: %clang_cc1 -triple riscv64 -emit-llvm %s -o - \
3 // RUN: | FileCheck -check-prefixes=LP64-LP64F-LP64D,LP64-LP64F,LP64 %s
4 // RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm %s -o - \
5 // RUN: | FileCheck -check-prefixes=LP64-LP64F-LP64D,LP64F-LP64D,LP64-LP64F,LP64F %s
6 // RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-feature +d -target-abi lp64d -emit-llvm %s -o - \
7 // RUN: | FileCheck -check-prefixes=LP64-LP64F-LP64D,LP64F-LP64D,LP64D %s
8 // RUN: %clang_cc1 -triple riscv64 -emit-llvm -target-abi lp64e %s -o - \
9 // RUN: | FileCheck -check-prefixes=LP64-LP64F-LP64D,LP64-LP64F,LP64,LP64E %s
10
11 #include <stddef.h>
12 #include <stdint.h>
13
14 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_void
15 // LP64-LP64F-LP64D-SAME: () #[[ATTR0:[0-9]+]] {
16 // LP64-LP64F-LP64D: entry:
17 //
f_void(void)18 void f_void(void) {}
19
20 // Scalar arguments and return values smaller than the word size are extended
21 // according to the sign of their type, up to 32 bits
22
23 // LP64-LP64F-LP64D-LABEL: define dso_local zeroext i1 @f_scalar_0
24 // LP64-LP64F-LP64D-SAME: (i1 noundef zeroext [[X:%.*]]) #[[ATTR0]] {
25 // LP64-LP64F-LP64D: entry:
26 //
f_scalar_0(_Bool x)27 _Bool f_scalar_0(_Bool x) { return x; }
28
29 // LP64-LP64F-LP64D-LABEL: define dso_local signext i8 @f_scalar_1
30 // LP64-LP64F-LP64D-SAME: (i8 noundef signext [[X:%.*]]) #[[ATTR0]] {
31 // LP64-LP64F-LP64D: entry:
32 //
f_scalar_1(int8_t x)33 int8_t f_scalar_1(int8_t x) { return x; }
34
35 // LP64-LP64F-LP64D-LABEL: define dso_local zeroext i8 @f_scalar_2
36 // LP64-LP64F-LP64D-SAME: (i8 noundef zeroext [[X:%.*]]) #[[ATTR0]] {
37 // LP64-LP64F-LP64D: entry:
38 //
f_scalar_2(uint8_t x)39 uint8_t f_scalar_2(uint8_t x) { return x; }
40
41 // LP64-LP64F-LP64D-LABEL: define dso_local signext i32 @f_scalar_3
42 // LP64-LP64F-LP64D-SAME: (i32 noundef signext [[X:%.*]]) #[[ATTR0]] {
43 // LP64-LP64F-LP64D: entry:
44 //
f_scalar_3(int32_t x)45 uint32_t f_scalar_3(int32_t x) { return x; }
46
47 // LP64-LP64F-LP64D-LABEL: define dso_local i64 @f_scalar_4
48 // LP64-LP64F-LP64D-SAME: (i64 noundef [[X:%.*]]) #[[ATTR0]] {
49 // LP64-LP64F-LP64D: entry:
50 //
f_scalar_4(int64_t x)51 int64_t f_scalar_4(int64_t x) { return x; }
52
53 // LP64-LP64F-LP64D-LABEL: define dso_local float @f_fp_scalar_1
54 // LP64-LP64F-LP64D-SAME: (float noundef [[X:%.*]]) #[[ATTR0]] {
55 // LP64-LP64F-LP64D: entry:
56 //
f_fp_scalar_1(float x)57 float f_fp_scalar_1(float x) { return x; }
58
59 // LP64-LP64F-LP64D-LABEL: define dso_local double @f_fp_scalar_2
60 // LP64-LP64F-LP64D-SAME: (double noundef [[X:%.*]]) #[[ATTR0]] {
61 // LP64-LP64F-LP64D: entry:
62 //
f_fp_scalar_2(double x)63 double f_fp_scalar_2(double x) { return x; }
64
65 // LP64-LP64F-LP64D-LABEL: define dso_local fp128 @f_fp_scalar_3
66 // LP64-LP64F-LP64D-SAME: (fp128 noundef [[X:%.*]]) #[[ATTR0]] {
67 // LP64-LP64F-LP64D: entry:
68 //
f_fp_scalar_3(long double x)69 long double f_fp_scalar_3(long double x) { return x; }
70
71 // LP64-LP64F-LP64D-LABEL: define dso_local half @f_fp_scalar_4
72 // LP64-LP64F-LP64D-SAME: (half noundef [[X:%.*]]) #[[ATTR0]] {
73 // LP64-LP64F-LP64D: entry:
74 //
f_fp_scalar_4(_Float16 x)75 _Float16 f_fp_scalar_4(_Float16 x) { return x; }
76
77 // Empty structs or unions are ignored.
78
79 struct empty_s {};
80
81 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_agg_empty_struct
82 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
83 // LP64-LP64F-LP64D: entry:
84 //
f_agg_empty_struct(struct empty_s x)85 struct empty_s f_agg_empty_struct(struct empty_s x) {
86 return x;
87 }
88
89 union empty_u {};
90
91 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_agg_empty_union
92 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
93 // LP64-LP64F-LP64D: entry:
94 //
f_agg_empty_union(union empty_u x)95 union empty_u f_agg_empty_union(union empty_u x) {
96 return x;
97 }
98
99 // Aggregates <= 2*xlen may be passed in registers, so will be coerced to
100 // integer arguments. The rules for return are the same.
101
102 struct tiny {
103 uint16_t a, b, c, d;
104 };
105
106 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_agg_tiny
107 // LP64-LP64F-LP64D-SAME: (i64 [[X_COERCE:%.*]]) #[[ATTR0]] {
108 // LP64-LP64F-LP64D: entry:
109 //
f_agg_tiny(struct tiny x)110 void f_agg_tiny(struct tiny x) {
111 x.a += x.b;
112 x.c += x.d;
113 }
114
115 // LP64-LP64F-LP64D-LABEL: define dso_local i64 @f_agg_tiny_ret
116 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
117 // LP64-LP64F-LP64D: entry:
118 //
f_agg_tiny_ret(void)119 struct tiny f_agg_tiny_ret(void) {
120 return (struct tiny){1, 2, 3, 4};
121 }
122
123 typedef uint16_t v4i16 __attribute__((vector_size(8)));
124 typedef int64_t v1i64 __attribute__((vector_size(8)));
125
126 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_vec_tiny_v4i16
127 // LP64-LP64F-LP64D-SAME: (i64 noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
128 // LP64-LP64F-LP64D: entry:
129 //
f_vec_tiny_v4i16(v4i16 x)130 void f_vec_tiny_v4i16(v4i16 x) {
131 x[0] = x[1];
132 x[2] = x[3];
133 }
134
135 // LP64-LP64F-LP64D-LABEL: define dso_local i64 @f_vec_tiny_v4i16_ret
136 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
137 // LP64-LP64F-LP64D: entry:
138 //
f_vec_tiny_v4i16_ret(void)139 v4i16 f_vec_tiny_v4i16_ret(void) {
140 return (v4i16){1, 2, 3, 4};
141 }
142
143 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_vec_tiny_v1i64
144 // LP64-LP64F-LP64D-SAME: (i64 noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
145 // LP64-LP64F-LP64D: entry:
146 //
f_vec_tiny_v1i64(v1i64 x)147 void f_vec_tiny_v1i64(v1i64 x) {
148 x[0] = 114;
149 }
150
151 // LP64-LP64F-LP64D-LABEL: define dso_local i64 @f_vec_tiny_v1i64_ret
152 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
153 // LP64-LP64F-LP64D: entry:
154 //
f_vec_tiny_v1i64_ret(void)155 v1i64 f_vec_tiny_v1i64_ret(void) {
156 return (v1i64){1};
157 }
158
159 struct small {
160 int64_t a, *b;
161 };
162
163 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_agg_small
164 // LP64-LP64F-LP64D-SAME: ([2 x i64] [[X_COERCE:%.*]]) #[[ATTR0]] {
165 // LP64-LP64F-LP64D: entry:
166 //
f_agg_small(struct small x)167 void f_agg_small(struct small x) {
168 x.a += *x.b;
169 x.b = &x.a;
170 }
171
172 // LP64-LP64F-LP64D-LABEL: define dso_local [2 x i64] @f_agg_small_ret
173 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
174 // LP64-LP64F-LP64D: entry:
175 //
f_agg_small_ret(void)176 struct small f_agg_small_ret(void) {
177 return (struct small){1, 0};
178 }
179
180 typedef uint16_t v8i16 __attribute__((vector_size(16)));
181 typedef __int128_t v1i128 __attribute__((vector_size(16)));
182
183 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_vec_small_v8i16
184 // LP64-LP64F-LP64D-SAME: (i128 noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
185 // LP64-LP64F-LP64D: entry:
186 //
f_vec_small_v8i16(v8i16 x)187 void f_vec_small_v8i16(v8i16 x) {
188 x[0] = x[7];
189 }
190
191 // LP64-LP64F-LP64D-LABEL: define dso_local i128 @f_vec_small_v8i16_ret
192 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
193 // LP64-LP64F-LP64D: entry:
194 //
f_vec_small_v8i16_ret(void)195 v8i16 f_vec_small_v8i16_ret(void) {
196 return (v8i16){1, 2, 3, 4, 5, 6, 7, 8};
197 }
198
199 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_vec_small_v1i128
200 // LP64-LP64F-LP64D-SAME: (i128 noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
201 // LP64-LP64F-LP64D: entry:
202 //
f_vec_small_v1i128(v1i128 x)203 void f_vec_small_v1i128(v1i128 x) {
204 x[0] = 114;
205 }
206
207 // LP64-LP64F-LP64D-LABEL: define dso_local i128 @f_vec_small_v1i128_ret
208 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
209 // LP64-LP64F-LP64D: entry:
210 //
f_vec_small_v1i128_ret(void)211 v1i128 f_vec_small_v1i128_ret(void) {
212 return (v1i128){1};
213 }
214
215 // Aggregates of 2*xlen size and 2*xlen alignment should be coerced to a
216 // single 2*xlen-sized argument, to ensure that alignment can be maintained if
217 // passed on the stack.
218
219 struct small_aligned {
220 __int128_t a;
221 };
222
223 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_agg_small_aligned
224 // LP64-LP64F-LP64D-SAME: (i128 [[X_COERCE:%.*]]) #[[ATTR0]] {
225 // LP64-LP64F-LP64D: entry:
226 //
f_agg_small_aligned(struct small_aligned x)227 void f_agg_small_aligned(struct small_aligned x) {
228 x.a += x.a;
229 }
230
231 // LP64-LP64F-LP64D-LABEL: define dso_local i128 @f_agg_small_aligned_ret
232 // LP64-LP64F-LP64D-SAME: (i128 [[X_COERCE:%.*]]) #[[ATTR0]] {
233 // LP64-LP64F-LP64D: entry:
234 //
f_agg_small_aligned_ret(struct small_aligned x)235 struct small_aligned f_agg_small_aligned_ret(struct small_aligned x) {
236 return (struct small_aligned){10};
237 }
238
239 // Aggregates greater > 2*xlen will be passed and returned indirectly
240 struct large {
241 int64_t a, b, c, d;
242 };
243
244 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_agg_large
245 // LP64-LP64F-LP64D-SAME: (ptr noundef [[X:%.*]]) #[[ATTR0]] {
246 // LP64-LP64F-LP64D: entry:
247 //
f_agg_large(struct large x)248 void f_agg_large(struct large x) {
249 x.a = x.b + x.c + x.d;
250 }
251
252 // The address where the struct should be written to will be the first
253 // argument
254 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_agg_large_ret
255 // LP64-LP64F-LP64D-SAME: (ptr dead_on_unwind noalias writable sret([[STRUCT_LARGE:%.*]]) align 8 [[AGG_RESULT:%.*]], i32 noundef signext [[I:%.*]], i8 noundef signext [[J:%.*]]) #[[ATTR0]] {
256 // LP64-LP64F-LP64D: entry:
257 //
f_agg_large_ret(int32_t i,int8_t j)258 struct large f_agg_large_ret(int32_t i, int8_t j) {
259 return (struct large){1, 2, 3, 4};
260 }
261
262 typedef unsigned char v32i8 __attribute__((vector_size(32)));
263
264 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_vec_large_v32i8
265 // LP64-LP64F-LP64D-SAME: (ptr noundef [[TMP0:%.*]]) #[[ATTR0]] {
266 // LP64-LP64F-LP64D: entry:
267 //
f_vec_large_v32i8(v32i8 x)268 void f_vec_large_v32i8(v32i8 x) {
269 x[0] = x[7];
270 }
271
272 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_vec_large_v32i8_ret
273 // LP64-LP64F-LP64D-SAME: (ptr dead_on_unwind noalias writable sret(<32 x i8>) align 32 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
274 // LP64-LP64F-LP64D: entry:
275 //
f_vec_large_v32i8_ret(void)276 v32i8 f_vec_large_v32i8_ret(void) {
277 return (v32i8){1, 2, 3, 4, 5, 6, 7, 8};
278 }
279
280 // Scalars passed on the stack should have signext/zeroext attributes, just as
281 // if they were passed in registers.
282
283 // LP64-LP64F-LP64D-LABEL: define dso_local signext i32 @f_scalar_stack_1
284 // LP64-LP64F-LP64D-SAME: (i64 [[A_COERCE:%.*]], [2 x i64] [[B_COERCE:%.*]], i128 [[C_COERCE:%.*]], ptr noundef [[D:%.*]], i8 noundef zeroext [[E:%.*]], i8 noundef signext [[F:%.*]], i8 noundef zeroext [[G:%.*]], i8 noundef signext [[H:%.*]]) #[[ATTR0]] {
285 // LP64-LP64F-LP64D: entry:
286 //
f_scalar_stack_1(struct tiny a,struct small b,struct small_aligned c,struct large d,uint8_t e,int8_t f,uint8_t g,int8_t h)287 int f_scalar_stack_1(struct tiny a, struct small b, struct small_aligned c,
288 struct large d, uint8_t e, int8_t f, uint8_t g, int8_t h) {
289 return g + h;
290 }
291
292 // LP64-LP64F-LP64D-LABEL: define dso_local signext i32 @f_scalar_stack_2
293 // LP64-LP64F-LP64D-SAME: (i32 noundef signext [[A:%.*]], i128 noundef [[B:%.*]], i64 noundef [[C:%.*]], fp128 noundef [[D:%.*]], ptr noundef [[TMP0:%.*]], i8 noundef zeroext [[F:%.*]], i8 noundef signext [[G:%.*]], i8 noundef zeroext [[H:%.*]]) #[[ATTR0]] {
294 // LP64-LP64F-LP64D: entry:
295 //
f_scalar_stack_2(int32_t a,__int128_t b,int64_t c,long double d,v32i8 e,uint8_t f,int8_t g,uint8_t h)296 int f_scalar_stack_2(int32_t a, __int128_t b, int64_t c, long double d, v32i8 e,
297 uint8_t f, int8_t g, uint8_t h) {
298 return g + h;
299 }
300
301 // LP64-LP64F-LP64D-LABEL: define dso_local signext i32 @f_scalar_stack_3
302 // LP64-LP64F-LP64D-SAME: (i32 noundef signext [[A:%.*]], i128 noundef [[B:%.*]], double noundef [[C:%.*]], fp128 noundef [[D:%.*]], ptr noundef [[TMP0:%.*]], i8 noundef zeroext [[F:%.*]], i8 noundef signext [[G:%.*]], i8 noundef zeroext [[H:%.*]]) #[[ATTR0]] {
303 // LP64-LP64F-LP64D: entry:
304 //
f_scalar_stack_3(int32_t a,__int128_t b,double c,long double d,v32i8 e,uint8_t f,int8_t g,uint8_t h)305 int f_scalar_stack_3(int32_t a, __int128_t b, double c, long double d, v32i8 e,
306 uint8_t f, int8_t g, uint8_t h) {
307 return g + h;
308 }
309
310 // Ensure that scalars passed on the stack are still determined correctly in
311 // the presence of large return values that consume a register due to the need
312 // to pass a pointer.
313
314 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_scalar_stack_4
315 // LP64-LP64F-LP64D-SAME: (ptr dead_on_unwind noalias writable sret([[STRUCT_LARGE:%.*]]) align 8 [[AGG_RESULT:%.*]], i32 noundef signext [[A:%.*]], i128 noundef [[B:%.*]], fp128 noundef [[C:%.*]], ptr noundef [[TMP0:%.*]], i8 noundef zeroext [[E:%.*]], i8 noundef signext [[F:%.*]], i8 noundef zeroext [[G:%.*]]) #[[ATTR0]] {
316 // LP64-LP64F-LP64D: entry:
317 //
f_scalar_stack_4(uint32_t a,__int128_t b,long double c,v32i8 d,uint8_t e,int8_t f,uint8_t g)318 struct large f_scalar_stack_4(uint32_t a, __int128_t b, long double c, v32i8 d,
319 uint8_t e, int8_t f, uint8_t g) {
320 return (struct large){a, e, f, g};
321 }
322
323 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_scalar_stack_5
324 // LP64-LP64F-LP64D-SAME: (ptr dead_on_unwind noalias writable sret([[STRUCT_LARGE:%.*]]) align 8 [[AGG_RESULT:%.*]], double noundef [[A:%.*]], i128 noundef [[B:%.*]], fp128 noundef [[C:%.*]], ptr noundef [[TMP0:%.*]], i8 noundef zeroext [[E:%.*]], i8 noundef signext [[F:%.*]], i8 noundef zeroext [[G:%.*]]) #[[ATTR0]] {
325 // LP64-LP64F-LP64D: entry:
326 //
f_scalar_stack_5(double a,__int128_t b,long double c,v32i8 d,uint8_t e,int8_t f,uint8_t g)327 struct large f_scalar_stack_5(double a, __int128_t b, long double c, v32i8 d,
328 uint8_t e, int8_t f, uint8_t g) {
329 return (struct large){a, e, f, g};
330 }
331
332 // LP64-LP64F-LP64D-LABEL: define dso_local signext i32 @f_scalar_stack_6
333 // LP64-LP64F-LP64D-SAME: (i32 noundef signext [[A:%.*]], i128 noundef [[B:%.*]], float noundef [[C:%.*]], fp128 noundef [[D:%.*]], ptr noundef [[TMP0:%.*]], i8 noundef zeroext [[F:%.*]], i8 noundef signext [[G:%.*]], i8 noundef zeroext [[H:%.*]], half noundef [[I:%.*]]) #[[ATTR0]] {
334 // LP64-LP64F-LP64D: entry:
335 //
f_scalar_stack_6(int32_t a,__int128_t b,float c,long double d,v32i8 e,uint8_t f,int8_t g,uint8_t h,_Float16 i)336 int f_scalar_stack_6(int32_t a, __int128_t b, float c, long double d, v32i8 e,
337 uint8_t f, int8_t g, uint8_t h, _Float16 i) {
338 return g + h;
339 }
340
341 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_fpr_tracking
342 // LP64-LP64F-LP64D-SAME: (float noundef [[A:%.*]], float noundef [[B:%.*]], float noundef [[C:%.*]], float noundef [[D:%.*]], float noundef [[E:%.*]], float noundef [[F:%.*]], float noundef [[G:%.*]], float noundef [[H:%.*]], i8 noundef zeroext [[I:%.*]]) #[[ATTR0]] {
343 // LP64-LP64F-LP64D: entry:
344 //
f_fpr_tracking(float a,float b,float c,float d,float e,float f,float g,float h,uint8_t i)345 void f_fpr_tracking(float a, float b, float c, float d, float e, float f,
346 float g, float h, uint8_t i) {}
347
348 // Check that fp, fp+fp, and int+fp structs are lowered correctly. These will
349 // be passed in FPR, FPR+FPR, or GPR+FPR regs if sufficient registers are
350 // available the widths are <= XLEN and FLEN, and should be expanded to
351 // separate arguments in IR. They are passed by the same rules for returns,
352 // but will be lowered to simple two-element structs if necessary (as LLVM IR
353 // functions cannot return multiple values).
354
355 // A struct containing just one floating-point real is passed as though it
356 // were a standalone floating-point real.
357
358 struct float_s { float f; };
359
360 // LP64-LABEL: define dso_local void @f_float_s_arg
361 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
362 // LP64: entry:
363 //
364 // LP64F-LP64D-LABEL: define dso_local void @f_float_s_arg
365 // LP64F-LP64D-SAME: (float [[TMP0:%.*]]) #[[ATTR0]] {
366 // LP64F-LP64D: entry:
367 //
f_float_s_arg(struct float_s a)368 void f_float_s_arg(struct float_s a) {}
369
370 // LP64-LABEL: define dso_local i64 @f_ret_float_s
371 // LP64-SAME: () #[[ATTR0]] {
372 // LP64: entry:
373 //
374 // LP64F-LP64D-LABEL: define dso_local float @f_ret_float_s
375 // LP64F-LP64D-SAME: () #[[ATTR0]] {
376 // LP64F-LP64D: entry:
377 //
f_ret_float_s(void)378 struct float_s f_ret_float_s(void) {
379 return (struct float_s){1.0};
380 }
381
382 // A struct containing a float and any number of zero-width bitfields is
383 // passed as though it were a standalone floating-point real.
384
385 struct zbf_float_s { int : 0; float f; };
386 struct zbf_float_zbf_s { int : 0; float f; int : 0; };
387
388 // LP64-LABEL: define dso_local void @f_zbf_float_s_arg
389 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
390 // LP64: entry:
391 //
392 // LP64F-LP64D-LABEL: define dso_local void @f_zbf_float_s_arg
393 // LP64F-LP64D-SAME: (float [[TMP0:%.*]]) #[[ATTR0]] {
394 // LP64F-LP64D: entry:
395 //
f_zbf_float_s_arg(struct zbf_float_s a)396 void f_zbf_float_s_arg(struct zbf_float_s a) {}
397
398 // LP64-LABEL: define dso_local i64 @f_ret_zbf_float_s
399 // LP64-SAME: () #[[ATTR0]] {
400 // LP64: entry:
401 //
402 // LP64F-LP64D-LABEL: define dso_local float @f_ret_zbf_float_s
403 // LP64F-LP64D-SAME: () #[[ATTR0]] {
404 // LP64F-LP64D: entry:
405 //
f_ret_zbf_float_s(void)406 struct zbf_float_s f_ret_zbf_float_s(void) {
407 return (struct zbf_float_s){1.0};
408 }
409
410 // LP64-LABEL: define dso_local void @f_zbf_float_zbf_s_arg
411 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
412 // LP64: entry:
413 //
414 // LP64F-LP64D-LABEL: define dso_local void @f_zbf_float_zbf_s_arg
415 // LP64F-LP64D-SAME: (float [[TMP0:%.*]]) #[[ATTR0]] {
416 // LP64F-LP64D: entry:
417 //
f_zbf_float_zbf_s_arg(struct zbf_float_zbf_s a)418 void f_zbf_float_zbf_s_arg(struct zbf_float_zbf_s a) {}
419
420 // LP64-LABEL: define dso_local i64 @f_ret_zbf_float_zbf_s
421 // LP64-SAME: () #[[ATTR0]] {
422 // LP64: entry:
423 //
424 // LP64F-LP64D-LABEL: define dso_local float @f_ret_zbf_float_zbf_s
425 // LP64F-LP64D-SAME: () #[[ATTR0]] {
426 // LP64F-LP64D: entry:
427 //
f_ret_zbf_float_zbf_s(void)428 struct zbf_float_zbf_s f_ret_zbf_float_zbf_s(void) {
429 return (struct zbf_float_zbf_s){1.0};
430 }
431
432 // Check that structs containing two float values (FLEN <= width) are expanded
433 // provided sufficient FPRs are available.
434
435 struct float_float_s { float f; float g; };
436
437 // LP64-LABEL: define dso_local void @f_float_float_s_arg
438 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
439 // LP64: entry:
440 //
441 // LP64F-LP64D-LABEL: define dso_local void @f_float_float_s_arg
442 // LP64F-LP64D-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
443 // LP64F-LP64D: entry:
444 //
f_float_float_s_arg(struct float_float_s a)445 void f_float_float_s_arg(struct float_float_s a) {}
446
447 // LP64-LABEL: define dso_local i64 @f_ret_float_float_s
448 // LP64-SAME: () #[[ATTR0]] {
449 // LP64: entry:
450 //
451 // LP64F-LP64D-LABEL: define dso_local { float, float } @f_ret_float_float_s
452 // LP64F-LP64D-SAME: () #[[ATTR0]] {
453 // LP64F-LP64D: entry:
454 //
f_ret_float_float_s(void)455 struct float_float_s f_ret_float_float_s(void) {
456 return (struct float_float_s){1.0, 2.0};
457 }
458
459 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_float_float_s_arg_insufficient_fprs
460 // LP64-LP64F-LP64D-SAME: (float noundef [[A:%.*]], float noundef [[B:%.*]], float noundef [[C:%.*]], float noundef [[D:%.*]], float noundef [[E:%.*]], float noundef [[F:%.*]], float noundef [[G:%.*]], i64 [[H_COERCE:%.*]]) #[[ATTR0]] {
461 // LP64-LP64F-LP64D: entry:
462 //
f_float_float_s_arg_insufficient_fprs(float a,float b,float c,float d,float e,float f,float g,struct float_float_s h)463 void f_float_float_s_arg_insufficient_fprs(float a, float b, float c, float d,
464 float e, float f, float g, struct float_float_s h) {}
465
466 // Check that structs containing int+float values are expanded, provided
467 // sufficient FPRs and GPRs are available. The integer components are neither
468 // sign or zero-extended.
469
470 struct float_int8_s { float f; int8_t i; };
471 struct float_uint8_s { float f; uint8_t i; };
472 struct float_int32_s { float f; int32_t i; };
473 struct float_int64_s { float f; int64_t i; };
474 struct float_int128bf_s { float f; __int128_t i : 64; };
475 struct float_int8_zbf_s { float f; int8_t i; int : 0; };
476
477 // LP64-LABEL: define dso_local void @f_float_int8_s_arg
478 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
479 // LP64: entry:
480 //
481 // LP64F-LP64D-LABEL: define dso_local void @f_float_int8_s_arg
482 // LP64F-LP64D-SAME: (float [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
483 // LP64F-LP64D: entry:
484 //
f_float_int8_s_arg(struct float_int8_s a)485 void f_float_int8_s_arg(struct float_int8_s a) {}
486
487 // LP64-LABEL: define dso_local i64 @f_ret_float_int8_s
488 // LP64-SAME: () #[[ATTR0]] {
489 // LP64: entry:
490 //
491 // LP64F-LP64D-LABEL: define dso_local { float, i8 } @f_ret_float_int8_s
492 // LP64F-LP64D-SAME: () #[[ATTR0]] {
493 // LP64F-LP64D: entry:
494 //
f_ret_float_int8_s(void)495 struct float_int8_s f_ret_float_int8_s(void) {
496 return (struct float_int8_s){1.0, 2};
497 }
498
499 // LP64-LABEL: define dso_local void @f_float_uint8_s_arg
500 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
501 // LP64: entry:
502 //
503 // LP64F-LP64D-LABEL: define dso_local void @f_float_uint8_s_arg
504 // LP64F-LP64D-SAME: (float [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
505 // LP64F-LP64D: entry:
506 //
f_float_uint8_s_arg(struct float_uint8_s a)507 void f_float_uint8_s_arg(struct float_uint8_s a) {}
508
509 // LP64-LABEL: define dso_local i64 @f_ret_float_uint8_s
510 // LP64-SAME: () #[[ATTR0]] {
511 // LP64: entry:
512 //
513 // LP64F-LP64D-LABEL: define dso_local { float, i8 } @f_ret_float_uint8_s
514 // LP64F-LP64D-SAME: () #[[ATTR0]] {
515 // LP64F-LP64D: entry:
516 //
f_ret_float_uint8_s(void)517 struct float_uint8_s f_ret_float_uint8_s(void) {
518 return (struct float_uint8_s){1.0, 2};
519 }
520
521 // LP64-LABEL: define dso_local void @f_float_int32_s_arg
522 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
523 // LP64: entry:
524 //
525 // LP64F-LP64D-LABEL: define dso_local void @f_float_int32_s_arg
526 // LP64F-LP64D-SAME: (float [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR0]] {
527 // LP64F-LP64D: entry:
528 //
f_float_int32_s_arg(struct float_int32_s a)529 void f_float_int32_s_arg(struct float_int32_s a) {}
530
531 // LP64-LABEL: define dso_local i64 @f_ret_float_int32_s
532 // LP64-SAME: () #[[ATTR0]] {
533 // LP64: entry:
534 //
535 // LP64F-LP64D-LABEL: define dso_local { float, i32 } @f_ret_float_int32_s
536 // LP64F-LP64D-SAME: () #[[ATTR0]] {
537 // LP64F-LP64D: entry:
538 //
f_ret_float_int32_s(void)539 struct float_int32_s f_ret_float_int32_s(void) {
540 return (struct float_int32_s){1.0, 2};
541 }
542
543 // LP64-LABEL: define dso_local void @f_float_int64_s_arg
544 // LP64-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
545 // LP64: entry:
546 //
547 // LP64F-LP64D-LABEL: define dso_local void @f_float_int64_s_arg
548 // LP64F-LP64D-SAME: (float [[TMP0:%.*]], i64 [[TMP1:%.*]]) #[[ATTR0]] {
549 // LP64F-LP64D: entry:
550 //
f_float_int64_s_arg(struct float_int64_s a)551 void f_float_int64_s_arg(struct float_int64_s a) {}
552
553 // LP64-LABEL: define dso_local [2 x i64] @f_ret_float_int64_s
554 // LP64-SAME: () #[[ATTR0]] {
555 // LP64: entry:
556 //
557 // LP64F-LP64D-LABEL: define dso_local { float, i64 } @f_ret_float_int64_s
558 // LP64F-LP64D-SAME: () #[[ATTR0]] {
559 // LP64F-LP64D: entry:
560 //
f_ret_float_int64_s(void)561 struct float_int64_s f_ret_float_int64_s(void) {
562 return (struct float_int64_s){1.0, 2};
563 }
564
565 // LP64-LABEL: define dso_local void @f_float_int128bf_s_arg
566 // LP64-SAME: (i128 [[A_COERCE:%.*]]) #[[ATTR0]] {
567 // LP64: entry:
568 //
569 // LP64F-LP64D-LABEL: define dso_local void @f_float_int128bf_s_arg
570 // LP64F-LP64D-SAME: (float [[TMP0:%.*]], i64 [[TMP1:%.*]]) #[[ATTR0]] {
571 // LP64F-LP64D: entry:
572 //
f_float_int128bf_s_arg(struct float_int128bf_s a)573 void f_float_int128bf_s_arg(struct float_int128bf_s a) {}
574
575 // LP64-LABEL: define dso_local i128 @f_ret_float_int128bf_s
576 // LP64-SAME: () #[[ATTR0]] {
577 // LP64: entry:
578 //
579 // LP64F-LP64D-LABEL: define dso_local <{ float, i64 }> @f_ret_float_int128bf_s
580 // LP64F-LP64D-SAME: () #[[ATTR0]] {
581 // LP64F-LP64D: entry:
582 //
f_ret_float_int128bf_s(void)583 struct float_int128bf_s f_ret_float_int128bf_s(void) {
584 return (struct float_int128bf_s){1.0, 2};
585 }
586
587 // The zero-width bitfield means the struct can't be passed according to the
588 // floating point calling convention.
589
590 // LP64-LABEL: define dso_local void @f_float_int8_zbf_s
591 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
592 // LP64: entry:
593 //
594 // LP64F-LP64D-LABEL: define dso_local void @f_float_int8_zbf_s
595 // LP64F-LP64D-SAME: (float [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
596 // LP64F-LP64D: entry:
597 //
f_float_int8_zbf_s(struct float_int8_zbf_s a)598 void f_float_int8_zbf_s(struct float_int8_zbf_s a) {}
599
600 // LP64-LABEL: define dso_local i64 @f_ret_float_int8_zbf_s
601 // LP64-SAME: () #[[ATTR0]] {
602 // LP64: entry:
603 //
604 // LP64F-LP64D-LABEL: define dso_local { float, i8 } @f_ret_float_int8_zbf_s
605 // LP64F-LP64D-SAME: () #[[ATTR0]] {
606 // LP64F-LP64D: entry:
607 //
f_ret_float_int8_zbf_s(void)608 struct float_int8_zbf_s f_ret_float_int8_zbf_s(void) {
609 return (struct float_int8_zbf_s){1.0, 2};
610 }
611
612 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_float_int8_s_arg_insufficient_gprs
613 // LP64-LP64F-LP64D-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], i32 noundef signext [[C:%.*]], i32 noundef signext [[D:%.*]], i32 noundef signext [[E:%.*]], i32 noundef signext [[F:%.*]], i32 noundef signext [[G:%.*]], i32 noundef signext [[H:%.*]], i64 [[I_COERCE:%.*]]) #[[ATTR0]] {
614 // LP64-LP64F-LP64D: entry:
615 //
f_float_int8_s_arg_insufficient_gprs(int a,int b,int c,int d,int e,int f,int g,int h,struct float_int8_s i)616 void f_float_int8_s_arg_insufficient_gprs(int a, int b, int c, int d, int e,
617 int f, int g, int h, struct float_int8_s i) {}
618
619 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_struct_float_int8_insufficient_fprs
620 // LP64-LP64F-LP64D-SAME: (float noundef [[A:%.*]], float noundef [[B:%.*]], float noundef [[C:%.*]], float noundef [[D:%.*]], float noundef [[E:%.*]], float noundef [[F:%.*]], float noundef [[G:%.*]], float noundef [[H:%.*]], i64 [[I_COERCE:%.*]]) #[[ATTR0]] {
621 // LP64-LP64F-LP64D: entry:
622 //
f_struct_float_int8_insufficient_fprs(float a,float b,float c,float d,float e,float f,float g,float h,struct float_int8_s i)623 void f_struct_float_int8_insufficient_fprs(float a, float b, float c, float d,
624 float e, float f, float g, float h, struct float_int8_s i) {}
625
626 // Complex floating-point values or structs containing a single complex
627 // floating-point value should be passed as if it were an fp+fp struct.
628
629 // LP64-LABEL: define dso_local void @f_floatcomplex
630 // LP64-SAME: (i64 noundef [[A_COERCE:%.*]]) #[[ATTR0]] {
631 // LP64: entry:
632 //
633 // LP64F-LP64D-LABEL: define dso_local void @f_floatcomplex
634 // LP64F-LP64D-SAME: (float noundef [[A_COERCE0:%.*]], float noundef [[A_COERCE1:%.*]]) #[[ATTR0]] {
635 // LP64F-LP64D: entry:
636 //
f_floatcomplex(float __complex__ a)637 void f_floatcomplex(float __complex__ a) {}
638
639 // LP64-LABEL: define dso_local i64 @f_ret_floatcomplex
640 // LP64-SAME: () #[[ATTR0]] {
641 // LP64: entry:
642 //
643 // LP64F-LP64D-LABEL: define dso_local { float, float } @f_ret_floatcomplex
644 // LP64F-LP64D-SAME: () #[[ATTR0]] {
645 // LP64F-LP64D: entry:
646 //
f_ret_floatcomplex(void)647 float __complex__ f_ret_floatcomplex(void) {
648 return 1.0;
649 }
650
651 struct floatcomplex_s { float __complex__ c; };
652
653 // LP64-LABEL: define dso_local void @f_floatcomplex_s_arg
654 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
655 // LP64: entry:
656 //
657 // LP64F-LP64D-LABEL: define dso_local void @f_floatcomplex_s_arg
658 // LP64F-LP64D-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
659 // LP64F-LP64D: entry:
660 //
f_floatcomplex_s_arg(struct floatcomplex_s a)661 void f_floatcomplex_s_arg(struct floatcomplex_s a) {}
662
663 // LP64-LABEL: define dso_local i64 @f_ret_floatcomplex_s
664 // LP64-SAME: () #[[ATTR0]] {
665 // LP64: entry:
666 //
667 // LP64F-LP64D-LABEL: define dso_local { float, float } @f_ret_floatcomplex_s
668 // LP64F-LP64D-SAME: () #[[ATTR0]] {
669 // LP64F-LP64D: entry:
670 //
f_ret_floatcomplex_s(void)671 struct floatcomplex_s f_ret_floatcomplex_s(void) {
672 return (struct floatcomplex_s){1.0};
673 }
674
675 // Complex floating-point values or structs containing a single complex
676 // floating-point value should be passed in GPRs if no two FPRs is available.
677
678 // LP64-LABEL: define dso_local void @f_floatcomplex_insufficient_fprs1
679 // LP64-SAME: (i64 noundef [[A_COERCE:%.*]], i64 noundef [[B_COERCE:%.*]], i64 noundef [[C_COERCE:%.*]], i64 noundef [[D_COERCE:%.*]], i64 noundef [[E_COERCE:%.*]]) #[[ATTR0]] {
680 // LP64: entry:
681 //
682 // LP64F-LP64D-LABEL: define dso_local void @f_floatcomplex_insufficient_fprs1
683 // LP64F-LP64D-SAME: (float noundef [[A_COERCE0:%.*]], float noundef [[A_COERCE1:%.*]], float noundef [[B_COERCE0:%.*]], float noundef [[B_COERCE1:%.*]], float noundef [[C_COERCE0:%.*]], float noundef [[C_COERCE1:%.*]], float noundef [[D_COERCE0:%.*]], float noundef [[D_COERCE1:%.*]], i64 noundef [[E_COERCE:%.*]]) #[[ATTR0]] {
684 // LP64F-LP64D: entry:
685 //
f_floatcomplex_insufficient_fprs1(float __complex__ a,float __complex__ b,float __complex__ c,float __complex__ d,float __complex__ e)686 void f_floatcomplex_insufficient_fprs1(float __complex__ a, float __complex__ b,
687 float __complex__ c, float __complex__ d,
688 float __complex__ e) {}
689
690
691 // LP64-LABEL: define dso_local void @f_floatcomplex_s_arg_insufficient_fprs1
692 // LP64-SAME: (i64 [[A_COERCE:%.*]], i64 [[B_COERCE:%.*]], i64 [[C_COERCE:%.*]], i64 [[D_COERCE:%.*]], i64 [[E_COERCE:%.*]]) #[[ATTR0]] {
693 // LP64: entry:
694 //
695 // LP64F-LP64D-LABEL: define dso_local void @f_floatcomplex_s_arg_insufficient_fprs1
696 // LP64F-LP64D-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]], float [[TMP2:%.*]], float [[TMP3:%.*]], float [[TMP4:%.*]], float [[TMP5:%.*]], float [[TMP6:%.*]], float [[TMP7:%.*]], i64 [[E_COERCE:%.*]]) #[[ATTR0]] {
697 // LP64F-LP64D: entry:
698 //
f_floatcomplex_s_arg_insufficient_fprs1(struct floatcomplex_s a,struct floatcomplex_s b,struct floatcomplex_s c,struct floatcomplex_s d,struct floatcomplex_s e)699 void f_floatcomplex_s_arg_insufficient_fprs1(struct floatcomplex_s a,
700 struct floatcomplex_s b,
701 struct floatcomplex_s c,
702 struct floatcomplex_s d,
703 struct floatcomplex_s e) {}
704
705 // LP64-LABEL: define dso_local void @f_floatcomplex_insufficient_fprs2
706 // LP64-SAME: (float noundef [[A:%.*]], i64 noundef [[B_COERCE:%.*]], i64 noundef [[C_COERCE:%.*]], i64 noundef [[D_COERCE:%.*]], i64 noundef [[E_COERCE:%.*]]) #[[ATTR0]] {
707 // LP64: entry:
708 //
709 // LP64F-LP64D-LABEL: define dso_local void @f_floatcomplex_insufficient_fprs2
710 // LP64F-LP64D-SAME: (float noundef [[A:%.*]], float noundef [[B_COERCE0:%.*]], float noundef [[B_COERCE1:%.*]], float noundef [[C_COERCE0:%.*]], float noundef [[C_COERCE1:%.*]], float noundef [[D_COERCE0:%.*]], float noundef [[D_COERCE1:%.*]], i64 noundef [[E_COERCE:%.*]]) #[[ATTR0]] {
711 // LP64F-LP64D: entry:
712 //
f_floatcomplex_insufficient_fprs2(float a,float __complex__ b,float __complex__ c,float __complex__ d,float __complex__ e)713 void f_floatcomplex_insufficient_fprs2(float a,
714 float __complex__ b, float __complex__ c,
715 float __complex__ d, float __complex__ e) {}
716
717
718 // LP64-LABEL: define dso_local void @f_floatcomplex_s_arg_insufficient_fprs2
719 // LP64-SAME: (float noundef [[A:%.*]], i64 [[B_COERCE:%.*]], i64 [[C_COERCE:%.*]], i64 [[D_COERCE:%.*]], i64 [[E_COERCE:%.*]]) #[[ATTR0]] {
720 // LP64: entry:
721 //
722 // LP64F-LP64D-LABEL: define dso_local void @f_floatcomplex_s_arg_insufficient_fprs2
723 // LP64F-LP64D-SAME: (float noundef [[A:%.*]], float [[TMP0:%.*]], float [[TMP1:%.*]], float [[TMP2:%.*]], float [[TMP3:%.*]], float [[TMP4:%.*]], float [[TMP5:%.*]], i64 [[E_COERCE:%.*]]) #[[ATTR0]] {
724 // LP64F-LP64D: entry:
725 //
f_floatcomplex_s_arg_insufficient_fprs2(float a,struct floatcomplex_s b,struct floatcomplex_s c,struct floatcomplex_s d,struct floatcomplex_s e)726 void f_floatcomplex_s_arg_insufficient_fprs2(float a,
727 struct floatcomplex_s b,
728 struct floatcomplex_s c,
729 struct floatcomplex_s d,
730 struct floatcomplex_s e) {}
731
732 // Test single or two-element structs that need flattening. e.g. those
733 // containing nested structs, floats in small arrays, zero-length structs etc.
734
735 struct floatarr1_s { float a[1]; };
736
737 // LP64-LABEL: define dso_local void @f_floatarr1_s_arg
738 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
739 // LP64: entry:
740 //
741 // LP64F-LP64D-LABEL: define dso_local void @f_floatarr1_s_arg
742 // LP64F-LP64D-SAME: (float [[TMP0:%.*]]) #[[ATTR0]] {
743 // LP64F-LP64D: entry:
744 //
f_floatarr1_s_arg(struct floatarr1_s a)745 void f_floatarr1_s_arg(struct floatarr1_s a) {}
746
747 // LP64-LABEL: define dso_local i64 @f_ret_floatarr1_s
748 // LP64-SAME: () #[[ATTR0]] {
749 // LP64: entry:
750 //
751 // LP64F-LP64D-LABEL: define dso_local float @f_ret_floatarr1_s
752 // LP64F-LP64D-SAME: () #[[ATTR0]] {
753 // LP64F-LP64D: entry:
754 //
f_ret_floatarr1_s(void)755 struct floatarr1_s f_ret_floatarr1_s(void) {
756 return (struct floatarr1_s){{1.0}};
757 }
758
759 struct floatarr2_s { float a[2]; };
760
761 // LP64-LABEL: define dso_local void @f_floatarr2_s_arg
762 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
763 // LP64: entry:
764 //
765 // LP64F-LP64D-LABEL: define dso_local void @f_floatarr2_s_arg
766 // LP64F-LP64D-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
767 // LP64F-LP64D: entry:
768 //
f_floatarr2_s_arg(struct floatarr2_s a)769 void f_floatarr2_s_arg(struct floatarr2_s a) {}
770
771 // LP64-LABEL: define dso_local i64 @f_ret_floatarr2_s
772 // LP64-SAME: () #[[ATTR0]] {
773 // LP64: entry:
774 //
775 // LP64F-LP64D-LABEL: define dso_local { float, float } @f_ret_floatarr2_s
776 // LP64F-LP64D-SAME: () #[[ATTR0]] {
777 // LP64F-LP64D: entry:
778 //
f_ret_floatarr2_s(void)779 struct floatarr2_s f_ret_floatarr2_s(void) {
780 return (struct floatarr2_s){{1.0, 2.0}};
781 }
782
783 struct floatarr2_tricky1_s { struct { float f[1]; } g[2]; };
784
785 // LP64-LABEL: define dso_local void @f_floatarr2_tricky1_s_arg
786 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
787 // LP64: entry:
788 //
789 // LP64F-LP64D-LABEL: define dso_local void @f_floatarr2_tricky1_s_arg
790 // LP64F-LP64D-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
791 // LP64F-LP64D: entry:
792 //
f_floatarr2_tricky1_s_arg(struct floatarr2_tricky1_s a)793 void f_floatarr2_tricky1_s_arg(struct floatarr2_tricky1_s a) {}
794
795 // LP64-LABEL: define dso_local i64 @f_ret_floatarr2_tricky1_s
796 // LP64-SAME: () #[[ATTR0]] {
797 // LP64: entry:
798 //
799 // LP64F-LP64D-LABEL: define dso_local { float, float } @f_ret_floatarr2_tricky1_s
800 // LP64F-LP64D-SAME: () #[[ATTR0]] {
801 // LP64F-LP64D: entry:
802 //
f_ret_floatarr2_tricky1_s(void)803 struct floatarr2_tricky1_s f_ret_floatarr2_tricky1_s(void) {
804 return (struct floatarr2_tricky1_s){{{{1.0}}, {{2.0}}}};
805 }
806
807 struct floatarr2_tricky2_s { struct {}; struct { float f[1]; } g[2]; };
808
809 // LP64-LABEL: define dso_local void @f_floatarr2_tricky2_s_arg
810 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
811 // LP64: entry:
812 //
813 // LP64F-LP64D-LABEL: define dso_local void @f_floatarr2_tricky2_s_arg
814 // LP64F-LP64D-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
815 // LP64F-LP64D: entry:
816 //
f_floatarr2_tricky2_s_arg(struct floatarr2_tricky2_s a)817 void f_floatarr2_tricky2_s_arg(struct floatarr2_tricky2_s a) {}
818
819 // LP64-LABEL: define dso_local i64 @f_ret_floatarr2_tricky2_s
820 // LP64-SAME: () #[[ATTR0]] {
821 // LP64: entry:
822 //
823 // LP64F-LP64D-LABEL: define dso_local { float, float } @f_ret_floatarr2_tricky2_s
824 // LP64F-LP64D-SAME: () #[[ATTR0]] {
825 // LP64F-LP64D: entry:
826 //
f_ret_floatarr2_tricky2_s(void)827 struct floatarr2_tricky2_s f_ret_floatarr2_tricky2_s(void) {
828 return (struct floatarr2_tricky2_s){{}, {{{1.0}}, {{2.0}}}};
829 }
830
831 struct floatarr2_tricky3_s { union {}; struct { float f[1]; } g[2]; };
832
833 // LP64-LABEL: define dso_local void @f_floatarr2_tricky3_s_arg
834 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
835 // LP64: entry:
836 //
837 // LP64F-LP64D-LABEL: define dso_local void @f_floatarr2_tricky3_s_arg
838 // LP64F-LP64D-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
839 // LP64F-LP64D: entry:
840 //
f_floatarr2_tricky3_s_arg(struct floatarr2_tricky3_s a)841 void f_floatarr2_tricky3_s_arg(struct floatarr2_tricky3_s a) {}
842
843 // LP64-LABEL: define dso_local i64 @f_ret_floatarr2_tricky3_s
844 // LP64-SAME: () #[[ATTR0]] {
845 // LP64: entry:
846 //
847 // LP64F-LP64D-LABEL: define dso_local { float, float } @f_ret_floatarr2_tricky3_s
848 // LP64F-LP64D-SAME: () #[[ATTR0]] {
849 // LP64F-LP64D: entry:
850 //
f_ret_floatarr2_tricky3_s(void)851 struct floatarr2_tricky3_s f_ret_floatarr2_tricky3_s(void) {
852 return (struct floatarr2_tricky3_s){{}, {{{1.0}}, {{2.0}}}};
853 }
854
855 struct floatarr2_tricky4_s { union {}; struct { struct {}; float f[1]; } g[2]; };
856
857 // LP64-LABEL: define dso_local void @f_floatarr2_tricky4_s_arg
858 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
859 // LP64: entry:
860 //
861 // LP64F-LP64D-LABEL: define dso_local void @f_floatarr2_tricky4_s_arg
862 // LP64F-LP64D-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
863 // LP64F-LP64D: entry:
864 //
f_floatarr2_tricky4_s_arg(struct floatarr2_tricky4_s a)865 void f_floatarr2_tricky4_s_arg(struct floatarr2_tricky4_s a) {}
866
867 // LP64-LABEL: define dso_local i64 @f_ret_floatarr2_tricky4_s
868 // LP64-SAME: () #[[ATTR0]] {
869 // LP64: entry:
870 //
871 // LP64F-LP64D-LABEL: define dso_local { float, float } @f_ret_floatarr2_tricky4_s
872 // LP64F-LP64D-SAME: () #[[ATTR0]] {
873 // LP64F-LP64D: entry:
874 //
f_ret_floatarr2_tricky4_s(void)875 struct floatarr2_tricky4_s f_ret_floatarr2_tricky4_s(void) {
876 return (struct floatarr2_tricky4_s){{}, {{{}, {1.0}}, {{}, {2.0}}}};
877 }
878
879 // Test structs that should be passed according to the normal integer calling
880 // convention.
881
882 struct int_float_int_s { int a; float b; int c; };
883
884 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_int_float_int_s_arg
885 // LP64-LP64F-LP64D-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
886 // LP64-LP64F-LP64D: entry:
887 //
f_int_float_int_s_arg(struct int_float_int_s a)888 void f_int_float_int_s_arg(struct int_float_int_s a) {}
889
890 // LP64-LP64F-LP64D-LABEL: define dso_local [2 x i64] @f_ret_int_float_int_s
891 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
892 // LP64-LP64F-LP64D: entry:
893 //
f_ret_int_float_int_s(void)894 struct int_float_int_s f_ret_int_float_int_s(void) {
895 return (struct int_float_int_s){1, 2.0, 3};
896 }
897
898 struct char_char_float_s { char a; char b; float c; };
899
900 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_char_char_float_s_arg
901 // LP64-LP64F-LP64D-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
902 // LP64-LP64F-LP64D: entry:
903 //
f_char_char_float_s_arg(struct char_char_float_s a)904 void f_char_char_float_s_arg(struct char_char_float_s a) {}
905
906 // LP64-LP64F-LP64D-LABEL: define dso_local i64 @f_ret_char_char_float_s
907 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
908 // LP64-LP64F-LP64D: entry:
909 //
f_ret_char_char_float_s(void)910 struct char_char_float_s f_ret_char_char_float_s(void) {
911 return (struct char_char_float_s){1, 2, 3.0};
912 }
913
914 // Unions are always passed according to the integer calling convention, even
915 // if they can only contain a float.
916
917 union float_u { float a; };
918
919 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_float_u_arg
920 // LP64-LP64F-LP64D-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
921 // LP64-LP64F-LP64D: entry:
922 //
f_float_u_arg(union float_u a)923 void f_float_u_arg(union float_u a) {}
924
925 // LP64-LP64F-LP64D-LABEL: define dso_local i64 @f_ret_float_u
926 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
927 // LP64-LP64F-LP64D: entry:
928 //
f_ret_float_u(void)929 union float_u f_ret_float_u(void) {
930 return (union float_u){1.0};
931 }
932
933 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_fpr_tracking2
934 // LP64-LP64F-LP64D-SAME: (double noundef [[A:%.*]], double noundef [[B:%.*]], double noundef [[C:%.*]], double noundef [[D:%.*]], double noundef [[E:%.*]], double noundef [[F:%.*]], double noundef [[G:%.*]], double noundef [[H:%.*]], i8 noundef zeroext [[I:%.*]]) #[[ATTR0]] {
935 // LP64-LP64F-LP64D: entry:
936 //
f_fpr_tracking2(double a,double b,double c,double d,double e,double f,double g,double h,uint8_t i)937 void f_fpr_tracking2(double a, double b, double c, double d, double e, double f,
938 double g, double h, uint8_t i) {}
939
940 // Check that fp, fp+fp, and int+fp structs are lowered correctly. These will
941 // be passed in FPR, FPR+FPR, or GPR+FPR regs if sufficient registers are
942 // available the widths are <= XLEN and FLEN, and should be expanded to
943 // separate arguments in IR. They are passed by the same rules for returns,
944 // but will be lowered to simple two-element structs if necessary (as LLVM IR
945 // functions cannot return multiple values).
946
947 // A struct containing just one floating-point real is passed as though it
948 // were a standalone floating-point real.
949
950 struct double_s { double f; };
951
952 // LP64-LP64F-LABEL: define dso_local void @f_double_s_arg
953 // LP64-LP64F-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
954 // LP64-LP64F: entry:
955 //
956 // LP64D-LABEL: define dso_local void @f_double_s_arg
957 // LP64D-SAME: (double [[TMP0:%.*]]) #[[ATTR0]] {
958 // LP64D: entry:
959 //
f_double_s_arg(struct double_s a)960 void f_double_s_arg(struct double_s a) {}
961
962 // LP64-LP64F-LABEL: define dso_local i64 @f_ret_double_s
963 // LP64-LP64F-SAME: () #[[ATTR0]] {
964 // LP64-LP64F: entry:
965 //
966 // LP64D-LABEL: define dso_local double @f_ret_double_s
967 // LP64D-SAME: () #[[ATTR0]] {
968 // LP64D: entry:
969 //
f_ret_double_s(void)970 struct double_s f_ret_double_s(void) {
971 return (struct double_s){1.0};
972 }
973
974 // A struct containing a double and any number of zero-width bitfields is
975 // passed as though it were a standalone floating-point real.
976
977 struct zbf_double_s { int : 0; double f; };
978 struct zbf_double_zbf_s { int : 0; double f; int : 0; };
979
980 // LP64-LP64F-LABEL: define dso_local void @f_zbf_double_s_arg
981 // LP64-LP64F-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
982 // LP64-LP64F: entry:
983 //
984 // LP64D-LABEL: define dso_local void @f_zbf_double_s_arg
985 // LP64D-SAME: (double [[TMP0:%.*]]) #[[ATTR0]] {
986 // LP64D: entry:
987 //
f_zbf_double_s_arg(struct zbf_double_s a)988 void f_zbf_double_s_arg(struct zbf_double_s a) {}
989
990 // LP64-LP64F-LABEL: define dso_local i64 @f_ret_zbf_double_s
991 // LP64-LP64F-SAME: () #[[ATTR0]] {
992 // LP64-LP64F: entry:
993 //
994 // LP64D-LABEL: define dso_local double @f_ret_zbf_double_s
995 // LP64D-SAME: () #[[ATTR0]] {
996 // LP64D: entry:
997 //
f_ret_zbf_double_s(void)998 struct zbf_double_s f_ret_zbf_double_s(void) {
999 return (struct zbf_double_s){1.0};
1000 }
1001
1002 // LP64-LP64F-LABEL: define dso_local void @f_zbf_double_zbf_s_arg
1003 // LP64-LP64F-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1004 // LP64-LP64F: entry:
1005 //
1006 // LP64D-LABEL: define dso_local void @f_zbf_double_zbf_s_arg
1007 // LP64D-SAME: (double [[TMP0:%.*]]) #[[ATTR0]] {
1008 // LP64D: entry:
1009 //
f_zbf_double_zbf_s_arg(struct zbf_double_zbf_s a)1010 void f_zbf_double_zbf_s_arg(struct zbf_double_zbf_s a) {}
1011
1012 // LP64-LP64F-LABEL: define dso_local i64 @f_ret_zbf_double_zbf_s
1013 // LP64-LP64F-SAME: () #[[ATTR0]] {
1014 // LP64-LP64F: entry:
1015 //
1016 // LP64D-LABEL: define dso_local double @f_ret_zbf_double_zbf_s
1017 // LP64D-SAME: () #[[ATTR0]] {
1018 // LP64D: entry:
1019 //
f_ret_zbf_double_zbf_s(void)1020 struct zbf_double_zbf_s f_ret_zbf_double_zbf_s(void) {
1021 return (struct zbf_double_zbf_s){1.0};
1022 }
1023
1024 // Check that structs containing two floating point values (FLEN <= width) are
1025 // expanded provided sufficient FPRs are available.
1026
1027 struct double_double_s { double f; double g; };
1028 struct double_float_s { double f; float g; };
1029
1030 // LP64-LP64F-LABEL: define dso_local void @f_double_double_s_arg
1031 // LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1032 // LP64-LP64F: entry:
1033 //
1034 // LP64D-LABEL: define dso_local void @f_double_double_s_arg
1035 // LP64D-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
1036 // LP64D: entry:
1037 //
f_double_double_s_arg(struct double_double_s a)1038 void f_double_double_s_arg(struct double_double_s a) {}
1039
1040 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_double_double_s
1041 // LP64-LP64F-SAME: () #[[ATTR0]] {
1042 // LP64-LP64F: entry:
1043 //
1044 // LP64D-LABEL: define dso_local { double, double } @f_ret_double_double_s
1045 // LP64D-SAME: () #[[ATTR0]] {
1046 // LP64D: entry:
1047 //
f_ret_double_double_s(void)1048 struct double_double_s f_ret_double_double_s(void) {
1049 return (struct double_double_s){1.0, 2.0};
1050 }
1051
1052 // LP64-LP64F-LABEL: define dso_local void @f_double_float_s_arg
1053 // LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1054 // LP64-LP64F: entry:
1055 //
1056 // LP64D-LABEL: define dso_local void @f_double_float_s_arg
1057 // LP64D-SAME: (double [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
1058 // LP64D: entry:
1059 //
f_double_float_s_arg(struct double_float_s a)1060 void f_double_float_s_arg(struct double_float_s a) {}
1061
1062 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_double_float_s
1063 // LP64-LP64F-SAME: () #[[ATTR0]] {
1064 // LP64-LP64F: entry:
1065 //
1066 // LP64D-LABEL: define dso_local { double, float } @f_ret_double_float_s
1067 // LP64D-SAME: () #[[ATTR0]] {
1068 // LP64D: entry:
1069 //
f_ret_double_float_s(void)1070 struct double_float_s f_ret_double_float_s(void) {
1071 return (struct double_float_s){1.0, 2.0};
1072 }
1073
1074 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_double_double_s_arg_insufficient_fprs
1075 // LP64-LP64F-LP64D-SAME: (float noundef [[A:%.*]], double noundef [[B:%.*]], double noundef [[C:%.*]], double noundef [[D:%.*]], double noundef [[E:%.*]], double noundef [[F:%.*]], double noundef [[G:%.*]], [2 x i64] [[H_COERCE:%.*]]) #[[ATTR0]] {
1076 // LP64-LP64F-LP64D: entry:
1077 //
f_double_double_s_arg_insufficient_fprs(float a,double b,double c,double d,double e,double f,double g,struct double_double_s h)1078 void f_double_double_s_arg_insufficient_fprs(float a, double b, double c, double d,
1079 double e, double f, double g, struct double_double_s h) {}
1080
1081 // Check that structs containing int+double values are expanded, provided
1082 // sufficient FPRs and GPRs are available. The integer components are neither
1083 // sign or zero-extended.
1084
1085 struct double_int8_s { double f; int8_t i; };
1086 struct double_uint8_s { double f; uint8_t i; };
1087 struct double_int32_s { double f; int32_t i; };
1088 struct double_int64_s { double f; int64_t i; };
1089 struct double_int128bf_s { double f; __int128_t i : 64; };
1090 struct double_int8_zbf_s { double f; int8_t i; int : 0; };
1091
1092 // LP64-LP64F-LABEL: define dso_local void @f_double_int8_s_arg
1093 // LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1094 // LP64-LP64F: entry:
1095 //
1096 // LP64D-LABEL: define dso_local void @f_double_int8_s_arg
1097 // LP64D-SAME: (double [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
1098 // LP64D: entry:
1099 //
f_double_int8_s_arg(struct double_int8_s a)1100 void f_double_int8_s_arg(struct double_int8_s a) {}
1101
1102 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_double_int8_s
1103 // LP64-LP64F-SAME: () #[[ATTR0]] {
1104 // LP64-LP64F: entry:
1105 //
1106 // LP64D-LABEL: define dso_local { double, i8 } @f_ret_double_int8_s
1107 // LP64D-SAME: () #[[ATTR0]] {
1108 // LP64D: entry:
1109 //
f_ret_double_int8_s(void)1110 struct double_int8_s f_ret_double_int8_s(void) {
1111 return (struct double_int8_s){1.0, 2};
1112 }
1113
1114 // LP64-LP64F-LABEL: define dso_local void @f_double_uint8_s_arg
1115 // LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1116 // LP64-LP64F: entry:
1117 //
1118 // LP64D-LABEL: define dso_local void @f_double_uint8_s_arg
1119 // LP64D-SAME: (double [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
1120 // LP64D: entry:
1121 //
f_double_uint8_s_arg(struct double_uint8_s a)1122 void f_double_uint8_s_arg(struct double_uint8_s a) {}
1123
1124 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_double_uint8_s
1125 // LP64-LP64F-SAME: () #[[ATTR0]] {
1126 // LP64-LP64F: entry:
1127 //
1128 // LP64D-LABEL: define dso_local { double, i8 } @f_ret_double_uint8_s
1129 // LP64D-SAME: () #[[ATTR0]] {
1130 // LP64D: entry:
1131 //
f_ret_double_uint8_s(void)1132 struct double_uint8_s f_ret_double_uint8_s(void) {
1133 return (struct double_uint8_s){1.0, 2};
1134 }
1135
1136 // LP64-LP64F-LABEL: define dso_local void @f_double_int32_s_arg
1137 // LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1138 // LP64-LP64F: entry:
1139 //
1140 // LP64D-LABEL: define dso_local void @f_double_int32_s_arg
1141 // LP64D-SAME: (double [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR0]] {
1142 // LP64D: entry:
1143 //
f_double_int32_s_arg(struct double_int32_s a)1144 void f_double_int32_s_arg(struct double_int32_s a) {}
1145
1146 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_double_int32_s
1147 // LP64-LP64F-SAME: () #[[ATTR0]] {
1148 // LP64-LP64F: entry:
1149 //
1150 // LP64D-LABEL: define dso_local { double, i32 } @f_ret_double_int32_s
1151 // LP64D-SAME: () #[[ATTR0]] {
1152 // LP64D: entry:
1153 //
f_ret_double_int32_s(void)1154 struct double_int32_s f_ret_double_int32_s(void) {
1155 return (struct double_int32_s){1.0, 2};
1156 }
1157
1158 // LP64-LP64F-LABEL: define dso_local void @f_double_int64_s_arg
1159 // LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1160 // LP64-LP64F: entry:
1161 //
1162 // LP64D-LABEL: define dso_local void @f_double_int64_s_arg
1163 // LP64D-SAME: (double [[TMP0:%.*]], i64 [[TMP1:%.*]]) #[[ATTR0]] {
1164 // LP64D: entry:
1165 //
f_double_int64_s_arg(struct double_int64_s a)1166 void f_double_int64_s_arg(struct double_int64_s a) {}
1167
1168 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_double_int64_s
1169 // LP64-LP64F-SAME: () #[[ATTR0]] {
1170 // LP64-LP64F: entry:
1171 //
1172 // LP64D-LABEL: define dso_local { double, i64 } @f_ret_double_int64_s
1173 // LP64D-SAME: () #[[ATTR0]] {
1174 // LP64D: entry:
1175 //
f_ret_double_int64_s(void)1176 struct double_int64_s f_ret_double_int64_s(void) {
1177 return (struct double_int64_s){1.0, 2};
1178 }
1179
1180 // LP64-LP64F-LABEL: define dso_local void @f_double_int128bf_s_arg
1181 // LP64-LP64F-SAME: (i128 [[A_COERCE:%.*]]) #[[ATTR0]] {
1182 // LP64-LP64F: entry:
1183 //
1184 // LP64D-LABEL: define dso_local void @f_double_int128bf_s_arg
1185 // LP64D-SAME: (double [[TMP0:%.*]], i64 [[TMP1:%.*]]) #[[ATTR0]] {
1186 // LP64D: entry:
1187 //
f_double_int128bf_s_arg(struct double_int128bf_s a)1188 void f_double_int128bf_s_arg(struct double_int128bf_s a) {}
1189
1190 // LP64-LP64F-LABEL: define dso_local i128 @f_ret_double_int128bf_s
1191 // LP64-LP64F-SAME: () #[[ATTR0]] {
1192 // LP64-LP64F: entry:
1193 //
1194 // LP64D-LABEL: define dso_local { double, i64 } @f_ret_double_int128bf_s
1195 // LP64D-SAME: () #[[ATTR0]] {
1196 // LP64D: entry:
1197 //
f_ret_double_int128bf_s(void)1198 struct double_int128bf_s f_ret_double_int128bf_s(void) {
1199 return (struct double_int128bf_s){1.0, 2};
1200 }
1201
1202 // The zero-width bitfield means the struct can't be passed according to the
1203 // floating point calling convention.
1204
1205 // LP64-LP64F-LABEL: define dso_local void @f_double_int8_zbf_s
1206 // LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1207 // LP64-LP64F: entry:
1208 //
1209 // LP64D-LABEL: define dso_local void @f_double_int8_zbf_s
1210 // LP64D-SAME: (double [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
1211 // LP64D: entry:
1212 //
f_double_int8_zbf_s(struct double_int8_zbf_s a)1213 void f_double_int8_zbf_s(struct double_int8_zbf_s a) {}
1214
1215 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_double_int8_zbf_s
1216 // LP64-LP64F-SAME: () #[[ATTR0]] {
1217 // LP64-LP64F: entry:
1218 //
1219 // LP64D-LABEL: define dso_local { double, i8 } @f_ret_double_int8_zbf_s
1220 // LP64D-SAME: () #[[ATTR0]] {
1221 // LP64D: entry:
1222 //
f_ret_double_int8_zbf_s(void)1223 struct double_int8_zbf_s f_ret_double_int8_zbf_s(void) {
1224 return (struct double_int8_zbf_s){1.0, 2};
1225 }
1226
1227 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_double_int8_s_arg_insufficient_gprs
1228 // LP64-LP64F-LP64D-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], i32 noundef signext [[C:%.*]], i32 noundef signext [[D:%.*]], i32 noundef signext [[E:%.*]], i32 noundef signext [[F:%.*]], i32 noundef signext [[G:%.*]], i32 noundef signext [[H:%.*]], [2 x i64] [[I_COERCE:%.*]]) #[[ATTR0]] {
1229 // LP64-LP64F-LP64D: entry:
1230 //
f_double_int8_s_arg_insufficient_gprs(int a,int b,int c,int d,int e,int f,int g,int h,struct double_int8_s i)1231 void f_double_int8_s_arg_insufficient_gprs(int a, int b, int c, int d, int e,
1232 int f, int g, int h, struct double_int8_s i) {}
1233
1234 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_struct_double_int8_insufficient_fprs
1235 // LP64-LP64F-LP64D-SAME: (float noundef [[A:%.*]], double noundef [[B:%.*]], double noundef [[C:%.*]], double noundef [[D:%.*]], double noundef [[E:%.*]], double noundef [[F:%.*]], double noundef [[G:%.*]], double noundef [[H:%.*]], [2 x i64] [[I_COERCE:%.*]]) #[[ATTR0]] {
1236 // LP64-LP64F-LP64D: entry:
1237 //
f_struct_double_int8_insufficient_fprs(float a,double b,double c,double d,double e,double f,double g,double h,struct double_int8_s i)1238 void f_struct_double_int8_insufficient_fprs(float a, double b, double c, double d,
1239 double e, double f, double g, double h, struct double_int8_s i) {}
1240
1241 // Complex floating-point values or structs containing a single complex
1242 // floating-point value should be passed as if it were an fp+fp struct.
1243
1244 // LP64-LP64F-LABEL: define dso_local void @f_doublecomplex
1245 // LP64-LP64F-SAME: ([2 x i64] noundef [[A_COERCE:%.*]]) #[[ATTR0]] {
1246 // LP64-LP64F: entry:
1247 //
1248 // LP64D-LABEL: define dso_local void @f_doublecomplex
1249 // LP64D-SAME: (double noundef [[A_COERCE0:%.*]], double noundef [[A_COERCE1:%.*]]) #[[ATTR0]] {
1250 // LP64D: entry:
1251 //
f_doublecomplex(double __complex__ a)1252 void f_doublecomplex(double __complex__ a) {}
1253
1254 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_doublecomplex
1255 // LP64-LP64F-SAME: () #[[ATTR0]] {
1256 // LP64-LP64F: entry:
1257 //
1258 // LP64D-LABEL: define dso_local { double, double } @f_ret_doublecomplex
1259 // LP64D-SAME: () #[[ATTR0]] {
1260 // LP64D: entry:
1261 //
f_ret_doublecomplex(void)1262 double __complex__ f_ret_doublecomplex(void) {
1263 return 1.0;
1264 }
1265
1266 struct doublecomplex_s { double __complex__ c; };
1267
1268 // LP64-LP64F-LABEL: define dso_local void @f_doublecomplex_s_arg
1269 // LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1270 // LP64-LP64F: entry:
1271 //
1272 // LP64D-LABEL: define dso_local void @f_doublecomplex_s_arg
1273 // LP64D-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
1274 // LP64D: entry:
1275 //
f_doublecomplex_s_arg(struct doublecomplex_s a)1276 void f_doublecomplex_s_arg(struct doublecomplex_s a) {}
1277
1278 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_doublecomplex_s
1279 // LP64-LP64F-SAME: () #[[ATTR0]] {
1280 // LP64-LP64F: entry:
1281 //
1282 // LP64D-LABEL: define dso_local { double, double } @f_ret_doublecomplex_s
1283 // LP64D-SAME: () #[[ATTR0]] {
1284 // LP64D: entry:
1285 //
f_ret_doublecomplex_s(void)1286 struct doublecomplex_s f_ret_doublecomplex_s(void) {
1287 return (struct doublecomplex_s){1.0};
1288 }
1289
1290 // Test single or two-element structs that need flattening. e.g. those
1291 // containing nested structs, doubles in small arrays, zero-length structs etc.
1292
1293 struct doublearr1_s { double a[1]; };
1294
1295 // LP64-LP64F-LABEL: define dso_local void @f_doublearr1_s_arg
1296 // LP64-LP64F-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1297 // LP64-LP64F: entry:
1298 //
1299 // LP64D-LABEL: define dso_local void @f_doublearr1_s_arg
1300 // LP64D-SAME: (double [[TMP0:%.*]]) #[[ATTR0]] {
1301 // LP64D: entry:
1302 //
f_doublearr1_s_arg(struct doublearr1_s a)1303 void f_doublearr1_s_arg(struct doublearr1_s a) {}
1304
1305 // LP64-LP64F-LABEL: define dso_local i64 @f_ret_doublearr1_s
1306 // LP64-LP64F-SAME: () #[[ATTR0]] {
1307 // LP64-LP64F: entry:
1308 //
1309 // LP64D-LABEL: define dso_local double @f_ret_doublearr1_s
1310 // LP64D-SAME: () #[[ATTR0]] {
1311 // LP64D: entry:
1312 //
f_ret_doublearr1_s(void)1313 struct doublearr1_s f_ret_doublearr1_s(void) {
1314 return (struct doublearr1_s){{1.0}};
1315 }
1316
1317 struct doublearr2_s { double a[2]; };
1318
1319 // LP64-LP64F-LABEL: define dso_local void @f_doublearr2_s_arg
1320 // LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1321 // LP64-LP64F: entry:
1322 //
1323 // LP64D-LABEL: define dso_local void @f_doublearr2_s_arg
1324 // LP64D-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
1325 // LP64D: entry:
1326 //
f_doublearr2_s_arg(struct doublearr2_s a)1327 void f_doublearr2_s_arg(struct doublearr2_s a) {}
1328
1329 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_doublearr2_s
1330 // LP64-LP64F-SAME: () #[[ATTR0]] {
1331 // LP64-LP64F: entry:
1332 //
1333 // LP64D-LABEL: define dso_local { double, double } @f_ret_doublearr2_s
1334 // LP64D-SAME: () #[[ATTR0]] {
1335 // LP64D: entry:
1336 //
f_ret_doublearr2_s(void)1337 struct doublearr2_s f_ret_doublearr2_s(void) {
1338 return (struct doublearr2_s){{1.0, 2.0}};
1339 }
1340
1341 struct doublearr2_tricky1_s { struct { double f[1]; } g[2]; };
1342
1343 // LP64-LP64F-LABEL: define dso_local void @f_doublearr2_tricky1_s_arg
1344 // LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1345 // LP64-LP64F: entry:
1346 //
1347 // LP64D-LABEL: define dso_local void @f_doublearr2_tricky1_s_arg
1348 // LP64D-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
1349 // LP64D: entry:
1350 //
f_doublearr2_tricky1_s_arg(struct doublearr2_tricky1_s a)1351 void f_doublearr2_tricky1_s_arg(struct doublearr2_tricky1_s a) {}
1352
1353 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_doublearr2_tricky1_s
1354 // LP64-LP64F-SAME: () #[[ATTR0]] {
1355 // LP64-LP64F: entry:
1356 //
1357 // LP64D-LABEL: define dso_local { double, double } @f_ret_doublearr2_tricky1_s
1358 // LP64D-SAME: () #[[ATTR0]] {
1359 // LP64D: entry:
1360 //
f_ret_doublearr2_tricky1_s(void)1361 struct doublearr2_tricky1_s f_ret_doublearr2_tricky1_s(void) {
1362 return (struct doublearr2_tricky1_s){{{{1.0}}, {{2.0}}}};
1363 }
1364
1365 struct doublearr2_tricky2_s { struct {}; struct { double f[1]; } g[2]; };
1366
1367 // LP64-LP64F-LABEL: define dso_local void @f_doublearr2_tricky2_s_arg
1368 // LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1369 // LP64-LP64F: entry:
1370 //
1371 // LP64D-LABEL: define dso_local void @f_doublearr2_tricky2_s_arg
1372 // LP64D-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
1373 // LP64D: entry:
1374 //
f_doublearr2_tricky2_s_arg(struct doublearr2_tricky2_s a)1375 void f_doublearr2_tricky2_s_arg(struct doublearr2_tricky2_s a) {}
1376
1377 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_doublearr2_tricky2_s
1378 // LP64-LP64F-SAME: () #[[ATTR0]] {
1379 // LP64-LP64F: entry:
1380 //
1381 // LP64D-LABEL: define dso_local { double, double } @f_ret_doublearr2_tricky2_s
1382 // LP64D-SAME: () #[[ATTR0]] {
1383 // LP64D: entry:
1384 //
f_ret_doublearr2_tricky2_s(void)1385 struct doublearr2_tricky2_s f_ret_doublearr2_tricky2_s(void) {
1386 return (struct doublearr2_tricky2_s){{}, {{{1.0}}, {{2.0}}}};
1387 }
1388
1389 struct doublearr2_tricky3_s { union {}; struct { double f[1]; } g[2]; };
1390
1391 // LP64-LP64F-LABEL: define dso_local void @f_doublearr2_tricky3_s_arg
1392 // LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1393 // LP64-LP64F: entry:
1394 //
1395 // LP64D-LABEL: define dso_local void @f_doublearr2_tricky3_s_arg
1396 // LP64D-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
1397 // LP64D: entry:
1398 //
f_doublearr2_tricky3_s_arg(struct doublearr2_tricky3_s a)1399 void f_doublearr2_tricky3_s_arg(struct doublearr2_tricky3_s a) {}
1400
1401 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_doublearr2_tricky3_s
1402 // LP64-LP64F-SAME: () #[[ATTR0]] {
1403 // LP64-LP64F: entry:
1404 //
1405 // LP64D-LABEL: define dso_local { double, double } @f_ret_doublearr2_tricky3_s
1406 // LP64D-SAME: () #[[ATTR0]] {
1407 // LP64D: entry:
1408 //
f_ret_doublearr2_tricky3_s(void)1409 struct doublearr2_tricky3_s f_ret_doublearr2_tricky3_s(void) {
1410 return (struct doublearr2_tricky3_s){{}, {{{1.0}}, {{2.0}}}};
1411 }
1412
1413 struct doublearr2_tricky4_s { union {}; struct { struct {}; double f[1]; } g[2]; };
1414
1415 // LP64-LP64F-LABEL: define dso_local void @f_doublearr2_tricky4_s_arg
1416 // LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1417 // LP64-LP64F: entry:
1418 //
1419 // LP64D-LABEL: define dso_local void @f_doublearr2_tricky4_s_arg
1420 // LP64D-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
1421 // LP64D: entry:
1422 //
f_doublearr2_tricky4_s_arg(struct doublearr2_tricky4_s a)1423 void f_doublearr2_tricky4_s_arg(struct doublearr2_tricky4_s a) {}
1424
1425 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_doublearr2_tricky4_s
1426 // LP64-LP64F-SAME: () #[[ATTR0]] {
1427 // LP64-LP64F: entry:
1428 //
1429 // LP64D-LABEL: define dso_local { double, double } @f_ret_doublearr2_tricky4_s
1430 // LP64D-SAME: () #[[ATTR0]] {
1431 // LP64D: entry:
1432 //
f_ret_doublearr2_tricky4_s(void)1433 struct doublearr2_tricky4_s f_ret_doublearr2_tricky4_s(void) {
1434 return (struct doublearr2_tricky4_s){{}, {{{}, {1.0}}, {{}, {2.0}}}};
1435 }
1436
1437 // Test structs that should be passed according to the normal integer calling
1438 // convention.
1439
1440 struct int_double_int_s { int a; double b; int c; };
1441
1442 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_int_double_int_s_arg
1443 // LP64-LP64F-LP64D-SAME: (ptr noundef [[A:%.*]]) #[[ATTR0]] {
1444 // LP64-LP64F-LP64D: entry:
1445 //
f_int_double_int_s_arg(struct int_double_int_s a)1446 void f_int_double_int_s_arg(struct int_double_int_s a) {}
1447
1448 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_ret_int_double_int_s
1449 // LP64-LP64F-LP64D-SAME: (ptr dead_on_unwind noalias writable sret([[STRUCT_INT_DOUBLE_INT_S:%.*]]) align 8 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
1450 // LP64-LP64F-LP64D: entry:
1451 //
f_ret_int_double_int_s(void)1452 struct int_double_int_s f_ret_int_double_int_s(void) {
1453 return (struct int_double_int_s){1, 2.0, 3};
1454 }
1455
1456 struct char_char_double_s { char a; char b; double c; };
1457
1458 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_char_char_double_s_arg
1459 // LP64-LP64F-LP64D-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1460 // LP64-LP64F-LP64D: entry:
1461 //
f_char_char_double_s_arg(struct char_char_double_s a)1462 void f_char_char_double_s_arg(struct char_char_double_s a) {}
1463
1464 // LP64-LP64F-LP64D-LABEL: define dso_local [2 x i64] @f_ret_char_char_double_s
1465 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
1466 // LP64-LP64F-LP64D: entry:
1467 //
f_ret_char_char_double_s(void)1468 struct char_char_double_s f_ret_char_char_double_s(void) {
1469 return (struct char_char_double_s){1, 2, 3.0};
1470 }
1471
1472 // Unions are always passed according to the integer calling convention, even
1473 // if they can only contain a double.
1474
1475 union double_u { double a; };
1476
1477 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_double_u_arg
1478 // LP64-LP64F-LP64D-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1479 // LP64-LP64F-LP64D: entry:
1480 //
f_double_u_arg(union double_u a)1481 void f_double_u_arg(union double_u a) {}
1482
1483 // LP64-LP64F-LP64D-LABEL: define dso_local i64 @f_ret_double_u
1484 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
1485 // LP64-LP64F-LP64D: entry:
1486 //
f_ret_double_u(void)1487 union double_u f_ret_double_u(void) {
1488 return (union double_u){1.0};
1489 }
1490
1491 // Check that fp, fp+fp, and int+fp structs are lowered correctly. These will
1492 // be passed in FPR, FPR+FPR, or GPR+FPR regs if sufficient registers are
1493 // available the widths are <= XLEN and FLEN, and should be expanded to
1494 // separate arguments in IR. They are passed by the same rules for returns,
1495 // but will be lowered to simple two-element structs if necessary (as LLVM IR
1496 // functions cannot return multiple values).
1497
1498 struct float16_s { _Float16 f; };
1499
1500 // A struct containing just one floating-point real is passed as though it
1501 // were a standalone floating-point real.
1502
1503 // LP64-LABEL: define dso_local void @f_float16_s_arg
1504 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1505 // LP64: entry:
1506 //
1507 // LP64F-LP64D-LABEL: define dso_local void @f_float16_s_arg
1508 // LP64F-LP64D-SAME: (half [[TMP0:%.*]]) #[[ATTR0]] {
1509 // LP64F-LP64D: entry:
1510 //
f_float16_s_arg(struct float16_s a)1511 void f_float16_s_arg(struct float16_s a) {}
1512
1513 // LP64-LABEL: define dso_local i64 @f_ret_float16_s
1514 // LP64-SAME: () #[[ATTR0]] {
1515 // LP64: entry:
1516 //
1517 // LP64F-LP64D-LABEL: define dso_local half @f_ret_float16_s
1518 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1519 // LP64F-LP64D: entry:
1520 //
f_ret_float16_s(void)1521 struct float16_s f_ret_float16_s(void) {
1522 return (struct float16_s){1.0};
1523 }
1524
1525 // A struct containing a double and any number of zero-width bitfields is
1526 // passed as though it were a standalone floating-point real.
1527
1528 struct zbf_float16_s { int : 0; _Float16 f; };
1529 struct zbf_float16_zbf_s { int : 0; _Float16 f; int : 0; };
1530
1531 // LP64-LABEL: define dso_local void @f_zbf_float16_s_arg
1532 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1533 // LP64: entry:
1534 //
1535 // LP64F-LP64D-LABEL: define dso_local void @f_zbf_float16_s_arg
1536 // LP64F-LP64D-SAME: (half [[TMP0:%.*]]) #[[ATTR0]] {
1537 // LP64F-LP64D: entry:
1538 //
f_zbf_float16_s_arg(struct zbf_float16_s a)1539 void f_zbf_float16_s_arg(struct zbf_float16_s a) {}
1540
1541 // LP64-LABEL: define dso_local i64 @f_ret_zbf_float16_s
1542 // LP64-SAME: () #[[ATTR0]] {
1543 // LP64: entry:
1544 //
1545 // LP64F-LP64D-LABEL: define dso_local half @f_ret_zbf_float16_s
1546 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1547 // LP64F-LP64D: entry:
1548 //
f_ret_zbf_float16_s(void)1549 struct zbf_float16_s f_ret_zbf_float16_s(void) {
1550 return (struct zbf_float16_s){1.0};
1551 }
1552
1553 // LP64-LABEL: define dso_local void @f_zbf_float16_zbf_s_arg
1554 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1555 // LP64: entry:
1556 //
1557 // LP64F-LP64D-LABEL: define dso_local void @f_zbf_float16_zbf_s_arg
1558 // LP64F-LP64D-SAME: (half [[TMP0:%.*]]) #[[ATTR0]] {
1559 // LP64F-LP64D: entry:
1560 //
f_zbf_float16_zbf_s_arg(struct zbf_float16_zbf_s a)1561 void f_zbf_float16_zbf_s_arg(struct zbf_float16_zbf_s a) {}
1562
1563 // LP64-LABEL: define dso_local i64 @f_ret_zbf_float16_zbf_s
1564 // LP64-SAME: () #[[ATTR0]] {
1565 // LP64: entry:
1566 //
1567 // LP64F-LP64D-LABEL: define dso_local half @f_ret_zbf_float16_zbf_s
1568 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1569 // LP64F-LP64D: entry:
1570 //
f_ret_zbf_float16_zbf_s(void)1571 struct zbf_float16_zbf_s f_ret_zbf_float16_zbf_s(void) {
1572 return (struct zbf_float16_zbf_s){1.0};
1573 }
1574
1575 // Check that structs containing two floating point values (FLEN <= width) are
1576 // expanded provided sufficient FPRs are available.
1577
1578 struct double_float16_s { double f; _Float16 g; };
1579
1580 // LP64-LP64F-LABEL: define dso_local void @f_double_float16_s_arg
1581 // LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1582 // LP64-LP64F: entry:
1583 //
1584 // LP64D-LABEL: define dso_local void @f_double_float16_s_arg
1585 // LP64D-SAME: (double [[TMP0:%.*]], half [[TMP1:%.*]]) #[[ATTR0]] {
1586 // LP64D: entry:
1587 //
f_double_float16_s_arg(struct double_float16_s a)1588 void f_double_float16_s_arg(struct double_float16_s a) {}
1589
1590 // LP64-LP64F-LABEL: define dso_local [2 x i64] @f_ret_double_float16_s
1591 // LP64-LP64F-SAME: () #[[ATTR0]] {
1592 // LP64-LP64F: entry:
1593 //
1594 // LP64D-LABEL: define dso_local { double, half } @f_ret_double_float16_s
1595 // LP64D-SAME: () #[[ATTR0]] {
1596 // LP64D: entry:
1597 //
f_ret_double_float16_s(void)1598 struct double_float16_s f_ret_double_float16_s(void) {
1599 return (struct double_float16_s){1.0, 2.0};
1600 }
1601
1602 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_double_float16_s_arg_insufficient_fprs
1603 // LP64-LP64F-LP64D-SAME: (float noundef [[A:%.*]], double noundef [[B:%.*]], double noundef [[C:%.*]], double noundef [[D:%.*]], double noundef [[E:%.*]], double noundef [[F:%.*]], double noundef [[G:%.*]], [2 x i64] [[H_COERCE:%.*]]) #[[ATTR0]] {
1604 // LP64-LP64F-LP64D: entry:
1605 //
f_double_float16_s_arg_insufficient_fprs(float a,double b,double c,double d,double e,double f,double g,struct double_float16_s h)1606 void f_double_float16_s_arg_insufficient_fprs(float a, double b, double c, double d,
1607 double e, double f, double g, struct double_float16_s h) {}
1608
1609 // Check that structs containing int+_Float16 values are expanded, provided
1610 // sufficient FPRs and GPRs are available. The integer components are neither
1611 // sign or zero-extended.
1612
1613 struct float16_int8_s { _Float16 f; int8_t i; };
1614 struct float16_uint8_s { _Float16 f; uint8_t i; };
1615 struct float16_int32_s { _Float16 f; int32_t i; };
1616 struct float16_int64_s { _Float16 f; int64_t i; };
1617 struct float16_int64bf_s { _Float16 f; int64_t i : 32; };
1618 struct float16_int8_zbf_s { _Float16 f; int8_t i; int : 0; };
1619
1620 // LP64-LABEL: define dso_local void @f_float16_int8_s_arg
1621 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1622 // LP64: entry:
1623 //
1624 // LP64F-LP64D-LABEL: define dso_local void @f_float16_int8_s_arg
1625 // LP64F-LP64D-SAME: (half [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
1626 // LP64F-LP64D: entry:
1627 //
f_float16_int8_s_arg(struct float16_int8_s a)1628 void f_float16_int8_s_arg(struct float16_int8_s a) {}
1629
1630 // LP64-LABEL: define dso_local i64 @f_ret_float16_int8_s
1631 // LP64-SAME: () #[[ATTR0]] {
1632 // LP64: entry:
1633 //
1634 // LP64F-LP64D-LABEL: define dso_local { half, i8 } @f_ret_float16_int8_s
1635 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1636 // LP64F-LP64D: entry:
1637 //
f_ret_float16_int8_s(void)1638 struct float16_int8_s f_ret_float16_int8_s(void) {
1639 return (struct float16_int8_s){1.0, 2};
1640 }
1641
1642 // LP64-LABEL: define dso_local void @f_float16_uint8_s_arg
1643 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1644 // LP64: entry:
1645 //
1646 // LP64F-LP64D-LABEL: define dso_local void @f_float16_uint8_s_arg
1647 // LP64F-LP64D-SAME: (half [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
1648 // LP64F-LP64D: entry:
1649 //
f_float16_uint8_s_arg(struct float16_uint8_s a)1650 void f_float16_uint8_s_arg(struct float16_uint8_s a) {}
1651
1652 // LP64-LABEL: define dso_local i64 @f_ret_float16_uint8_s
1653 // LP64-SAME: () #[[ATTR0]] {
1654 // LP64: entry:
1655 //
1656 // LP64F-LP64D-LABEL: define dso_local { half, i8 } @f_ret_float16_uint8_s
1657 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1658 // LP64F-LP64D: entry:
1659 //
f_ret_float16_uint8_s(void)1660 struct float16_uint8_s f_ret_float16_uint8_s(void) {
1661 return (struct float16_uint8_s){1.0, 2};
1662 }
1663
1664 // LP64-LABEL: define dso_local void @f_float16_int32_s_arg
1665 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1666 // LP64: entry:
1667 //
1668 // LP64F-LP64D-LABEL: define dso_local void @f_float16_int32_s_arg
1669 // LP64F-LP64D-SAME: (half [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR0]] {
1670 // LP64F-LP64D: entry:
1671 //
f_float16_int32_s_arg(struct float16_int32_s a)1672 void f_float16_int32_s_arg(struct float16_int32_s a) {}
1673
1674 // LP64-LABEL: define dso_local i64 @f_ret_float16_int32_s
1675 // LP64-SAME: () #[[ATTR0]] {
1676 // LP64: entry:
1677 //
1678 // LP64F-LP64D-LABEL: define dso_local { half, i32 } @f_ret_float16_int32_s
1679 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1680 // LP64F-LP64D: entry:
1681 //
f_ret_float16_int32_s(void)1682 struct float16_int32_s f_ret_float16_int32_s(void) {
1683 return (struct float16_int32_s){1.0, 2};
1684 }
1685
1686 // LP64-LABEL: define dso_local void @f_float16_int64_s_arg
1687 // LP64-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1688 // LP64: entry:
1689 //
1690 // LP64F-LP64D-LABEL: define dso_local void @f_float16_int64_s_arg
1691 // LP64F-LP64D-SAME: (half [[TMP0:%.*]], i64 [[TMP1:%.*]]) #[[ATTR0]] {
1692 // LP64F-LP64D: entry:
1693 //
f_float16_int64_s_arg(struct float16_int64_s a)1694 void f_float16_int64_s_arg(struct float16_int64_s a) {}
1695
1696 // LP64-LABEL: define dso_local [2 x i64] @f_ret_float16_int64_s
1697 // LP64-SAME: () #[[ATTR0]] {
1698 // LP64: entry:
1699 //
1700 // LP64F-LP64D-LABEL: define dso_local { half, i64 } @f_ret_float16_int64_s
1701 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1702 // LP64F-LP64D: entry:
1703 //
f_ret_float16_int64_s(void)1704 struct float16_int64_s f_ret_float16_int64_s(void) {
1705 return (struct float16_int64_s){1.0, 2};
1706 }
1707
1708 // LP64-LABEL: define dso_local void @f_float16_int64bf_s_arg
1709 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1710 // LP64: entry:
1711 //
1712 // LP64F-LP64D-LABEL: define dso_local void @f_float16_int64bf_s_arg
1713 // LP64F-LP64D-SAME: (half [[TMP0:%.*]], i64 [[TMP1:%.*]]) #[[ATTR0]] {
1714 // LP64F-LP64D: entry:
1715 //
f_float16_int64bf_s_arg(struct float16_int64bf_s a)1716 void f_float16_int64bf_s_arg(struct float16_int64bf_s a) {}
1717
1718 // LP64-LABEL: define dso_local i64 @f_ret_float16_int64bf_s
1719 // LP64-SAME: () #[[ATTR0]] {
1720 // LP64: entry:
1721 //
1722 // LP64F-LP64D-LABEL: define dso_local <{ half, i64 }> @f_ret_float16_int64bf_s
1723 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1724 // LP64F-LP64D: entry:
1725 //
f_ret_float16_int64bf_s(void)1726 struct float16_int64bf_s f_ret_float16_int64bf_s(void) {
1727 return (struct float16_int64bf_s){1.0, 2};
1728 }
1729
1730 // The zero-width bitfield means the struct can't be passed according to the
1731 // floating point calling convention.
1732
1733 // LP64-LABEL: define dso_local void @f_float16_int8_zbf_s
1734 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1735 // LP64: entry:
1736 //
1737 // LP64F-LP64D-LABEL: define dso_local void @f_float16_int8_zbf_s
1738 // LP64F-LP64D-SAME: (half [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
1739 // LP64F-LP64D: entry:
1740 //
f_float16_int8_zbf_s(struct float16_int8_zbf_s a)1741 void f_float16_int8_zbf_s(struct float16_int8_zbf_s a) {}
1742
1743 // LP64-LABEL: define dso_local i64 @f_ret_float16_int8_zbf_s
1744 // LP64-SAME: () #[[ATTR0]] {
1745 // LP64: entry:
1746 //
1747 // LP64F-LP64D-LABEL: define dso_local { half, i8 } @f_ret_float16_int8_zbf_s
1748 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1749 // LP64F-LP64D: entry:
1750 //
f_ret_float16_int8_zbf_s(void)1751 struct float16_int8_zbf_s f_ret_float16_int8_zbf_s(void) {
1752 return (struct float16_int8_zbf_s){1.0, 2};
1753 }
1754
1755 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_float16_int8_s_arg_insufficient_gprs
1756 // LP64-LP64F-LP64D-SAME: (i32 noundef signext [[A:%.*]], i32 noundef signext [[B:%.*]], i32 noundef signext [[C:%.*]], i32 noundef signext [[D:%.*]], i32 noundef signext [[E:%.*]], i32 noundef signext [[F:%.*]], i32 noundef signext [[G:%.*]], i32 noundef signext [[H:%.*]], i64 [[I_COERCE:%.*]]) #[[ATTR0]] {
1757 // LP64-LP64F-LP64D: entry:
1758 //
f_float16_int8_s_arg_insufficient_gprs(int a,int b,int c,int d,int e,int f,int g,int h,struct float16_int8_s i)1759 void f_float16_int8_s_arg_insufficient_gprs(int a, int b, int c, int d, int e,
1760 int f, int g, int h, struct float16_int8_s i) {}
1761
1762 // LP64-LABEL: define dso_local void @f_struct_float16_int8_insufficient_fprs
1763 // LP64-SAME: (float noundef [[A:%.*]], double noundef [[B:%.*]], double noundef [[C:%.*]], double noundef [[D:%.*]], double noundef [[E:%.*]], double noundef [[F:%.*]], double noundef [[G:%.*]], double noundef [[H:%.*]], i64 [[I_COERCE:%.*]]) #[[ATTR0]] {
1764 // LP64: entry:
1765 //
1766 // LP64F-LABEL: define dso_local void @f_struct_float16_int8_insufficient_fprs
1767 // LP64F-SAME: (float noundef [[A:%.*]], double noundef [[B:%.*]], double noundef [[C:%.*]], double noundef [[D:%.*]], double noundef [[E:%.*]], double noundef [[F:%.*]], double noundef [[G:%.*]], double noundef [[H:%.*]], half [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
1768 // LP64F: entry:
1769 //
1770 // LP64D-LABEL: define dso_local void @f_struct_float16_int8_insufficient_fprs
1771 // LP64D-SAME: (float noundef [[A:%.*]], double noundef [[B:%.*]], double noundef [[C:%.*]], double noundef [[D:%.*]], double noundef [[E:%.*]], double noundef [[F:%.*]], double noundef [[G:%.*]], double noundef [[H:%.*]], i64 [[I_COERCE:%.*]]) #[[ATTR0]] {
1772 // LP64D: entry:
1773 //
f_struct_float16_int8_insufficient_fprs(float a,double b,double c,double d,double e,double f,double g,double h,struct float16_int8_s i)1774 void f_struct_float16_int8_insufficient_fprs(float a, double b, double c, double d,
1775 double e, double f, double g, double h, struct float16_int8_s i) {}
1776
1777 // Complex floating-point values or structs containing a single complex
1778 // floating-point value should be passed as if it were an fp+fp struct.
1779
1780 // LP64-LABEL: define dso_local void @f_float16complex
1781 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1782 // LP64: entry:
1783 //
1784 // LP64F-LP64D-LABEL: define dso_local void @f_float16complex
1785 // LP64F-LP64D-SAME: (half noundef [[A_COERCE0:%.*]], half noundef [[A_COERCE1:%.*]]) #[[ATTR0]] {
1786 // LP64F-LP64D: entry:
1787 //
f_float16complex(_Float16 __complex__ a)1788 void f_float16complex(_Float16 __complex__ a) {}
1789
1790 // LP64-LABEL: define dso_local i64 @f_ret_float16complex
1791 // LP64-SAME: () #[[ATTR0]] {
1792 // LP64: entry:
1793 //
1794 // LP64F-LP64D-LABEL: define dso_local { half, half } @f_ret_float16complex
1795 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1796 // LP64F-LP64D: entry:
1797 //
f_ret_float16complex(void)1798 _Float16 __complex__ f_ret_float16complex(void) {
1799 return 1.0;
1800 }
1801
1802 struct float16complex_s { _Float16 __complex__ c; };
1803
1804 // LP64-LABEL: define dso_local void @f_float16complex_s_arg
1805 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1806 // LP64: entry:
1807 //
1808 // LP64F-LP64D-LABEL: define dso_local void @f_float16complex_s_arg
1809 // LP64F-LP64D-SAME: (half [[TMP0:%.*]], half [[TMP1:%.*]]) #[[ATTR0]] {
1810 // LP64F-LP64D: entry:
1811 //
f_float16complex_s_arg(struct float16complex_s a)1812 void f_float16complex_s_arg(struct float16complex_s a) {}
1813
1814 // LP64-LABEL: define dso_local i64 @f_ret_float16complex_s
1815 // LP64-SAME: () #[[ATTR0]] {
1816 // LP64: entry:
1817 //
1818 // LP64F-LP64D-LABEL: define dso_local { half, half } @f_ret_float16complex_s
1819 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1820 // LP64F-LP64D: entry:
1821 //
f_ret_float16complex_s(void)1822 struct float16complex_s f_ret_float16complex_s(void) {
1823 return (struct float16complex_s){1.0};
1824 }
1825
1826 // Test single or two-element structs that need flattening. e.g. those
1827 // containing nested structs, _Float16 in small arrays, zero-length structs etc.
1828
1829 struct float16arr1_s { _Float16 a[1]; };
1830
1831 // LP64-LABEL: define dso_local void @f_float16arr1_s_arg
1832 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1833 // LP64: entry:
1834 //
1835 // LP64F-LP64D-LABEL: define dso_local void @f_float16arr1_s_arg
1836 // LP64F-LP64D-SAME: (half [[TMP0:%.*]]) #[[ATTR0]] {
1837 // LP64F-LP64D: entry:
1838 //
f_float16arr1_s_arg(struct float16arr1_s a)1839 void f_float16arr1_s_arg(struct float16arr1_s a) {}
1840
1841 // LP64-LABEL: define dso_local i64 @f_ret_float16arr1_s
1842 // LP64-SAME: () #[[ATTR0]] {
1843 // LP64: entry:
1844 //
1845 // LP64F-LP64D-LABEL: define dso_local half @f_ret_float16arr1_s
1846 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1847 // LP64F-LP64D: entry:
1848 //
f_ret_float16arr1_s(void)1849 struct float16arr1_s f_ret_float16arr1_s(void) {
1850 return (struct float16arr1_s){{1.0}};
1851 }
1852
1853 struct float16arr2_s { _Float16 a[2]; };
1854
1855 // LP64-LABEL: define dso_local void @f_float16arr2_s_arg
1856 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1857 // LP64: entry:
1858 //
1859 // LP64F-LP64D-LABEL: define dso_local void @f_float16arr2_s_arg
1860 // LP64F-LP64D-SAME: (half [[TMP0:%.*]], half [[TMP1:%.*]]) #[[ATTR0]] {
1861 // LP64F-LP64D: entry:
1862 //
f_float16arr2_s_arg(struct float16arr2_s a)1863 void f_float16arr2_s_arg(struct float16arr2_s a) {}
1864
1865 // LP64-LABEL: define dso_local i64 @f_ret_float16arr2_s
1866 // LP64-SAME: () #[[ATTR0]] {
1867 // LP64: entry:
1868 //
1869 // LP64F-LP64D-LABEL: define dso_local { half, half } @f_ret_float16arr2_s
1870 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1871 // LP64F-LP64D: entry:
1872 //
f_ret_float16arr2_s(void)1873 struct float16arr2_s f_ret_float16arr2_s(void) {
1874 return (struct float16arr2_s){{1.0, 2.0}};
1875 }
1876
1877 struct float16arr2_tricky1_s { struct { _Float16 f[1]; } g[2]; };
1878
1879 // LP64-LABEL: define dso_local void @f_float16arr2_tricky1_s_arg
1880 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1881 // LP64: entry:
1882 //
1883 // LP64F-LP64D-LABEL: define dso_local void @f_float16arr2_tricky1_s_arg
1884 // LP64F-LP64D-SAME: (half [[TMP0:%.*]], half [[TMP1:%.*]]) #[[ATTR0]] {
1885 // LP64F-LP64D: entry:
1886 //
f_float16arr2_tricky1_s_arg(struct float16arr2_tricky1_s a)1887 void f_float16arr2_tricky1_s_arg(struct float16arr2_tricky1_s a) {}
1888
1889 // LP64-LABEL: define dso_local i64 @f_ret_float16arr2_tricky1_s
1890 // LP64-SAME: () #[[ATTR0]] {
1891 // LP64: entry:
1892 //
1893 // LP64F-LP64D-LABEL: define dso_local { half, half } @f_ret_float16arr2_tricky1_s
1894 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1895 // LP64F-LP64D: entry:
1896 //
f_ret_float16arr2_tricky1_s(void)1897 struct float16arr2_tricky1_s f_ret_float16arr2_tricky1_s(void) {
1898 return (struct float16arr2_tricky1_s){{{{1.0}}, {{2.0}}}};
1899 }
1900
1901 struct float16arr2_tricky2_s { struct {}; struct { _Float16 f[1]; } g[2]; };
1902
1903 // LP64-LABEL: define dso_local void @f_float16arr2_tricky2_s_arg
1904 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1905 // LP64: entry:
1906 //
1907 // LP64F-LP64D-LABEL: define dso_local void @f_float16arr2_tricky2_s_arg
1908 // LP64F-LP64D-SAME: (half [[TMP0:%.*]], half [[TMP1:%.*]]) #[[ATTR0]] {
1909 // LP64F-LP64D: entry:
1910 //
f_float16arr2_tricky2_s_arg(struct float16arr2_tricky2_s a)1911 void f_float16arr2_tricky2_s_arg(struct float16arr2_tricky2_s a) {}
1912
1913 // LP64-LABEL: define dso_local i64 @f_ret_float16arr2_tricky2_s
1914 // LP64-SAME: () #[[ATTR0]] {
1915 // LP64: entry:
1916 //
1917 // LP64F-LP64D-LABEL: define dso_local { half, half } @f_ret_float16arr2_tricky2_s
1918 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1919 // LP64F-LP64D: entry:
1920 //
f_ret_float16arr2_tricky2_s(void)1921 struct float16arr2_tricky2_s f_ret_float16arr2_tricky2_s(void) {
1922 return (struct float16arr2_tricky2_s){{}, {{{1.0}}, {{2.0}}}};
1923 }
1924
1925 struct float16arr2_tricky3_s { union {}; struct { _Float16 f[1]; } g[2]; };
1926
1927 // LP64-LABEL: define dso_local void @f_float16arr2_tricky3_s_arg
1928 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1929 // LP64: entry:
1930 //
1931 // LP64F-LP64D-LABEL: define dso_local void @f_float16arr2_tricky3_s_arg
1932 // LP64F-LP64D-SAME: (half [[TMP0:%.*]], half [[TMP1:%.*]]) #[[ATTR0]] {
1933 // LP64F-LP64D: entry:
1934 //
f_float16arr2_tricky3_s_arg(struct float16arr2_tricky3_s a)1935 void f_float16arr2_tricky3_s_arg(struct float16arr2_tricky3_s a) {}
1936
1937 // LP64-LABEL: define dso_local i64 @f_ret_float16arr2_tricky3_s
1938 // LP64-SAME: () #[[ATTR0]] {
1939 // LP64: entry:
1940 //
1941 // LP64F-LP64D-LABEL: define dso_local { half, half } @f_ret_float16arr2_tricky3_s
1942 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1943 // LP64F-LP64D: entry:
1944 //
f_ret_float16arr2_tricky3_s(void)1945 struct float16arr2_tricky3_s f_ret_float16arr2_tricky3_s(void) {
1946 return (struct float16arr2_tricky3_s){{}, {{{1.0}}, {{2.0}}}};
1947 }
1948
1949 struct float16arr2_tricky4_s { union {}; struct { struct {}; _Float16 f[1]; } g[2]; };
1950
1951 // LP64-LABEL: define dso_local void @f_float16arr2_tricky4_s_arg
1952 // LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
1953 // LP64: entry:
1954 //
1955 // LP64F-LP64D-LABEL: define dso_local void @f_float16arr2_tricky4_s_arg
1956 // LP64F-LP64D-SAME: (half [[TMP0:%.*]], half [[TMP1:%.*]]) #[[ATTR0]] {
1957 // LP64F-LP64D: entry:
1958 //
f_float16arr2_tricky4_s_arg(struct float16arr2_tricky4_s a)1959 void f_float16arr2_tricky4_s_arg(struct float16arr2_tricky4_s a) {}
1960
1961 // LP64-LABEL: define dso_local i64 @f_ret_float16arr2_tricky4_s
1962 // LP64-SAME: () #[[ATTR0]] {
1963 // LP64: entry:
1964 //
1965 // LP64F-LP64D-LABEL: define dso_local { half, half } @f_ret_float16arr2_tricky4_s
1966 // LP64F-LP64D-SAME: () #[[ATTR0]] {
1967 // LP64F-LP64D: entry:
1968 //
f_ret_float16arr2_tricky4_s(void)1969 struct float16arr2_tricky4_s f_ret_float16arr2_tricky4_s(void) {
1970 return (struct float16arr2_tricky4_s){{}, {{{}, {1.0}}, {{}, {2.0}}}};
1971 }
1972
1973 // Test structs that should be passed according to the normal integer calling
1974 // convention.
1975
1976 struct int_float16_int_s { int a; _Float16 b; int c; };
1977
1978 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_int_float16_int_s_arg
1979 // LP64-LP64F-LP64D-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1980 // LP64-LP64F-LP64D: entry:
1981 //
f_int_float16_int_s_arg(struct int_float16_int_s a)1982 void f_int_float16_int_s_arg(struct int_float16_int_s a) {}
1983
1984 // LP64-LP64F-LP64D-LABEL: define dso_local [2 x i64] @f_ret_int_float16_int_s
1985 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
1986 // LP64-LP64F-LP64D: entry:
1987 //
f_ret_int_float16_int_s(void)1988 struct int_float16_int_s f_ret_int_float16_int_s(void) {
1989 return (struct int_float16_int_s){1, 2.0, 3};
1990 }
1991
1992 struct int64_float16_s { int64_t a; _Float16 b; };
1993
1994 // LP64-LABEL: define dso_local void @f_int64_float16_s_arg
1995 // LP64-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
1996 // LP64: entry:
1997 //
1998 // LP64F-LP64D-LABEL: define dso_local void @f_int64_float16_s_arg
1999 // LP64F-LP64D-SAME: (i64 [[TMP0:%.*]], half [[TMP1:%.*]]) #[[ATTR0]] {
2000 // LP64F-LP64D: entry:
2001 //
f_int64_float16_s_arg(struct int64_float16_s a)2002 void f_int64_float16_s_arg(struct int64_float16_s a) {}
2003
2004 // LP64-LABEL: define dso_local [2 x i64] @f_ret_int64_float16_s
2005 // LP64-SAME: () #[[ATTR0]] {
2006 // LP64: entry:
2007 //
2008 // LP64F-LP64D-LABEL: define dso_local { i64, half } @f_ret_int64_float16_s
2009 // LP64F-LP64D-SAME: () #[[ATTR0]] {
2010 // LP64F-LP64D: entry:
2011 //
f_ret_int64_float16_s(void)2012 struct int64_float16_s f_ret_int64_float16_s(void) {
2013 return (struct int64_float16_s){1, 2.0};
2014 }
2015
2016 struct char_char_float16_s { char a; char b; _Float16 c; };
2017
2018 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_char_char_float16_s_arg
2019 // LP64-LP64F-LP64D-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
2020 // LP64-LP64F-LP64D: entry:
2021 //
f_char_char_float16_s_arg(struct char_char_float16_s a)2022 void f_char_char_float16_s_arg(struct char_char_float16_s a) {}
2023
2024 // LP64-LP64F-LP64D-LABEL: define dso_local i64 @f_ret_char_char_float16_s
2025 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
2026 // LP64-LP64F-LP64D: entry:
2027 //
f_ret_char_char_float16_s(void)2028 struct char_char_float16_s f_ret_char_char_float16_s(void) {
2029 return (struct char_char_float16_s){1, 2, 3.0};
2030 }
2031
2032 // Unions are always passed according to the integer calling convention, even
2033 // if they can only contain a double.
2034
2035 union float16_u { _Float16 a; };
2036
2037 // LP64-LP64F-LP64D-LABEL: define dso_local void @f_float16_u_arg
2038 // LP64-LP64F-LP64D-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
2039 // LP64-LP64F-LP64D: entry:
2040 //
f_float16_u_arg(union float16_u a)2041 void f_float16_u_arg(union float16_u a) {}
2042
2043 // LP64-LP64F-LP64D-LABEL: define dso_local i64 @f_ret_float16_u
2044 // LP64-LP64F-LP64D-SAME: () #[[ATTR0]] {
2045 // LP64-LP64F-LP64D: entry:
2046 //
f_ret_float16_u(void)2047 union float16_u f_ret_float16_u(void) {
2048 return (union float16_u){1.0};
2049 }
2050
2051 //// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
2052 // LP64E: {{.*}}
2053