1 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 2 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s 3 4 typedef struct { struct {} a; } empty; 5 6 // CHECK-LABEL: @_Z17empty_record_testiz( 7 // CHECK-NEXT: entry: 8 // CHECK-NEXT: [[Z_ADDR:%.*]] = alloca i32, align 4 9 // CHECK-NEXT: [[LIST:%.*]] = alloca [1 x %struct.__va_list_tag], align 16 10 // CHECK-NEXT: store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4 11 // CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0 12 // CHECK-NEXT: call void @llvm.va_start.p0(ptr [[ARRAYDECAY]]) 13 // CHECK-NEXT: [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0 14 // CHECK-NEXT: ret void 15 // 16 empty empty_record_test(int z, ...) { 17 __builtin_va_list list; 18 __builtin_va_start(list, z); 19 return __builtin_va_arg(list, empty); 20 } 21 22 typedef struct { 23 struct{} a; 24 double b; 25 } s1; 26 27 // CHECK-LABEL: @_Z1fiz( 28 // CHECK-NEXT: entry: 29 // CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_S1:%.*]], align 8 30 // CHECK-NEXT: [[Z_ADDR:%.*]] = alloca i32, align 4 31 // CHECK-NEXT: [[LIST:%.*]] = alloca [1 x %struct.__va_list_tag], align 16 32 // CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_S1]], align 8 33 // CHECK-NEXT: store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4 34 // CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0 35 // CHECK-NEXT: call void @llvm.va_start.p0(ptr [[ARRAYDECAY]]) 36 // CHECK-NEXT: [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0 37 // CHECK-NEXT: [[FP_OFFSET_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[ARRAYDECAY1]], i32 0, i32 1 38 // CHECK-NEXT: [[FP_OFFSET:%.*]] = load i32, ptr [[FP_OFFSET_P]], align 4 39 // CHECK-NEXT: [[FITS_IN_FP:%.*]] = icmp ule i32 [[FP_OFFSET]], 160 40 // CHECK-NEXT: br i1 [[FITS_IN_FP]], label [[VAARG_IN_REG:%.*]], label [[VAARG_IN_MEM:%.*]] 41 // CHECK: vaarg.in_reg: 42 // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 3 43 // CHECK-NEXT: [[REG_SAVE_AREA:%.*]] = load ptr, ptr [[TMP0]], align 16 44 // CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[REG_SAVE_AREA]], i32 [[FP_OFFSET]] 45 // CHECK-NEXT: [[TMP2:%.*]] = load double, ptr [[TMP1]], align 8 46 // CHECK-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP]], i32 8 47 // CHECK-NEXT: store double [[TMP2]], ptr [[TMP3]], align 8 48 // CHECK-NEXT: [[TMP4:%.*]] = add i32 [[FP_OFFSET]], 16 49 // CHECK-NEXT: store i32 [[TMP4]], ptr [[FP_OFFSET_P]], align 4 50 // CHECK-NEXT: br label [[VAARG_END:%.*]] 51 // CHECK: vaarg.in_mem: 52 // CHECK-NEXT: [[OVERFLOW_ARG_AREA_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 2 53 // CHECK-NEXT: [[OVERFLOW_ARG_AREA:%.*]] = load ptr, ptr [[OVERFLOW_ARG_AREA_P]], align 8 54 // CHECK-NEXT: [[OVERFLOW_ARG_AREA_NEXT:%.*]] = getelementptr i8, ptr [[OVERFLOW_ARG_AREA]], i32 16 55 // CHECK-NEXT: store ptr [[OVERFLOW_ARG_AREA_NEXT]], ptr [[OVERFLOW_ARG_AREA_P]], align 8 56 // CHECK-NEXT: br label [[VAARG_END]] 57 // CHECK: vaarg.end: 58 // CHECK-NEXT: [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ] 59 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[VAARG_ADDR]], i64 16, i1 false) 60 // CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[RETVAL]], i64 8 61 // CHECK-NEXT: [[TMP6:%.*]] = load double, ptr [[TMP5]], align 8 62 // CHECK-NEXT: ret double [[TMP6]] 63 // 64 s1 f(int z, ...) { 65 __builtin_va_list list; 66 __builtin_va_start(list, z); 67 return __builtin_va_arg(list, s1); 68 } 69 70 typedef struct { 71 struct{} a[5]; 72 float b; 73 float c; 74 } s2; 75 76 // CHECK-LABEL: @_Z2f2iz( 77 // CHECK-NEXT: entry: 78 // CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_S2:%.*]], align 4 79 // CHECK-NEXT: [[Z_ADDR:%.*]] = alloca i32, align 4 80 // CHECK-NEXT: [[LIST:%.*]] = alloca [1 x %struct.__va_list_tag], align 16 81 // CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_S2]], align 4 82 // CHECK-NEXT: store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4 83 // CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0 84 // CHECK-NEXT: call void @llvm.va_start.p0(ptr [[ARRAYDECAY]]) 85 // CHECK-NEXT: [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0 86 // CHECK-NEXT: [[FP_OFFSET_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[ARRAYDECAY1]], i32 0, i32 1 87 // CHECK-NEXT: [[FP_OFFSET:%.*]] = load i32, ptr [[FP_OFFSET_P]], align 4 88 // CHECK-NEXT: [[FITS_IN_FP:%.*]] = icmp ule i32 [[FP_OFFSET]], 160 89 // CHECK-NEXT: br i1 [[FITS_IN_FP]], label [[VAARG_IN_REG:%.*]], label [[VAARG_IN_MEM:%.*]] 90 // CHECK: vaarg.in_reg: 91 // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 3 92 // CHECK-NEXT: [[REG_SAVE_AREA:%.*]] = load ptr, ptr [[TMP0]], align 16 93 // CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[REG_SAVE_AREA]], i32 [[FP_OFFSET]] 94 // CHECK-NEXT: [[TMP2:%.*]] = load <2 x float>, ptr [[TMP1]], align 4 95 // CHECK-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP]], i32 8 96 // CHECK-NEXT: store <2 x float> [[TMP2]], ptr [[TMP3]], align 4 97 // CHECK-NEXT: [[TMP4:%.*]] = add i32 [[FP_OFFSET]], 16 98 // CHECK-NEXT: store i32 [[TMP4]], ptr [[FP_OFFSET_P]], align 4 99 // CHECK-NEXT: br label [[VAARG_END:%.*]] 100 // CHECK: vaarg.in_mem: 101 // CHECK-NEXT: [[OVERFLOW_ARG_AREA_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 2 102 // CHECK-NEXT: [[OVERFLOW_ARG_AREA:%.*]] = load ptr, ptr [[OVERFLOW_ARG_AREA_P]], align 8 103 // CHECK-NEXT: [[OVERFLOW_ARG_AREA_NEXT:%.*]] = getelementptr i8, ptr [[OVERFLOW_ARG_AREA]], i32 16 104 // CHECK-NEXT: store ptr [[OVERFLOW_ARG_AREA_NEXT]], ptr [[OVERFLOW_ARG_AREA_P]], align 8 105 // CHECK-NEXT: br label [[VAARG_END]] 106 // CHECK: vaarg.end: 107 // CHECK-NEXT: [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ] 108 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[RETVAL]], ptr align 4 [[VAARG_ADDR]], i64 16, i1 false) 109 // CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[RETVAL]], i64 8 110 // CHECK-NEXT: [[TMP6:%.*]] = load <2 x float>, ptr [[TMP5]], align 4 111 // CHECK-NEXT: ret <2 x float> [[TMP6]] 112 // 113 s2 f2(int z, ...) { 114 __builtin_va_list list; 115 __builtin_va_start(list, z); 116 return __builtin_va_arg(list, s2); 117 } 118 119 typedef struct { 120 struct{} a; 121 long long b; 122 } s3; 123 124 // CHECK-LABEL: @_Z2f3iz( 125 // CHECK-NEXT: entry: 126 // CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_S3:%.*]], align 8 127 // CHECK-NEXT: [[Z_ADDR:%.*]] = alloca i32, align 4 128 // CHECK-NEXT: [[LIST:%.*]] = alloca [1 x %struct.__va_list_tag], align 16 129 // CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_S3]], align 8 130 // CHECK-NEXT: store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4 131 // CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0 132 // CHECK-NEXT: call void @llvm.va_start.p0(ptr [[ARRAYDECAY]]) 133 // CHECK-NEXT: [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0 134 // CHECK-NEXT: [[GP_OFFSET_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[ARRAYDECAY1]], i32 0, i32 0 135 // CHECK-NEXT: [[GP_OFFSET:%.*]] = load i32, ptr [[GP_OFFSET_P]], align 16 136 // CHECK-NEXT: [[FITS_IN_GP:%.*]] = icmp ule i32 [[GP_OFFSET]], 40 137 // CHECK-NEXT: br i1 [[FITS_IN_GP]], label [[VAARG_IN_REG:%.*]], label [[VAARG_IN_MEM:%.*]] 138 // CHECK: vaarg.in_reg: 139 // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 3 140 // CHECK-NEXT: [[REG_SAVE_AREA:%.*]] = load ptr, ptr [[TMP0]], align 16 141 // CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[REG_SAVE_AREA]], i32 [[GP_OFFSET]] 142 // CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8 143 // CHECK-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP]], i32 8 144 // CHECK-NEXT: store i64 [[TMP2]], ptr [[TMP3]], align 8 145 // CHECK-NEXT: [[TMP4:%.*]] = add i32 [[GP_OFFSET]], 8 146 // CHECK-NEXT: store i32 [[TMP4]], ptr [[GP_OFFSET_P]], align 16 147 // CHECK-NEXT: br label [[VAARG_END:%.*]] 148 // CHECK: vaarg.in_mem: 149 // CHECK-NEXT: [[OVERFLOW_ARG_AREA_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 2 150 // CHECK-NEXT: [[OVERFLOW_ARG_AREA:%.*]] = load ptr, ptr [[OVERFLOW_ARG_AREA_P]], align 8 151 // CHECK-NEXT: [[OVERFLOW_ARG_AREA_NEXT:%.*]] = getelementptr i8, ptr [[OVERFLOW_ARG_AREA]], i32 16 152 // CHECK-NEXT: store ptr [[OVERFLOW_ARG_AREA_NEXT]], ptr [[OVERFLOW_ARG_AREA_P]], align 8 153 // CHECK-NEXT: br label [[VAARG_END]] 154 // CHECK: vaarg.end: 155 // CHECK-NEXT: [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ] 156 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[VAARG_ADDR]], i64 16, i1 false) 157 // CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[RETVAL]], i64 8 158 // CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr [[TMP5]], align 8 159 // CHECK-NEXT: ret i64 [[TMP6]] 160 // 161 s3 f3(int z, ...) { 162 __builtin_va_list list; 163 __builtin_va_start(list, z); 164 return __builtin_va_arg(list, s3); 165 } 166 167 typedef struct { 168 struct{} a[7]; 169 short b; 170 int c; 171 } s4; 172 173 // CHECK-LABEL: @_Z2f4iz( 174 // CHECK-NEXT: entry: 175 // CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_S4:%.*]], align 4 176 // CHECK-NEXT: [[Z_ADDR:%.*]] = alloca i32, align 4 177 // CHECK-NEXT: [[LIST:%.*]] = alloca [1 x %struct.__va_list_tag], align 16 178 // CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_S4]], align 4 179 // CHECK-NEXT: store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4 180 // CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0 181 // CHECK-NEXT: call void @llvm.va_start.p0(ptr [[ARRAYDECAY]]) 182 // CHECK-NEXT: [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0 183 // CHECK-NEXT: [[GP_OFFSET_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[ARRAYDECAY1]], i32 0, i32 0 184 // CHECK-NEXT: [[GP_OFFSET:%.*]] = load i32, ptr [[GP_OFFSET_P]], align 16 185 // CHECK-NEXT: [[FITS_IN_GP:%.*]] = icmp ule i32 [[GP_OFFSET]], 40 186 // CHECK-NEXT: br i1 [[FITS_IN_GP]], label [[VAARG_IN_REG:%.*]], label [[VAARG_IN_MEM:%.*]] 187 // CHECK: vaarg.in_reg: 188 // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 3 189 // CHECK-NEXT: [[REG_SAVE_AREA:%.*]] = load ptr, ptr [[TMP0]], align 16 190 // CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[REG_SAVE_AREA]], i32 [[GP_OFFSET]] 191 // CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 4 192 // CHECK-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP]], i32 8 193 // CHECK-NEXT: store i64 [[TMP2]], ptr [[TMP3]], align 4 194 // CHECK-NEXT: [[TMP4:%.*]] = add i32 [[GP_OFFSET]], 8 195 // CHECK-NEXT: store i32 [[TMP4]], ptr [[GP_OFFSET_P]], align 16 196 // CHECK-NEXT: br label [[VAARG_END:%.*]] 197 // CHECK: vaarg.in_mem: 198 // CHECK-NEXT: [[OVERFLOW_ARG_AREA_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 2 199 // CHECK-NEXT: [[OVERFLOW_ARG_AREA:%.*]] = load ptr, ptr [[OVERFLOW_ARG_AREA_P]], align 8 200 // CHECK-NEXT: [[OVERFLOW_ARG_AREA_NEXT:%.*]] = getelementptr i8, ptr [[OVERFLOW_ARG_AREA]], i32 16 201 // CHECK-NEXT: store ptr [[OVERFLOW_ARG_AREA_NEXT]], ptr [[OVERFLOW_ARG_AREA_P]], align 8 202 // CHECK-NEXT: br label [[VAARG_END]] 203 // CHECK: vaarg.end: 204 // CHECK-NEXT: [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ] 205 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[RETVAL]], ptr align 4 [[VAARG_ADDR]], i64 16, i1 false) 206 // CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[RETVAL]], i64 8 207 // CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr [[TMP5]], align 4 208 // CHECK-NEXT: ret i64 [[TMP6]] 209 // 210 s4 f4(int z, ...) { 211 __builtin_va_list list; 212 __builtin_va_start(list, z); 213 return __builtin_va_arg(list, s4); 214 } 215 216 typedef struct { 217 struct{} a[5]; 218 float b; 219 int c; 220 } s5; 221 222 // CHECK-LABEL: @_Z2f5iz( 223 // CHECK-NEXT: entry: 224 // CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_S5:%.*]], align 4 225 // CHECK-NEXT: [[Z_ADDR:%.*]] = alloca i32, align 4 226 // CHECK-NEXT: [[LIST:%.*]] = alloca [1 x %struct.__va_list_tag], align 16 227 // CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_S5]], align 4 228 // CHECK-NEXT: store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4 229 // CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0 230 // CHECK-NEXT: call void @llvm.va_start.p0(ptr [[ARRAYDECAY]]) 231 // CHECK-NEXT: [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0 232 // CHECK-NEXT: [[GP_OFFSET_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[ARRAYDECAY1]], i32 0, i32 0 233 // CHECK-NEXT: [[GP_OFFSET:%.*]] = load i32, ptr [[GP_OFFSET_P]], align 16 234 // CHECK-NEXT: [[FITS_IN_GP:%.*]] = icmp ule i32 [[GP_OFFSET]], 40 235 // CHECK-NEXT: br i1 [[FITS_IN_GP]], label [[VAARG_IN_REG:%.*]], label [[VAARG_IN_MEM:%.*]] 236 // CHECK: vaarg.in_reg: 237 // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 3 238 // CHECK-NEXT: [[REG_SAVE_AREA:%.*]] = load ptr, ptr [[TMP0]], align 16 239 // CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[REG_SAVE_AREA]], i32 [[GP_OFFSET]] 240 // CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 4 241 // CHECK-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP]], i32 8 242 // CHECK-NEXT: store i64 [[TMP2]], ptr [[TMP3]], align 4 243 // CHECK-NEXT: [[TMP4:%.*]] = add i32 [[GP_OFFSET]], 8 244 // CHECK-NEXT: store i32 [[TMP4]], ptr [[GP_OFFSET_P]], align 16 245 // CHECK-NEXT: br label [[VAARG_END:%.*]] 246 // CHECK: vaarg.in_mem: 247 // CHECK-NEXT: [[OVERFLOW_ARG_AREA_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 2 248 // CHECK-NEXT: [[OVERFLOW_ARG_AREA:%.*]] = load ptr, ptr [[OVERFLOW_ARG_AREA_P]], align 8 249 // CHECK-NEXT: [[OVERFLOW_ARG_AREA_NEXT:%.*]] = getelementptr i8, ptr [[OVERFLOW_ARG_AREA]], i32 16 250 // CHECK-NEXT: store ptr [[OVERFLOW_ARG_AREA_NEXT]], ptr [[OVERFLOW_ARG_AREA_P]], align 8 251 // CHECK-NEXT: br label [[VAARG_END]] 252 // CHECK: vaarg.end: 253 // CHECK-NEXT: [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ] 254 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[RETVAL]], ptr align 4 [[VAARG_ADDR]], i64 16, i1 false) 255 // CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[RETVAL]], i64 8 256 // CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr [[TMP5]], align 4 257 // CHECK-NEXT: ret i64 [[TMP6]] 258 // 259 s5 f5(int z, ...) { 260 __builtin_va_list list; 261 __builtin_va_start(list, z); 262 return __builtin_va_arg(list, s5); 263 } 264 265 typedef struct { 266 long long a; 267 struct{} b; 268 } s6; 269 270 // CHECK-LABEL: @_Z2f6iz( 271 // CHECK-NEXT: entry: 272 // CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_S6:%.*]], align 8 273 // CHECK-NEXT: [[Z_ADDR:%.*]] = alloca i32, align 4 274 // CHECK-NEXT: [[LIST:%.*]] = alloca [1 x %struct.__va_list_tag], align 16 275 // CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_S6]], align 8 276 // CHECK-NEXT: store i32 [[Z:%.*]], ptr [[Z_ADDR]], align 4 277 // CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0 278 // CHECK-NEXT: call void @llvm.va_start.p0(ptr [[ARRAYDECAY]]) 279 // CHECK-NEXT: [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr [[LIST]], i64 0, i64 0 280 // CHECK-NEXT: [[GP_OFFSET_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[ARRAYDECAY1]], i32 0, i32 0 281 // CHECK-NEXT: [[GP_OFFSET:%.*]] = load i32, ptr [[GP_OFFSET_P]], align 16 282 // CHECK-NEXT: [[FITS_IN_GP:%.*]] = icmp ule i32 [[GP_OFFSET]], 40 283 // CHECK-NEXT: br i1 [[FITS_IN_GP]], label [[VAARG_IN_REG:%.*]], label [[VAARG_IN_MEM:%.*]] 284 // CHECK: vaarg.in_reg: 285 // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 3 286 // CHECK-NEXT: [[REG_SAVE_AREA:%.*]] = load ptr, ptr [[TMP0]], align 16 287 // CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[REG_SAVE_AREA]], i32 [[GP_OFFSET]] 288 // CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8 289 // CHECK-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[TMP]], i32 0 290 // CHECK-NEXT: store i64 [[TMP2]], ptr [[TMP3]], align 8 291 // CHECK-NEXT: [[TMP4:%.*]] = add i32 [[GP_OFFSET]], 8 292 // CHECK-NEXT: store i32 [[TMP4]], ptr [[GP_OFFSET_P]], align 16 293 // CHECK-NEXT: br label [[VAARG_END:%.*]] 294 // CHECK: vaarg.in_mem: 295 // CHECK-NEXT: [[OVERFLOW_ARG_AREA_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 2 296 // CHECK-NEXT: [[OVERFLOW_ARG_AREA:%.*]] = load ptr, ptr [[OVERFLOW_ARG_AREA_P]], align 8 297 // CHECK-NEXT: [[OVERFLOW_ARG_AREA_NEXT:%.*]] = getelementptr i8, ptr [[OVERFLOW_ARG_AREA]], i32 16 298 // CHECK-NEXT: store ptr [[OVERFLOW_ARG_AREA_NEXT]], ptr [[OVERFLOW_ARG_AREA_P]], align 8 299 // CHECK-NEXT: br label [[VAARG_END]] 300 // CHECK: vaarg.end: 301 // CHECK-NEXT: [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ] 302 // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[VAARG_ADDR]], i64 16, i1 false) 303 // CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_S6]], ptr [[RETVAL]], i32 0, i32 0 304 // CHECK-NEXT: [[TMP5:%.*]] = load i64, ptr [[COERCE_DIVE]], align 8 305 // CHECK-NEXT: ret i64 [[TMP5]] 306 // 307 s6 f6(int z, ...) { 308 __builtin_va_list list; 309 __builtin_va_start(list, z); 310 return __builtin_va_arg(list, s6); 311 } 312