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