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
9 // CHECK-LABEL: define{{.*}} signext i8 @f0()
14 // CHECK-LABEL: define{{.*}} signext i16 @f1()
19 // CHECK-LABEL: define{{.*}} i32 @f2()
24 // CHECK-LABEL: define{{.*}} float @f3()
29 // CHECK-LABEL: define{{.*}} double @f4()
34 // CHECK-LABEL: define{{.*}} x86_fp80 @f5()
35 long double f5(void) {
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
;
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)
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
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
,
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
,
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)
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
{
117 void f20(struct s20 x
) {}
124 // CHECK-LABEL: define{{.*}} ptr @f21(i64 %S.coerce0, ptr %S.coerce1)
125 const char *f21(struct StringRef S
) { return S
.x
+S
.Ptr
; }
128 typedef __attribute__ ((aligned(16))) struct f22s
{ unsigned long long x
[2]; } L
;
129 void f22(L x
, L y
) { }
131 // CHECK: %x = alloca{{.*}}, align 16
132 // CHECK: %y = alloca{{.*}}, align 16
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
) {
153 // CHECK: define{{.*}} { i64, i32 } @f24(ptr noundef %X, ptr noundef %P2)
156 typedef float v4f32
__attribute__((__vector_size__(16)));
158 // CHECK-LABEL: define{{.*}} <4 x float> @f25(<4 x float> noundef %X)
160 // CHECK: alloca <4 x float>
162 // CHECK: store <4 x float> %X, ptr
164 // CHECK: ret <4 x float>
173 struct foo26
f26(struct foo26
*P
) {
174 // CHECK: define{{.*}} { ptr, ptr } @f26(ptr noundef %P)
179 struct v4f32wrapper
{
183 struct v4f32wrapper
f27(struct v4f32wrapper X
) {
184 // CHECK-LABEL: define{{.*}} <4 x float> @f27(<4 x float> %X.coerce)
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
{
196 struct v8f32wrapper
f27a(struct v8f32wrapper X
) {
197 // AVX-LABEL: define{{.*}} <8 x float> @f27a(<8 x float> %X.coerce)
201 struct v8f32wrapper_wrapper
{
205 struct v8f32wrapper_wrapper
f27b(struct v8f32wrapper_wrapper X
) {
206 // AVX-LABEL: define{{.*}} <8 x float> @f27b(<8 x float> %X.coerce)
214 void f28(struct f28c C
) {
215 // CHECK-LABEL: define{{.*}} void @f28(double %C.coerce0, i32 %C.coerce1)
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)
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)
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
{
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)));
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
{
306 extern void func40(two128 s
);
307 void func41(two128 s
) {
311 // CHECK: declare void @func42(ptr noundef byval(%struct.t128_2) align 16)
315 typedef struct t128_2
{
319 extern void func42(SA 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
);
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)));
345 // Make sure we don't use a varargs convention for a function without a
346 // prototype where AVX types are involved.
348 // AVX: call i32 @f45
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.
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
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
;
389 void test49_helper(double, ...);
390 void test49(double d
, double 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
) {
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
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, ...);
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
437 void test54_helper(__m256
, ...);
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)));
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)
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)
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
{
477 extern void f58(two256 s
);
482 // CHECK: declare void @f60(ptr noundef byval(%struct.sat256) align 32)
483 typedef struct at256
{
486 typedef struct sat256
{
490 extern void f60(SAtwo256 s
);
491 void f61(SAtwo256 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, ...);
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
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
, ...);
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
);
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)
536 typedef long long t67
__attribute__((aligned (4)));
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)));
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",