277 lines · cpp
1// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOCOMPAT2// 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-V6COMPAT3// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-scei-ps4 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-V6COMPAT4// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-sie-ps5 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-V6COMPAT5 6extern int int_source();7extern void int_sink(int x);8 9namespace test0 {10 struct A {11 int aField;12 int bField;13 };14 15 struct B {16 int onebit : 2;17 int twobit : 6;18 int intField;19 };20 21 struct __attribute__((packed, aligned(2))) C : A, B {22 };23 24 // These accesses should have alignment 4 because they're at offset 025 // in a reference with an assumed alignment of 4.26 // CHECK-LABEL: @_ZN5test01aERNS_1BE27 void a(B &b) {28 // CHECK: [[CALL:%.*]] = call noundef i32 @_Z10int_sourcev()29 // CHECK: [[B_P:%.*]] = load ptr, ptr30 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i831 // CHECK: [[OLD_VALUE:%.*]] = load i8, ptr [[B_P]], align 432 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 333 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -434 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]]35 // CHECK: store i8 [[T2]], ptr [[B_P]], align 436 b.onebit = int_source();37 38 // CHECK: [[B_P:%.*]] = load ptr, ptr39 // CHECK: [[VALUE:%.*]] = load i8, ptr [[B_P]], align 440 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 641 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 642 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i3243 // CHECK: call void @_Z8int_sinki(i32 noundef [[T2]])44 int_sink(b.onebit);45 }46 47 // These accesses should have alignment 2 because they're at offset 848 // in a reference/pointer with an assumed alignment of 2.49 // CHECK-LABEL: @_ZN5test01bERNS_1CE50 void b(C &c) {51 // CHECK: [[CALL:%.*]] = call noundef i32 @_Z10int_sourcev()52 // CHECK: [[C_P:%.*]] = load ptr, ptr53 // CHECK: [[FIELD_P:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 854 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i855 // CHECK-V6COMPAT: [[OLD_VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 256 // CHECK-NOCOMPAT: [[OLD_VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 457 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 358 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -459 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]]60 // CHECK-V6COMPAT: store i8 [[T2]], ptr [[FIELD_P]], align 261 // CHECK-NOCOMPAT: store i8 [[T2]], ptr [[FIELD_P]], align 462 c.onebit = int_source();63 64 // CHECK: [[C_P:%.*]] = load ptr, ptr65 // CHECK: [[FIELD_P:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 866 // CHECK-V6COMPAT: [[VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 267 // CHECK-NOCOMPAT: [[VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 468 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 669 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 670 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i3271 // CHECK: call void @_Z8int_sinki(i32 noundef [[T2]])72 int_sink(c.onebit);73 }74 75 // CHECK-LABEL: @_ZN5test01cEPNS_1CE76 void c(C *c) {77 // CHECK: [[CALL:%.*]] = call noundef i32 @_Z10int_sourcev()78 // CHECK: [[C_P:%.*]] = load ptr, ptr79 // CHECK: [[FIELD_P:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 880 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i881 // CHECK-V6COMPAT: [[OLD_VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 282 // CHECK-NOCOMPAT: [[OLD_VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 483 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 384 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -485 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]]86 // CHECK-V6COMPAT: store i8 [[T2]], ptr [[FIELD_P]], align 287 // CHECK-NOCOMPAT: store i8 [[T2]], ptr [[FIELD_P]], align 488 c->onebit = int_source();89 90 // CHECK: [[C_P:%.*]] = load ptr, ptr91 // CHECK: [[P:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 892 // CHECK-V6COMPAT: [[VALUE:%.*]] = load i8, ptr [[P]], align 293 // CHECK-NOCOMPAT: [[VALUE:%.*]] = load i8, ptr [[P]], align 494 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 695 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 696 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i3297 // CHECK: call void @_Z8int_sinki(i32 noundef [[T2]])98 int_sink(c->onebit);99 }100 101 // These accesses should have alignment 2 because they're at offset 8102 // in an alignment-2 variable.103 // CHECK-LABEL: @_ZN5test01dEv104 void d() {105 // CHECK-V6COMPAT: [[C_P:%.*]] = alloca [[C:%.*]], align 2106 // CHECK-NOCOMPAT: [[C_P:%.*]] = alloca [[C:%.*]], align 4107 C c;108 109 // CHECK: [[CALL:%.*]] = call noundef i32 @_Z10int_sourcev()110 // CHECK: [[FIELD_P:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 8111 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i8112 // CHECK-V6COMPAT: [[OLD_VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 2113 // CHECK-NOCOMPAT: [[OLD_VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 4114 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 3115 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -4116 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]]117 // CHECK-V6COMPAT: store i8 [[T2]], ptr [[FIELD_P]], align 2118 // CHECK-NOCOMPAT: store i8 [[T2]], ptr [[FIELD_P]], align 4119 c.onebit = int_source();120 121 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 8122 // CHECK-V6COMPAT: [[VALUE:%.*]] = load i8, ptr [[T1]], align 2123 // CHECK-NOCOMPAT: [[VALUE:%.*]] = load i8, ptr [[T1]], align 4124 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 6125 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 6126 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i32127 // CHECK: call void @_Z8int_sinki(i32 noundef [[T2]])128 int_sink(c.onebit);129 }130 131 // These accesses should have alignment 8 because they're at offset 8132 // in an alignment-16 variable.133 // CHECK-LABEL: @_ZN5test01eEv134 void e() {135 // CHECK: [[C_P:%.*]] = alloca [[C:%.*]], align 16136 __attribute__((aligned(16))) C c;137 138 // CHECK: [[CALL:%.*]] = call noundef i32 @_Z10int_sourcev()139 // CHECK: [[FIELD_P:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 8140 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i8141 // CHECK: [[OLD_VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 8142 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 3143 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -4144 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]]145 // CHECK: store i8 [[T2]], ptr [[FIELD_P]], align 8146 c.onebit = int_source();147 148 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 8149 // CHECK: [[VALUE:%.*]] = load i8, ptr [[T1]], align 8150 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 6151 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 6152 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i32153 // CHECK: call void @_Z8int_sinki(i32 noundef [[T2]])154 int_sink(c.onebit);155 }156}157 158namespace test1 {159 struct Array {160 int elts[4];161 };162 163 struct A {164 __attribute__((aligned(16))) Array aArray;165 };166 167 struct B : virtual A {168 void *bPointer; // puts bArray at offset 16169 Array bArray;170 };171 172 struct C : virtual A { // must be viable as primary base173 // Non-empty, nv-size not a multiple of 16.174 void *cPointer1;175 void *cPointer2;176 };177 178 // Proof of concept that the non-virtual components of B do not have179 // to be 16-byte-aligned.180 struct D : C, B {};181 182 // For the following tests, we want to assign into a variable whose183 // alignment is high enough that it will absolutely not be the184 // constraint on the memcpy alignment.185 typedef __attribute__((aligned(64))) Array AlignedArray;186 187 // CHECK-LABEL: @_ZN5test11aERNS_1AE188 void a(A &a) {189 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY:%.*]], align 64190 // CHECK: [[A_P:%.*]] = load ptr, ptr191 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[A:%.*]], ptr [[A_P]], i32 0, i32 0192 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 16 [[ARRAY_P]], i64 16, i1 false)193 AlignedArray result = a.aArray;194 }195 196 // CHECK-LABEL: @_ZN5test11bERNS_1BE197 void b(B &b) {198 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64199 // CHECK: [[B_P:%.*]] = load ptr, ptr200 // CHECK: [[VPTR:%.*]] = load ptr, ptr [[B_P]], align 8201 // CHECK: [[T0:%.*]] = getelementptr i8, ptr [[VPTR]], i64 -24202 // CHECK: [[OFFSET:%.*]] = load i64, ptr [[T0]], align 8203 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, ptr [[B_P]], i64 [[OFFSET]]204 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[A]], ptr [[T1]], i32 0, i32 0205 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 16 [[ARRAY_P]], i64 16, i1 false)206 AlignedArray result = b.aArray;207 }208 209 // CHECK-LABEL: @_ZN5test11cERNS_1BE210 void c(B &b) {211 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64212 // CHECK: [[B_P:%.*]] = load ptr, ptr213 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[B:%.*]], ptr [[B_P]], i32 0, i32 2214 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 8 [[ARRAY_P]], i64 16, i1 false)215 AlignedArray result = b.bArray;216 }217 218 // CHECK-LABEL: @_ZN5test11dEPNS_1BE219 void d(B *b) {220 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64221 // CHECK: [[B_P:%.*]] = load ptr, ptr222 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[B:%.*]], ptr [[B_P]], i32 0, i32 2223 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 8 [[ARRAY_P]], i64 16, i1 false)224 AlignedArray result = b->bArray;225 }226 227 // CHECK-LABEL: @_ZN5test11eEv228 void e() {229 // CHECK: [[B_P:%.*]] = alloca [[B:%.*]], align 16230 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64231 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[B:%.*]], ptr [[B_P]], i32 0, i32 2232 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 16 [[ARRAY_P]], i64 16, i1 false)233 B b;234 AlignedArray result = b.bArray;235 }236 237 // CHECK-LABEL: @_ZN5test11fEv238 void f() {239 // TODO: we should devirtualize this derived-to-base conversion.240 // CHECK: [[D_P:%.*]] = alloca [[D:%.*]], align 16241 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64242 // CHECK: [[VPTR:%.*]] = load ptr, ptr [[D_P]], align 16243 // CHECK: [[T0:%.*]] = getelementptr i8, ptr [[VPTR]], i64 -24244 // CHECK: [[OFFSET:%.*]] = load i64, ptr [[T0]], align 8245 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, ptr [[D_P]], i64 [[OFFSET]]246 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[A]], ptr [[T1]], i32 0, i32 0247 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 16 [[ARRAY_P]], i64 16, i1 false)248 D d;249 AlignedArray result = d.aArray;250 }251 252 // CHECK-LABEL: @_ZN5test11gEv253 void g() {254 // CHECK: [[D_P:%.*]] = alloca [[D]], align 16255 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64256 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, ptr [[D_P]], i64 24257 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[B:%.*]], ptr [[T1]], i32 0, i32 2258 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 8 [[ARRAY_P]], i64 16, i1 false)259 D d;260 AlignedArray result = d.bArray;261 }262 263 // CHECK-LABEL: @_ZN5test11hEPA_NS_1BE264 void h(B (*b)[]) {265 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64266 // CHECK: [[B_P:%.*]] = load ptr, ptr267 // CHECK: [[ELEMENT_P:%.*]] = getelementptr inbounds [0 x [[B]]], ptr [[B_P]], i64 0268 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[B]], ptr [[ELEMENT_P]], i32 0, i32 2269 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 16 [[ARRAY_P]], i64 16, i1 false)270 AlignedArray result = (*b)->bArray;271 }272}273 274// CHECK-LABEL: @_Z22incomplete_array_derefPA_i275// CHECK: load i32, ptr {{%.*}}, align 4276int incomplete_array_deref(int (*p)[]) { return (*p)[2]; }277