598 lines · c
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-AVX5123// 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-AVX5125// 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=AVX5127#include <stdarg.h>8 9// CHECK-LABEL: define{{.*}} signext i8 @f0()10char f0(void) {11 return 0;12}13 14// CHECK-LABEL: define{{.*}} signext i16 @f1()15short f1(void) {16 return 0;17}18 19// CHECK-LABEL: define{{.*}} i32 @f2()20int f2(void) {21 return 0;22}23 24// CHECK-LABEL: define{{.*}} float @f3()25float f3(void) {26 return 0;27}28 29// CHECK-LABEL: define{{.*}} double @f4()30double f4(void) {31 return 0;32}33 34// CHECK-LABEL: define{{.*}} x86_fp80 @f5()35long double f5(void) {36 return 0;37}38 39// CHECK-LABEL: define{{.*}} void @f6(i8 noundef signext %a0, i16 noundef signext %a1, i32 noundef %a2, i64 noundef %a3, ptr noundef %a4)40void f6(char a0, short a1, int a2, long long a3, void *a4) {41}42 43// CHECK-LABEL: define{{.*}} void @f7(i32 noundef %a0)44typedef enum { A, B, C } e7;45void f7(e7 a0) {46}47 48// Test merging/passing of upper eightbyte with X87 class.49//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)52union u8 {53 long double a;54 int b;55};56union u8 f8_1(void) { while (1) {} }57void f8_2(union u8 a0) {}58 59// CHECK-LABEL: define{{.*}} i64 @f9()60struct s9 { int a; int b; int : 0; } f9(void) { while (1) {} }61 62// CHECK-LABEL: define{{.*}} void @f10(i64 %a0.coerce)63struct s10 { int a; int b; int : 0; };64void f10(struct s10 a0) {}65 66// CHECK-LABEL: define{{.*}} void @f11(ptr dead_on_unwind noalias writable sret(%union.anon) align 16 %agg.result)67union { long double a; float b; } f11(void) { while (1) {} }68 69// CHECK-LABEL: define{{.*}} i32 @f12_0()70// CHECK-LABEL: define{{.*}} void @f12_1(i32 %a0.coerce)71struct s12 { int a __attribute__((aligned(16))); };72struct s12 f12_0(void) { while (1) {} }73void f12_1(struct s12 a0) {}74 75// Check that sret parameter is accounted for when checking available integer76// 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)78 79struct s13_0 { long long f0[3]; };80struct s13_1 { long long f0[2]; };81struct s13_0 f13(int a, int b, int c, int d,82 struct s13_1 e, int f) { while (1) {} }83 84// CHECK: define{{.*}} void @f14({{.*}}, i8 noundef signext %X)85void f14(int a, int b, int c, int d, int e, int f, char X) {}86 87// CHECK: define{{.*}} void @f15({{.*}}, ptr noundef %X)88void f15(int a, int b, int c, int d, int e, int f, void *X) {}89 90// CHECK: define{{.*}} void @f16({{.*}}, float noundef %X)91void f16(float a, float b, float c, float d, float e, float f, float g, float h,92 float X) {}93 94// CHECK: define{{.*}} void @f17({{.*}}, x86_fp80 noundef %X)95void f17(float a, float b, float c, float d, float e, float f, float g, float h,96 long double X) {}97 98// Check for valid coercion. The struct should be passed/returned as i32, not99// as i64 for better code quality.100// CHECK-LABEL: define{{.*}} void @f18(i32 noundef %a, i32 %f18_arg1.coerce)101struct f18_s0 { int f0; };102void f18(int a, struct f18_s0 f18_arg1) { while (1) {} }103 104// Check byval alignment.105 106// CHECK-LABEL: define{{.*}} void @f19(ptr noundef byval(%struct.s19) align 16 %x)107struct s19 {108 long double a;109};110void f19(struct s19 x) {}111 112// CHECK-LABEL: define{{.*}} void @f20(ptr noundef byval(%struct.s20) align 32 %x)113struct __attribute__((aligned(32))) s20 {114 int x;115 int y;116};117void f20(struct s20 x) {}118 119struct StringRef {120 long x;121 const char *Ptr;122};123 124// CHECK-LABEL: define{{.*}} ptr @f21(i64 %S.coerce0, ptr %S.coerce1)125const char *f21(struct StringRef S) { return S.x+S.Ptr; }126 127// PR7567128typedef __attribute__ ((aligned(16))) struct f22s { unsigned long long x[2]; } L;129void f22(L x, L y) { }130// CHECK: @f22131// CHECK: %x = alloca{{.*}}, align 16132// CHECK: %y = alloca{{.*}}, align 16133 134 135 136// PR7714137struct f23S {138 short f0;139 unsigned f1;140 int f2;141};142 143 144void f23(int A, struct f23S B) {145 // CHECK-LABEL: define{{.*}} void @f23(i32 noundef %A, i64 %B.coerce0, i32 %B.coerce1)146}147 148struct f24s { long a; int b; };149 150struct f23S f24(struct f23S *X, struct f24s *P2) {151 return *X;152 153 // CHECK: define{{.*}} { i64, i32 } @f24(ptr noundef %X, ptr noundef %P2)154}155 156typedef float v4f32 __attribute__((__vector_size__(16)));157v4f32 f25(v4f32 X) {158 // CHECK-LABEL: define{{.*}} <4 x float> @f25(<4 x float> noundef %X)159 // CHECK-NOT: alloca160 // CHECK: alloca <4 x float>161 // CHECK-NOT: alloca162 // CHECK: store <4 x float> %X, ptr163 // CHECK-NOT: store164 // CHECK: ret <4 x float>165 return X+X;166}167 168struct foo26 {169 int *X;170 float *Y;171};172 173struct foo26 f26(struct foo26 *P) {174 // CHECK: define{{.*}} { ptr, ptr } @f26(ptr noundef %P)175 return *P;176}177 178 179struct v4f32wrapper {180 v4f32 v;181};182 183struct v4f32wrapper f27(struct v4f32wrapper X) {184 // CHECK-LABEL: define{{.*}} <4 x float> @f27(<4 x float> %X.coerce)185 return X;186}187 188// PR22563 - We should unwrap simple structs and arrays to pass189// and return them in the appropriate vector registers if possible.190 191typedef float v8f32 __attribute__((__vector_size__(32)));192struct v8f32wrapper {193 v8f32 v;194};195 196struct v8f32wrapper f27a(struct v8f32wrapper X) {197 // AVX-LABEL: define{{.*}} <8 x float> @f27a(<8 x float> %X.coerce)198 return X;199}200 201struct v8f32wrapper_wrapper {202 v8f32 v[1];203};204 205struct v8f32wrapper_wrapper f27b(struct v8f32wrapper_wrapper X) {206 // AVX-LABEL: define{{.*}} <8 x float> @f27b(<8 x float> %X.coerce)207 return X;208}209 210struct f28c {211 double x;212 int y;213};214void f28(struct f28c C) {215 // CHECK-LABEL: define{{.*}} void @f28(double %C.coerce0, i32 %C.coerce1)216}217 218struct f29a {219 struct c {220 double x;221 int y;222 } x[1];223};224 225void f29a(struct f29a A) {226 // CHECK-LABEL: define{{.*}} void @f29a(double %A.coerce0, i32 %A.coerce1)227}228 229struct S0 { char f0[8]; char f2; char f3; char f4; };230void f30(struct S0 p_4) {231 // CHECK-LABEL: define{{.*}} void @f30(i64 %p_4.coerce0, i24 %p_4.coerce1)232}233 234// Pass the third element as a float when followed by tail padding.235struct f31foo { float a, b, c; };236float f31(struct f31foo X) {237 // CHECK-LABEL: define{{.*}} float @f31(<2 x float> %X.coerce0, float %X.coerce1)238 return X.c;239}240 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;244}245 246struct f33s { long x; float c,d; };247 248void f33(va_list X) {249 va_arg(X, struct f33s);250}251 252typedef unsigned long long v1i64 __attribute__((__vector_size__(8)));253 254// CHECK-LABEL: define{{.*}} double @f34(double noundef %arg.coerce)255v1i64 f34(v1i64 arg) { return arg; }256 257// CHECK-LABEL: define{{.*}} double @f35(double noundef %arg.coerce)258typedef unsigned long v1i64_2 __attribute__((__vector_size__(8)));259v1i64_2 f35(v1i64_2 arg) { return arg+arg; }260 261// CHECK: declare void @func(ptr noundef byval(%struct._str) align 16)262typedef struct _str {263 union {264 long double a;265 long c;266 };267} str;268 269void func(str s);270str ss;271void f9122143(void)272{273 func(ss);274}275 276// CHECK-LABEL: define{{.*}} double @f36(double noundef %arg.coerce)277typedef unsigned v2i32 __attribute((__vector_size__(8)));278v2i32 f36(v2i32 arg) { return arg; }279 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)284typedef float __m256 __attribute__ ((__vector_size__ (32)));285typedef struct {286 __m256 m;287} s256;288 289s256 x38;290__m256 x37;291 292void f38(s256 x);293void f37(__m256 x);294void f39(void) { f38(x38); f37(x37); }295 296// The two next tests make sure that the struct below is passed297// in the same way regardless of avx being used298 299// CHECK: declare void @func40(ptr noundef byval(%struct.t128) align 16)300typedef float __m128 __attribute__ ((__vector_size__ (16)));301typedef struct t128 {302 __m128 m;303 __m128 n;304} two128;305 306extern void func40(two128 s);307void func41(two128 s) {308 func40(s);309}310 311// CHECK: declare void @func42(ptr noundef byval(%struct.t128_2) align 16)312typedef struct xxx {313 __m128 array[2];314} Atwo128;315typedef struct t128_2 {316 Atwo128 x;317} SA;318 319extern void func42(SA s);320void func43(SA s) {321 func42(s);322}323 324// CHECK-LABEL: define{{.*}} i32 @f44325// CHECK: getelementptr inbounds i8, ptr %{{.+}}, i32 31326// CHECK-NEXT: call ptr @llvm.ptrmask.p0.i64(ptr %{{[0-9]+}}, i64 -32)327typedef int T44 __attribute((vector_size(32)));328struct s44 { T44 x; int y; };329int 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;335}336 337// Text that vec3 returns the correct LLVM IR type.338// AVX-LABEL: define{{.*}} i32 @foo(<3 x i64> noundef %X)339typedef long long3 __attribute((ext_vector_type(3)));340int foo(long3 X)341{342 return 0;343}344 345// Make sure we don't use a varargs convention for a function without a346// prototype where AVX types are involved.347// AVX: @test45348// AVX: call i32 @f45349int f45();350__m256 x45;351void test45(void) { f45(x45); }352 353// Make sure we use byval to pass 64-bit vectors in memory; the LLVM call354// lowering can't handle this case correctly because it runs after legalization.355// CHECK: @test46356// CHECK: call void @f46({{.*}}ptr noundef byval(<2 x float>) align 8 {{.*}}, ptr noundef byval(<2 x float>) align 8 {{.*}})357typedef float v46 __attribute((vector_size(8)));358void f46(v46,v46,v46,v46,v46,v46,v46,v46,v46,v46);359void test46(void) { v46 x = {1,2}; f46(x,x,x,x,x,x,x,x,x,x); }360 361// Check that we pass the struct below without using byval, which helps out362// codegen.363//364// CHECK: @test47365// CHECK: call void @f47(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}})366struct s47 { unsigned a; };367void f47(int,int,int,int,int,int,struct s47);368void test47(int a, struct s47 b) { f47(a, a, a, a, a, a, b); }369 370// In the following example, there are holes in T4 at the 3rd byte and the 4th371// byte, however, T2 does not have those holes. T4 is chosen to be the372// representing type for union T1, but we can't use load or store of T4 since373// 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.376typedef _Complex int T2;377typedef _Complex char T5;378typedef _Complex int T7;379typedef struct T4 { T5 field0; T7 field1; } T4;380typedef union T1 { T2 field0; T4 field1; } T1;381extern T1 T1_retval;382T1 test48(void) {383// CHECK: @test48384// CHECK: memcpy385// CHECK: memcpy386 return T1_retval;387}388 389void test49_helper(double, ...);390void test49(double d, double e) {391 test49_helper(d, e);392}393// CHECK-LABEL: define{{.*}} void @test49(394// CHECK: [[T0:%.*]] = load double, ptr395// CHECK-NEXT: [[T1:%.*]] = load double, ptr396// CHECK-NEXT: call void (double, ...) @test49_helper(double noundef [[T0]], double noundef [[T1]])397 398void test50_helper();399void test50(double d, double e) {400 test50_helper(d, e);401}402// CHECK-LABEL: define{{.*}} void @test50(403// CHECK: [[T0:%.*]] = load double, ptr404// CHECK-NEXT: [[T1:%.*]] = load double, ptr405// CHECK-NEXT: call void (double, double, ...) @test50_helper(double noundef [[T0]], double noundef [[T1]])406 407struct test51_s { __uint128_t intval; };408void test51(struct test51_s *s, __builtin_va_list argList) {409 *s = __builtin_va_arg(argList, struct test51_s);410}411 412// CHECK-LABEL: define{{.*}} void @test51413// CHECK: [[TMP_ADDR:%.*]] = alloca [[STRUCT_TEST51:%.*]], align 16414// CHECK: br i1415// CHECK: [[REG_SAVE_AREA_PTR:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 3416// 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 {{.*}}, 16420// CHECK-NEXT: store i32 {{.*}}, ptr {{.*}}421// CHECK-NEXT: br label422 423void test52_helper(int, ...);424__m256 x52;425void test52(void) {426 test52_helper(0, x52, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0i);427}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]+}})429 430void test53(__m256 *m, __builtin_va_list argList) {431 *m = __builtin_va_arg(argList, __m256);432}433// AVX-LABEL: define{{.*}} void @test53434// AVX-NOT: br i1435// AVX: ret void436 437void test54_helper(__m256, ...);438__m256 x54;439void 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);442}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 {{%[^)]+}})445 446typedef float __m512 __attribute__ ((__vector_size__ (64)));447typedef struct {448 __m512 m;449} s512;450 451s512 x55;452__m512 x56;453 454// On AVX512, aggregates which contain a __m512 type are classified as SSE/SSEUP455// as per https://github.com/hjl-tools/x86-psABI/commit/30f9c9 3.2.3p2 Rule 1456//457// AVX512: declare void @f55(<16 x float>)458// NO-AVX512: declare void @f55(ptr noundef byval(%struct.s512) align 64)459void f55(s512 x);460 461// __m512 has type SSE/SSEUP on AVX512.462//463// AVX512: declare void @f56(<16 x float> noundef)464// NO-AVX512: declare void @f56(ptr noundef byval(<16 x float>) align 64)465void f56(__m512 x);466void f57(void) { f55(x55); f56(x56); }467 468// Like for __m128 on AVX, check that the struct below is passed469// in the same way regardless of AVX512 being used.470//471// CHECK: declare void @f58(ptr noundef byval(%struct.t256) align 32)472typedef struct t256 {473 __m256 m;474 __m256 n;475} two256;476 477extern void f58(two256 s);478void f59(two256 s) {479 f58(s);480}481 482// CHECK: declare void @f60(ptr noundef byval(%struct.sat256) align 32)483typedef struct at256 {484 __m256 array[2];485} Atwo256;486typedef struct sat256 {487 Atwo256 x;488} SAtwo256;489 490extern void f60(SAtwo256 s);491void f61(SAtwo256 s) {492 f60(s);493}494 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]+}})496void f62_helper(int, ...);497__m512 x62;498void f62(void) {499 f62_helper(0, x62, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0i);500}501 502// Like for __m256 on AVX, we always pass __m512 in memory, and don't503// need to use the register save area.504//505// AVX512-LABEL: define{{.*}} void @f63506// AVX512-NOT: br i1507// AVX512: ret void508void f63(__m512 *m, __builtin_va_list argList) {509 *m = __builtin_va_arg(argList, __m512);510}511 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 {{%[^)]+}})514void f64_helper(__m512, ...);515__m512 x64;516void 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);519}520 521struct t65 {522 __m256 m;523 int : 0;524};525// SSE-LABEL: @f65(ptr noundef byval(%struct.t65) align 32 %{{[^,)]+}})526// AVX: @f65(<8 x float> %{{[^,)]+}})527void f65(struct t65 a0) {528}529 530typedef float t66 __attribute__((__vector_size__(128), __aligned__(128)));531 532// AVX512: @f66(ptr noundef byval(<32 x float>) align 128 %0)533void f66(t66 a0) {534}535 536typedef long long t67 __attribute__((aligned (4)));537struct s67 {538 int a;539 t67 b;540};541// CHECK-LABEL: define{{.*}} void @f67(ptr noundef byval(%struct.s67) align 8 %x)542void f67(struct s67 x) {543}544 545typedef double t68 __attribute__((aligned (4)));546struct s68 {547 int a;548 t68 b;549};550// CHECK-LABEL: define{{.*}} void @f68(ptr noundef byval(%struct.s68) align 8 %x)551void f68(struct s68 x) {552}553 554// CHECK-LABEL: define{{.*}} i128 @f69(i128 noundef %a)555__int128_t f69(__int128_t a) {556 return a;557}558 559// CHECK-LABEL: define{{.*}} i128 @f70(i128 noundef %a)560__uint128_t f70(__uint128_t a) {561 return a;562}563 564// check that registers are correctly counted for (u)int128_t arguments565struct s71 {566 long long a, b;567};568// CHECK-LABEL: define{{.*}} void @f71(i128 noundef %a, i128 noundef %b, i64 noundef %c, ptr noundef byval(%struct.s71) align 8 %d)569void f71(__int128_t a, __int128_t b, long long c, struct s71 d) {570}571// CHECK-LABEL: define{{.*}} void @f72(i128 noundef %a, i128 noundef %b, i64 %d.coerce0, i64 %d.coerce1)572void f72(__int128_t a, __int128_t b, struct s71 d) {573}574 575// check that structs containing (u)int128_t are passed correctly576struct s73 {577 struct inner {578 __uint128_t a;579 };580 struct inner in;581};582// CHECK-LABEL: define{{.*}} i128 @f73(i128 %a.coerce)583struct s73 f73(struct s73 a) {584 return a;585}586 587// check that _BitInt(128) is still passed correctly on the stack588// CHECK-LABEL: define{{.*}} i128 @f74(i128 noundef %b, i128 noundef %c, i128 noundef %d, i64 noundef %e, ptr noundef byval(i128) align 8 %0)589_BitInt(128) f74(__uint128_t b, __uint128_t c, __uint128_t d, long e, _BitInt(128) a) {590 return a;591}592 593/// The synthesized __va_list_tag does not have file/line fields.594// CHECK: = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__va_list_tag",595// CHECK-NOT: file:596// CHECK-NOT: line:597// CHECK-SAME: size:598