• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s \
2 // RUN:   | FileCheck -check-prefix=CHECK-X86-64 %s
3 // RUN: %clang_cc1 -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.
8 
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;
21   };
read00(S * s)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;
36   }
read01(S * s)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;
53   }
read20(S * s)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;
70   }
read21(S * s)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;
87   }
read30(S * s)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;
104   }
read31(S * s)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;
121   }
read70(S * s)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;
138   }
read71(S * s)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;
153   }
154 }
155 
156 namespace 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   };
read(S * s)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;
182   }
write(S * s,unsigned x)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;
202   }
203 }
204 
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;
211   };
read(S * s)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;
224   }
write(S * s,unsigned x)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;
242   }
243 }
244 
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;
250   };
read(S * s)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;
263   }
write(S * s,unsigned x)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;
281   }
282 }
283 
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 {
~BaseN4::Base289     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
read(Base * s)299   unsigned read(Base* s) {
300     // FIXME: We should widen this load as long as the function isn't being
301     // instrumented by ThreadSanitizer.
302     //
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;
316   }
write(Base * s,unsigned x)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;
329   }
330 }
331 
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;
343   };
read(U * u)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;
356   }
write(U * u,unsigned x)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;
374   }
375 }
376 
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;
388   };
read(S * s)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;
409   }
write(S * s,unsigned x)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;
427   }
428 }
429 
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;
438   };
439   struct B2 : virtual B1 {
440     virtual ~B2();
441     unsigned b : 24;
442   };
443   // Imagine some other translation unit introduces:
444 #if 0
445   struct Derived : public B2 {
446     char c;
447   };
448 #endif
read(B2 * s)449   unsigned read(B2* s) {
450     // FIXME: We should widen this load as long as the function isn't being
451     // instrumented by ThreadSanitizer.
452     //
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;
466   }
write(B2 * s,unsigned x)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;
479   }
480 }
481