1 // RUN: %clang_cc1 -emit-llvm -triple x86_64 -O3 -o %t.opt.ll %s \
2 // RUN:   -fdump-record-layouts > %t.dump.txt
3 // RUN: FileCheck -check-prefix=CHECK-RECORD < %t.dump.txt %s
4 // RUN: FileCheck -check-prefix=CHECK-OPT < %t.opt.ll %s
5 
6 /****/
7 
8 // Check that we don't read off the end a packed 24-bit structure.
9 // PR6176
10 
11 // CHECK-RECORD: *** Dumping IRgen Record Layout
12 // CHECK-RECORD: Record: RecordDecl{{.*}}s0
13 // CHECK-RECORD: Layout: <CGRecordLayout
14 // CHECK-RECORD:   LLVMType:%struct.s0 = type { [3 x i8] }
15 // CHECK-RECORD:   IsZeroInitializable:1
16 // CHECK-RECORD:   BitFields:[
17 // CHECK-RECORD:     <CGBitFieldInfo Offset:0 Size:24 IsSigned:1 StorageSize:24 StorageOffset:0>
18 struct __attribute((packed)) s0 {
19   int f0 : 24;
20 };
21 
22 struct s0 g0 = { 0xdeadbeef };
23 
f0_load(struct s0 * a0)24 int f0_load(struct s0 *a0) {
25   int size_check[sizeof(struct s0) == 3 ? 1 : -1];
26   return a0->f0;
27 }
f0_store(struct s0 * a0)28 int f0_store(struct s0 *a0) {
29   return (a0->f0 = 1);
30 }
f0_reload(struct s0 * a0)31 int f0_reload(struct s0 *a0) {
32   return (a0->f0 += 1);
33 }
34 
35 // CHECK-OPT-LABEL: define i64 @test_0()
36 // CHECK-OPT:  ret i64 1
37 // CHECK-OPT: }
test_0()38 unsigned long long test_0() {
39   struct s0 g0 = { 0xdeadbeef };
40   unsigned long long res = 0;
41   res ^= g0.f0;
42   res ^= f0_load(&g0) ^ f0_store(&g0) ^ f0_reload(&g0);
43   res ^= g0.f0;
44   return res;
45 }
46 
47 /****/
48 
49 // PR5591
50 
51 // CHECK-RECORD: *** Dumping IRgen Record Layout
52 // CHECK-RECORD: Record: RecordDecl{{.*}}s1
53 // CHECK-RECORD: Layout: <CGRecordLayout
54 // CHECK-RECORD:   LLVMType:%struct.s1 = type { [3 x i8] }
55 // CHECK-RECORD:   IsZeroInitializable:1
56 // CHECK-RECORD:   BitFields:[
57 // CHECK-RECORD:     <CGBitFieldInfo Offset:0 Size:10 IsSigned:1 StorageSize:24 StorageOffset:0>
58 // CHECK-RECORD:     <CGBitFieldInfo Offset:10 Size:10 IsSigned:1 StorageSize:24 StorageOffset:0>
59 
60 #pragma pack(push)
61 #pragma pack(1)
62 struct __attribute((packed)) s1 {
63   signed f0 : 10;
64   signed f1 : 10;
65 };
66 #pragma pack(pop)
67 
68 struct s1 g1 = { 0xdeadbeef, 0xdeadbeef };
69 
f1_load(struct s1 * a0)70 int f1_load(struct s1 *a0) {
71   int size_check[sizeof(struct s1) == 3 ? 1 : -1];
72   return a0->f1;
73 }
f1_store(struct s1 * a0)74 int f1_store(struct s1 *a0) {
75   return (a0->f1 = 1234);
76 }
f1_reload(struct s1 * a0)77 int f1_reload(struct s1 *a0) {
78   return (a0->f1 += 1234);
79 }
80 
81 // CHECK-OPT-LABEL: define i64 @test_1()
82 // CHECK-OPT:  ret i64 210
83 // CHECK-OPT: }
test_1()84 unsigned long long test_1() {
85   struct s1 g1 = { 0xdeadbeef, 0xdeadbeef };
86   unsigned long long res = 0;
87   res ^= g1.f0 ^ g1.f1;
88   res ^= f1_load(&g1) ^ f1_store(&g1) ^ f1_reload(&g1);
89   res ^= g1.f0 ^ g1.f1;
90   return res;
91 }
92 
93 /****/
94 
95 // Check that we don't access beyond the bounds of a union.
96 //
97 // PR5567
98 
99 // CHECK-RECORD: *** Dumping IRgen Record Layout
100 // CHECK-RECORD: Record: RecordDecl{{.*}}u2
101 // CHECK-RECORD: Layout: <CGRecordLayout
102 // CHECK-RECORD:   LLVMType:%union.u2 = type { i8 }
103 // CHECK-RECORD:   IsZeroInitializable:1
104 // CHECK-RECORD:   BitFields:[
105 // CHECK-RECORD:     <CGBitFieldInfo Offset:0 Size:3 IsSigned:0 StorageSize:8 StorageOffset:0>
106 
107 union __attribute__((packed)) u2 {
108   unsigned long long f0 : 3;
109 };
110 
111 union u2 g2 = { 0xdeadbeef };
112 
f2_load(union u2 * a0)113 int f2_load(union u2 *a0) {
114   return a0->f0;
115 }
f2_store(union u2 * a0)116 int f2_store(union u2 *a0) {
117   return (a0->f0 = 1234);
118 }
f2_reload(union u2 * a0)119 int f2_reload(union u2 *a0) {
120   return (a0->f0 += 1234);
121 }
122 
123 // CHECK-OPT-LABEL: define i64 @test_2()
124 // CHECK-OPT:  ret i64 2
125 // CHECK-OPT: }
test_2()126 unsigned long long test_2() {
127   union u2 g2 = { 0xdeadbeef };
128   unsigned long long res = 0;
129   res ^= g2.f0;
130   res ^= f2_load(&g2) ^ f2_store(&g2) ^ f2_reload(&g2);
131   res ^= g2.f0;
132   return res;
133 }
134 
135 /***/
136 
137 // PR5039
138 
139 struct s3 {
140   long long f0 : 32;
141   long long f1 : 32;
142 };
143 
144 struct s3 g3 = { 0xdeadbeef, 0xdeadbeef };
145 
f3_load(struct s3 * a0)146 int f3_load(struct s3 *a0) {
147   a0->f0 = 1;
148   return a0->f0;
149 }
f3_store(struct s3 * a0)150 int f3_store(struct s3 *a0) {
151   a0->f0 = 1;
152   return (a0->f0 = 1234);
153 }
f3_reload(struct s3 * a0)154 int f3_reload(struct s3 *a0) {
155   a0->f0 = 1;
156   return (a0->f0 += 1234);
157 }
158 
159 // CHECK-OPT-LABEL: define i64 @test_3()
160 // CHECK-OPT:  ret i64 -559039940
161 // CHECK-OPT: }
test_3()162 unsigned long long test_3() {
163   struct s3 g3 = { 0xdeadbeef, 0xdeadbeef };
164   unsigned long long res = 0;
165   res ^= g3.f0 ^ g3.f1;
166   res ^= f3_load(&g3) ^ f3_store(&g3) ^ f3_reload(&g3);
167   res ^= g3.f0 ^ g3.f1;
168   return res;
169 }
170 
171 /***/
172 
173 // This is a case where the bitfield access will straddle an alignment boundary
174 // of its underlying type.
175 
176 struct s4 {
177   unsigned f0 : 16;
178   unsigned f1 : 28 __attribute__ ((packed));
179 };
180 
181 struct s4 g4 = { 0xdeadbeef, 0xdeadbeef };
182 
f4_load(struct s4 * a0)183 int f4_load(struct s4 *a0) {
184   return a0->f0 ^ a0->f1;
185 }
f4_store(struct s4 * a0)186 int f4_store(struct s4 *a0) {
187   return (a0->f0 = 1234) ^ (a0->f1 = 5678);
188 }
f4_reload(struct s4 * a0)189 int f4_reload(struct s4 *a0) {
190   return (a0->f0 += 1234) ^ (a0->f1 += 5678);
191 }
192 
193 // CHECK-OPT-LABEL: define i64 @test_4()
194 // CHECK-OPT:  ret i64 4860
195 // CHECK-OPT: }
test_4()196 unsigned long long test_4() {
197   struct s4 g4 = { 0xdeadbeef, 0xdeadbeef };
198   unsigned long long res = 0;
199   res ^= g4.f0 ^ g4.f1;
200   res ^= f4_load(&g4) ^ f4_store(&g4) ^ f4_reload(&g4);
201   res ^= g4.f0 ^ g4.f1;
202   return res;
203 }
204 
205 /***/
206 
207 struct s5 {
208   unsigned f0 : 2;
209   _Bool f1 : 1;
210   _Bool f2 : 1;
211 };
212 
213 struct s5 g5 = { 0xdeadbeef, 0xdeadbeef };
214 
f5_load(struct s5 * a0)215 int f5_load(struct s5 *a0) {
216   return a0->f0 ^ a0->f1;
217 }
f5_store(struct s5 * a0)218 int f5_store(struct s5 *a0) {
219   return (a0->f0 = 0xF) ^ (a0->f1 = 0xF) ^ (a0->f2 = 0xF);
220 }
f5_reload(struct s5 * a0)221 int f5_reload(struct s5 *a0) {
222   return (a0->f0 += 0xF) ^ (a0->f1 += 0xF) ^ (a0->f2 += 0xF);
223 }
224 
225 // CHECK-OPT-LABEL: define i64 @test_5()
226 // CHECK-OPT:  ret i64 2
227 // CHECK-OPT: }
test_5()228 unsigned long long test_5() {
229   struct s5 g5 = { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef };
230   unsigned long long res = 0;
231   res ^= g5.f0 ^ g5.f1 ^ g5.f2;
232   res ^= f5_load(&g5) ^ f5_store(&g5) ^ f5_reload(&g5);
233   res ^= g5.f0 ^ g5.f1 ^ g5.f2;
234   return res;
235 }
236 
237 /***/
238 
239 struct s6 {
240   unsigned f0 : 2;
241 };
242 
243 struct s6 g6 = { 0xF };
244 
f6_load(struct s6 * a0)245 int f6_load(struct s6 *a0) {
246   return a0->f0;
247 }
f6_store(struct s6 * a0)248 int f6_store(struct s6 *a0) {
249   return a0->f0 = 0x0;
250 }
f6_reload(struct s6 * a0)251 int f6_reload(struct s6 *a0) {
252   return (a0->f0 += 0xF);
253 }
254 
255 // CHECK-OPT-LABEL: define zeroext i1 @test_6()
256 // CHECK-OPT:  ret i1 true
257 // CHECK-OPT: }
test_6()258 _Bool test_6() {
259   struct s6 g6 = { 0xF };
260   unsigned long long res = 0;
261   res ^= g6.f0;
262   res ^= f6_load(&g6);
263   res ^= g6.f0;
264   return res;
265 }
266 
267 /***/
268 
269 // Check that we compute the best alignment possible for each access.
270 //
271 // CHECK-RECORD: *** Dumping IRgen Record Layout
272 // CHECK-RECORD: Record: RecordDecl{{.*}}s7
273 // CHECK-RECORD: Layout: <CGRecordLayout
274 // CHECK-RECORD:   LLVMType:%struct.s7 = type { i32, i32, i32, i8, i32, [12 x i8] }
275 // CHECK-RECORD:   IsZeroInitializable:1
276 // CHECK-RECORD:   BitFields:[
277 // CHECK-RECORD:     <CGBitFieldInfo Offset:0 Size:5 IsSigned:1 StorageSize:8 StorageOffset:12>
278 // CHECK-RECORD:     <CGBitFieldInfo Offset:0 Size:29 IsSigned:1 StorageSize:32 StorageOffset:16>
279 
280 struct __attribute__((aligned(16))) s7 {
281   int a, b, c;
282   int f0 : 5;
283   int f1 : 29;
284 };
285 
f7_load(struct s7 * a0)286 int f7_load(struct s7 *a0) {
287   return a0->f0;
288 }
289 
290 /***/
291 
292 // This is a case where we narrow the access width immediately.
293 
294 struct __attribute__((packed)) s8 {
295   char f0 : 4;
296   char f1;
297   int  f2 : 4;
298   char f3 : 4;
299 };
300 
301 struct s8 g8 = { 0xF };
302 
f8_load(struct s8 * a0)303 int f8_load(struct s8 *a0) {
304   return a0->f0 ^ a0 ->f2 ^ a0->f3;
305 }
f8_store(struct s8 * a0)306 int f8_store(struct s8 *a0) {
307   return (a0->f0 = 0xFD) ^ (a0->f2 = 0xFD) ^ (a0->f3 = 0xFD);
308 }
f8_reload(struct s8 * a0)309 int f8_reload(struct s8 *a0) {
310   return (a0->f0 += 0xFD) ^ (a0->f2 += 0xFD) ^ (a0->f3 += 0xFD);
311 }
312 
313 // CHECK-OPT-LABEL: define i32 @test_8()
314 // CHECK-OPT:  ret i32 -3
315 // CHECK-OPT: }
test_8()316 unsigned test_8() {
317   struct s8 g8 = { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef };
318   unsigned long long res = 0;
319   res ^= g8.f0 ^ g8.f2 ^ g8.f3;
320   res ^= f8_load(&g8) ^ f8_store(&g8) ^ f8_reload(&g8);
321   res ^= g8.f0 ^ g8.f2 ^ g8.f3;
322   return res;
323 }
324 
325 /***/
326 
327 // This is another case where we narrow the access width immediately.
328 //
329 // <rdar://problem/7893760>
330 
331 struct __attribute__((packed)) s9 {
332   unsigned f0 : 7;
333   unsigned f1 : 7;
334   unsigned f2 : 7;
335   unsigned f3 : 7;
336   unsigned f4 : 7;
337   unsigned f5 : 7;
338   unsigned f6 : 7;
339   unsigned f7 : 7;
340 };
341 
f9_load(struct s9 * a0)342 int f9_load(struct s9 *a0) {
343   return a0->f7;
344 }
345