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