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