1 // RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOCOMPAT 2 // RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 -fclang-abi-compat=6.0 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-V6COMPAT 3 // Check that the PS4 target uses the 6.0 compat settings. 4 // RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-scei-ps4 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-V6COMPAT 5 // RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-scei-ps4 -fclang-abi-compat=latest | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-V6COMPAT 6 7 extern int int_source(); 8 extern void int_sink(int x); 9 10 namespace test0 { 11 struct A { 12 int aField; 13 int bField; 14 }; 15 16 struct B { 17 int onebit : 2; 18 int twobit : 6; 19 int intField; 20 }; 21 22 struct __attribute__((packed, aligned(2))) C : A, B { 23 }; 24 25 // These accesses should have alignment 4 because they're at offset 0 26 // in a reference with an assumed alignment of 4. 27 // CHECK-LABEL: @_ZN5test01aERNS_1BE 28 void a(B &b) { 29 // CHECK: [[CALL:%.*]] = call i32 @_Z10int_sourcev() 30 // CHECK: [[B_P:%.*]] = load [[B:%.*]]*, [[B]]** 31 // CHECK: [[FIELD_P:%.*]] = bitcast [[B]]* [[B_P]] to i8* 32 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i8 33 // CHECK: [[OLD_VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 4 34 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 3 35 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -4 36 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]] 37 // CHECK: store i8 [[T2]], i8* [[FIELD_P]], align 4 38 b.onebit = int_source(); 39 40 // CHECK: [[B_P:%.*]] = load [[B]]*, [[B]]** 41 // CHECK: [[FIELD_P:%.*]] = bitcast [[B]]* [[B_P]] to i8* 42 // CHECK: [[VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 4 43 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 6 44 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 6 45 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i32 46 // CHECK: call void @_Z8int_sinki(i32 [[T2]]) 47 int_sink(b.onebit); 48 } 49 50 // These accesses should have alignment 2 because they're at offset 8 51 // in a reference/pointer with an assumed alignment of 2. 52 // CHECK-LABEL: @_ZN5test01bERNS_1CE 53 void b(C &c) { 54 // CHECK: [[CALL:%.*]] = call i32 @_Z10int_sourcev() 55 // CHECK: [[C_P:%.*]] = load [[C:%.*]]*, [[C]]** 56 // CHECK: [[T0:%.*]] = bitcast [[C]]* [[C_P]] to i8* 57 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, i8* [[T0]], i64 8 58 // CHECK: [[B_P:%.*]] = bitcast i8* [[T1]] to [[B]]* 59 // CHECK: [[FIELD_P:%.*]] = bitcast [[B]]* [[B_P]] to i8* 60 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i8 61 // CHECK-V6COMPAT: [[OLD_VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 2 62 // CHECK-NOCOMPAT: [[OLD_VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 4 63 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 3 64 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -4 65 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]] 66 // CHECK-V6COMPAT: store i8 [[T2]], i8* [[FIELD_P]], align 2 67 // CHECK-NOCOMPAT: store i8 [[T2]], i8* [[FIELD_P]], align 4 68 c.onebit = int_source(); 69 70 // CHECK: [[C_P:%.*]] = load [[C]]*, [[C]]** 71 // CHECK: [[T0:%.*]] = bitcast [[C]]* [[C_P]] to i8* 72 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, i8* [[T0]], i64 8 73 // CHECK: [[B_P:%.*]] = bitcast i8* [[T1]] to [[B]]* 74 // CHECK: [[FIELD_P:%.*]] = bitcast [[B]]* [[B_P]] to i8* 75 // CHECK-V6COMPAT: [[VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 2 76 // CHECK-NOCOMPAT: [[VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 4 77 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 6 78 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 6 79 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i32 80 // CHECK: call void @_Z8int_sinki(i32 [[T2]]) 81 int_sink(c.onebit); 82 } 83 84 // CHECK-LABEL: @_ZN5test01cEPNS_1CE 85 void c(C *c) { 86 // CHECK: [[CALL:%.*]] = call i32 @_Z10int_sourcev() 87 // CHECK: [[C_P:%.*]] = load [[C]]*, [[C]]** 88 // CHECK: [[T0:%.*]] = bitcast [[C]]* [[C_P]] to i8* 89 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, i8* [[T0]], i64 8 90 // CHECK: [[B_P:%.*]] = bitcast i8* [[T1]] to [[B]]* 91 // CHECK: [[FIELD_P:%.*]] = bitcast [[B]]* [[B_P]] to i8* 92 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i8 93 // CHECK-V6COMPAT: [[OLD_VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 2 94 // CHECK-NOCOMPAT: [[OLD_VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 4 95 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 3 96 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -4 97 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]] 98 // CHECK-V6COMPAT: store i8 [[T2]], i8* [[FIELD_P]], align 2 99 // CHECK-NOCOMPAT: store i8 [[T2]], i8* [[FIELD_P]], align 4 100 c->onebit = int_source(); 101 102 // CHECK: [[C_P:%.*]] = load [[C:%.*]]*, [[C]]** 103 // CHECK: [[T0:%.*]] = bitcast [[C]]* [[C_P]] to i8* 104 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, i8* [[T0]], i64 8 105 // CHECK: [[B_P:%.*]] = bitcast i8* [[T1]] to [[B:%.*]]* 106 // CHECK: [[FIELD_P:%.*]] = bitcast [[B]]* [[B_P]] to i8* 107 // CHECK-V6COMPAT: [[VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 2 108 // CHECK-NOCOMPAT: [[VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 4 109 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 6 110 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 6 111 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i32 112 // CHECK: call void @_Z8int_sinki(i32 [[T2]]) 113 int_sink(c->onebit); 114 } 115 116 // These accesses should have alignment 2 because they're at offset 8 117 // in an alignment-2 variable. 118 // CHECK-LABEL: @_ZN5test01dEv 119 void d() { 120 // CHECK-V6COMPAT: [[C_P:%.*]] = alloca [[C:%.*]], align 2 121 // CHECK-NOCOMPAT: [[C_P:%.*]] = alloca [[C:%.*]], align 4 122 C c; 123 124 // CHECK: [[CALL:%.*]] = call i32 @_Z10int_sourcev() 125 // CHECK: [[T0:%.*]] = bitcast [[C]]* [[C_P]] to i8* 126 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, i8* [[T0]], i64 8 127 // CHECK: [[B_P:%.*]] = bitcast i8* [[T1]] to [[B]]* 128 // CHECK: [[FIELD_P:%.*]] = bitcast [[B]]* [[B_P]] to i8* 129 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i8 130 // CHECK-V6COMPAT: [[OLD_VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 2 131 // CHECK-NOCOMPAT: [[OLD_VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 4 132 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 3 133 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -4 134 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]] 135 // CHECK-V6COMPAT: store i8 [[T2]], i8* [[FIELD_P]], align 2 136 // CHECK-NOCOMPAT: store i8 [[T2]], i8* [[FIELD_P]], align 4 137 c.onebit = int_source(); 138 139 // CHECK: [[T0:%.*]] = bitcast [[C]]* [[C_P]] to i8* 140 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, i8* [[T0]], i64 8 141 // CHECK: [[B_P:%.*]] = bitcast i8* [[T1]] to [[B:%.*]]* 142 // CHECK: [[FIELD_P:%.*]] = bitcast [[B]]* [[B_P]] to i8* 143 // CHECK-V6COMPAT: [[VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 2 144 // CHECK-NOCOMPAT: [[VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 4 145 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 6 146 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 6 147 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i32 148 // CHECK: call void @_Z8int_sinki(i32 [[T2]]) 149 int_sink(c.onebit); 150 } 151 152 // These accesses should have alignment 8 because they're at offset 8 153 // in an alignment-16 variable. 154 // CHECK-LABEL: @_ZN5test01eEv 155 void e() { 156 // CHECK: [[C_P:%.*]] = alloca [[C:%.*]], align 16 157 __attribute__((aligned(16))) C c; 158 159 // CHECK: [[CALL:%.*]] = call i32 @_Z10int_sourcev() 160 // CHECK: [[T0:%.*]] = bitcast [[C]]* [[C_P]] to i8* 161 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, i8* [[T0]], i64 8 162 // CHECK: [[B_P:%.*]] = bitcast i8* [[T1]] to [[B]]* 163 // CHECK: [[FIELD_P:%.*]] = bitcast [[B]]* [[B_P]] to i8* 164 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i8 165 // CHECK: [[OLD_VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 8 166 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 3 167 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -4 168 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]] 169 // CHECK: store i8 [[T2]], i8* [[FIELD_P]], align 8 170 c.onebit = int_source(); 171 172 // CHECK: [[T0:%.*]] = bitcast [[C]]* [[C_P]] to i8* 173 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, i8* [[T0]], i64 8 174 // CHECK: [[B_P:%.*]] = bitcast i8* [[T1]] to [[B:%.*]]* 175 // CHECK: [[FIELD_P:%.*]] = bitcast [[B]]* [[B_P]] to i8* 176 // CHECK: [[VALUE:%.*]] = load i8, i8* [[FIELD_P]], align 8 177 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 6 178 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 6 179 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i32 180 // CHECK: call void @_Z8int_sinki(i32 [[T2]]) 181 int_sink(c.onebit); 182 } 183 } 184 185 namespace test1 { 186 struct Array { 187 int elts[4]; 188 }; 189 190 struct A { 191 __attribute__((aligned(16))) Array aArray; 192 }; 193 194 struct B : virtual A { 195 void *bPointer; // puts bArray at offset 16 196 Array bArray; 197 }; 198 199 struct C : virtual A { // must be viable as primary base 200 // Non-empty, nv-size not a multiple of 16. 201 void *cPointer1; 202 void *cPointer2; 203 }; 204 205 // Proof of concept that the non-virtual components of B do not have 206 // to be 16-byte-aligned. 207 struct D : C, B {}; 208 209 // For the following tests, we want to assign into a variable whose 210 // alignment is high enough that it will absolutely not be the 211 // constraint on the memcpy alignment. 212 typedef __attribute__((aligned(64))) Array AlignedArray; 213 214 // CHECK-LABEL: @_ZN5test11aERNS_1AE 215 void a(A &a) { 216 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY:%.*]], align 64 217 // CHECK: [[A_P:%.*]] = load [[A:%.*]]*, [[A]]** 218 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds [[A]], [[A]]* [[A_P]], i32 0, i32 0 219 // CHECK: [[T0:%.*]] = bitcast [[ARRAY]]* [[RESULT]] to i8* 220 // CHECK: [[T1:%.*]] = bitcast [[ARRAY]]* [[ARRAY_P]] to i8* 221 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 64 [[T0]], i8* align 16 [[T1]], i64 16, i1 false) 222 AlignedArray result = a.aArray; 223 } 224 225 // CHECK-LABEL: @_ZN5test11bERNS_1BE 226 void b(B &b) { 227 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64 228 // CHECK: [[B_P:%.*]] = load [[B:%.*]]*, [[B]]** 229 // CHECK: [[VPTR_P:%.*]] = bitcast [[B]]* [[B_P]] to i8** 230 // CHECK: [[VPTR:%.*]] = load i8*, i8** [[VPTR_P]], align 8 231 // CHECK: [[T0:%.*]] = getelementptr i8, i8* [[VPTR]], i64 -24 232 // CHECK: [[OFFSET_P:%.*]] = bitcast i8* [[T0]] to i64* 233 // CHECK: [[OFFSET:%.*]] = load i64, i64* [[OFFSET_P]], align 8 234 // CHECK: [[T0:%.*]] = bitcast [[B]]* [[B_P]] to i8* 235 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, i8* [[T0]], i64 [[OFFSET]] 236 // CHECK: [[A_P:%.*]] = bitcast i8* [[T1]] to [[A]]* 237 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds [[A]], [[A]]* [[A_P]], i32 0, i32 0 238 // CHECK: [[T0:%.*]] = bitcast [[ARRAY]]* [[RESULT]] to i8* 239 // CHECK: [[T1:%.*]] = bitcast [[ARRAY]]* [[ARRAY_P]] to i8* 240 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 64 [[T0]], i8* align 16 [[T1]], i64 16, i1 false) 241 AlignedArray result = b.aArray; 242 } 243 244 // CHECK-LABEL: @_ZN5test11cERNS_1BE 245 void c(B &b) { 246 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64 247 // CHECK: [[B_P:%.*]] = load [[B]]*, [[B]]** 248 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds [[B]], [[B]]* [[B_P]], i32 0, i32 2 249 // CHECK: [[T0:%.*]] = bitcast [[ARRAY]]* [[RESULT]] to i8* 250 // CHECK: [[T1:%.*]] = bitcast [[ARRAY]]* [[ARRAY_P]] to i8* 251 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 64 [[T0]], i8* align 8 [[T1]], i64 16, i1 false) 252 AlignedArray result = b.bArray; 253 } 254 255 // CHECK-LABEL: @_ZN5test11dEPNS_1BE 256 void d(B *b) { 257 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64 258 // CHECK: [[B_P:%.*]] = load [[B]]*, [[B]]** 259 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds [[B]], [[B]]* [[B_P]], i32 0, i32 2 260 // CHECK: [[T0:%.*]] = bitcast [[ARRAY]]* [[RESULT]] to i8* 261 // CHECK: [[T1:%.*]] = bitcast [[ARRAY]]* [[ARRAY_P]] to i8* 262 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 64 [[T0]], i8* align 8 [[T1]], i64 16, i1 false) 263 AlignedArray result = b->bArray; 264 } 265 266 // CHECK-LABEL: @_ZN5test11eEv 267 void e() { 268 // CHECK: [[B_P:%.*]] = alloca [[B]], align 16 269 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64 270 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds [[B]], [[B]]* [[B_P]], i32 0, i32 2 271 // CHECK: [[T0:%.*]] = bitcast [[ARRAY]]* [[RESULT]] to i8* 272 // CHECK: [[T1:%.*]] = bitcast [[ARRAY]]* [[ARRAY_P]] to i8* 273 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 64 [[T0]], i8* align 16 [[T1]], i64 16, i1 false) 274 B b; 275 AlignedArray result = b.bArray; 276 } 277 278 // CHECK-LABEL: @_ZN5test11fEv 279 void f() { 280 // TODO: we should devirtualize this derived-to-base conversion. 281 // CHECK: [[D_P:%.*]] = alloca [[D:%.*]], align 16 282 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64 283 // CHECK: [[VPTR_P:%.*]] = bitcast [[D]]* [[D_P]] to i8** 284 // CHECK: [[VPTR:%.*]] = load i8*, i8** [[VPTR_P]], align 16 285 // CHECK: [[T0:%.*]] = getelementptr i8, i8* [[VPTR]], i64 -24 286 // CHECK: [[OFFSET_P:%.*]] = bitcast i8* [[T0]] to i64* 287 // CHECK: [[OFFSET:%.*]] = load i64, i64* [[OFFSET_P]], align 8 288 // CHECK: [[T0:%.*]] = bitcast [[D]]* [[D_P]] to i8* 289 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, i8* [[T0]], i64 [[OFFSET]] 290 // CHECK: [[A_P:%.*]] = bitcast i8* [[T1]] to [[A]]* 291 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds [[A]], [[A]]* [[A_P]], i32 0, i32 0 292 // CHECK: [[T0:%.*]] = bitcast [[ARRAY]]* [[RESULT]] to i8* 293 // CHECK: [[T1:%.*]] = bitcast [[ARRAY]]* [[ARRAY_P]] to i8* 294 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 64 [[T0]], i8* align 16 [[T1]], i64 16, i1 false) 295 D d; 296 AlignedArray result = d.aArray; 297 } 298 299 // CHECK-LABEL: @_ZN5test11gEv 300 void g() { 301 // CHECK: [[D_P:%.*]] = alloca [[D]], align 16 302 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64 303 // CHECK: [[T0:%.*]] = bitcast [[D]]* [[D_P]] to i8* 304 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, i8* [[T0]], i64 24 305 // CHECK: [[B_P:%.*]] = bitcast i8* [[T1]] to [[B:%.*]]* 306 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds [[B]], [[B]]* [[B_P]], i32 0, i32 2 307 // CHECK: [[T0:%.*]] = bitcast [[ARRAY]]* [[RESULT]] to i8* 308 // CHECK: [[T1:%.*]] = bitcast [[ARRAY]]* [[ARRAY_P]] to i8* 309 // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 64 [[T0]], i8* align 8 [[T1]], i64 16, i1 false) 310 D d; 311 AlignedArray result = d.bArray; 312 } 313 } 314