Revert "[llvm] Improve llvm.objectsize computation by computing GEP, alloca and mallo...
[llvm-project.git] / clang / test / CodeGen / X86 / x86_64-arguments.c
blob82845f0a2b31fdadbfaf32183d1c73fc77765622
1 // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -debug-info-kind=limited -Wno-strict-prototypes -o - %s | \
2 // RUN: FileCheck %s -check-prefix=CHECK -check-prefix=SSE -check-prefix=NO-AVX512
3 // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -debug-info-kind=limited -Wno-strict-prototypes -o - %s -target-feature +avx | \
4 // RUN: FileCheck %s -check-prefix=CHECK -check-prefix=AVX -check-prefix=NO-AVX512
5 // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -debug-info-kind=limited -Wno-strict-prototypes -o - %s -target-feature +avx512f | \
6 // RUN: FileCheck %s -check-prefix=CHECK -check-prefix=AVX -check-prefix=AVX512
7 #include <stdarg.h>
9 // CHECK-LABEL: define{{.*}} signext i8 @f0()
10 char f0(void) {
11 return 0;
14 // CHECK-LABEL: define{{.*}} signext i16 @f1()
15 short f1(void) {
16 return 0;
19 // CHECK-LABEL: define{{.*}} i32 @f2()
20 int f2(void) {
21 return 0;
24 // CHECK-LABEL: define{{.*}} float @f3()
25 float f3(void) {
26 return 0;
29 // CHECK-LABEL: define{{.*}} double @f4()
30 double f4(void) {
31 return 0;
34 // CHECK-LABEL: define{{.*}} x86_fp80 @f5()
35 long double f5(void) {
36 return 0;
39 // CHECK-LABEL: define{{.*}} void @f6(i8 noundef signext %a0, i16 noundef signext %a1, i32 noundef %a2, i64 noundef %a3, ptr noundef %a4)
40 void f6(char a0, short a1, int a2, long long a3, void *a4) {
43 // CHECK-LABEL: define{{.*}} void @f7(i32 noundef %a0)
44 typedef enum { A, B, C } e7;
45 void f7(e7 a0) {
48 // Test merging/passing of upper eightbyte with X87 class.
50 // CHECK-LABEL: define{{.*}} void @f8_1(ptr dead_on_unwind noalias writable sret(%union.u8) align 16 %agg.result)
51 // CHECK-LABEL: define{{.*}} void @f8_2(ptr noundef byval(%union.u8) align 16 %a0)
52 union u8 {
53 long double a;
54 int b;
56 union u8 f8_1(void) { while (1) {} }
57 void f8_2(union u8 a0) {}
59 // CHECK-LABEL: define{{.*}} i64 @f9()
60 struct s9 { int a; int b; int : 0; } f9(void) { while (1) {} }
62 // CHECK-LABEL: define{{.*}} void @f10(i64 %a0.coerce)
63 struct s10 { int a; int b; int : 0; };
64 void f10(struct s10 a0) {}
66 // CHECK-LABEL: define{{.*}} void @f11(ptr dead_on_unwind noalias writable sret(%union.anon) align 16 %agg.result)
67 union { long double a; float b; } f11(void) { while (1) {} }
69 // CHECK-LABEL: define{{.*}} i32 @f12_0()
70 // CHECK-LABEL: define{{.*}} void @f12_1(i32 %a0.coerce)
71 struct s12 { int a __attribute__((aligned(16))); };
72 struct s12 f12_0(void) { while (1) {} }
73 void f12_1(struct s12 a0) {}
75 // Check that sret parameter is accounted for when checking available integer
76 // registers.
77 // CHECK: define{{.*}} void @f13(ptr dead_on_unwind noalias writable sret(%struct.s13_0) align 8 %agg.result, i32 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d, ptr noundef byval({{.*}}) align 8 %e, i32 noundef %f)
79 struct s13_0 { long long f0[3]; };
80 struct s13_1 { long long f0[2]; };
81 struct s13_0 f13(int a, int b, int c, int d,
82 struct s13_1 e, int f) { while (1) {} }
84 // CHECK: define{{.*}} void @f14({{.*}}, i8 noundef signext %X)
85 void f14(int a, int b, int c, int d, int e, int f, char X) {}
87 // CHECK: define{{.*}} void @f15({{.*}}, ptr noundef %X)
88 void f15(int a, int b, int c, int d, int e, int f, void *X) {}
90 // CHECK: define{{.*}} void @f16({{.*}}, float noundef %X)
91 void f16(float a, float b, float c, float d, float e, float f, float g, float h,
92 float X) {}
94 // CHECK: define{{.*}} void @f17({{.*}}, x86_fp80 noundef %X)
95 void f17(float a, float b, float c, float d, float e, float f, float g, float h,
96 long double X) {}
98 // Check for valid coercion. The struct should be passed/returned as i32, not
99 // as i64 for better code quality.
100 // CHECK-LABEL: define{{.*}} void @f18(i32 noundef %a, i32 %f18_arg1.coerce)
101 struct f18_s0 { int f0; };
102 void f18(int a, struct f18_s0 f18_arg1) { while (1) {} }
104 // Check byval alignment.
106 // CHECK-LABEL: define{{.*}} void @f19(ptr noundef byval(%struct.s19) align 16 %x)
107 struct s19 {
108 long double a;
110 void f19(struct s19 x) {}
112 // CHECK-LABEL: define{{.*}} void @f20(ptr noundef byval(%struct.s20) align 32 %x)
113 struct __attribute__((aligned(32))) s20 {
114 int x;
115 int y;
117 void f20(struct s20 x) {}
119 struct StringRef {
120 long x;
121 const char *Ptr;
124 // CHECK-LABEL: define{{.*}} ptr @f21(i64 %S.coerce0, ptr %S.coerce1)
125 const char *f21(struct StringRef S) { return S.x+S.Ptr; }
127 // PR7567
128 typedef __attribute__ ((aligned(16))) struct f22s { unsigned long long x[2]; } L;
129 void f22(L x, L y) { }
130 // CHECK: @f22
131 // CHECK: %x = alloca{{.*}}, align 16
132 // CHECK: %y = alloca{{.*}}, align 16
136 // PR7714
137 struct f23S {
138 short f0;
139 unsigned f1;
140 int f2;
144 void f23(int A, struct f23S B) {
145 // CHECK-LABEL: define{{.*}} void @f23(i32 noundef %A, i64 %B.coerce0, i32 %B.coerce1)
148 struct f24s { long a; int b; };
150 struct f23S f24(struct f23S *X, struct f24s *P2) {
151 return *X;
153 // CHECK: define{{.*}} { i64, i32 } @f24(ptr noundef %X, ptr noundef %P2)
156 typedef float v4f32 __attribute__((__vector_size__(16)));
157 v4f32 f25(v4f32 X) {
158 // CHECK-LABEL: define{{.*}} <4 x float> @f25(<4 x float> noundef %X)
159 // CHECK-NOT: alloca
160 // CHECK: alloca <4 x float>
161 // CHECK-NOT: alloca
162 // CHECK: store <4 x float> %X, ptr
163 // CHECK-NOT: store
164 // CHECK: ret <4 x float>
165 return X+X;
168 struct foo26 {
169 int *X;
170 float *Y;
173 struct foo26 f26(struct foo26 *P) {
174 // CHECK: define{{.*}} { ptr, ptr } @f26(ptr noundef %P)
175 return *P;
179 struct v4f32wrapper {
180 v4f32 v;
183 struct v4f32wrapper f27(struct v4f32wrapper X) {
184 // CHECK-LABEL: define{{.*}} <4 x float> @f27(<4 x float> %X.coerce)
185 return X;
188 // PR22563 - We should unwrap simple structs and arrays to pass
189 // and return them in the appropriate vector registers if possible.
191 typedef float v8f32 __attribute__((__vector_size__(32)));
192 struct v8f32wrapper {
193 v8f32 v;
196 struct v8f32wrapper f27a(struct v8f32wrapper X) {
197 // AVX-LABEL: define{{.*}} <8 x float> @f27a(<8 x float> %X.coerce)
198 return X;
201 struct v8f32wrapper_wrapper {
202 v8f32 v[1];
205 struct v8f32wrapper_wrapper f27b(struct v8f32wrapper_wrapper X) {
206 // AVX-LABEL: define{{.*}} <8 x float> @f27b(<8 x float> %X.coerce)
207 return X;
210 struct f28c {
211 double x;
212 int y;
214 void f28(struct f28c C) {
215 // CHECK-LABEL: define{{.*}} void @f28(double %C.coerce0, i32 %C.coerce1)
218 struct f29a {
219 struct c {
220 double x;
221 int y;
222 } x[1];
225 void f29a(struct f29a A) {
226 // CHECK-LABEL: define{{.*}} void @f29a(double %A.coerce0, i32 %A.coerce1)
229 struct S0 { char f0[8]; char f2; char f3; char f4; };
230 void f30(struct S0 p_4) {
231 // CHECK-LABEL: define{{.*}} void @f30(i64 %p_4.coerce0, i24 %p_4.coerce1)
234 // Pass the third element as a float when followed by tail padding.
235 struct f31foo { float a, b, c; };
236 float f31(struct f31foo X) {
237 // CHECK-LABEL: define{{.*}} float @f31(<2 x float> %X.coerce0, float %X.coerce1)
238 return X.c;
241 _Complex float f32(_Complex float A, _Complex float B) {
242 // CHECK-LABEL: define{{.*}} <2 x float> @f32(<2 x float> noundef %A.coerce, <2 x float> noundef %B.coerce)
243 return A+B;
246 struct f33s { long x; float c,d; };
248 void f33(va_list X) {
249 va_arg(X, struct f33s);
252 typedef unsigned long long v1i64 __attribute__((__vector_size__(8)));
254 // CHECK-LABEL: define{{.*}} double @f34(double noundef %arg.coerce)
255 v1i64 f34(v1i64 arg) { return arg; }
257 // CHECK-LABEL: define{{.*}} double @f35(double noundef %arg.coerce)
258 typedef unsigned long v1i64_2 __attribute__((__vector_size__(8)));
259 v1i64_2 f35(v1i64_2 arg) { return arg+arg; }
261 // CHECK: declare void @func(ptr noundef byval(%struct._str) align 16)
262 typedef struct _str {
263 union {
264 long double a;
265 long c;
267 } str;
269 void func(str s);
270 str ss;
271 void f9122143(void)
273 func(ss);
276 // CHECK-LABEL: define{{.*}} double @f36(double noundef %arg.coerce)
277 typedef unsigned v2i32 __attribute((__vector_size__(8)));
278 v2i32 f36(v2i32 arg) { return arg; }
280 // AVX: declare void @f38(<8 x float>)
281 // AVX: declare void @f37(<8 x float> noundef)
282 // SSE: declare void @f38(ptr noundef byval(%struct.s256) align 32)
283 // SSE: declare void @f37(ptr noundef byval(<8 x float>) align 32)
284 typedef float __m256 __attribute__ ((__vector_size__ (32)));
285 typedef struct {
286 __m256 m;
287 } s256;
289 s256 x38;
290 __m256 x37;
292 void f38(s256 x);
293 void f37(__m256 x);
294 void f39(void) { f38(x38); f37(x37); }
296 // The two next tests make sure that the struct below is passed
297 // in the same way regardless of avx being used
299 // CHECK: declare void @func40(ptr noundef byval(%struct.t128) align 16)
300 typedef float __m128 __attribute__ ((__vector_size__ (16)));
301 typedef struct t128 {
302 __m128 m;
303 __m128 n;
304 } two128;
306 extern void func40(two128 s);
307 void func41(two128 s) {
308 func40(s);
311 // CHECK: declare void @func42(ptr noundef byval(%struct.t128_2) align 16)
312 typedef struct xxx {
313 __m128 array[2];
314 } Atwo128;
315 typedef struct t128_2 {
316 Atwo128 x;
317 } SA;
319 extern void func42(SA s);
320 void func43(SA s) {
321 func42(s);
324 // CHECK-LABEL: define{{.*}} i32 @f44
325 // CHECK: getelementptr inbounds i8, ptr %{{.+}}, i32 31
326 // CHECK-NEXT: call ptr @llvm.ptrmask.p0.i64(ptr %{{[0-9]+}}, i64 -32)
327 typedef int T44 __attribute((vector_size(32)));
328 struct s44 { T44 x; int y; };
329 int f44(int i, ...) {
330 __builtin_va_list ap;
331 __builtin_va_start(ap, i);
332 struct s44 s = __builtin_va_arg(ap, struct s44);
333 __builtin_va_end(ap);
334 return s.y;
337 // Text that vec3 returns the correct LLVM IR type.
338 // AVX-LABEL: define{{.*}} i32 @foo(<3 x i64> noundef %X)
339 typedef long long3 __attribute((ext_vector_type(3)));
340 int foo(long3 X)
342 return 0;
345 // Make sure we don't use a varargs convention for a function without a
346 // prototype where AVX types are involved.
347 // AVX: @test45
348 // AVX: call i32 @f45
349 int f45();
350 __m256 x45;
351 void test45(void) { f45(x45); }
353 // Make sure we use byval to pass 64-bit vectors in memory; the LLVM call
354 // lowering can't handle this case correctly because it runs after legalization.
355 // CHECK: @test46
356 // CHECK: call void @f46({{.*}}ptr noundef byval(<2 x float>) align 8 {{.*}}, ptr noundef byval(<2 x float>) align 8 {{.*}})
357 typedef float v46 __attribute((vector_size(8)));
358 void f46(v46,v46,v46,v46,v46,v46,v46,v46,v46,v46);
359 void test46(void) { v46 x = {1,2}; f46(x,x,x,x,x,x,x,x,x,x); }
361 // Check that we pass the struct below without using byval, which helps out
362 // codegen.
364 // CHECK: @test47
365 // CHECK: call void @f47(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}})
366 struct s47 { unsigned a; };
367 void f47(int,int,int,int,int,int,struct s47);
368 void test47(int a, struct s47 b) { f47(a, a, a, a, a, a, b); }
370 // In the following example, there are holes in T4 at the 3rd byte and the 4th
371 // byte, however, T2 does not have those holes. T4 is chosen to be the
372 // representing type for union T1, but we can't use load or store of T4 since
373 // it will skip the 3rd byte and the 4th byte.
374 // In general, Since we don't accurately represent the data fields of a union,
375 // do not use load or store of the representing llvm type for the union.
376 typedef _Complex int T2;
377 typedef _Complex char T5;
378 typedef _Complex int T7;
379 typedef struct T4 { T5 field0; T7 field1; } T4;
380 typedef union T1 { T2 field0; T4 field1; } T1;
381 extern T1 T1_retval;
382 T1 test48(void) {
383 // CHECK: @test48
384 // CHECK: memcpy
385 // CHECK: memcpy
386 return T1_retval;
389 void test49_helper(double, ...);
390 void test49(double d, double e) {
391 test49_helper(d, e);
393 // CHECK-LABEL: define{{.*}} void @test49(
394 // CHECK: [[T0:%.*]] = load double, ptr
395 // CHECK-NEXT: [[T1:%.*]] = load double, ptr
396 // CHECK-NEXT: call void (double, ...) @test49_helper(double noundef [[T0]], double noundef [[T1]])
398 void test50_helper();
399 void test50(double d, double e) {
400 test50_helper(d, e);
402 // CHECK-LABEL: define{{.*}} void @test50(
403 // CHECK: [[T0:%.*]] = load double, ptr
404 // CHECK-NEXT: [[T1:%.*]] = load double, ptr
405 // CHECK-NEXT: call void (double, double, ...) @test50_helper(double noundef [[T0]], double noundef [[T1]])
407 struct test51_s { __uint128_t intval; };
408 void test51(struct test51_s *s, __builtin_va_list argList) {
409 *s = __builtin_va_arg(argList, struct test51_s);
412 // CHECK-LABEL: define{{.*}} void @test51
413 // CHECK: [[TMP_ADDR:%.*]] = alloca [[STRUCT_TEST51:%.*]], align 16
414 // CHECK: br i1
415 // CHECK: [[REG_SAVE_AREA_PTR:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 3
416 // CHECK-NEXT: [[REG_SAVE_AREA:%.*]] = load ptr, ptr [[REG_SAVE_AREA_PTR]]
417 // CHECK-NEXT: [[VALUE_ADDR:%.*]] = getelementptr i8, ptr [[REG_SAVE_AREA]], i32 {{.*}}
418 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 16 [[TMP_ADDR]], ptr align 8 [[VALUE_ADDR]], i64 16, i1 false)
419 // CHECK-NEXT: add i32 {{.*}}, 16
420 // CHECK-NEXT: store i32 {{.*}}, ptr {{.*}}
421 // CHECK-NEXT: br label
423 void test52_helper(int, ...);
424 __m256 x52;
425 void test52(void) {
426 test52_helper(0, x52, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0i);
428 // AVX: @test52_helper(i32 noundef 0, <8 x float> noundef {{%[a-zA-Z0-9]+}}, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef {{%[a-zA-Z0-9]+}}, double noundef {{%[a-zA-Z0-9]+}})
430 void test53(__m256 *m, __builtin_va_list argList) {
431 *m = __builtin_va_arg(argList, __m256);
433 // AVX-LABEL: define{{.*}} void @test53
434 // AVX-NOT: br i1
435 // AVX: ret void
437 void test54_helper(__m256, ...);
438 __m256 x54;
439 void test54(void) {
440 test54_helper(x54, x54, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0i);
441 test54_helper(x54, x54, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0i);
443 // AVX: @test54_helper(<8 x float> noundef {{%[a-zA-Z0-9]+}}, <8 x float> noundef {{%[a-zA-Z0-9]+}}, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef {{%[a-zA-Z0-9]+}}, double noundef {{%[a-zA-Z0-9]+}})
444 // AVX: @test54_helper(<8 x float> noundef {{%[a-zA-Z0-9]+}}, <8 x float> noundef {{%[a-zA-Z0-9]+}}, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, ptr noundef byval({ double, double }) align 8 {{%[^)]+}})
446 typedef float __m512 __attribute__ ((__vector_size__ (64)));
447 typedef struct {
448 __m512 m;
449 } s512;
451 s512 x55;
452 __m512 x56;
454 // On AVX512, aggregates which contain a __m512 type are classified as SSE/SSEUP
455 // as per https://github.com/hjl-tools/x86-psABI/commit/30f9c9 3.2.3p2 Rule 1
457 // AVX512: declare void @f55(<16 x float>)
458 // NO-AVX512: declare void @f55(ptr noundef byval(%struct.s512) align 64)
459 void f55(s512 x);
461 // __m512 has type SSE/SSEUP on AVX512.
463 // AVX512: declare void @f56(<16 x float> noundef)
464 // NO-AVX512: declare void @f56(ptr noundef byval(<16 x float>) align 64)
465 void f56(__m512 x);
466 void f57(void) { f55(x55); f56(x56); }
468 // Like for __m128 on AVX, check that the struct below is passed
469 // in the same way regardless of AVX512 being used.
471 // CHECK: declare void @f58(ptr noundef byval(%struct.t256) align 32)
472 typedef struct t256 {
473 __m256 m;
474 __m256 n;
475 } two256;
477 extern void f58(two256 s);
478 void f59(two256 s) {
479 f58(s);
482 // CHECK: declare void @f60(ptr noundef byval(%struct.sat256) align 32)
483 typedef struct at256 {
484 __m256 array[2];
485 } Atwo256;
486 typedef struct sat256 {
487 Atwo256 x;
488 } SAtwo256;
490 extern void f60(SAtwo256 s);
491 void f61(SAtwo256 s) {
492 f60(s);
495 // AVX512: @f62_helper(i32 noundef 0, <16 x float> noundef {{%[a-zA-Z0-9]+}}, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef {{%[a-zA-Z0-9]+}}, double noundef {{%[a-zA-Z0-9]+}})
496 void f62_helper(int, ...);
497 __m512 x62;
498 void f62(void) {
499 f62_helper(0, x62, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0i);
502 // Like for __m256 on AVX, we always pass __m512 in memory, and don't
503 // need to use the register save area.
505 // AVX512-LABEL: define{{.*}} void @f63
506 // AVX512-NOT: br i1
507 // AVX512: ret void
508 void f63(__m512 *m, __builtin_va_list argList) {
509 *m = __builtin_va_arg(argList, __m512);
512 // AVX512: @f64_helper(<16 x float> noundef {{%[a-zA-Z0-9]+}}, <16 x float> noundef {{%[a-zA-Z0-9]+}}, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef {{%[a-zA-Z0-9]+}}, double noundef {{%[a-zA-Z0-9]+}})
513 // AVX512: @f64_helper(<16 x float> noundef {{%[a-zA-Z0-9]+}}, <16 x float> noundef {{%[a-zA-Z0-9]+}}, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, double noundef 1.000000e+00, ptr noundef byval({ double, double }) align 8 {{%[^)]+}})
514 void f64_helper(__m512, ...);
515 __m512 x64;
516 void f64(void) {
517 f64_helper(x64, x64, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0i);
518 f64_helper(x64, x64, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0i);
521 struct t65 {
522 __m256 m;
523 int : 0;
525 // SSE-LABEL: @f65(ptr noundef byval(%struct.t65) align 32 %{{[^,)]+}})
526 // AVX: @f65(<8 x float> %{{[^,)]+}})
527 void f65(struct t65 a0) {
530 typedef float t66 __attribute__((__vector_size__(128), __aligned__(128)));
532 // AVX512: @f66(ptr noundef byval(<32 x float>) align 128 %0)
533 void f66(t66 a0) {
536 typedef long long t67 __attribute__((aligned (4)));
537 struct s67 {
538 int a;
539 t67 b;
541 // CHECK-LABEL: define{{.*}} void @f67(ptr noundef byval(%struct.s67) align 8 %x)
542 void f67(struct s67 x) {
545 typedef double t68 __attribute__((aligned (4)));
546 struct s68 {
547 int a;
548 t68 b;
550 // CHECK-LABEL: define{{.*}} void @f68(ptr noundef byval(%struct.s68) align 8 %x)
551 void f68(struct s68 x) {
554 /// The synthesized __va_list_tag does not have file/line fields.
555 // CHECK: = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__va_list_tag",
556 // CHECK-NOT: file:
557 // CHECK-NOT: line:
558 // CHECK-SAME: size: