1 // RUN: %clang_cc1 -triple arm64-linux-gnu -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-LE %s 2 // RUN: %clang_cc1 -triple aarch64_be-linux-gnu -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-BE %s 3 4 #include <stdarg.h> 5 6 // Obviously there's more than one way to implement va_arg. This test should at 7 // least prevent unintentional regressions caused by refactoring. 8 9 va_list the_list; 10 11 int simple_int(void) { 12 // CHECK-LABEL: define{{.*}} i32 @simple_int 13 return va_arg(the_list, int); 14 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 15 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 16 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 17 18 // CHECK: [[VAARG_MAYBE_REG]] 19 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8 20 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 21 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 22 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 23 24 // CHECK: [[VAARG_IN_REG]] 25 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 26 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 27 // CHECK-BE: [[REG_ADDR_ALIGNED:%[0-9]+]] = getelementptr inbounds i8, ptr [[REG_ADDR]], i64 4 28 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 29 30 // CHECK: [[VAARG_ON_STACK]] 31 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 32 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 33 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 34 // CHECK-BE: [[STACK_ALIGNED:%[a-z_0-9]*]] = getelementptr inbounds i8, ptr [[STACK]], i64 4 35 // CHECK: br label %[[VAARG_END]] 36 37 // CHECK: [[VAARG_END]] 38 // CHECK-LE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 39 // CHECK-BE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR_ALIGNED]], %[[VAARG_IN_REG]] ], [ [[STACK_ALIGNED]], %[[VAARG_ON_STACK]] ] 40 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i32, ptr [[ADDR]] 41 // CHECK: ret i32 [[RESULT]] 42 } 43 44 __int128 aligned_int(void) { 45 // CHECK-LABEL: define{{.*}} i128 @aligned_int 46 return va_arg(the_list, __int128); 47 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 48 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 49 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 50 51 // CHECK: [[VAARG_MAYBE_REG]] 52 // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15 53 // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16 54 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16 55 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 56 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 57 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 58 59 // CHECK: [[VAARG_IN_REG]] 60 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 61 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[ALIGNED_REGOFFS]] 62 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 63 64 // CHECK: [[VAARG_ON_STACK]] 65 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 66 // CHECK: [[STACKINC:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i32 15 67 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9.]+]] = call ptr @llvm.ptrmask.p0.i64(ptr [[STACKINC]], i64 -16) 68 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16 69 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 70 // CHECK: br label %[[VAARG_END]] 71 72 // CHECK: [[VAARG_END]] 73 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ] 74 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i128, ptr [[ADDR]] 75 // CHECK: ret i128 [[RESULT]] 76 } 77 78 struct bigstruct { 79 int a[10]; 80 }; 81 82 struct bigstruct simple_indirect(void) { 83 // CHECK-LABEL: define{{.*}} void @simple_indirect 84 return va_arg(the_list, struct bigstruct); 85 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 86 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 87 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 88 89 // CHECK: [[VAARG_MAYBE_REG]] 90 // CHECK-NOT: and i32 91 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8 92 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 93 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 94 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 95 96 // CHECK: [[VAARG_IN_REG]] 97 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 98 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 99 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 100 101 // CHECK: [[VAARG_ON_STACK]] 102 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 103 // CHECK-NOT: and i64 104 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 105 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 106 // CHECK: br label %[[VAARG_END]] 107 108 // CHECK: [[VAARG_END]] 109 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 110 // CHECK: load ptr, ptr [[ADDR]] 111 } 112 113 struct aligned_bigstruct { 114 float a; 115 long double b; 116 }; 117 118 struct aligned_bigstruct simple_aligned_indirect(void) { 119 // CHECK-LABEL: define{{.*}} void @simple_aligned_indirect 120 return va_arg(the_list, struct aligned_bigstruct); 121 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 122 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 123 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 124 125 // CHECK: [[VAARG_MAYBE_REG]] 126 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8 127 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 128 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 129 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 130 131 // CHECK: [[VAARG_IN_REG]] 132 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 133 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 134 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 135 136 // CHECK: [[VAARG_ON_STACK]] 137 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 138 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 139 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 140 // CHECK: br label %[[VAARG_END]] 141 142 // CHECK: [[VAARG_END]] 143 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 144 // CHECK: load ptr, ptr [[ADDR]] 145 } 146 147 double simple_double(void) { 148 // CHECK-LABEL: define{{.*}} double @simple_double 149 return va_arg(the_list, double); 150 // CHECK: [[VR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 4) 151 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[VR_OFFS]], 0 152 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG]] 153 154 // CHECK: [[VAARG_MAYBE_REG]] 155 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[VR_OFFS]], 16 156 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 4) 157 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 158 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 159 160 // CHECK: [[VAARG_IN_REG]] 161 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 2) 162 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[VR_OFFS]] 163 // CHECK-BE: [[REG_ADDR_ALIGNED:%[a-z_0-9]*]] = getelementptr inbounds i8, ptr [[REG_ADDR]], i64 8 164 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 165 166 // CHECK: [[VAARG_ON_STACK]] 167 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 168 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 169 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 170 // CHECK: br label %[[VAARG_END]] 171 172 // CHECK: [[VAARG_END]] 173 // CHECK-LE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 174 // CHECK-BE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR_ALIGNED]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 175 // CHECK: [[RESULT:%[a-z_0-9]+]] = load double, ptr [[ADDR]] 176 // CHECK: ret double [[RESULT]] 177 } 178 179 struct hfa { 180 float a, b; 181 }; 182 183 struct hfa simple_hfa(void) { 184 // CHECK-LABEL: define{{.*}} %struct.hfa @simple_hfa 185 return va_arg(the_list, struct hfa); 186 // CHECK: [[VR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 4) 187 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[VR_OFFS]], 0 188 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 189 190 // CHECK: [[VAARG_MAYBE_REG]] 191 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[VR_OFFS]], 32 192 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 4) 193 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 194 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 195 196 // CHECK: [[VAARG_IN_REG]] 197 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 2) 198 // CHECK: [[FIRST_REG:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[VR_OFFS]] 199 // CHECK-LE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[FIRST_REG]], i64 0 200 // CHECK-BE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[FIRST_REG]], i64 12 201 // CHECK: [[EL_TMPADDR:%[a-z_0-9]+]] = getelementptr inbounds [2 x float], ptr %[[TMP_HFA:[a-z_.0-9]+]], i64 0, i64 0 202 // CHECK: [[EL:%[a-z_0-9]+]] = load float, ptr [[EL_ADDR]] 203 // CHECK: store float [[EL]], ptr [[EL_TMPADDR]] 204 // CHECK-LE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[FIRST_REG]], i64 16 205 // CHECK-BE: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[FIRST_REG]], i64 28 206 // CHECK: [[EL_TMPADDR:%[a-z_0-9]+]] = getelementptr inbounds [2 x float], ptr %[[TMP_HFA]], i64 0, i64 1 207 // CHECK: [[EL:%[a-z_0-9]+]] = load float, ptr [[EL_ADDR]] 208 // CHECK: store float [[EL]], ptr [[EL_TMPADDR]] 209 // CHECK: br label %[[VAARG_END:[a-z_.0-9]+]] 210 211 // CHECK: [[VAARG_ON_STACK]] 212 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 213 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 214 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 215 // CHECK: br label %[[VAARG_END]] 216 217 // CHECK: [[VAARG_END]] 218 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ %[[TMP_HFA]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 219 } 220 221 // Over and under alignment on fundamental types has no effect on parameter 222 // passing, so the code generated for va_arg should be the same as for 223 // non-aligned fundamental types. 224 225 typedef int underaligned_int __attribute__((packed,aligned(2))); 226 underaligned_int underaligned_int_test(void) { 227 // CHECK-LABEL: define{{.*}} i32 @underaligned_int_test() 228 return va_arg(the_list, underaligned_int); 229 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 230 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 231 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 232 233 // CHECK: [[VAARG_MAYBE_REG]] 234 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8 235 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 236 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 237 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 238 239 // CHECK: [[VAARG_IN_REG]] 240 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 241 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 242 // CHECK-BE: [[REG_ADDR_ALIGNED:%[0-9]+]] = getelementptr inbounds i8, ptr [[REG_ADDR]], i64 4 243 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 244 245 // CHECK: [[VAARG_ON_STACK]] 246 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 247 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 248 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 249 // CHECK-BE: [[STACK_ALIGNED:%[a-z_0-9]*]] = getelementptr inbounds i8, ptr [[STACK]], i64 4 250 // CHECK: br label %[[VAARG_END]] 251 252 // CHECK: [[VAARG_END]] 253 // CHECK-LE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 254 // CHECK-BE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR_ALIGNED]], %[[VAARG_IN_REG]] ], [ [[STACK_ALIGNED]], %[[VAARG_ON_STACK]] ] 255 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i32, ptr [[ADDR]] 256 // CHECK: ret i32 [[RESULT]] 257 } 258 259 typedef int overaligned_int __attribute__((aligned(32))); 260 overaligned_int overaligned_int_test(void) { 261 // CHECK-LABEL: define{{.*}} i32 @overaligned_int_test() 262 return va_arg(the_list, overaligned_int); 263 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 264 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 265 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 266 267 // CHECK: [[VAARG_MAYBE_REG]] 268 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8 269 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 270 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 271 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 272 273 // CHECK: [[VAARG_IN_REG]] 274 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 275 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 276 // CHECK-BE: [[REG_ADDR_ALIGNED:%[0-9]+]] = getelementptr inbounds i8, ptr [[REG_ADDR]], i64 4 277 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 278 279 // CHECK: [[VAARG_ON_STACK]] 280 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 281 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 282 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 283 // CHECK-BE: [[STACK_ALIGNED:%[a-z_0-9]*]] = getelementptr inbounds i8, ptr [[STACK]], i64 4 284 // CHECK: br label %[[VAARG_END]] 285 286 // CHECK: [[VAARG_END]] 287 // CHECK-LE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 288 // CHECK-BE: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR_ALIGNED]], %[[VAARG_IN_REG]] ], [ [[STACK_ALIGNED]], %[[VAARG_ON_STACK]] ] 289 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i32, ptr [[ADDR]] 290 // CHECK: ret i32 [[RESULT]] 291 } 292 293 typedef long long underaligned_long_long __attribute__((packed,aligned(2))); 294 underaligned_long_long underaligned_long_long_test(void) { 295 // CHECK-LABEL: define{{.*}} i64 @underaligned_long_long_test() 296 return va_arg(the_list, underaligned_long_long); 297 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 298 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 299 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 300 301 // CHECK: [[VAARG_MAYBE_REG]] 302 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8 303 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 304 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 305 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 306 307 // CHECK: [[VAARG_IN_REG]] 308 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 309 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 310 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 311 312 // CHECK: [[VAARG_ON_STACK]] 313 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 314 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 315 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 316 // CHECK: br label %[[VAARG_END]] 317 318 // CHECK: [[VAARG_END]] 319 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 320 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i64, ptr [[ADDR]] 321 // CHECK: ret i64 [[RESULT]] 322 } 323 324 typedef long long overaligned_long_long __attribute__((aligned(32))); 325 overaligned_long_long overaligned_long_long_test(void) { 326 // CHECK-LABEL: define{{.*}} i64 @overaligned_long_long_test() 327 return va_arg(the_list, overaligned_long_long); 328 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 329 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 330 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 331 332 // CHECK: [[VAARG_MAYBE_REG]] 333 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8 334 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 335 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 336 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 337 338 // CHECK: [[VAARG_IN_REG]] 339 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 340 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 341 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 342 343 // CHECK: [[VAARG_ON_STACK]] 344 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 345 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 346 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 347 // CHECK: br label %[[VAARG_END]] 348 349 // CHECK: [[VAARG_END]] 350 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 351 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i64, ptr [[ADDR]] 352 // CHECK: ret i64 [[RESULT]] 353 } 354 355 typedef __int128 underaligned_int128 __attribute__((packed,aligned(2))); 356 underaligned_int128 underaligned_int128_test(void) { 357 // CHECK-LABEL: define{{.*}} i128 @underaligned_int128_test() 358 return va_arg(the_list, underaligned_int128); 359 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 360 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 361 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 362 363 // CHECK: [[VAARG_MAYBE_REG]] 364 // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15 365 // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16 366 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16 367 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 368 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 369 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 370 371 // CHECK: [[VAARG_IN_REG]] 372 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 373 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[ALIGNED_REGOFFS]] 374 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 375 376 // CHECK: [[VAARG_ON_STACK]] 377 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 378 // CHECK: [[STACKINC:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i32 15 379 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9.]+]] = call ptr @llvm.ptrmask.p0.i64(ptr [[STACKINC]], i64 -16) 380 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16 381 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 382 // CHECK: br label %[[VAARG_END]] 383 384 // CHECK: [[VAARG_END]] 385 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ] 386 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i128, ptr [[ADDR]] 387 // CHECK: ret i128 [[RESULT]] 388 } 389 390 typedef __int128 overaligned_int128 __attribute__((aligned(32))); 391 overaligned_int128 overaligned_int128_test(void) { 392 // CHECK-LABEL: define{{.*}} i128 @overaligned_int128_test() 393 return va_arg(the_list, overaligned_int128); 394 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 395 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 396 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 397 398 // CHECK: [[VAARG_MAYBE_REG]] 399 // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15 400 // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16 401 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16 402 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 403 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 404 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 405 406 // CHECK: [[VAARG_IN_REG]] 407 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 408 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[ALIGNED_REGOFFS]] 409 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 410 411 // CHECK: [[VAARG_ON_STACK]] 412 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 413 // CHECK: [[STACKINC:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i32 15 414 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9.]+]] = call ptr @llvm.ptrmask.p0.i64(ptr [[STACKINC]], i64 -16) 415 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16 416 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 417 // CHECK: br label %[[VAARG_END]] 418 419 // CHECK: [[VAARG_END]] 420 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ] 421 // CHECK: [[RESULT:%[a-z_0-9]+]] = load i128, ptr [[ADDR]] 422 // CHECK: ret i128 [[RESULT]] 423 } 424 425 // The way that attributes applied to a struct change parameter passing is a 426 // little strange, in that the alignment due to attributes is used when 427 // calculating the size of the struct, but the alignment is based only on the 428 // alignment of the members (which can be affected by attributes). What this 429 // means is: 430 // * The only effect of the aligned attribute on a struct is to increase its 431 // size if the alignment is greater than the member alignment. 432 // * The packed attribute is considered as applying to the members, so it will 433 // affect the alignment. 434 // Additionally the alignment can't go below 8 or above 16, so it's only 435 // __int128 that can be affected by a change in alignment. 436 437 typedef struct __attribute__((packed,aligned(2))) { 438 int val; 439 } underaligned_int_struct; 440 underaligned_int_struct underaligned_int_struct_test(void) { 441 // CHECK-LE-LABEL: define{{.*}} i32 @underaligned_int_struct_test() 442 // CHECK-BE-LABEL: define{{.*}} i64 @underaligned_int_struct_test() 443 return va_arg(the_list, underaligned_int_struct); 444 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 445 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 446 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 447 448 // CHECK: [[VAARG_MAYBE_REG]] 449 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8 450 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 451 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 452 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 453 454 // CHECK: [[VAARG_IN_REG]] 455 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 456 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 457 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 458 459 // CHECK: [[VAARG_ON_STACK]] 460 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 461 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 462 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 463 // CHECK: br label %[[VAARG_END]] 464 465 // CHECK: [[VAARG_END]] 466 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 467 } 468 469 typedef struct __attribute__((aligned(16))) { 470 int val; 471 } overaligned_int_struct; 472 overaligned_int_struct overaligned_int_struct_test(void) { 473 // CHECK-LABEL: define{{.*}} i128 @overaligned_int_struct_test() 474 return va_arg(the_list, overaligned_int_struct); 475 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 476 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 477 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 478 479 // CHECK: [[VAARG_MAYBE_REG]] 480 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 16 481 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 482 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 483 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 484 485 // CHECK: [[VAARG_IN_REG]] 486 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 487 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 488 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 489 490 // CHECK: [[VAARG_ON_STACK]] 491 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 492 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 16 493 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 494 // CHECK: br label %[[VAARG_END]] 495 496 // CHECK: [[VAARG_END]] 497 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 498 } 499 500 typedef struct __attribute__((packed,aligned(2))) { 501 long long val; 502 } underaligned_long_long_struct; 503 underaligned_long_long_struct underaligned_long_long_struct_test(void) { 504 // CHECK-LABEL: define{{.*}} i64 @underaligned_long_long_struct_test() 505 return va_arg(the_list, underaligned_long_long_struct); 506 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 507 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 508 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 509 510 // CHECK: [[VAARG_MAYBE_REG]] 511 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8 512 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 513 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 514 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 515 516 // CHECK: [[VAARG_IN_REG]] 517 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 518 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 519 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 520 521 // CHECK: [[VAARG_ON_STACK]] 522 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 523 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 524 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 525 // CHECK: br label %[[VAARG_END]] 526 527 // CHECK: [[VAARG_END]] 528 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 529 } 530 531 typedef struct __attribute__((aligned(16))) { 532 long long val; 533 } overaligned_long_long_struct; 534 overaligned_long_long_struct overaligned_long_long_struct_test(void) { 535 // CHECK-LABEL: define{{.*}} i128 @overaligned_long_long_struct_test() 536 return va_arg(the_list, overaligned_long_long_struct); 537 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 538 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 539 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 540 541 // CHECK: [[VAARG_MAYBE_REG]] 542 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 16 543 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 544 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 545 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 546 547 // CHECK: [[VAARG_IN_REG]] 548 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 549 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 550 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 551 552 // CHECK: [[VAARG_ON_STACK]] 553 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 554 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 16 555 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 556 // CHECK: br label %[[VAARG_END]] 557 558 // CHECK: [[VAARG_END]] 559 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 560 } 561 562 typedef struct __attribute__((packed,aligned(2))) { 563 __int128 val; 564 } underaligned_int128_struct; 565 underaligned_int128_struct underaligned_int128_struct_test(void) { 566 // CHECK-LABEL: define{{.*}} [2 x i64] @underaligned_int128_struct_test() 567 return va_arg(the_list, underaligned_int128_struct); 568 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 569 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 570 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 571 572 // CHECK: [[VAARG_MAYBE_REG]] 573 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 16 574 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 575 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 576 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 577 578 // CHECK: [[VAARG_IN_REG]] 579 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 580 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 581 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 582 583 // CHECK: [[VAARG_ON_STACK]] 584 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 585 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 16 586 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 587 // CHECK: br label %[[VAARG_END]] 588 589 // CHECK: [[VAARG_END]] 590 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 591 } 592 593 // Overaligning to 32 bytes causes it to be passed indirectly via a pointer 594 typedef struct __attribute__((aligned(32))) { 595 __int128 val; 596 } overaligned_int128_struct; 597 overaligned_int128_struct overaligned_int128_struct_test(void) { 598 // CHECK-LABEL: define{{.*}} void @overaligned_int128_struct_test(ptr dead_on_unwind noalias writable sret(%struct.overaligned_int128_struct) align 32 %agg.result) 599 return va_arg(the_list, overaligned_int128_struct); 600 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 601 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 602 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 603 604 // CHECK: [[VAARG_MAYBE_REG]] 605 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8 606 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 607 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 608 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 609 610 // CHECK: [[VAARG_IN_REG]] 611 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 612 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 613 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 614 615 // CHECK: [[VAARG_ON_STACK]] 616 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 617 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 618 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 619 // CHECK: br label %[[VAARG_END]] 620 621 // CHECK: [[VAARG_END]] 622 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 623 } 624 625 // Overaligning or underaligning a struct member changes both its alignment and 626 // size when passed as an argument. 627 628 typedef struct { 629 int val __attribute__((packed,aligned(2))); 630 } underaligned_int_struct_member; 631 underaligned_int_struct_member underaligned_int_struct_member_test(void) { 632 // CHECK-LE-LABEL: define{{.*}} i32 @underaligned_int_struct_member_test() 633 // CHECK-BE-LABEL: define{{.*}} i64 @underaligned_int_struct_member_test() 634 return va_arg(the_list, underaligned_int_struct_member); 635 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 636 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 637 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 638 639 // CHECK: [[VAARG_MAYBE_REG]] 640 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8 641 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 642 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 643 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 644 645 // CHECK: [[VAARG_IN_REG]] 646 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 647 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 648 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 649 650 // CHECK: [[VAARG_ON_STACK]] 651 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 652 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 653 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 654 // CHECK: br label %[[VAARG_END]] 655 656 // CHECK: [[VAARG_END]] 657 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 658 } 659 660 typedef struct { 661 int val __attribute__((aligned(16))); 662 } overaligned_int_struct_member; 663 overaligned_int_struct_member overaligned_int_struct_member_test(void) { 664 // CHECK-LABEL: define{{.*}} i128 @overaligned_int_struct_member_test() 665 return va_arg(the_list, overaligned_int_struct_member); 666 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 667 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 668 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 669 670 // CHECK: [[VAARG_MAYBE_REG]] 671 // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15 672 // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16 673 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16 674 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 675 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 676 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 677 678 // CHECK: [[VAARG_IN_REG]] 679 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 680 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[ALIGNED_REGOFFS]] 681 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 682 683 // CHECK: [[VAARG_ON_STACK]] 684 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 685 // CHECK: [[STACKINC:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i32 15 686 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9.]+]] = call ptr @llvm.ptrmask.p0.i64(ptr [[STACKINC]], i64 -16) 687 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16 688 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 689 // CHECK: br label %[[VAARG_END]] 690 691 // CHECK: [[VAARG_END]] 692 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ] 693 } 694 695 typedef struct { 696 long long val __attribute__((packed,aligned(2))); 697 } underaligned_long_long_struct_member; 698 underaligned_long_long_struct_member underaligned_long_long_struct_member_test(void) { 699 // CHECK-LABEL: define{{.*}} i64 @underaligned_long_long_struct_member_test() 700 return va_arg(the_list, underaligned_long_long_struct_member); 701 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 702 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 703 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 704 705 // CHECK: [[VAARG_MAYBE_REG]] 706 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8 707 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 708 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 709 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 710 711 // CHECK: [[VAARG_IN_REG]] 712 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 713 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 714 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 715 716 // CHECK: [[VAARG_ON_STACK]] 717 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 718 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 719 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 720 // CHECK: br label %[[VAARG_END]] 721 722 // CHECK: [[VAARG_END]] 723 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 724 } 725 726 typedef struct { 727 long long val __attribute__((aligned(16))); 728 } overaligned_long_long_struct_member; 729 overaligned_long_long_struct_member overaligned_long_long_struct_member_test(void) { 730 // CHECK-LABEL: define{{.*}} i128 @overaligned_long_long_struct_member_test() 731 return va_arg(the_list, overaligned_long_long_struct_member); 732 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 733 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 734 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 735 736 // CHECK: [[VAARG_MAYBE_REG]] 737 // CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15 738 // CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16 739 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16 740 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 741 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 742 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 743 744 // CHECK: [[VAARG_IN_REG]] 745 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 746 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[ALIGNED_REGOFFS]] 747 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 748 749 // CHECK: [[VAARG_ON_STACK]] 750 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 751 // CHECK: [[STACKINC:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i32 15 752 // CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9.]+]] = call ptr @llvm.ptrmask.p0.i64(ptr [[STACKINC]], i64 -16) 753 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[ALIGNED_STACK_PTR]], i64 16 754 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 755 // CHECK: br label %[[VAARG_END]] 756 757 // CHECK: [[VAARG_END]] 758 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[ALIGNED_STACK_PTR]], %[[VAARG_ON_STACK]] ] 759 } 760 761 typedef struct { 762 __int128 val __attribute__((packed,aligned(2))); 763 } underaligned_int128_struct_member; 764 underaligned_int128_struct_member underaligned_int128_struct_member_test(void) { 765 // CHECK-LABEL: define{{.*}} [2 x i64] @underaligned_int128_struct_member_test() 766 return va_arg(the_list, underaligned_int128_struct_member); 767 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 768 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 769 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 770 771 // CHECK: [[VAARG_MAYBE_REG]] 772 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 16 773 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 774 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 775 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 776 777 // CHECK: [[VAARG_IN_REG]] 778 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 779 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 780 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 781 782 // CHECK: [[VAARG_ON_STACK]] 783 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 784 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 16 785 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 786 // CHECK: br label %[[VAARG_END]] 787 788 // CHECK: [[VAARG_END]] 789 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 790 } 791 792 // Overaligning to 32 bytes causes it to be passed indirectly via a pointer 793 typedef struct { 794 __int128 val __attribute__((aligned(32))); 795 } overaligned_int128_struct_member; 796 overaligned_int128_struct_member overaligned_int128_struct_member_test(void) { 797 // CHECK-LABEL: define{{.*}} void @overaligned_int128_struct_member_test(ptr dead_on_unwind noalias writable sret(%struct.overaligned_int128_struct_member) align 32 %agg.result) 798 return va_arg(the_list, overaligned_int128_struct_member); 799 // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 800 // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 801 // CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]] 802 803 // CHECK: [[VAARG_MAYBE_REG]] 804 // CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8 805 // CHECK: store i32 [[NEW_REG_OFFS]], ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 3) 806 // CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0 807 // CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]] 808 809 // CHECK: [[VAARG_IN_REG]] 810 // CHECK: [[REG_TOP:%[a-z_0-9]+]] = load ptr, ptr getelementptr inbounds nuw (%struct.__va_list, ptr @the_list, i32 0, i32 1) 811 // CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[REG_TOP]], i32 [[GR_OFFS]] 812 // CHECK: br label %[[VAARG_END:[a-z._0-9]+]] 813 814 // CHECK: [[VAARG_ON_STACK]] 815 // CHECK: [[STACK:%[a-z_0-9]+]] = load ptr, ptr @the_list 816 // CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr inbounds i8, ptr [[STACK]], i64 8 817 // CHECK: store ptr [[NEW_STACK]], ptr @the_list 818 // CHECK: br label %[[VAARG_END]] 819 820 // CHECK: [[VAARG_END]] 821 // CHECK: [[ADDR:%[a-z._0-9]+]] = phi ptr [ [[REG_ADDR]], %[[VAARG_IN_REG]] ], [ [[STACK]], %[[VAARG_ON_STACK]] ] 822 } 823 824 void check_start(int n, ...) { 825 // CHECK-LABEL: define{{.*}} void @check_start(i32 noundef %n, ...) 826 827 va_list the_list; 828 va_start(the_list, n); 829 // CHECK: [[THE_LIST:%[a-z_0-9]+]] = alloca %struct.__va_list 830 // CHECK: call void @llvm.va_start.p0(ptr [[THE_LIST]]) 831 } 832 833 typedef struct {} empty; 834 empty empty_record_test(void) { 835 // CHECK-LABEL: define{{.*}} void @empty_record_test() 836 // CHECK: entry 837 // CHECK-NEXT: ret void 838 return va_arg(the_list, empty); 839 } 840