xref: /llvm-project/clang/test/CodeGenCXX/alignment.cpp (revision dde9de7cf943ace41ac69589df661b2ab54dd76b)
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