480 lines · c
1// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py2// REQUIRES: webassembly-registered-target3// RUN: %clang_cc1 -triple wasm32-unknown-unknown -emit-llvm -o - %s | FileCheck %s4 5// Multiple targets use emitVoidPtrVAArg to lower va_arg instructions in clang6// PPC is complicated, excluding from this case analysis7// ForceRightAdjust is false for all non-PPC targets8// AllowHigherAlign is only false for two Microsoft targets, both of which9// pass most things by reference.10//11// Address emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr,12// QualType ValueTy, bool IsIndirect,13// TypeInfoChars ValueInfo, CharUnits SlotSizeAndAlign,14// bool AllowHigherAlign, bool ForceRightAdjust =15// false);16//17// Target IsIndirect SlotSize AllowHigher ForceRightAdjust18// ARC false four true false19// ARM varies four true false20// Mips false 4 or 8 true false21// RISCV varies register true false22// PPC elided23// LoongArch varies register true false24// NVPTX WIP25// AMDGPU WIP26// X86_32 false four true false27// X86_64 MS varies eight false false28// CSKY false four true false29// Webassembly varies four true false30// AArch64 false eight true false31// AArch64 MS false eight false false32//33// Webassembly passes indirectly iff it's an aggregate of multiple values34// Choosing this as a representative architecture to check IR generation35// partly because it has a relatively simple variadic calling convention.36 37// Int, by itself and packed in structs38// CHECK-LABEL: @raw_int(39// CHECK-NEXT: entry:40// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 441// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 442// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 443// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 444// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 445// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARGP_CUR]], align 446// CHECK-NEXT: ret i32 [[TMP0]]47//48int raw_int(__builtin_va_list list) { return __builtin_va_arg(list, int); }49 50typedef struct {51 int x;52} one_int_t;53 54// CHECK-LABEL: @one_int(55// CHECK-NEXT: entry:56// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_ONE_INT_T:%.*]], align 457// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 458// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 459// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 460// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 461// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 462// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[RETVAL]], ptr align 4 [[ARGP_CUR]], i32 4, i1 false)63// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_ONE_INT_T]], ptr [[RETVAL]], i32 0, i32 064// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[COERCE_DIVE]], align 465// CHECK-NEXT: ret i32 [[TMP0]]66//67one_int_t one_int(__builtin_va_list list) {68 return __builtin_va_arg(list, one_int_t);69}70 71typedef struct {72 int x;73 int y;74} two_int_t;75 76// CHECK-LABEL: @two_int(77// CHECK-NEXT: entry:78// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 479// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 480// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 481// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 482// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 483// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGP_CUR]], align 484// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AGG_RESULT:%.*]], ptr align 4 [[TMP0]], i32 8, i1 false)85// CHECK-NEXT: ret void86//87two_int_t two_int(__builtin_va_list list) {88 return __builtin_va_arg(list, two_int_t);89}90 91// Double, by itself and packed in structs92// CHECK-LABEL: @raw_double(93// CHECK-NEXT: entry:94// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 495// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 496// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 497// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 798// CHECK-NEXT: [[ARGP_CUR_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[TMP0]], i32 -8)99// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i32 8100// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4101// CHECK-NEXT: [[TMP1:%.*]] = load double, ptr [[ARGP_CUR_ALIGNED]], align 8102// CHECK-NEXT: ret double [[TMP1]]103//104double raw_double(__builtin_va_list list) {105 return __builtin_va_arg(list, double);106}107 108typedef struct {109 double x;110} one_double_t;111 112// CHECK-LABEL: @one_double(113// CHECK-NEXT: entry:114// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_ONE_DOUBLE_T:%.*]], align 8115// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 4116// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 4117// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4118// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 7119// CHECK-NEXT: [[ARGP_CUR_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[TMP0]], i32 -8)120// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i32 8121// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4122// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 8 [[RETVAL]], ptr align 8 [[ARGP_CUR_ALIGNED]], i32 8, i1 false)123// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_ONE_DOUBLE_T]], ptr [[RETVAL]], i32 0, i32 0124// CHECK-NEXT: [[TMP1:%.*]] = load double, ptr [[COERCE_DIVE]], align 8125// CHECK-NEXT: ret double [[TMP1]]126//127one_double_t one_double(__builtin_va_list list) {128 return __builtin_va_arg(list, one_double_t);129}130 131typedef struct {132 double x;133 double y;134} two_double_t;135 136// CHECK-LABEL: @two_double(137// CHECK-NEXT: entry:138// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 4139// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 4140// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4141// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4142// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4143// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4144// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 8 [[AGG_RESULT:%.*]], ptr align 8 [[TMP0]], i32 16, i1 false)145// CHECK-NEXT: ret void146//147two_double_t two_double(__builtin_va_list list) {148 return __builtin_va_arg(list, two_double_t);149}150 151// Scalar smaller than the slot size (C would promote a short to int)152typedef struct {153 char x;154} one_char_t;155 156// CHECK-LABEL: @one_char(157// CHECK-NEXT: entry:158// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_ONE_CHAR_T:%.*]], align 1159// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 4160// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 4161// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4162// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4163// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4164// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[RETVAL]], ptr align 4 [[ARGP_CUR]], i32 1, i1 false)165// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_ONE_CHAR_T]], ptr [[RETVAL]], i32 0, i32 0166// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[COERCE_DIVE]], align 1167// CHECK-NEXT: ret i8 [[TMP0]]168//169one_char_t one_char(__builtin_va_list list) {170 return __builtin_va_arg(list, one_char_t);171}172 173typedef struct {174 short x;175} one_short_t;176 177// CHECK-LABEL: @one_short(178// CHECK-NEXT: entry:179// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_ONE_SHORT_T:%.*]], align 2180// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 4181// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 4182// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4183// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4184// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4185// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 2 [[RETVAL]], ptr align 4 [[ARGP_CUR]], i32 2, i1 false)186// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_ONE_SHORT_T]], ptr [[RETVAL]], i32 0, i32 0187// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[COERCE_DIVE]], align 2188// CHECK-NEXT: ret i16 [[TMP0]]189//190one_short_t one_short(__builtin_va_list list) {191 return __builtin_va_arg(list, one_short_t);192}193 194// Composite smaller than the slot size195typedef struct {196 _Alignas(2) char x;197 char y;198} char_pair_t;199 200// CHECK-LABEL: @char_pair(201// CHECK-NEXT: entry:202// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 4203// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 4204// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4205// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4206// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4207// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4208// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 2 [[AGG_RESULT:%.*]], ptr align 2 [[TMP0]], i32 2, i1 false)209// CHECK-NEXT: ret void210//211char_pair_t char_pair(__builtin_va_list list) {212 return __builtin_va_arg(list, char_pair_t);213}214 215// Empty struct216typedef struct {217} empty_t;218 219// CHECK-LABEL: @empty(220// CHECK-NEXT: entry:221// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_EMPTY_T:%.*]], align 1222// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 4223// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 4224// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4225// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 0226// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4227// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[RETVAL]], ptr align 4 [[ARGP_CUR]], i32 0, i1 false)228// CHECK-NEXT: ret void229//230empty_t empty(__builtin_va_list list) {231 return __builtin_va_arg(list, empty_t);232}233 234typedef struct {235 empty_t x;236 int y;237} empty_int_t;238 239// CHECK-LABEL: @empty_int(240// CHECK-NEXT: entry:241// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_EMPTY_INT_T:%.*]], align 4242// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 4243// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 4244// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4245// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4246// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4247// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[RETVAL]], ptr align 4 [[ARGP_CUR]], i32 4, i1 false)248// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_EMPTY_INT_T]], ptr [[RETVAL]], i32 0, i32 0249// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[COERCE_DIVE]], align 4250// CHECK-NEXT: ret i32 [[TMP0]]251//252empty_int_t empty_int(__builtin_va_list list) {253 return __builtin_va_arg(list, empty_int_t);254}255 256typedef struct {257 int x;258 empty_t y;259} int_empty_t;260 261// CHECK-LABEL: @int_empty(262// CHECK-NEXT: entry:263// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_INT_EMPTY_T:%.*]], align 4264// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 4265// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 4266// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4267// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4268// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4269// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[RETVAL]], ptr align 4 [[ARGP_CUR]], i32 4, i1 false)270// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_INT_EMPTY_T]], ptr [[RETVAL]], i32 0, i32 0271// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[COERCE_DIVE]], align 4272// CHECK-NEXT: ret i32 [[TMP0]]273//274int_empty_t int_empty(__builtin_va_list list) {275 return __builtin_va_arg(list, int_empty_t);276}277 278// Need multiple va_arg instructions to check the postincrement279// Using types that are passed directly as the indirect handling280// is independent of the alignment handling in emitVoidPtrDirectVAArg.281 282// CHECK-LABEL: @multiple_int(283// CHECK-NEXT: entry:284// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 4285// CHECK-NEXT: [[OUT0_ADDR:%.*]] = alloca ptr, align 4286// CHECK-NEXT: [[OUT1_ADDR:%.*]] = alloca ptr, align 4287// CHECK-NEXT: [[OUT2_ADDR:%.*]] = alloca ptr, align 4288// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 4289// CHECK-NEXT: store ptr [[OUT0:%.*]], ptr [[OUT0_ADDR]], align 4290// CHECK-NEXT: store ptr [[OUT1:%.*]], ptr [[OUT1_ADDR]], align 4291// CHECK-NEXT: store ptr [[OUT2:%.*]], ptr [[OUT2_ADDR]], align 4292// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4293// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4294// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4295// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARGP_CUR]], align 4296// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[OUT0_ADDR]], align 4297// CHECK-NEXT: store i32 [[TMP0]], ptr [[TMP1]], align 4298// CHECK-NEXT: [[ARGP_CUR1:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4299// CHECK-NEXT: [[ARGP_NEXT2:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR1]], i32 4300// CHECK-NEXT: store ptr [[ARGP_NEXT2]], ptr [[LIST_ADDR]], align 4301// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARGP_CUR1]], align 4302// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[OUT1_ADDR]], align 4303// CHECK-NEXT: store i32 [[TMP2]], ptr [[TMP3]], align 4304// CHECK-NEXT: [[ARGP_CUR3:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4305// CHECK-NEXT: [[ARGP_NEXT4:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR3]], i32 4306// CHECK-NEXT: store ptr [[ARGP_NEXT4]], ptr [[LIST_ADDR]], align 4307// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[ARGP_CUR3]], align 4308// CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[OUT2_ADDR]], align 4309// CHECK-NEXT: store i32 [[TMP4]], ptr [[TMP5]], align 4310// CHECK-NEXT: ret void311//312void multiple_int(__builtin_va_list list, int *out0, int *out1, int *out2) {313 *out0 = __builtin_va_arg(list, int);314 *out1 = __builtin_va_arg(list, int);315 *out2 = __builtin_va_arg(list, int);316}317 318// Scalars in structs are an easy way of specifying alignment from C319// CHECK-LABEL: @increasing_alignment(320// CHECK-NEXT: entry:321// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 4322// CHECK-NEXT: [[OUT0_ADDR:%.*]] = alloca ptr, align 4323// CHECK-NEXT: [[OUT1_ADDR:%.*]] = alloca ptr, align 4324// CHECK-NEXT: [[OUT2_ADDR:%.*]] = alloca ptr, align 4325// CHECK-NEXT: [[OUT3_ADDR:%.*]] = alloca ptr, align 4326// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 4327// CHECK-NEXT: store ptr [[OUT0:%.*]], ptr [[OUT0_ADDR]], align 4328// CHECK-NEXT: store ptr [[OUT1:%.*]], ptr [[OUT1_ADDR]], align 4329// CHECK-NEXT: store ptr [[OUT2:%.*]], ptr [[OUT2_ADDR]], align 4330// CHECK-NEXT: store ptr [[OUT3:%.*]], ptr [[OUT3_ADDR]], align 4331// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[OUT0_ADDR]], align 4332// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4333// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4334// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4335// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[TMP0]], ptr align 4 [[ARGP_CUR]], i32 1, i1 false)336// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[OUT1_ADDR]], align 4337// CHECK-NEXT: [[ARGP_CUR1:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4338// CHECK-NEXT: [[ARGP_NEXT2:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR1]], i32 4339// CHECK-NEXT: store ptr [[ARGP_NEXT2]], ptr [[LIST_ADDR]], align 4340// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 2 [[TMP1]], ptr align 4 [[ARGP_CUR1]], i32 2, i1 false)341// CHECK-NEXT: [[ARGP_CUR3:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4342// CHECK-NEXT: [[ARGP_NEXT4:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR3]], i32 4343// CHECK-NEXT: store ptr [[ARGP_NEXT4]], ptr [[LIST_ADDR]], align 4344// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARGP_CUR3]], align 4345// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[OUT2_ADDR]], align 4346// CHECK-NEXT: store i32 [[TMP2]], ptr [[TMP3]], align 4347// CHECK-NEXT: [[ARGP_CUR5:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4348// CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR5]], i32 7349// CHECK-NEXT: [[ARGP_CUR5_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[TMP4]], i32 -8)350// CHECK-NEXT: [[ARGP_NEXT6:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR5_ALIGNED]], i32 8351// CHECK-NEXT: store ptr [[ARGP_NEXT6]], ptr [[LIST_ADDR]], align 4352// CHECK-NEXT: [[TMP5:%.*]] = load double, ptr [[ARGP_CUR5_ALIGNED]], align 8353// CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr [[OUT3_ADDR]], align 4354// CHECK-NEXT: store double [[TMP5]], ptr [[TMP6]], align 8355// CHECK-NEXT: ret void356//357void increasing_alignment(__builtin_va_list list, one_char_t *out0,358 one_short_t *out1, int *out2, double *out3) {359 *out0 = __builtin_va_arg(list, one_char_t);360 *out1 = __builtin_va_arg(list, one_short_t);361 *out2 = __builtin_va_arg(list, int);362 *out3 = __builtin_va_arg(list, double);363}364 365// CHECK-LABEL: @decreasing_alignment(366// CHECK-NEXT: entry:367// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 4368// CHECK-NEXT: [[OUT0_ADDR:%.*]] = alloca ptr, align 4369// CHECK-NEXT: [[OUT1_ADDR:%.*]] = alloca ptr, align 4370// CHECK-NEXT: [[OUT2_ADDR:%.*]] = alloca ptr, align 4371// CHECK-NEXT: [[OUT3_ADDR:%.*]] = alloca ptr, align 4372// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 4373// CHECK-NEXT: store ptr [[OUT0:%.*]], ptr [[OUT0_ADDR]], align 4374// CHECK-NEXT: store ptr [[OUT1:%.*]], ptr [[OUT1_ADDR]], align 4375// CHECK-NEXT: store ptr [[OUT2:%.*]], ptr [[OUT2_ADDR]], align 4376// CHECK-NEXT: store ptr [[OUT3:%.*]], ptr [[OUT3_ADDR]], align 4377// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4378// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 7379// CHECK-NEXT: [[ARGP_CUR_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[TMP0]], i32 -8)380// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i32 8381// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4382// CHECK-NEXT: [[TMP1:%.*]] = load double, ptr [[ARGP_CUR_ALIGNED]], align 8383// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[OUT0_ADDR]], align 4384// CHECK-NEXT: store double [[TMP1]], ptr [[TMP2]], align 8385// CHECK-NEXT: [[ARGP_CUR1:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4386// CHECK-NEXT: [[ARGP_NEXT2:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR1]], i32 4387// CHECK-NEXT: store ptr [[ARGP_NEXT2]], ptr [[LIST_ADDR]], align 4388// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ARGP_CUR1]], align 4389// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[OUT1_ADDR]], align 4390// CHECK-NEXT: store i32 [[TMP3]], ptr [[TMP4]], align 4391// CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[OUT2_ADDR]], align 4392// CHECK-NEXT: [[ARGP_CUR3:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4393// CHECK-NEXT: [[ARGP_NEXT4:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR3]], i32 4394// CHECK-NEXT: store ptr [[ARGP_NEXT4]], ptr [[LIST_ADDR]], align 4395// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 2 [[TMP5]], ptr align 4 [[ARGP_CUR3]], i32 2, i1 false)396// CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr [[OUT3_ADDR]], align 4397// CHECK-NEXT: [[ARGP_CUR5:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4398// CHECK-NEXT: [[ARGP_NEXT6:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR5]], i32 4399// CHECK-NEXT: store ptr [[ARGP_NEXT6]], ptr [[LIST_ADDR]], align 4400// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[TMP6]], ptr align 4 [[ARGP_CUR5]], i32 1, i1 false)401// CHECK-NEXT: ret void402//403void decreasing_alignment(__builtin_va_list list, double *out0, int *out1,404 one_short_t *out2, one_char_t *out3) {405 *out0 = __builtin_va_arg(list, double);406 *out1 = __builtin_va_arg(list, int);407 *out2 = __builtin_va_arg(list, one_short_t);408 *out3 = __builtin_va_arg(list, one_char_t);409}410 411// Typical edge cases, none hit special handling in VAArg lowering.412typedef struct {413 int x[16];414 double y[8];415} large_value_t;416 417// CHECK-LABEL: @large_value(418// CHECK-NEXT: entry:419// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 4420// CHECK-NEXT: [[OUT_ADDR:%.*]] = alloca ptr, align 4421// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 4422// CHECK-NEXT: store ptr [[OUT:%.*]], ptr [[OUT_ADDR]], align 4423// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[OUT_ADDR]], align 4424// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4425// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4426// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4427// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4428// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 8 [[TMP0]], ptr align 8 [[TMP1]], i32 128, i1 false)429// CHECK-NEXT: ret void430//431void large_value(__builtin_va_list list, large_value_t *out) {432 *out = __builtin_va_arg(list, large_value_t);433}434 435typedef int v128_t __attribute__((__vector_size__(16), __aligned__(16)));436// CHECK-LABEL: @vector(437// CHECK-NEXT: entry:438// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 4439// CHECK-NEXT: [[OUT_ADDR:%.*]] = alloca ptr, align 4440// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 4441// CHECK-NEXT: store ptr [[OUT:%.*]], ptr [[OUT_ADDR]], align 4442// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4443// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 15444// CHECK-NEXT: [[ARGP_CUR_ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i32(ptr [[TMP0]], i32 -16)445// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i32 16446// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4447// CHECK-NEXT: [[TMP1:%.*]] = load <4 x i32>, ptr [[ARGP_CUR_ALIGNED]], align 16448// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[OUT_ADDR]], align 4449// CHECK-NEXT: store <4 x i32> [[TMP1]], ptr [[TMP2]], align 16450// CHECK-NEXT: ret void451//452void vector(__builtin_va_list list, v128_t *out) {453 *out = __builtin_va_arg(list, v128_t);454}455 456typedef struct BF {457 float not_an_i32[2];458 int A : 1;459 char B;460 int C : 13;461} BF;462 463// CHECK-LABEL: @bitfield(464// CHECK-NEXT: entry:465// CHECK-NEXT: [[LIST_ADDR:%.*]] = alloca ptr, align 4466// CHECK-NEXT: [[OUT_ADDR:%.*]] = alloca ptr, align 4467// CHECK-NEXT: store ptr [[LIST:%.*]], ptr [[LIST_ADDR]], align 4468// CHECK-NEXT: store ptr [[OUT:%.*]], ptr [[OUT_ADDR]], align 4469// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[OUT_ADDR]], align 4470// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[LIST_ADDR]], align 4471// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4472// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[LIST_ADDR]], align 4473// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR]], align 4474// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[TMP0]], ptr align 4 [[TMP1]], i32 12, i1 false)475// CHECK-NEXT: ret void476//477void bitfield(__builtin_va_list list, BF *out) {478 *out = __builtin_va_arg(list, BF);479}480