blob: 7f55b4daa241c9a3318a03825ad167d4fe54e900 [file] [log] [blame]
Rafael Espindola5230dbe2013-07-04 14:58:42 +00001// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s \
Chandler Carruthef8d5162012-12-09 07:26:04 +00002// RUN: | FileCheck -check-prefix=CHECK-X86-64 %s
Rafael Espindola5230dbe2013-07-04 14:58:42 +00003// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -emit-llvm -o - %s \
Chandler Carruthef8d5162012-12-09 07:26:04 +00004// RUN: | FileCheck -check-prefix=CHECK-PPC64 %s
Chandler Carruth72d2dab2012-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
Chandler Carruth5588a692012-12-09 10:08:22 +00009namespace 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 };
22 unsigned read00(S* s) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +000023 // CHECK-X86-64-LABEL: define i32 @_ZN2N06read00
Chandler Carruth5588a692012-12-09 10:08:22 +000024 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -070025 // CHECK-X86-64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +000026 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +000029 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read00
Chandler Carruth5588a692012-12-09 10:08:22 +000030 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -070031 // CHECK-PPC64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +000032 // 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 }
37 unsigned read01(S* s) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +000038 // CHECK-X86-64-LABEL: define i32 @_ZN2N06read01
Chandler Carruth5588a692012-12-09 10:08:22 +000039 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -070040 // CHECK-X86-64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +000041 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +000045 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read01
Chandler Carruth5588a692012-12-09 10:08:22 +000046 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -070047 // CHECK-PPC64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +000048 // 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 }
54 unsigned read20(S* s) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +000055 // CHECK-X86-64-LABEL: define i32 @_ZN2N06read20
Chandler Carruth5588a692012-12-09 10:08:22 +000056 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -070057 // CHECK-X86-64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +000058 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +000062 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read20
Chandler Carruth5588a692012-12-09 10:08:22 +000063 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -070064 // CHECK-PPC64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +000065 // 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 }
71 unsigned read21(S* s) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +000072 // CHECK-X86-64-LABEL: define i32 @_ZN2N06read21
Chandler Carruth5588a692012-12-09 10:08:22 +000073 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -070074 // CHECK-X86-64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +000075 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +000079 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read21
Chandler Carruth5588a692012-12-09 10:08:22 +000080 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -070081 // CHECK-PPC64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +000082 // 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 }
88 unsigned read30(S* s) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +000089 // CHECK-X86-64-LABEL: define i32 @_ZN2N06read30
Chandler Carruth5588a692012-12-09 10:08:22 +000090 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -070091 // CHECK-X86-64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +000092 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +000096 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read30
Chandler Carruth5588a692012-12-09 10:08:22 +000097 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -070098 // CHECK-PPC64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +000099 // 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 }
105 unsigned read31(S* s) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000106 // CHECK-X86-64-LABEL: define i32 @_ZN2N06read31
Chandler Carruth5588a692012-12-09 10:08:22 +0000107 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700108 // CHECK-X86-64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +0000109 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000113 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read31
Chandler Carruth5588a692012-12-09 10:08:22 +0000114 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700115 // CHECK-PPC64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +0000116 // 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 }
122 unsigned read70(S* s) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000123 // CHECK-X86-64-LABEL: define i32 @_ZN2N06read70
Chandler Carruth5588a692012-12-09 10:08:22 +0000124 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700125 // CHECK-X86-64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +0000126 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000130 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read70
Chandler Carruth5588a692012-12-09 10:08:22 +0000131 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700132 // CHECK-PPC64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +0000133 // 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 }
139 unsigned read71(S* s) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000140 // CHECK-X86-64-LABEL: define i32 @_ZN2N06read71
Chandler Carruth5588a692012-12-09 10:08:22 +0000141 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700142 // CHECK-X86-64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +0000143 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000146 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N06read71
Chandler Carruth5588a692012-12-09 10:08:22 +0000147 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700148 // CHECK-PPC64: %[[val:.*]] = load i64, i64* %[[ptr]]
Chandler Carruth5588a692012-12-09 10:08:22 +0000149 // 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
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000156namespace 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 };
168 unsigned read(S* s) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000169 // CHECK-X86-64-LABEL: define i32 @_ZN2N14read
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700170 // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}, %{{.*}}* %{{.*}}, i32 0, i32 1
171 // CHECK-X86-64: %[[val:.*]] = load i8, i8* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000172 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000175 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N14read
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700176 // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}, %{{.*}}* %{{.*}}, i32 0, i32 1
177 // CHECK-PPC64: %[[val:.*]] = load i8, i8* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000178 // CHECK-PPC64: %[[shr:.*]] = lshr i8 %[[val]], 7
179 // CHECK-PPC64: %[[ext:.*]] = zext i8 %[[shr]] to i32
180 // CHECK-PPC64: ret i32 %[[ext]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000181 return s->b;
182 }
183 void write(S* s, unsigned x) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000184 // CHECK-X86-64-LABEL: define void @_ZN2N15write
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700185 // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}, %{{.*}}* %{{.*}}, i32 0, i32 1
Chandler Carruthef8d5162012-12-09 07:26:04 +0000186 // CHECK-X86-64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700187 // CHECK-X86-64: %[[old:.*]] = load i8, i8* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000188 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000192 // CHECK-PPC64-LABEL: define void @_ZN2N15write
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700193 // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}, %{{.*}}* %{{.*}}, i32 0, i32 1
Chandler Carruthef8d5162012-12-09 07:26:04 +0000194 // CHECK-PPC64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700195 // CHECK-PPC64: %[[old:.*]] = load i8, i8* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000196 // 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]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000201 s->b = x;
202 }
203}
204
205namespace 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 };
212 unsigned read(S* s) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000213 // CHECK-X86-64-LABEL: define i32 @_ZN2N24read
Chandler Carruthef8d5162012-12-09 07:26:04 +0000214 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700215 // CHECK-X86-64: %[[val:.*]] = load i32, i32* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000216 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
217 // CHECK-X86-64: ret i32 %[[and]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000218 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N24read
Chandler Carruthef8d5162012-12-09 07:26:04 +0000219 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700220 // CHECK-PPC64: %[[val:.*]] = load i32, i32* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000221 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
222 // CHECK-PPC64: ret i32 %[[shr]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000223 return s->b;
224 }
225 void write(S* s, unsigned x) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000226 // CHECK-X86-64-LABEL: define void @_ZN2N25write
Chandler Carruthef8d5162012-12-09 07:26:04 +0000227 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700228 // CHECK-X86-64: %[[old:.*]] = load i32, i32* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000229 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000233 // CHECK-PPC64-LABEL: define void @_ZN2N25write
Chandler Carruthef8d5162012-12-09 07:26:04 +0000234 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700235 // CHECK-PPC64: %[[old:.*]] = load i32, i32* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000236 // 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]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000241 s->b = x;
242 }
243}
244
245namespace 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 };
251 unsigned read(S* s) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000252 // CHECK-X86-64-LABEL: define i32 @_ZN2N34read
Chandler Carruthef8d5162012-12-09 07:26:04 +0000253 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700254 // CHECK-X86-64: %[[val:.*]] = load i32, i32* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000255 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
256 // CHECK-X86-64: ret i32 %[[and]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000257 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N34read
Chandler Carruthef8d5162012-12-09 07:26:04 +0000258 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700259 // CHECK-PPC64: %[[val:.*]] = load i32, i32* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000260 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
261 // CHECK-PPC64: ret i32 %[[shr]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000262 return s->b;
263 }
264 void write(S* s, unsigned x) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000265 // CHECK-X86-64-LABEL: define void @_ZN2N35write
Chandler Carruthef8d5162012-12-09 07:26:04 +0000266 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700267 // CHECK-X86-64: %[[old:.*]] = load i32, i32* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000268 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000272 // CHECK-PPC64-LABEL: define void @_ZN2N35write
Chandler Carruthef8d5162012-12-09 07:26:04 +0000273 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700274 // CHECK-PPC64: %[[old:.*]] = load i32, i32* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000275 // 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]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000280 s->b = x;
281 }
282}
283
284namespace N4 {
285 // Do NOT widen loads and stores to bitfields into padding at the end of
286 // a class which might end up with members inside of it when inside a derived
287 // class.
288 struct Base {
289 virtual ~Base() {}
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
299 unsigned read(Base* s) {
300 // FIXME: We should widen this load as long as the function isn't being
Stephen Hines651f13c2014-04-23 16:59:28 -0700301 // instrumented by ThreadSanitizer.
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000302 //
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000303 // CHECK-X86-64-LABEL: define i32 @_ZN2N44read
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700304 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
Chandler Carruthef8d5162012-12-09 07:26:04 +0000305 // CHECK-X86-64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700306 // CHECK-X86-64: %[[val:.*]] = load i24, i24* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000307 // CHECK-X86-64: %[[ext:.*]] = zext i24 %[[val]] to i32
308 // CHECK-X86-64: ret i32 %[[ext]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000309 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N44read
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700310 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
Chandler Carruthef8d5162012-12-09 07:26:04 +0000311 // CHECK-PPC64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700312 // CHECK-PPC64: %[[val:.*]] = load i24, i24* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000313 // CHECK-PPC64: %[[ext:.*]] = zext i24 %[[val]] to i32
314 // CHECK-PPC64: ret i32 %[[ext]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000315 return s->b;
316 }
317 void write(Base* s, unsigned x) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000318 // CHECK-X86-64-LABEL: define void @_ZN2N45write
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700319 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
Chandler Carruthef8d5162012-12-09 07:26:04 +0000320 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000323 // CHECK-PPC64-LABEL: define void @_ZN2N45write
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700324 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
Chandler Carruthef8d5162012-12-09 07:26:04 +0000325 // 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]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000328 s->b = x;
329 }
330}
331
332namespace 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 };
344 unsigned read(U* u) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000345 // CHECK-X86-64-LABEL: define i32 @_ZN2N54read
Chandler Carruthef8d5162012-12-09 07:26:04 +0000346 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700347 // CHECK-X86-64: %[[val:.*]] = load i32, i32* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000348 // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
349 // CHECK-X86-64: ret i32 %[[and]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000350 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N54read
Chandler Carruthef8d5162012-12-09 07:26:04 +0000351 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700352 // CHECK-PPC64: %[[val:.*]] = load i32, i32* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000353 // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
354 // CHECK-PPC64: ret i32 %[[shr]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000355 return u->y.b;
356 }
357 void write(U* u, unsigned x) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000358 // CHECK-X86-64-LABEL: define void @_ZN2N55write
Chandler Carruthef8d5162012-12-09 07:26:04 +0000359 // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700360 // CHECK-X86-64: %[[old:.*]] = load i32, i32* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000361 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000365 // CHECK-PPC64-LABEL: define void @_ZN2N55write
Chandler Carruthef8d5162012-12-09 07:26:04 +0000366 // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700367 // CHECK-PPC64: %[[old:.*]] = load i32, i32* %[[ptr]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000368 // 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]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000373 u->y.b = x;
374 }
375}
376
377namespace 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
Stephen Hines651f13c2014-04-23 16:59:28 -0700381 // ThreadSanitizer.
382 // FIXME: We currently don't widen loads even without ThreadSanitizer, even
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000383 // though we could.
384 struct S {
385 unsigned b1 : 24;
386 unsigned char : 0;
387 unsigned char b2 : 8;
388 };
389 unsigned read(S* s) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000390 // CHECK-X86-64-LABEL: define i32 @_ZN2N64read
Chandler Carruthef8d5162012-12-09 07:26:04 +0000391 // CHECK-X86-64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700392 // CHECK-X86-64: %[[val1:.*]] = load i24, i24* %[[ptr1]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000393 // CHECK-X86-64: %[[ext1:.*]] = zext i24 %[[val1]] to i32
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700394 // CHECK-X86-64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
395 // CHECK-X86-64: %[[val2:.*]] = load i8, i8* %[[ptr2]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000396 // 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]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000399 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N64read
Chandler Carruthef8d5162012-12-09 07:26:04 +0000400 // CHECK-PPC64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700401 // CHECK-PPC64: %[[val1:.*]] = load i24, i24* %[[ptr1]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000402 // CHECK-PPC64: %[[ext1:.*]] = zext i24 %[[val1]] to i32
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700403 // CHECK-PPC64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
404 // CHECK-PPC64: %[[val2:.*]] = load i8, i8* %[[ptr2]]
Chandler Carruthef8d5162012-12-09 07:26:04 +0000405 // CHECK-PPC64: %[[ext2:.*]] = zext i8 %[[val2]] to i32
406 // CHECK-PPC64: %[[add:.*]] = add nsw i32 %[[ext1]], %[[ext2]]
407 // CHECK-PPC64: ret i32 %[[add]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000408 return s->b1 + s->b2;
409 }
410 void write(S* s, unsigned x) {
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000411 // CHECK-X86-64-LABEL: define void @_ZN2N65write
Chandler Carruthef8d5162012-12-09 07:26:04 +0000412 // 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
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700416 // CHECK-X86-64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
Chandler Carruthef8d5162012-12-09 07:26:04 +0000417 // CHECK-X86-64: store i8 %[[new2]], i8* %[[ptr2]]
Stephen Lin93ab6bf2013-08-15 06:47:53 +0000418 // CHECK-PPC64-LABEL: define void @_ZN2N65write
Chandler Carruthef8d5162012-12-09 07:26:04 +0000419 // 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
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700423 // CHECK-PPC64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
Chandler Carruthef8d5162012-12-09 07:26:04 +0000424 // CHECK-PPC64: store i8 %[[new2]], i8* %[[ptr2]]
Chandler Carruth72d2dab2012-12-06 11:14:44 +0000425 s->b1 = x;
426 s->b2 = x;
427 }
428}
Stephen Hines651f13c2014-04-23 16:59:28 -0700429
430namespace 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
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
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700454 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
Stephen Hines651f13c2014-04-23 16:59:28 -0700455 // CHECK-X86-64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700456 // CHECK-X86-64: %[[val:.*]] = load i24, i24* %[[ptr]]
Stephen Hines651f13c2014-04-23 16:59:28 -0700457 // CHECK-X86-64: %[[ext:.*]] = zext i24 %[[val]] to i32
458 // CHECK-X86-64: ret i32 %[[ext]]
459 // CHECK-PPC64-LABEL: define zeroext i32 @_ZN2N74read
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700460 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
Stephen Hines651f13c2014-04-23 16:59:28 -0700461 // CHECK-PPC64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700462 // CHECK-PPC64: %[[val:.*]] = load i24, i24* %[[ptr]]
Stephen Hines651f13c2014-04-23 16:59:28 -0700463 // CHECK-PPC64: %[[ext:.*]] = zext i24 %[[val]] to i32
464 // CHECK-PPC64: ret i32 %[[ext]]
465 return s->b;
466 }
467 void write(B2* s, unsigned x) {
468 // CHECK-X86-64-LABEL: define void @_ZN2N75write
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700469 // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
Stephen Hines651f13c2014-04-23 16:59:28 -0700470 // 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
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700474 // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %{{.*}}, i32 0, i32 1
Stephen Hines651f13c2014-04-23 16:59:28 -0700475 // 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}