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