[clang] Handle __declspec() attributes in using
[llvm-project.git] / clang / test / CodeGenCXX / bitfield.cpp
blob3ad2d34b5dc38e547fb1629a942be62185634100
1 // RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-unknown-unknown -emit-llvm -o - %s \
2 // RUN: | FileCheck -check-prefix=CHECK-X86-64 %s
3 // RUN: %clang_cc1 -no-opaque-pointers -triple powerpc64-unknown-unknown -emit-llvm -o - %s \
4 // RUN: | FileCheck -check-prefix=CHECK-PPC64 %s
5 //
6 // Tests for bitfield access patterns in C++ with special attention to
7 // conformance to C++11 memory model requirements.
9 namespace 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;
22 unsigned read00(S* s) {
23 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read00
24 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
25 // CHECK-X86-64: %[[val:.*]] = load i64, 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-LABEL: define{{.*}} zeroext i32 @_ZN2N06read00
30 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
31 // CHECK-PPC64: %[[val:.*]] = load i64, 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;
37 unsigned read01(S* s) {
38 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read01
39 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
40 // CHECK-X86-64: %[[val:.*]] = load i64, 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-LABEL: define{{.*}} zeroext i32 @_ZN2N06read01
46 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
47 // CHECK-PPC64: %[[val:.*]] = load i64, 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;
54 unsigned read20(S* s) {
55 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read20
56 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
57 // CHECK-X86-64: %[[val:.*]] = load i64, 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-LABEL: define{{.*}} zeroext i32 @_ZN2N06read20
63 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
64 // CHECK-PPC64: %[[val:.*]] = load i64, 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;
71 unsigned read21(S* s) {
72 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read21
73 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
74 // CHECK-X86-64: %[[val:.*]] = load i64, 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-LABEL: define{{.*}} zeroext i32 @_ZN2N06read21
80 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
81 // CHECK-PPC64: %[[val:.*]] = load i64, 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;
88 unsigned read30(S* s) {
89 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read30
90 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
91 // CHECK-X86-64: %[[val:.*]] = load i64, 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-LABEL: define{{.*}} zeroext i32 @_ZN2N06read30
97 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
98 // CHECK-PPC64: %[[val:.*]] = load i64, 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;
105 unsigned read31(S* s) {
106 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read31
107 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
108 // CHECK-X86-64: %[[val:.*]] = load i64, 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-LABEL: define{{.*}} zeroext i32 @_ZN2N06read31
114 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
115 // CHECK-PPC64: %[[val:.*]] = load i64, 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;
122 unsigned read70(S* s) {
123 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read70
124 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
125 // CHECK-X86-64: %[[val:.*]] = load i64, 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-LABEL: define{{.*}} zeroext i32 @_ZN2N06read70
131 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
132 // CHECK-PPC64: %[[val:.*]] = load i64, 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;
139 unsigned read71(S* s) {
140 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read71
141 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
142 // CHECK-X86-64: %[[val:.*]] = load i64, 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-LABEL: define{{.*}} zeroext i32 @_ZN2N06read71
147 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
148 // CHECK-PPC64: %[[val:.*]] = load i64, 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;
156 namespace N1 {
157 // Ensure that neither loads nor stores to bitfields are not widened into
158 // other memory locations. (PR13691)
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;
168 unsigned read(S* s) {
169 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N14read
170 // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}, %{{.*}}* %{{.*}}, i32 0, i32 1
171 // CHECK-X86-64: %[[val:.*]] = load i8, 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-LABEL: define{{.*}} zeroext i32 @_ZN2N14read
176 // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}, %{{.*}}* %{{.*}}, i32 0, i32 1
177 // CHECK-PPC64: %[[val:.*]] = load i8, 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]]
181 return s->b;
183 void write(S* s, unsigned x) {
184 // CHECK-X86-64-LABEL: 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, 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-LABEL: 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, 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]]
201 s->b = x;
205 namespace 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;
212 unsigned read(S* s) {
213 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N24read
214 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
215 // CHECK-X86-64: %[[val:.*]] = load i32, i32* %[[ptr]]
216 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
217 // CHECK-X86-64: ret i32 %[[and]]
218 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N24read
219 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
220 // CHECK-PPC64: %[[val:.*]] = load i32, i32* %[[ptr]]
221 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
222 // CHECK-PPC64: ret i32 %[[shr]]
223 return s->b;
225 void write(S* s, unsigned x) {
226 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N25write
227 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
228 // CHECK-X86-64: %[[old:.*]] = load i32, 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-LABEL: define{{.*}} void @_ZN2N25write
234 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
235 // CHECK-PPC64: %[[old:.*]] = load i32, 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]]
241 s->b = x;
245 namespace 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;
251 unsigned read(S* s) {
252 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N34read
253 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
254 // CHECK-X86-64: %[[val:.*]] = load i32, i32* %[[ptr]]
255 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
256 // CHECK-X86-64: ret i32 %[[and]]
257 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N34read
258 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
259 // CHECK-PPC64: %[[val:.*]] = load i32, i32* %[[ptr]]
260 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
261 // CHECK-PPC64: ret i32 %[[shr]]
262 return s->b;
264 void write(S* s, unsigned x) {
265 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N35write
266 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
267 // CHECK-X86-64: %[[old:.*]] = load i32, 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-LABEL: define{{.*}} void @_ZN2N35write
273 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
274 // CHECK-PPC64: %[[old:.*]] = load i32, 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]]
280 s->b = x;
284 namespace 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() {}
291 unsigned b : 24;
293 // Imagine some other translation unit introduces:
294 #if 0
295 struct Derived : public Base {
296 char c;
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 ThreadSanitizer.
303 // CHECK-X86-64-LABEL: 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, i24* %[[ptr]]
307 // CHECK-X86-64: %[[ext:.*]] = zext i24 %[[val]] to i32
308 // CHECK-X86-64: ret i32 %[[ext]]
309 // CHECK-PPC64-LABEL: 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, i24* %[[ptr]]
313 // CHECK-PPC64: %[[ext:.*]] = zext i24 %[[val]] to i32
314 // CHECK-PPC64: ret i32 %[[ext]]
315 return s->b;
317 void write(Base* s, unsigned x) {
318 // CHECK-X86-64-LABEL: 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-LABEL: 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]]
328 s->b = x;
332 namespace 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;
344 unsigned read(U* u) {
345 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N54read
346 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
347 // CHECK-X86-64: %[[val:.*]] = load i32, i32* %[[ptr]]
348 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
349 // CHECK-X86-64: ret i32 %[[and]]
350 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N54read
351 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
352 // CHECK-PPC64: %[[val:.*]] = load i32, i32* %[[ptr]]
353 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
354 // CHECK-PPC64: ret i32 %[[shr]]
355 return u->y.b;
357 void write(U* u, unsigned x) {
358 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N55write
359 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
360 // CHECK-X86-64: %[[old:.*]] = load i32, 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-LABEL: define{{.*}} void @_ZN2N55write
366 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
367 // CHECK-PPC64: %[[old:.*]] = load i32, 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]]
373 u->y.b = x;
377 namespace 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 // ThreadSanitizer.
382 // FIXME: We currently don't widen loads even without ThreadSanitizer, even
383 // though we could.
384 struct S {
385 unsigned b1 : 24;
386 unsigned char : 0;
387 unsigned char b2 : 8;
389 unsigned read(S* s) {
390 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N64read
391 // CHECK-X86-64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
392 // CHECK-X86-64: %[[val1:.*]] = load i24, 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, 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-LABEL: define{{.*}} zeroext i32 @_ZN2N64read
400 // CHECK-PPC64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
401 // CHECK-PPC64: %[[val1:.*]] = load i24, 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, 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]]
408 return s->b1 + s->b2;
410 void write(S* s, unsigned x) {
411 // CHECK-X86-64-LABEL: 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-LABEL: 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]]
425 s->b1 = x;
426 s->b2 = x;
430 namespace N7 {
431 // Similar to N4 except that this adds a virtual base to the picture. (PR18430)
432 // Do NOT widen loads and stores to bitfields into padding at the end of
433 // a class which might end up with members inside of it when inside a derived
434 // class.
435 struct B1 {
436 virtual void f();
437 unsigned b1 : 24;
439 struct B2 : virtual B1 {
440 virtual ~B2();
441 unsigned b : 24;
443 // Imagine some other translation unit introduces:
444 #if 0
445 struct Derived : public B2 {
446 char c;
448 #endif
449 unsigned read(B2* s) {
450 // FIXME: We should widen this load as long as the function isn't being
451 // instrumented by ThreadSanitizer.
453 // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N74read
454 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
455 // CHECK-X86-64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
456 // CHECK-X86-64: %[[val:.*]] = load i24, i24* %[[ptr]]
457 // CHECK-X86-64: %[[ext:.*]] = zext i24 %[[val]] to i32
458 // CHECK-X86-64: ret i32 %[[ext]]
459 // CHECK-PPC64-LABEL: define{{.*}} zeroext i32 @_ZN2N74read
460 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
461 // CHECK-PPC64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
462 // CHECK-PPC64: %[[val:.*]] = load i24, i24* %[[ptr]]
463 // CHECK-PPC64: %[[ext:.*]] = zext i24 %[[val]] to i32
464 // CHECK-PPC64: ret i32 %[[ext]]
465 return s->b;
467 void write(B2* s, unsigned x) {
468 // CHECK-X86-64-LABEL: define{{.*}} void @_ZN2N75write
469 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
470 // CHECK-X86-64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
471 // CHECK-X86-64: %[[new:.*]] = trunc i32 %{{.*}} to i24
472 // CHECK-X86-64: store i24 %[[new]], i24* %[[ptr]]
473 // CHECK-PPC64-LABEL: define{{.*}} void @_ZN2N75write
474 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
475 // CHECK-PPC64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
476 // CHECK-PPC64: %[[new:.*]] = trunc i32 %{{.*}} to i24
477 // CHECK-PPC64: store i24 %[[new]], i24* %[[ptr]]
478 s->b = x;