// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 // REQUIRES: hexagon-registered-target // RUN: %clang_cc1 -emit-llvm -triple hexagon-unknown-linux-musl %s -o - | FileCheck %s #include struct AAA { int x; int y; int z; int d; }; struct AAA aaa = {100, 200, 300, 400}; // CHECK-LABEL: define dso_local i32 @foo( // CHECK-SAME: i32 noundef [[XX:%.*]], ...) #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[XX_ADDR:%.*]] = alloca i32, align 4 // CHECK-NEXT: [[AP:%.*]] = alloca [1 x [[STRUCT___VA_LIST_TAG:%.*]]], align 8 // CHECK-NEXT: [[D:%.*]] = alloca i32, align 4 // CHECK-NEXT: [[RET:%.*]] = alloca i32, align 4 // CHECK-NEXT: [[BBB:%.*]] = alloca [[STRUCT_AAA:%.*]], align 4 // CHECK-NEXT: store i32 [[XX]], ptr [[XX_ADDR]], align 4 // CHECK-NEXT: store i32 0, ptr [[RET]], align 4 // CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x [[STRUCT___VA_LIST_TAG]]], ptr [[AP]], i32 0, i32 0 // CHECK-NEXT: call void @llvm.va_start.p0(ptr [[ARRAYDECAY]]) // CHECK-NEXT: [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x [[STRUCT___VA_LIST_TAG]]], ptr [[AP]], i32 0, i32 0 // CHECK-NEXT: br label %[[VAARG_MAYBE_REG:.*]] // CHECK: [[VAARG_MAYBE_REG]]: // CHECK-NEXT: [[__CURRENT_SAVED_REG_AREA_POINTER_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 0 // CHECK-NEXT: [[__CURRENT_SAVED_REG_AREA_POINTER:%.*]] = load ptr, ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P]], align 8 // CHECK-NEXT: [[__SAVED_REG_AREA_END_POINTER_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 1 // CHECK-NEXT: [[__SAVED_REG_AREA_END_POINTER:%.*]] = load ptr, ptr [[__SAVED_REG_AREA_END_POINTER_P]], align 4 // CHECK-NEXT: [[__NEW_SAVED_REG_AREA_POINTER:%.*]] = getelementptr i8, ptr [[__CURRENT_SAVED_REG_AREA_POINTER]], i32 4 // CHECK-NEXT: [[TMP0:%.*]] = icmp sgt ptr [[__NEW_SAVED_REG_AREA_POINTER]], [[__SAVED_REG_AREA_END_POINTER]] // CHECK-NEXT: br i1 [[TMP0]], label %[[VAARG_ON_STACK:.*]], label %[[VAARG_IN_REG:.*]] // CHECK: [[VAARG_IN_REG]]: // CHECK-NEXT: store ptr [[__NEW_SAVED_REG_AREA_POINTER]], ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P]], align 8 // CHECK-NEXT: br label %[[VAARG_END:.*]] // CHECK: [[VAARG_ON_STACK]]: // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 2 // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER:%.*]] = load ptr, ptr [[__OVERFLOW_AREA_POINTER_P]], align 8 // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_NEXT:%.*]] = getelementptr i8, ptr [[__OVERFLOW_AREA_POINTER]], i32 4 // CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT]], ptr [[__OVERFLOW_AREA_POINTER_P]], align 8 // CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT]], ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P]], align 8 // CHECK-NEXT: br label %[[VAARG_END]] // CHECK: [[VAARG_END]]: // CHECK-NEXT: [[VAARG_ADDR:%.*]] = phi ptr [ [[__CURRENT_SAVED_REG_AREA_POINTER]], %[[VAARG_IN_REG]] ], [ [[__OVERFLOW_AREA_POINTER]], %[[VAARG_ON_STACK]] ] // CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[VAARG_ADDR]], align 4 // CHECK-NEXT: store i32 [[TMP1]], ptr [[D]], align 4 // CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[D]], align 4 // CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[RET]], align 4 // CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP3]], [[TMP2]] // CHECK-NEXT: store i32 [[ADD]], ptr [[RET]], align 4 // CHECK-NEXT: [[ARRAYDECAY2:%.*]] = getelementptr inbounds [1 x [[STRUCT___VA_LIST_TAG]]], ptr [[AP]], i32 0, i32 0 // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_P3:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY2]], i32 0, i32 2 // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER4:%.*]] = load ptr, ptr [[__OVERFLOW_AREA_POINTER_P3]], align 8 // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_NEXT5:%.*]] = getelementptr i8, ptr [[__OVERFLOW_AREA_POINTER4]], i32 16 // CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT5]], ptr [[__OVERFLOW_AREA_POINTER_P3]], align 8 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[BBB]], ptr align 4 [[__OVERFLOW_AREA_POINTER4]], i32 16, i1 false) // CHECK-NEXT: [[D6:%.*]] = getelementptr inbounds nuw [[STRUCT_AAA]], ptr [[BBB]], i32 0, i32 3 // CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[D6]], align 4 // CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[RET]], align 4 // CHECK-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP5]], [[TMP4]] // CHECK-NEXT: store i32 [[ADD7]], ptr [[RET]], align 4 // CHECK-NEXT: [[ARRAYDECAY8:%.*]] = getelementptr inbounds [1 x [[STRUCT___VA_LIST_TAG]]], ptr [[AP]], i32 0, i32 0 // CHECK-NEXT: br label %[[VAARG_MAYBE_REG9:.*]] // CHECK: [[VAARG_MAYBE_REG9]]: // CHECK-NEXT: [[__CURRENT_SAVED_REG_AREA_POINTER_P10:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY8]], i32 0, i32 0 // CHECK-NEXT: [[__CURRENT_SAVED_REG_AREA_POINTER11:%.*]] = load ptr, ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P10]], align 8 // CHECK-NEXT: [[__SAVED_REG_AREA_END_POINTER_P12:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY8]], i32 0, i32 1 // CHECK-NEXT: [[__SAVED_REG_AREA_END_POINTER13:%.*]] = load ptr, ptr [[__SAVED_REG_AREA_END_POINTER_P12]], align 4 // CHECK-NEXT: [[__NEW_SAVED_REG_AREA_POINTER14:%.*]] = getelementptr i8, ptr [[__CURRENT_SAVED_REG_AREA_POINTER11]], i32 4 // CHECK-NEXT: [[TMP6:%.*]] = icmp sgt ptr [[__NEW_SAVED_REG_AREA_POINTER14]], [[__SAVED_REG_AREA_END_POINTER13]] // CHECK-NEXT: br i1 [[TMP6]], label %[[VAARG_ON_STACK16:.*]], label %[[VAARG_IN_REG15:.*]] // CHECK: [[VAARG_IN_REG15]]: // CHECK-NEXT: store ptr [[__NEW_SAVED_REG_AREA_POINTER14]], ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P10]], align 8 // CHECK-NEXT: br label %[[VAARG_END20:.*]] // CHECK: [[VAARG_ON_STACK16]]: // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_P17:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY8]], i32 0, i32 2 // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER18:%.*]] = load ptr, ptr [[__OVERFLOW_AREA_POINTER_P17]], align 8 // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_NEXT19:%.*]] = getelementptr i8, ptr [[__OVERFLOW_AREA_POINTER18]], i32 4 // CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT19]], ptr [[__OVERFLOW_AREA_POINTER_P17]], align 8 // CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT19]], ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P10]], align 8 // CHECK-NEXT: br label %[[VAARG_END20]] // CHECK: [[VAARG_END20]]: // CHECK-NEXT: [[VAARG_ADDR21:%.*]] = phi ptr [ [[__CURRENT_SAVED_REG_AREA_POINTER11]], %[[VAARG_IN_REG15]] ], [ [[__OVERFLOW_AREA_POINTER18]], %[[VAARG_ON_STACK16]] ] // CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[VAARG_ADDR21]], align 4 // CHECK-NEXT: store i32 [[TMP7]], ptr [[D]], align 4 // CHECK-NEXT: [[TMP8:%.*]] = load i32, ptr [[D]], align 4 // CHECK-NEXT: [[TMP9:%.*]] = load i32, ptr [[RET]], align 4 // CHECK-NEXT: [[ADD22:%.*]] = add nsw i32 [[TMP9]], [[TMP8]] // CHECK-NEXT: store i32 [[ADD22]], ptr [[RET]], align 4 // CHECK-NEXT: [[ARRAYDECAY23:%.*]] = getelementptr inbounds [1 x [[STRUCT___VA_LIST_TAG]]], ptr [[AP]], i32 0, i32 0 // CHECK-NEXT: call void @llvm.va_end.p0(ptr [[ARRAYDECAY23]]) // CHECK-NEXT: [[TMP10:%.*]] = load i32, ptr [[RET]], align 4 // CHECK-NEXT: ret i32 [[TMP10]] // int foo(int xx, ...) { va_list ap; int d; int ret = 0; struct AAA bbb; va_start(ap, xx); d = va_arg(ap, int); ret += d; bbb = va_arg(ap, struct AAA); ret += bbb.d; d = va_arg(ap, int); ret += d; va_end(ap); return ret; } // CHECK-LABEL: define dso_local i64 @test_align( // CHECK-SAME: ptr noundef [[ARGS:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[ARGS_ADDR:%.*]] = alloca ptr, align 4 // CHECK-NEXT: store ptr [[ARGS]], ptr [[ARGS_ADDR]], align 4 // CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGS_ADDR]], align 4 // CHECK-NEXT: br label %[[VAARG_MAYBE_REG:.*]] // CHECK: [[VAARG_MAYBE_REG]]: // CHECK-NEXT: [[__CURRENT_SAVED_REG_AREA_POINTER_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[TMP0]], i32 0, i32 0 // CHECK-NEXT: [[__CURRENT_SAVED_REG_AREA_POINTER:%.*]] = load ptr, ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P]], align 4 // CHECK-NEXT: [[__SAVED_REG_AREA_END_POINTER_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[TMP0]], i32 0, i32 1 // CHECK-NEXT: [[__SAVED_REG_AREA_END_POINTER:%.*]] = load ptr, ptr [[__SAVED_REG_AREA_END_POINTER_P]], align 4 // CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[__CURRENT_SAVED_REG_AREA_POINTER]] to i32 // CHECK-NEXT: [[ALIGN_CURRENT_SAVED_REG_AREA_POINTER:%.*]] = add i32 [[TMP1]], 7 // CHECK-NEXT: [[ALIGN_CURRENT_SAVED_REG_AREA_POINTER1:%.*]] = and i32 [[ALIGN_CURRENT_SAVED_REG_AREA_POINTER]], -8 // CHECK-NEXT: [[ALIGN_CURRENT_SAVED_REG_AREA_POINTER2:%.*]] = inttoptr i32 [[ALIGN_CURRENT_SAVED_REG_AREA_POINTER1]] to ptr // CHECK-NEXT: [[__NEW_SAVED_REG_AREA_POINTER:%.*]] = getelementptr i8, ptr [[ALIGN_CURRENT_SAVED_REG_AREA_POINTER2]], i32 8 // CHECK-NEXT: [[TMP2:%.*]] = icmp sgt ptr [[__NEW_SAVED_REG_AREA_POINTER]], [[__SAVED_REG_AREA_END_POINTER]] // CHECK-NEXT: br i1 [[TMP2]], label %[[VAARG_ON_STACK:.*]], label %[[VAARG_IN_REG:.*]] // CHECK: [[VAARG_IN_REG]]: // CHECK-NEXT: store ptr [[__NEW_SAVED_REG_AREA_POINTER]], ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P]], align 4 // CHECK-NEXT: br label %[[VAARG_END:.*]] // CHECK: [[VAARG_ON_STACK]]: // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[TMP0]], i32 0, i32 2 // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER:%.*]] = load ptr, ptr [[__OVERFLOW_AREA_POINTER_P]], align 4 // CHECK-NEXT: [[TMP3:%.*]] = ptrtoint ptr [[__OVERFLOW_AREA_POINTER]] to i32 // CHECK-NEXT: [[ALIGN_OVERFLOW_AREA_POINTER:%.*]] = add i32 [[TMP3]], 7 // CHECK-NEXT: [[ALIGN_OVERFLOW_AREA_POINTER3:%.*]] = and i32 [[ALIGN_OVERFLOW_AREA_POINTER]], -8 // CHECK-NEXT: [[ALIGN_OVERFLOW_AREA_POINTER4:%.*]] = inttoptr i32 [[ALIGN_OVERFLOW_AREA_POINTER3]] to ptr // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_NEXT:%.*]] = getelementptr i8, ptr [[ALIGN_OVERFLOW_AREA_POINTER4]], i32 8 // CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT]], ptr [[__OVERFLOW_AREA_POINTER_P]], align 4 // CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT]], ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P]], align 4 // CHECK-NEXT: br label %[[VAARG_END]] // CHECK: [[VAARG_END]]: // CHECK-NEXT: [[VAARG_ADDR:%.*]] = phi ptr [ [[ALIGN_CURRENT_SAVED_REG_AREA_POINTER2]], %[[VAARG_IN_REG]] ], [ [[ALIGN_OVERFLOW_AREA_POINTER4]], %[[VAARG_ON_STACK]] ] // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr [[VAARG_ADDR]], align 8 // CHECK-NEXT: ret i64 [[TMP4]] // long long test_align(va_list args) { return va_arg(args, long long); } // Struct > 8 bytes with 8-byte alignment to test EmitVAArgFromMemory alignment. // This triggers the alignment masking code where -(int)Align must use getSigned. struct LargeAligned { long long x; int y; }; // CHECK-LABEL: define dso_local i64 @test_large_aligned_vaarg( // CHECK-SAME: ptr noundef [[ARGS:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[ARGS_ADDR:%.*]] = alloca ptr, align 4 // CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_LARGEALIGNED:%.*]], align 8 // CHECK-NEXT: store ptr [[ARGS]], ptr [[ARGS_ADDR]], align 4 // CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGS_ADDR]], align 4 // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[TMP0]], i32 0, i32 2 // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER:%.*]] = load ptr, ptr [[__OVERFLOW_AREA_POINTER_P]], align 4 // CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[__OVERFLOW_AREA_POINTER]], i64 7 // CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[TMP1]] to i32 // The mask must be -8 (0xFFFFFFF8), not a large positive number. // CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], -8 // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_ALIGN:%.*]] = inttoptr i32 [[TMP3]] to ptr // CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_NEXT:%.*]] = getelementptr i8, ptr [[__OVERFLOW_AREA_POINTER_ALIGN]], i32 16 // CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT]], ptr [[__OVERFLOW_AREA_POINTER_P]], align 4 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 8 [[S]], ptr align 8 [[__OVERFLOW_AREA_POINTER_ALIGN]], i32 16, i1 false) // CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_LARGEALIGNED]], ptr [[S]], i32 0, i32 0 // CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr [[X]], align 8 // CHECK-NEXT: ret i64 [[TMP4]] // long long test_large_aligned_vaarg(va_list args) { struct LargeAligned s = va_arg(args, struct LargeAligned); return s.x; }