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