blob: 1814aa2d534c2809cab65bc192f98ff164e237b4 [file] [log] [blame]
Chandler Carruthef8d5162012-12-09 07:26:04 +00001// RUN: %clang_cc1 -triple x86_64-unknown-unknown -verify -emit-llvm -o - %s \
2// RUN: | FileCheck -check-prefix=CHECK-X86-64 %s
3// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -verify -emit-llvm -o - %s \
4// RUN: | FileCheck -check-prefix=CHECK-PPC64 %s
Chandler Carruth72d2dab2012-12-06 11:14:44 +00005//
6// Tests for bitfield access patterns in C++ with special attention to
7// conformance to C++11 memory model requirements.
8
Chandler Carruth5588a692012-12-09 10:08:22 +00009namespace N0 {
10 // Test basic bitfield layout access across interesting byte and word
11 // boundaries on both little endian and big endian platforms.
12 struct __attribute__((packed)) S {
13 unsigned b00 : 14;
14 unsigned b01 : 2;
15 unsigned b20 : 6;
16 unsigned b21 : 2;
17 unsigned b30 : 30;
18 unsigned b31 : 2;
19 unsigned b70 : 6;
20 unsigned b71 : 2;
21 };
22 unsigned read00(S* s) {
23 // CHECK-X86-64: define i32 @_ZN2N06read00
24 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
25 // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
26 // CHECK-X86-64: %[[and:.*]] = and i64 %[[val]], 16383
27 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
28 // CHECK-X86-64: ret i32 %[[trunc]]
29 // CHECK-PPC64: define zeroext i32 @_ZN2N06read00
30 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
31 // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
32 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 50
33 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[shr]] to i32
34 // CHECK-PPC64: ret i32 %[[trunc]]
35 return s->b00;
36 }
37 unsigned read01(S* s) {
38 // CHECK-X86-64: define i32 @_ZN2N06read01
39 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
40 // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
41 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 14
42 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3
43 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
44 // CHECK-X86-64: ret i32 %[[trunc]]
45 // CHECK-PPC64: define zeroext i32 @_ZN2N06read01
46 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
47 // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
48 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 48
49 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 3
50 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
51 // CHECK-PPC64: ret i32 %[[trunc]]
52 return s->b01;
53 }
54 unsigned read20(S* s) {
55 // CHECK-X86-64: define i32 @_ZN2N06read20
56 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
57 // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
58 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 16
59 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 63
60 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
61 // CHECK-X86-64: ret i32 %[[trunc]]
62 // CHECK-PPC64: define zeroext i32 @_ZN2N06read20
63 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
64 // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
65 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 42
66 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 63
67 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
68 // CHECK-PPC64: ret i32 %[[trunc]]
69 return s->b20;
70 }
71 unsigned read21(S* s) {
72 // CHECK-X86-64: define i32 @_ZN2N06read21
73 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
74 // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
75 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 22
76 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3
77 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
78 // CHECK-X86-64: ret i32 %[[trunc]]
79 // CHECK-PPC64: define zeroext i32 @_ZN2N06read21
80 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
81 // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
82 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 40
83 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 3
84 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
85 // CHECK-PPC64: ret i32 %[[trunc]]
86 return s->b21;
87 }
88 unsigned read30(S* s) {
89 // CHECK-X86-64: define i32 @_ZN2N06read30
90 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
91 // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
92 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 24
93 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 1073741823
94 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
95 // CHECK-X86-64: ret i32 %[[trunc]]
96 // CHECK-PPC64: define zeroext i32 @_ZN2N06read30
97 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
98 // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
99 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 10
100 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 1073741823
101 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
102 // CHECK-PPC64: ret i32 %[[trunc]]
103 return s->b30;
104 }
105 unsigned read31(S* s) {
106 // CHECK-X86-64: define i32 @_ZN2N06read31
107 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
108 // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
109 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 54
110 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3
111 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
112 // CHECK-X86-64: ret i32 %[[trunc]]
113 // CHECK-PPC64: define zeroext i32 @_ZN2N06read31
114 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
115 // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
116 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 8
117 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 3
118 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
119 // CHECK-PPC64: ret i32 %[[trunc]]
120 return s->b31;
121 }
122 unsigned read70(S* s) {
123 // CHECK-X86-64: define i32 @_ZN2N06read70
124 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
125 // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
126 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 56
127 // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 63
128 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
129 // CHECK-X86-64: ret i32 %[[trunc]]
130 // CHECK-PPC64: define zeroext i32 @_ZN2N06read70
131 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
132 // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
133 // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 2
134 // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 63
135 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
136 // CHECK-PPC64: ret i32 %[[trunc]]
137 return s->b70;
138 }
139 unsigned read71(S* s) {
140 // CHECK-X86-64: define i32 @_ZN2N06read71
141 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
142 // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
143 // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 62
144 // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[shr]] to i32
145 // CHECK-X86-64: ret i32 %[[trunc]]
146 // CHECK-PPC64: define zeroext i32 @_ZN2N06read71
147 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
148 // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
149 // CHECK-PPC64: %[[and:.*]] = and i64 %[[val]], 3
150 // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
151 // CHECK-PPC64: ret i32 %[[trunc]]
152 return s->b71;
153 }
154}
155
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000156namespace N1 {
157 // Ensure that neither loads nor stores to bitfields are not widened into
158 // other memory locations. (PR13691)
159 //
160 // NOTE: We could potentially widen loads based on their alignment if we are
161 // comfortable requiring that subsequent memory locations within the
162 // alignment-widened load are not volatile.
163 struct S {
164 char a;
165 unsigned b : 1;
166 char c;
167 };
168 unsigned read(S* s) {
Chandler Carruthef8d5162012-12-09 07:26:04 +0000169 // CHECK-X86-64: define i32 @_ZN2N14read
170 // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
171 // CHECK-X86-64: %[[val:.*]] = load i8* %[[ptr]]
172 // CHECK-X86-64: %[[and:.*]] = and i8 %[[val]], 1
173 // CHECK-X86-64: %[[ext:.*]] = zext i8 %[[and]] to i32
174 // CHECK-X86-64: ret i32 %[[ext]]
175 // CHECK-PPC64: define zeroext i32 @_ZN2N14read
176 // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
177 // CHECK-PPC64: %[[val:.*]] = load i8* %[[ptr]]
178 // CHECK-PPC64: %[[shr:.*]] = lshr i8 %[[val]], 7
179 // CHECK-PPC64: %[[ext:.*]] = zext i8 %[[shr]] to i32
180 // CHECK-PPC64: ret i32 %[[ext]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000181 return s->b;
182 }
183 void write(S* s, unsigned x) {
Chandler Carruthef8d5162012-12-09 07:26:04 +0000184 // CHECK-X86-64: define void @_ZN2N15write
185 // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
186 // CHECK-X86-64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8
187 // CHECK-X86-64: %[[old:.*]] = load i8* %[[ptr]]
188 // CHECK-X86-64: %[[x_and:.*]] = and i8 %[[x_trunc]], 1
189 // CHECK-X86-64: %[[old_and:.*]] = and i8 %[[old]], -2
190 // CHECK-X86-64: %[[new:.*]] = or i8 %[[old_and]], %[[x_and]]
191 // CHECK-X86-64: store i8 %[[new]], i8* %[[ptr]]
192 // CHECK-PPC64: define void @_ZN2N15write
193 // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
194 // CHECK-PPC64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8
195 // CHECK-PPC64: %[[old:.*]] = load i8* %[[ptr]]
196 // CHECK-PPC64: %[[x_and:.*]] = and i8 %[[x_trunc]], 1
197 // CHECK-PPC64: %[[x_shl:.*]] = shl i8 %[[x_and]], 7
198 // CHECK-PPC64: %[[old_and:.*]] = and i8 %[[old]], 127
199 // CHECK-PPC64: %[[new:.*]] = or i8 %[[old_and]], %[[x_shl]]
200 // CHECK-PPC64: store i8 %[[new]], i8* %[[ptr]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000201 s->b = x;
202 }
203}
204
205namespace N2 {
206 // Do widen loads and stores to bitfields when those bitfields have padding
207 // within the struct following them.
208 struct S {
209 unsigned b : 24;
210 void *p;
211 };
212 unsigned read(S* s) {
Chandler Carruthef8d5162012-12-09 07:26:04 +0000213 // CHECK-X86-64: define i32 @_ZN2N24read
214 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
215 // CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]]
216 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
217 // CHECK-X86-64: ret i32 %[[and]]
218 // CHECK-PPC64: define zeroext i32 @_ZN2N24read
219 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
220 // CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]]
221 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
222 // CHECK-PPC64: ret i32 %[[shr]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000223 return s->b;
224 }
225 void write(S* s, unsigned x) {
Chandler Carruthef8d5162012-12-09 07:26:04 +0000226 // CHECK-X86-64: define void @_ZN2N25write
227 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
228 // CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]]
229 // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
230 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216
231 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]
232 // CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]]
233 // CHECK-PPC64: define void @_ZN2N25write
234 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
235 // CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]]
236 // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
237 // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8
238 // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255
239 // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]]
240 // CHECK-PPC64: store i32 %[[new]], i32* %[[ptr]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000241 s->b = x;
242 }
243}
244
245namespace N3 {
246 // Do widen loads and stores to bitfields through the trailing padding at the
247 // end of a struct.
248 struct S {
249 unsigned b : 24;
250 };
251 unsigned read(S* s) {
Chandler Carruthef8d5162012-12-09 07:26:04 +0000252 // CHECK-X86-64: define i32 @_ZN2N34read
253 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
254 // CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]]
255 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
256 // CHECK-X86-64: ret i32 %[[and]]
257 // CHECK-PPC64: define zeroext i32 @_ZN2N34read
258 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
259 // CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]]
260 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
261 // CHECK-PPC64: ret i32 %[[shr]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000262 return s->b;
263 }
264 void write(S* s, unsigned x) {
Chandler Carruthef8d5162012-12-09 07:26:04 +0000265 // CHECK-X86-64: define void @_ZN2N35write
266 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
267 // CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]]
268 // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
269 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216
270 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]
271 // CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]]
272 // CHECK-PPC64: define void @_ZN2N35write
273 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
274 // CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]]
275 // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
276 // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8
277 // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255
278 // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]]
279 // CHECK-PPC64: store i32 %[[new]], i32* %[[ptr]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000280 s->b = x;
281 }
282}
283
284namespace N4 {
285 // Do NOT widen loads and stores to bitfields into padding at the end of
286 // a class which might end up with members inside of it when inside a derived
287 // class.
288 struct Base {
289 virtual ~Base() {}
290
291 unsigned b : 24;
292 };
293 // Imagine some other translation unit introduces:
294#if 0
295 struct Derived : public Base {
296 char c;
297 };
298#endif
299 unsigned read(Base* s) {
300 // FIXME: We should widen this load as long as the function isn't being
301 // instrumented by thread-sanitizer.
302 //
Chandler Carruthef8d5162012-12-09 07:26:04 +0000303 // CHECK-X86-64: define i32 @_ZN2N44read
304 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
305 // CHECK-X86-64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
306 // CHECK-X86-64: %[[val:.*]] = load i24* %[[ptr]]
307 // CHECK-X86-64: %[[ext:.*]] = zext i24 %[[val]] to i32
308 // CHECK-X86-64: ret i32 %[[ext]]
309 // CHECK-PPC64: define zeroext i32 @_ZN2N44read
310 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
311 // CHECK-PPC64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
312 // CHECK-PPC64: %[[val:.*]] = load i24* %[[ptr]]
313 // CHECK-PPC64: %[[ext:.*]] = zext i24 %[[val]] to i32
314 // CHECK-PPC64: ret i32 %[[ext]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000315 return s->b;
316 }
317 void write(Base* s, unsigned x) {
Chandler Carruthef8d5162012-12-09 07:26:04 +0000318 // CHECK-X86-64: define void @_ZN2N45write
319 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
320 // CHECK-X86-64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
321 // CHECK-X86-64: %[[new:.*]] = trunc i32 %{{.*}} to i24
322 // CHECK-X86-64: store i24 %[[new]], i24* %[[ptr]]
323 // CHECK-PPC64: define void @_ZN2N45write
324 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
325 // CHECK-PPC64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
326 // CHECK-PPC64: %[[new:.*]] = trunc i32 %{{.*}} to i24
327 // CHECK-PPC64: store i24 %[[new]], i24* %[[ptr]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000328 s->b = x;
329 }
330}
331
332namespace N5 {
333 // Widen through padding at the end of a struct even if that struct
334 // participates in a union with another struct which has a separate field in
335 // that location. The reasoning is that if the operation is storing to that
336 // member of the union, it must be the active member, and thus we can write
337 // through the padding. If it is a load, it might be a load of a common
338 // prefix through a non-active member, but in such a case the extra bits
339 // loaded are masked off anyways.
340 union U {
341 struct X { unsigned b : 24; char c; } x;
342 struct Y { unsigned b : 24; } y;
343 };
344 unsigned read(U* u) {
Chandler Carruthef8d5162012-12-09 07:26:04 +0000345 // CHECK-X86-64: define i32 @_ZN2N54read
346 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
347 // CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]]
348 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
349 // CHECK-X86-64: ret i32 %[[and]]
350 // CHECK-PPC64: define zeroext i32 @_ZN2N54read
351 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
352 // CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]]
353 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
354 // CHECK-PPC64: ret i32 %[[shr]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000355 return u->y.b;
356 }
357 void write(U* u, unsigned x) {
Chandler Carruthef8d5162012-12-09 07:26:04 +0000358 // CHECK-X86-64: define void @_ZN2N55write
359 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
360 // CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]]
361 // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
362 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216
363 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]
364 // CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]]
365 // CHECK-PPC64: define void @_ZN2N55write
366 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
367 // CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]]
368 // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
369 // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8
370 // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255
371 // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]]
372 // CHECK-PPC64: store i32 %[[new]], i32* %[[ptr]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000373 u->y.b = x;
374 }
375}
376
377namespace N6 {
378 // Zero-length bitfields partition the memory locations of bitfields for the
379 // purposes of the memory model. That means stores must not span zero-length
380 // bitfields and loads may only span them when we are not instrumenting with
381 // thread sanitizer.
382 // FIXME: We currently don't widen loads even without thread sanitizer, even
383 // though we could.
384 struct S {
385 unsigned b1 : 24;
386 unsigned char : 0;
387 unsigned char b2 : 8;
388 };
389 unsigned read(S* s) {
Chandler Carruthef8d5162012-12-09 07:26:04 +0000390 // CHECK-X86-64: define i32 @_ZN2N64read
391 // CHECK-X86-64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
392 // CHECK-X86-64: %[[val1:.*]] = load i24* %[[ptr1]]
393 // CHECK-X86-64: %[[ext1:.*]] = zext i24 %[[val1]] to i32
394 // CHECK-X86-64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
395 // CHECK-X86-64: %[[val2:.*]] = load i8* %[[ptr2]]
396 // CHECK-X86-64: %[[ext2:.*]] = zext i8 %[[val2]] to i32
397 // CHECK-X86-64: %[[add:.*]] = add nsw i32 %[[ext1]], %[[ext2]]
398 // CHECK-X86-64: ret i32 %[[add]]
399 // CHECK-PPC64: define zeroext i32 @_ZN2N64read
400 // CHECK-PPC64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
401 // CHECK-PPC64: %[[val1:.*]] = load i24* %[[ptr1]]
402 // CHECK-PPC64: %[[ext1:.*]] = zext i24 %[[val1]] to i32
403 // CHECK-PPC64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
404 // CHECK-PPC64: %[[val2:.*]] = load i8* %[[ptr2]]
405 // CHECK-PPC64: %[[ext2:.*]] = zext i8 %[[val2]] to i32
406 // CHECK-PPC64: %[[add:.*]] = add nsw i32 %[[ext1]], %[[ext2]]
407 // CHECK-PPC64: ret i32 %[[add]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000408 return s->b1 + s->b2;
409 }
410 void write(S* s, unsigned x) {
Chandler Carruthef8d5162012-12-09 07:26:04 +0000411 // CHECK-X86-64: define void @_ZN2N65write
412 // CHECK-X86-64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
413 // CHECK-X86-64: %[[new1:.*]] = trunc i32 %{{.*}} to i24
414 // CHECK-X86-64: store i24 %[[new1]], i24* %[[ptr1]]
415 // CHECK-X86-64: %[[new2:.*]] = trunc i32 %{{.*}} to i8
416 // CHECK-X86-64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
417 // CHECK-X86-64: store i8 %[[new2]], i8* %[[ptr2]]
418 // CHECK-PPC64: define void @_ZN2N65write
419 // CHECK-PPC64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
420 // CHECK-PPC64: %[[new1:.*]] = trunc i32 %{{.*}} to i24
421 // CHECK-PPC64: store i24 %[[new1]], i24* %[[ptr1]]
422 // CHECK-PPC64: %[[new2:.*]] = trunc i32 %{{.*}} to i8
423 // CHECK-PPC64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
424 // CHECK-PPC64: store i8 %[[new2]], i8* %[[ptr2]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000425 s->b1 = x;
426 s->b2 = x;
427 }
428}