blob: 49471d245a8bab2ce15657097aca5d88cc1594b7 [file] [log] [blame]
Chandler Carruthfd8eca22012-12-09 07:26:04 +00001// RUN: %clang_cc1 -triple x86_64-unknown-unknown -verify -emit-llvm -o - %s \
2// RUN: | FileCheck -check-prefix=CHECK-X86-64 %s
3// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -verify -emit-llvm -o - %s \
4// RUN: | FileCheck -check-prefix=CHECK-PPC64 %s
Chandler Carruthff0e3a12012-12-06 11:14:44 +00005//
6// Tests for bitfield access patterns in C++ with special attention to
7// conformance to C++11 memory model requirements.
8
9namespace N1 {
10 // Ensure that neither loads nor stores to bitfields are not widened into
11 // other memory locations. (PR13691)
12 //
13 // NOTE: We could potentially widen loads based on their alignment if we are
14 // comfortable requiring that subsequent memory locations within the
15 // alignment-widened load are not volatile.
16 struct S {
17 char a;
18 unsigned b : 1;
19 char c;
20 };
21 unsigned read(S* s) {
Chandler Carruthfd8eca22012-12-09 07:26:04 +000022 // CHECK-X86-64: define i32 @_ZN2N14read
23 // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
24 // CHECK-X86-64: %[[val:.*]] = load i8* %[[ptr]]
25 // CHECK-X86-64: %[[and:.*]] = and i8 %[[val]], 1
26 // CHECK-X86-64: %[[ext:.*]] = zext i8 %[[and]] to i32
27 // CHECK-X86-64: ret i32 %[[ext]]
28 // CHECK-PPC64: define zeroext i32 @_ZN2N14read
29 // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
30 // CHECK-PPC64: %[[val:.*]] = load i8* %[[ptr]]
31 // CHECK-PPC64: %[[shr:.*]] = lshr i8 %[[val]], 7
32 // CHECK-PPC64: %[[ext:.*]] = zext i8 %[[shr]] to i32
33 // CHECK-PPC64: ret i32 %[[ext]]
Chandler Carruthff0e3a12012-12-06 11:14:44 +000034 return s->b;
35 }
36 void write(S* s, unsigned x) {
Chandler Carruthfd8eca22012-12-09 07:26:04 +000037 // CHECK-X86-64: define void @_ZN2N15write
38 // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
39 // CHECK-X86-64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8
40 // CHECK-X86-64: %[[old:.*]] = load i8* %[[ptr]]
41 // CHECK-X86-64: %[[x_and:.*]] = and i8 %[[x_trunc]], 1
42 // CHECK-X86-64: %[[old_and:.*]] = and i8 %[[old]], -2
43 // CHECK-X86-64: %[[new:.*]] = or i8 %[[old_and]], %[[x_and]]
44 // CHECK-X86-64: store i8 %[[new]], i8* %[[ptr]]
45 // CHECK-PPC64: define void @_ZN2N15write
46 // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
47 // CHECK-PPC64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8
48 // CHECK-PPC64: %[[old:.*]] = load i8* %[[ptr]]
49 // CHECK-PPC64: %[[x_and:.*]] = and i8 %[[x_trunc]], 1
50 // CHECK-PPC64: %[[x_shl:.*]] = shl i8 %[[x_and]], 7
51 // CHECK-PPC64: %[[old_and:.*]] = and i8 %[[old]], 127
52 // CHECK-PPC64: %[[new:.*]] = or i8 %[[old_and]], %[[x_shl]]
53 // CHECK-PPC64: store i8 %[[new]], i8* %[[ptr]]
Chandler Carruthff0e3a12012-12-06 11:14:44 +000054 s->b = x;
55 }
56}
57
58namespace N2 {
59 // Do widen loads and stores to bitfields when those bitfields have padding
60 // within the struct following them.
61 struct S {
62 unsigned b : 24;
63 void *p;
64 };
65 unsigned read(S* s) {
Chandler Carruthfd8eca22012-12-09 07:26:04 +000066 // CHECK-X86-64: define i32 @_ZN2N24read
67 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
68 // CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]]
69 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
70 // CHECK-X86-64: ret i32 %[[and]]
71 // CHECK-PPC64: define zeroext i32 @_ZN2N24read
72 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
73 // CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]]
74 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
75 // CHECK-PPC64: ret i32 %[[shr]]
Chandler Carruthff0e3a12012-12-06 11:14:44 +000076 return s->b;
77 }
78 void write(S* s, unsigned x) {
Chandler Carruthfd8eca22012-12-09 07:26:04 +000079 // CHECK-X86-64: define void @_ZN2N25write
80 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
81 // CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]]
82 // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
83 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216
84 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]
85 // CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]]
86 // CHECK-PPC64: define void @_ZN2N25write
87 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
88 // CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]]
89 // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
90 // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8
91 // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255
92 // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]]
93 // CHECK-PPC64: store i32 %[[new]], i32* %[[ptr]]
Chandler Carruthff0e3a12012-12-06 11:14:44 +000094 s->b = x;
95 }
96}
97
98namespace N3 {
99 // Do widen loads and stores to bitfields through the trailing padding at the
100 // end of a struct.
101 struct S {
102 unsigned b : 24;
103 };
104 unsigned read(S* s) {
Chandler Carruthfd8eca22012-12-09 07:26:04 +0000105 // CHECK-X86-64: define i32 @_ZN2N34read
106 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
107 // CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]]
108 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
109 // CHECK-X86-64: ret i32 %[[and]]
110 // CHECK-PPC64: define zeroext i32 @_ZN2N34read
111 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
112 // CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]]
113 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
114 // CHECK-PPC64: ret i32 %[[shr]]
Chandler Carruthff0e3a12012-12-06 11:14:44 +0000115 return s->b;
116 }
117 void write(S* s, unsigned x) {
Chandler Carruthfd8eca22012-12-09 07:26:04 +0000118 // CHECK-X86-64: define void @_ZN2N35write
119 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
120 // CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]]
121 // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
122 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216
123 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]
124 // CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]]
125 // CHECK-PPC64: define void @_ZN2N35write
126 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
127 // CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]]
128 // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
129 // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8
130 // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255
131 // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]]
132 // CHECK-PPC64: store i32 %[[new]], i32* %[[ptr]]
Chandler Carruthff0e3a12012-12-06 11:14:44 +0000133 s->b = x;
134 }
135}
136
137namespace N4 {
138 // Do NOT widen loads and stores to bitfields into padding at the end of
139 // a class which might end up with members inside of it when inside a derived
140 // class.
141 struct Base {
142 virtual ~Base() {}
143
144 unsigned b : 24;
145 };
146 // Imagine some other translation unit introduces:
147#if 0
148 struct Derived : public Base {
149 char c;
150 };
151#endif
152 unsigned read(Base* s) {
153 // FIXME: We should widen this load as long as the function isn't being
154 // instrumented by thread-sanitizer.
155 //
Chandler Carruthfd8eca22012-12-09 07:26:04 +0000156 // CHECK-X86-64: define i32 @_ZN2N44read
157 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
158 // CHECK-X86-64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
159 // CHECK-X86-64: %[[val:.*]] = load i24* %[[ptr]]
160 // CHECK-X86-64: %[[ext:.*]] = zext i24 %[[val]] to i32
161 // CHECK-X86-64: ret i32 %[[ext]]
162 // CHECK-PPC64: define zeroext i32 @_ZN2N44read
163 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
164 // CHECK-PPC64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
165 // CHECK-PPC64: %[[val:.*]] = load i24* %[[ptr]]
166 // CHECK-PPC64: %[[ext:.*]] = zext i24 %[[val]] to i32
167 // CHECK-PPC64: ret i32 %[[ext]]
Chandler Carruthff0e3a12012-12-06 11:14:44 +0000168 return s->b;
169 }
170 void write(Base* s, unsigned x) {
Chandler Carruthfd8eca22012-12-09 07:26:04 +0000171 // CHECK-X86-64: define void @_ZN2N45write
172 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
173 // CHECK-X86-64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
174 // CHECK-X86-64: %[[new:.*]] = trunc i32 %{{.*}} to i24
175 // CHECK-X86-64: store i24 %[[new]], i24* %[[ptr]]
176 // CHECK-PPC64: define void @_ZN2N45write
177 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
178 // CHECK-PPC64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
179 // CHECK-PPC64: %[[new:.*]] = trunc i32 %{{.*}} to i24
180 // CHECK-PPC64: store i24 %[[new]], i24* %[[ptr]]
Chandler Carruthff0e3a12012-12-06 11:14:44 +0000181 s->b = x;
182 }
183}
184
185namespace N5 {
186 // Widen through padding at the end of a struct even if that struct
187 // participates in a union with another struct which has a separate field in
188 // that location. The reasoning is that if the operation is storing to that
189 // member of the union, it must be the active member, and thus we can write
190 // through the padding. If it is a load, it might be a load of a common
191 // prefix through a non-active member, but in such a case the extra bits
192 // loaded are masked off anyways.
193 union U {
194 struct X { unsigned b : 24; char c; } x;
195 struct Y { unsigned b : 24; } y;
196 };
197 unsigned read(U* u) {
Chandler Carruthfd8eca22012-12-09 07:26:04 +0000198 // CHECK-X86-64: define i32 @_ZN2N54read
199 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
200 // CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]]
201 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
202 // CHECK-X86-64: ret i32 %[[and]]
203 // CHECK-PPC64: define zeroext i32 @_ZN2N54read
204 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
205 // CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]]
206 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
207 // CHECK-PPC64: ret i32 %[[shr]]
Chandler Carruthff0e3a12012-12-06 11:14:44 +0000208 return u->y.b;
209 }
210 void write(U* u, unsigned x) {
Chandler Carruthfd8eca22012-12-09 07:26:04 +0000211 // CHECK-X86-64: define void @_ZN2N55write
212 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
213 // CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]]
214 // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
215 // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216
216 // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]
217 // CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]]
218 // CHECK-PPC64: define void @_ZN2N55write
219 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
220 // CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]]
221 // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
222 // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8
223 // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255
224 // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]]
225 // CHECK-PPC64: store i32 %[[new]], i32* %[[ptr]]
Chandler Carruthff0e3a12012-12-06 11:14:44 +0000226 u->y.b = x;
227 }
228}
229
230namespace N6 {
231 // Zero-length bitfields partition the memory locations of bitfields for the
232 // purposes of the memory model. That means stores must not span zero-length
233 // bitfields and loads may only span them when we are not instrumenting with
234 // thread sanitizer.
235 // FIXME: We currently don't widen loads even without thread sanitizer, even
236 // though we could.
237 struct S {
238 unsigned b1 : 24;
239 unsigned char : 0;
240 unsigned char b2 : 8;
241 };
242 unsigned read(S* s) {
Chandler Carruthfd8eca22012-12-09 07:26:04 +0000243 // CHECK-X86-64: define i32 @_ZN2N64read
244 // CHECK-X86-64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
245 // CHECK-X86-64: %[[val1:.*]] = load i24* %[[ptr1]]
246 // CHECK-X86-64: %[[ext1:.*]] = zext i24 %[[val1]] to i32
247 // CHECK-X86-64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
248 // CHECK-X86-64: %[[val2:.*]] = load i8* %[[ptr2]]
249 // CHECK-X86-64: %[[ext2:.*]] = zext i8 %[[val2]] to i32
250 // CHECK-X86-64: %[[add:.*]] = add nsw i32 %[[ext1]], %[[ext2]]
251 // CHECK-X86-64: ret i32 %[[add]]
252 // CHECK-PPC64: define zeroext i32 @_ZN2N64read
253 // CHECK-PPC64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
254 // CHECK-PPC64: %[[val1:.*]] = load i24* %[[ptr1]]
255 // CHECK-PPC64: %[[ext1:.*]] = zext i24 %[[val1]] to i32
256 // CHECK-PPC64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
257 // CHECK-PPC64: %[[val2:.*]] = load i8* %[[ptr2]]
258 // CHECK-PPC64: %[[ext2:.*]] = zext i8 %[[val2]] to i32
259 // CHECK-PPC64: %[[add:.*]] = add nsw i32 %[[ext1]], %[[ext2]]
260 // CHECK-PPC64: ret i32 %[[add]]
Chandler Carruthff0e3a12012-12-06 11:14:44 +0000261 return s->b1 + s->b2;
262 }
263 void write(S* s, unsigned x) {
Chandler Carruthfd8eca22012-12-09 07:26:04 +0000264 // CHECK-X86-64: define void @_ZN2N65write
265 // CHECK-X86-64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
266 // CHECK-X86-64: %[[new1:.*]] = trunc i32 %{{.*}} to i24
267 // CHECK-X86-64: store i24 %[[new1]], i24* %[[ptr1]]
268 // CHECK-X86-64: %[[new2:.*]] = trunc i32 %{{.*}} to i8
269 // CHECK-X86-64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
270 // CHECK-X86-64: store i8 %[[new2]], i8* %[[ptr2]]
271 // CHECK-PPC64: define void @_ZN2N65write
272 // CHECK-PPC64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
273 // CHECK-PPC64: %[[new1:.*]] = trunc i32 %{{.*}} to i24
274 // CHECK-PPC64: store i24 %[[new1]], i24* %[[ptr1]]
275 // CHECK-PPC64: %[[new2:.*]] = trunc i32 %{{.*}} to i8
276 // CHECK-PPC64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
277 // CHECK-PPC64: store i8 %[[new2]], i8* %[[ptr2]]
Chandler Carruthff0e3a12012-12-06 11:14:44 +0000278 s->b1 = x;
279 s->b2 = x;
280 }
281}