1 // RUN: %clang_cc1 -triple arm-none-eabi -emit-llvm -o - %s | FileCheck %s 2 // RUN: %clang_cc1 -triple armeb-none-eabi -emit-llvm -o - %s | FileCheck %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: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 15 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 4 16 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 17 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to i32* 18 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, i32* [[ADDR]] 19 // CHECK: ret i32 [[RESULT]] 20 } 21 22 struct bigstruct { 23 int a[10]; 24 }; 25 26 struct bigstruct simple_struct(void) { 27 // CHECK-LABEL: define{{.*}} void @simple_struct(%struct.bigstruct* noalias sret(%struct.bigstruct) align 4 %agg.result) 28 return va_arg(the_list, struct bigstruct); 29 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 30 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 40 31 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 32 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to %struct.bigstruct* 33 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.bigstruct* %agg.result to i8* 34 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.bigstruct* [[ADDR]] to i8* 35 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[DEST_ADDR]], i8* align 4 [[SRC_ADDR]], i32 40, i1 false) 36 // CHECK: ret void 37 } 38 39 struct aligned_bigstruct { 40 float a; 41 long double b; 42 }; 43 44 struct aligned_bigstruct simple_aligned_struct(void) { 45 // CHECK-LABEL: define{{.*}} void @simple_aligned_struct(%struct.aligned_bigstruct* noalias sret(%struct.aligned_bigstruct) align 8 %agg.result) 46 return va_arg(the_list, struct aligned_bigstruct); 47 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 48 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 49 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7 50 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8 51 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to i8* 52 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR_ALIGNED]], i32 16 53 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 54 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR_ALIGNED]] to %struct.aligned_bigstruct* 55 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.aligned_bigstruct* %agg.result to i8* 56 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.aligned_bigstruct* [[ADDR]] to i8* 57 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 [[DEST_ADDR]], i8* align 8 [[SRC_ADDR]], i32 16, i1 false) 58 // CHECK: ret void 59 } 60 61 double simple_double(void) { 62 // CHECK-LABEL: define{{.*}} double @simple_double 63 return va_arg(the_list, double); 64 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 65 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 66 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7 67 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8 68 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to i8* 69 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR_ALIGNED]], i32 8 70 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 71 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR_ALIGNED]] to double* 72 // CHECK: [[RESULT:%[a-z0-9._]+]] = load double, double* [[ADDR]] 73 // CHECK: ret double [[RESULT]] 74 } 75 76 struct hfa { 77 float a, b; 78 }; 79 80 struct hfa simple_hfa(void) { 81 // CHECK-LABEL: define{{.*}} void @simple_hfa(%struct.hfa* noalias sret(%struct.hfa) align 4 %agg.result) 82 return va_arg(the_list, struct hfa); 83 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 84 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 8 85 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 86 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to %struct.hfa* 87 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.hfa* %agg.result to i8* 88 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.hfa* [[ADDR]] to i8* 89 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[DEST_ADDR]], i8* align 4 [[SRC_ADDR]], i32 8, i1 false) 90 // CHECK: ret void 91 } 92 93 // Over and under alignment on fundamental types has no effect on parameter 94 // passing, so the code generated for va_arg should be the same as for 95 // non-aligned fundamental types. 96 97 typedef int underaligned_int __attribute__((packed,aligned(2))); 98 underaligned_int underaligned_int_test() { 99 // CHECK-LABEL: define{{.*}} i32 @underaligned_int_test() 100 return va_arg(the_list, underaligned_int); 101 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 102 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 4 103 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 104 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to i32* 105 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, i32* [[ADDR]] 106 // CHECK: ret i32 [[RESULT]] 107 } 108 109 typedef int overaligned_int __attribute__((aligned(32))); 110 overaligned_int overaligned_int_test() { 111 // CHECK-LABEL: define{{.*}} i32 @overaligned_int_test() 112 return va_arg(the_list, overaligned_int); 113 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 114 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 4 115 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 116 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to i32* 117 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, i32* [[ADDR]] 118 // CHECK: ret i32 [[RESULT]] 119 } 120 121 typedef long long underaligned_long_long __attribute__((packed,aligned(2))); 122 underaligned_long_long underaligned_long_long_test() { 123 // CHECK-LABEL: define{{.*}} i64 @underaligned_long_long_test() 124 return va_arg(the_list, underaligned_long_long); 125 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 126 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 127 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7 128 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8 129 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to i8* 130 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR_ALIGNED]], i32 8 131 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 132 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR_ALIGNED]] to i64* 133 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i64, i64* [[ADDR]] 134 // CHECK: ret i64 [[RESULT]] 135 } 136 137 typedef long long overaligned_long_long __attribute__((aligned(32))); 138 overaligned_long_long overaligned_long_long_test() { 139 // CHECK-LABEL: define{{.*}} i64 @overaligned_long_long_test() 140 return va_arg(the_list, overaligned_long_long); 141 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 142 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 143 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7 144 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8 145 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to i8* 146 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR_ALIGNED]], i32 8 147 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 148 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR_ALIGNED]] to i64* 149 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i64, i64* [[ADDR]] 150 // CHECK: ret i64 [[RESULT]] 151 } 152 153 // The way that attributes applied to a struct change parameter passing is a 154 // little strange, in that the alignment due to attributes is used when 155 // calculating the size of the struct, but the alignment is based only on the 156 // alignment of the members (which can be affected by attributes). What this 157 // means is: 158 // * The only effect of the aligned attribute on a struct is to increase its 159 // size if the alignment is greater than the member alignment. 160 // * The packed attribute is considered as applying to the members, so it will 161 // affect the alignment. 162 // Additionally the alignment can't go below 4 or above 8, so it's only 163 // long long and double that can be affected by a change in alignment. 164 165 typedef struct __attribute__((packed,aligned(2))) { 166 int val; 167 } underaligned_int_struct; 168 underaligned_int_struct underaligned_int_struct_test() { 169 // CHECK-LABEL: define{{.*}} i32 @underaligned_int_struct_test() 170 return va_arg(the_list, underaligned_int_struct); 171 // CHECK: [[RETVAL:%[a-z0-9._]+]] = alloca %struct.underaligned_int_struct, align 2 172 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 173 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 4 174 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 175 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to %struct.underaligned_int_struct* 176 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_int_struct* [[RETVAL]] to i8* 177 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_int_struct* [[ADDR]] to i8* 178 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 2 [[DEST_ADDR]], i8* align 4 [[SRC_ADDR]], i32 4, i1 false) 179 // CHECK: [[COERCE:%[a-z0-9._]+]] = getelementptr inbounds %struct.underaligned_int_struct, %struct.underaligned_int_struct* [[RETVAL]], i32 0, i32 0 180 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, i32* [[COERCE]] 181 // CHECK: ret i32 [[RESULT]] 182 } 183 184 typedef struct __attribute__((aligned(16))) { 185 int val; 186 } overaligned_int_struct; 187 overaligned_int_struct overaligned_int_struct_test() { 188 // CHECK-LABEL: define{{.*}} void @overaligned_int_struct_test(%struct.overaligned_int_struct* noalias sret(%struct.overaligned_int_struct) align 16 %agg.result) 189 return va_arg(the_list, overaligned_int_struct); 190 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 191 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 16 192 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 193 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to %struct.overaligned_int_struct* 194 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_int_struct* %agg.result to i8* 195 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_int_struct* [[ADDR]] to i8* 196 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 [[DEST_ADDR]], i8* align 4 [[SRC_ADDR]], i32 16, i1 false) 197 // CHECK: ret void 198 } 199 200 typedef struct __attribute__((packed,aligned(2))) { 201 long long val; 202 } underaligned_long_long_struct; 203 underaligned_long_long_struct underaligned_long_long_struct_test() { 204 // CHECK-LABEL: define{{.*}} void @underaligned_long_long_struct_test(%struct.underaligned_long_long_struct* noalias sret(%struct.underaligned_long_long_struct) align 2 %agg.result) 205 return va_arg(the_list, underaligned_long_long_struct); 206 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 207 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 8 208 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 209 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to %struct.underaligned_long_long_struct* 210 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_long_long_struct* %agg.result to i8* 211 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_long_long_struct* [[ADDR]] to i8* 212 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 2 [[DEST_ADDR]], i8* align 4 [[SRC_ADDR]], i32 8, i1 false) 213 // CHECK: ret void 214 } 215 216 typedef struct __attribute__((aligned(16))) { 217 long long val; 218 } overaligned_long_long_struct; 219 overaligned_long_long_struct overaligned_long_long_struct_test() { 220 // CHECK-LABEL: define{{.*}} void @overaligned_long_long_struct_test(%struct.overaligned_long_long_struct* noalias sret(%struct.overaligned_long_long_struct) align 16 %agg.result) 221 return va_arg(the_list, overaligned_long_long_struct); 222 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 223 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 224 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7 225 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8 226 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to i8* 227 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR_ALIGNED]], i32 16 228 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 229 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR_ALIGNED]] to %struct.overaligned_long_long_struct* 230 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_long_long_struct* %agg.result to i8* 231 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_long_long_struct* [[ADDR]] to i8* 232 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 [[DEST_ADDR]], i8* align 8 [[SRC_ADDR]], i32 16, i1 false) 233 // CHECK: ret void 234 } 235 236 // Overaligning or underaligning a struct member changes both its alignment and 237 // size when passed as an argument. 238 239 typedef struct { 240 int val __attribute__((packed,aligned(2))); 241 } underaligned_int_struct_member; 242 underaligned_int_struct_member underaligned_int_struct_member_test() { 243 // CHECK-LABEL: define{{.*}} i32 @underaligned_int_struct_member_test() 244 return va_arg(the_list, underaligned_int_struct_member); 245 // CHECK: [[RETVAL:%[a-z0-9._]+]] = alloca %struct.underaligned_int_struct_member, align 2 246 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 247 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 4 248 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 249 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to %struct.underaligned_int_struct_member* 250 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_int_struct_member* [[RETVAL]] to i8* 251 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_int_struct_member* [[ADDR]] to i8* 252 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 2 [[DEST_ADDR]], i8* align 4 [[SRC_ADDR]], i32 4, i1 false) 253 // CHECK: [[COERCE:%[a-z0-9._]+]] = getelementptr inbounds %struct.underaligned_int_struct_member, %struct.underaligned_int_struct_member* [[RETVAL]], i32 0, i32 0 254 // CHECK: [[RESULT:%[a-z0-9._]+]] = load i32, i32* [[COERCE]] 255 // CHECK: ret i32 [[RESULT]] 256 } 257 258 typedef struct { 259 int val __attribute__((aligned(16))); 260 } overaligned_int_struct_member; 261 overaligned_int_struct_member overaligned_int_struct_member_test() { 262 // CHECK-LABEL: define{{.*}} void @overaligned_int_struct_member_test(%struct.overaligned_int_struct_member* noalias sret(%struct.overaligned_int_struct_member) align 16 %agg.result) 263 return va_arg(the_list, overaligned_int_struct_member); 264 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 265 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 266 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7 267 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8 268 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to i8* 269 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR_ALIGNED]], i32 16 270 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 271 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR_ALIGNED]] to %struct.overaligned_int_struct_member* 272 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_int_struct_member* %agg.result to i8* 273 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_int_struct_member* [[ADDR]] to i8* 274 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 [[DEST_ADDR]], i8* align 8 [[SRC_ADDR]], i32 16, i1 false) 275 // CHECK: ret void 276 } 277 278 typedef struct { 279 long long val __attribute__((packed,aligned(2))); 280 } underaligned_long_long_struct_member; 281 underaligned_long_long_struct_member underaligned_long_long_struct_member_test() { 282 // CHECK-LABEL: define{{.*}} void @underaligned_long_long_struct_member_test(%struct.underaligned_long_long_struct_member* noalias sret(%struct.underaligned_long_long_struct_member) align 2 %agg.result) 283 return va_arg(the_list, underaligned_long_long_struct_member); 284 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 285 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 8 286 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 287 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR]] to %struct.underaligned_long_long_struct_member* 288 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_long_long_struct_member* %agg.result to i8* 289 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.underaligned_long_long_struct_member* [[ADDR]] to i8* 290 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 2 [[DEST_ADDR]], i8* align 4 [[SRC_ADDR]], i32 8, i1 false) 291 // CHECK: ret void 292 } 293 294 typedef struct { 295 long long val __attribute__((aligned(16))); 296 } overaligned_long_long_struct_member; 297 overaligned_long_long_struct_member overaligned_long_long_struct_member_test() { 298 // CHECK-LABEL: define{{.*}} void @overaligned_long_long_struct_member_test(%struct.overaligned_long_long_struct_member* noalias sret(%struct.overaligned_long_long_struct_member) align 16 %agg.result) 299 return va_arg(the_list, overaligned_long_long_struct_member); 300 // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 301 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 302 // CHECK: [[CUR_INT_ADD:%[a-z0-9._]+]] = add i32 [[CUR_INT]], 7 303 // CHECK: [[CUR_INT_ALIGNED:%[a-z0-9._]+]] = and i32 [[CUR_INT_ADD]], -8 304 // CHECK: [[CUR_ALIGNED:%[a-z0-9._]+]] = inttoptr i32 [[CUR_INT_ALIGNED]] to i8* 305 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR_ALIGNED]], i32 16 306 // CHECK: store i8* [[NEXT]], i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 307 // CHECK: [[ADDR:%[a-z0-9._]+]] = bitcast i8* [[CUR_ALIGNED]] to %struct.overaligned_long_long_struct_member* 308 // CHECK: [[DEST_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_long_long_struct_member* %agg.result to i8* 309 // CHECK: [[SRC_ADDR:%[a-z0-9._]+]] = bitcast %struct.overaligned_long_long_struct_member* [[ADDR]] to i8* 310 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 [[DEST_ADDR]], i8* align 8 [[SRC_ADDR]], i32 16, i1 false) 311 // CHECK: ret void 312 } 313 314 void check_start(int n, ...) { 315 // CHECK-LABEL: define{{.*}} void @check_start(i32 %n, ...) 316 317 va_list the_list; 318 va_start(the_list, n); 319 // CHECK: [[THE_LIST:%[a-z0-9._]+]] = alloca %struct.__va_list 320 // CHECK: [[VOIDP_THE_LIST:%[a-z0-9._]+]] = bitcast %struct.__va_list* [[THE_LIST]] to i8* 321 // CHECK: call void @llvm.va_start(i8* [[VOIDP_THE_LIST]]) 322 } 323