1 | // RUN: %clang_cc1 -Wno-return-type -Wno-unused-value -emit-llvm %s -w -o - | FileCheck %s |
2 | |
3 | // CHECK: @i = common {{(dso_local )?}}global [[INT:i[0-9]+]] 0 |
4 | volatile int i, j, k; |
5 | volatile int ar[5]; |
6 | volatile char c; |
7 | // CHECK: @ci = common {{(dso_local )?}}global [[CINT:.*]] zeroinitializer |
8 | volatile _Complex int ci; |
9 | volatile struct S { |
10 | #ifdef __cplusplus |
11 | void operator =(volatile struct S&o) volatile; |
12 | #endif |
13 | int i; |
14 | } a, b; |
15 | |
16 | //void operator =(volatile struct S&o1, volatile struct S&o2) volatile; |
17 | int printf(const char *, ...); |
18 | |
19 | |
20 | // Note that these test results are very much specific to C! |
21 | // Assignments in C++ yield l-values, not r-values, and the situations |
22 | // that do implicit lvalue-to-rvalue conversion are substantially |
23 | // reduced. |
24 | |
25 | // CHECK-LABEL: define {{.*}}void @test() |
26 | void test() { |
27 | // CHECK: load volatile [[INT]], [[INT]]* @i |
28 | i; |
29 | // CHECK-NEXT: load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4 |
30 | // CHECK-NEXT: load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4 |
31 | // CHECK-NEXT: sitofp [[INT]] |
32 | (float)(ci); |
33 | // CHECK-NEXT: load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4 |
34 | // CHECK-NEXT: load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4 |
35 | (void)ci; |
36 | // CHECK-NEXT: bitcast |
37 | // CHECK-NEXT: memcpy |
38 | (void)a; |
39 | // CHECK-NEXT: [[R:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4 |
40 | // CHECK-NEXT: [[I:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4 |
41 | // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4 |
42 | // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4 |
43 | (void)(ci=ci); |
44 | // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]], [[INT]]* @j |
45 | // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* @i |
46 | (void)(i=j); |
47 | // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4 |
48 | // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4 |
49 | // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4 |
50 | // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4 |
51 | // Not sure why they're ordered this way. |
52 | // CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]] |
53 | // CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]] |
54 | // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4 |
55 | // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4 |
56 | ci+=ci; |
57 | |
58 | // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4 |
59 | // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4 |
60 | // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4 |
61 | // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4 |
62 | // CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]] |
63 | // CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]] |
64 | // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4 |
65 | // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4 |
66 | // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 0), align 4 |
67 | // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1), align 4 |
68 | // These additions can be elided |
69 | // CHECK-NEXT: add [[INT]] [[R]], [[R2]] |
70 | // CHECK-NEXT: add [[INT]] [[I]], [[I2]] |
71 | (ci += ci) + ci; |
72 | // CHECK-NEXT: call void asm |
73 | asm("nop"); |
74 | // CHECK-NEXT: load volatile |
75 | // CHECK-NEXT: load volatile |
76 | // CHECK-NEXT: add nsw [[INT]] |
77 | // CHECK-NEXT: store volatile |
78 | // CHECK-NEXT: load volatile |
79 | // CHECK-NEXT: add nsw [[INT]] |
80 | (i += j) + k; |
81 | // CHECK-NEXT: call void asm |
82 | asm("nop"); |
83 | // CHECK-NEXT: load volatile |
84 | // CHECK-NEXT: load volatile |
85 | // CHECK-NEXT: add nsw [[INT]] |
86 | // CHECK-NEXT: store volatile |
87 | // CHECK-NEXT: add nsw [[INT]] |
88 | (i += j) + 1; |
89 | // CHECK-NEXT: call void asm |
90 | asm("nop"); |
91 | // CHECK-NEXT: load volatile |
92 | // CHECK-NEXT: load volatile |
93 | // CHECK-NEXT: load volatile |
94 | // CHECK-NEXT: load volatile |
95 | // CHECK-NEXT: add [[INT]] |
96 | // CHECK-NEXT: add [[INT]] |
97 | ci+ci; |
98 | |
99 | // CHECK-NEXT: load volatile |
100 | __real i; |
101 | // CHECK-NEXT: load volatile |
102 | // CHECK-NEXT: load volatile |
103 | +ci; |
104 | // CHECK-NEXT: call void asm |
105 | asm("nop"); |
106 | // CHECK-NEXT: load volatile |
107 | // CHECK-NEXT: store volatile |
108 | (void)(i=i); |
109 | // CHECK-NEXT: load volatile |
110 | // CHECK-NEXT: store volatile |
111 | // CHECK-NEXT: sitofp |
112 | (float)(i=i); |
113 | // CHECK-NEXT: load volatile |
114 | (void)i; |
115 | // CHECK-NEXT: load volatile |
116 | // CHECK-NEXT: store volatile |
117 | i=i; |
118 | // CHECK-NEXT: load volatile |
119 | // CHECK-NEXT: store volatile |
120 | // CHECK-NEXT: store volatile |
121 | i=i=i; |
122 | #ifndef __cplusplus |
123 | // CHECK-NEXT: load volatile |
124 | // CHECK-NEXT: store volatile |
125 | (void)__builtin_choose_expr(0, i=i, j=j); |
126 | #endif |
127 | // CHECK-NEXT: load volatile |
128 | // CHECK-NEXT: icmp |
129 | // CHECK-NEXT: br i1 |
130 | // CHECK: load volatile |
131 | // CHECK-NEXT: store volatile |
132 | // CHECK-NEXT: br label |
133 | // CHECK: load volatile |
134 | // CHECK-NEXT: store volatile |
135 | // CHECK-NEXT: br label |
136 | k ? (i=i) : (j=j); |
137 | // CHECK: phi |
138 | // CHECK-NEXT: load volatile |
139 | // CHECK-NEXT: load volatile |
140 | // CHECK-NEXT: store volatile |
141 | (void)(i,(i=i)); |
142 | // CHECK-NEXT: load volatile |
143 | // CHECK-NEXT: store volatile |
144 | // CHECK-NEXT: load volatile |
145 | i=i,i; |
146 | // CHECK-NEXT: load volatile |
147 | // CHECK-NEXT: store volatile |
148 | // CHECK-NEXT: load volatile |
149 | // CHECK-NEXT: store volatile |
150 | (i=j,k=j); |
151 | // CHECK-NEXT: load volatile |
152 | // CHECK-NEXT: store volatile |
153 | // CHECK-NEXT: load volatile |
154 | (i=j,k); |
155 | // CHECK-NEXT: load volatile |
156 | // CHECK-NEXT: load volatile |
157 | (i,j); |
158 | // CHECK-NEXT: load volatile |
159 | // CHECK-NEXT: trunc |
160 | // CHECK-NEXT: store volatile |
161 | // CHECK-NEXT: sext |
162 | // CHECK-NEXT: store volatile |
163 | i=c=k; |
164 | // CHECK-NEXT: load volatile |
165 | // CHECK-NEXT: load volatile |
166 | // CHECK-NEXT: add nsw [[INT]] |
167 | // CHECK-NEXT: store volatile |
168 | i+=k; |
169 | // CHECK-NEXT: load volatile |
170 | // CHECK-NEXT: load volatile |
171 | ci; |
172 | #ifndef __cplusplus |
173 | // CHECK-NEXT: load volatile |
174 | // CHECK-NEXT: load volatile |
175 | (int)ci; |
176 | // CHECK-NEXT: load volatile |
177 | // CHECK-NEXT: load volatile |
178 | // CHECK-NEXT: icmp ne |
179 | // CHECK-NEXT: icmp ne |
180 | // CHECK-NEXT: or i1 |
181 | (_Bool)ci; |
182 | #endif |
183 | // CHECK-NEXT: load volatile |
184 | // CHECK-NEXT: load volatile |
185 | // CHECK-NEXT: store volatile |
186 | // CHECK-NEXT: store volatile |
187 | ci=ci; |
188 | // CHECK-NEXT: load volatile |
189 | // CHECK-NEXT: load volatile |
190 | // CHECK-NEXT: store volatile |
191 | // CHECK-NEXT: store volatile |
192 | // CHECK-NEXT: store volatile |
193 | // CHECK-NEXT: store volatile |
194 | ci=ci=ci; |
195 | // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1) |
196 | // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1) |
197 | // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]], [[CINT]]* @ci, i32 0, i32 1) |
198 | __imag ci = __imag ci = __imag ci; |
199 | // CHECK-NEXT: load volatile |
200 | // CHECK-NEXT: store volatile |
201 | __real (i = j); |
202 | // CHECK-NEXT: load volatile |
203 | __imag i; |
204 | |
205 | // ============================================================ |
206 | // FIXME: Test cases we get wrong. |
207 | |
208 | // A use. We load all of a into a copy of a, then load i. gcc forgets to do |
209 | // the assignment. |
210 | // (a = a).i; |
211 | |
212 | // ============================================================ |
213 | // Test cases where we intentionally differ from gcc, due to suspected bugs in |
214 | // gcc. |
215 | |
216 | // Not a use. gcc forgets to do the assignment. |
217 | // CHECK-NEXT: call void @llvm.memcpy{{.*}}, i1 true |
218 | // CHECK-NEXT: bitcast |
219 | // CHECK-NEXT: call void @llvm.memcpy{{.*}}, i1 true |
220 | ((a=a),a); |
221 | |
222 | // Not a use. gcc gets this wrong, it doesn't emit the copy! |
223 | // (void)(a=a); |
224 | |
225 | // Not a use. gcc got this wrong in 4.2 and omitted the side effects |
226 | // entirely, but it is fixed in 4.4.0. |
227 | // CHECK-NEXT: load volatile |
228 | // CHECK-NEXT: store volatile |
229 | __imag (i = j); |
230 | |
231 | #ifndef __cplusplus |
232 | // A use of the real part |
233 | // CHECK-NEXT: load volatile |
234 | // CHECK-NEXT: load volatile |
235 | // CHECK-NEXT: store volatile |
236 | // CHECK-NEXT: store volatile |
237 | // CHECK-NEXT: sitofp |
238 | (float)(ci=ci); |
239 | // Not a use, bug? gcc treats this as not a use, that's probably a bug due to |
240 | // tree folding ignoring volatile. |
241 | // CHECK-NEXT: load volatile |
242 | // CHECK-NEXT: load volatile |
243 | // CHECK-NEXT: store volatile |
244 | // CHECK-NEXT: store volatile |
245 | (int)(ci=ci); |
246 | #endif |
247 | |
248 | // A use. |
249 | // CHECK-NEXT: load volatile |
250 | // CHECK-NEXT: store volatile |
251 | // CHECK-NEXT: sitofp |
252 | (float)(i=i); |
253 | // A use. gcc treats this as not a use, that's probably a bug due to tree |
254 | // folding ignoring volatile. |
255 | // CHECK-NEXT: load volatile |
256 | // CHECK-NEXT: store volatile |
257 | (int)(i=i); |
258 | |
259 | // A use. |
260 | // CHECK-NEXT: load volatile |
261 | // CHECK-NEXT: store volatile |
262 | // CHECK-NEXT: sub |
263 | -(i=j); |
264 | // A use. gcc treats this a not a use, that's probably a bug due to tree |
265 | // folding ignoring volatile. |
266 | // CHECK-NEXT: load volatile |
267 | // CHECK-NEXT: store volatile |
268 | +(i=k); |
269 | |
270 | // A use. gcc treats this a not a use, that's probably a bug due to tree |
271 | // folding ignoring volatile. |
272 | // CHECK-NEXT: load volatile |
273 | // CHECK-NEXT: load volatile |
274 | // CHECK-NEXT: store volatile |
275 | // CHECK-NEXT: store volatile |
276 | __real (ci=ci); |
277 | |
278 | // A use. |
279 | // CHECK-NEXT: load volatile |
280 | // CHECK-NEXT: add |
281 | i + 0; |
282 | // A use. |
283 | // CHECK-NEXT: load volatile |
284 | // CHECK-NEXT: store volatile |
285 | // CHECK-NEXT: load volatile |
286 | // CHECK-NEXT: add |
287 | (i=j) + i; |
288 | // A use. gcc treats this as not a use, that's probably a bug due to tree |
289 | // folding ignoring volatile. |
290 | // CHECK-NEXT: load volatile |
291 | // CHECK-NEXT: store volatile |
292 | // CHECK-NEXT: add |
293 | (i=j) + 0; |
294 | |
295 | #ifdef __cplusplus |
296 | (i,j)=k; |
297 | (j=k,i)=i; |
298 | struct { int x; } s, s1; |
299 | printf("s is at %p\n", &s); |
300 | printf("s is at %p\n", &(s = s1)); |
301 | printf("s.x is at %p\n", &((s = s1).x)); |
302 | #endif |
303 | } |
304 | |
305 | extern volatile enum X x; |
306 | // CHECK-LABEL: define {{.*}}void @test1() |
307 | void test1() { |
308 | extern void test1_helper(void); |
309 | test1_helper(); |
310 | // CHECK: call {{.*}}void @test1_helper() |
311 | // CHECK-NEXT: ret void |
312 | x; |
313 | (void) x; |
314 | return x; |
315 | } |
316 | |
317 | // CHECK: define {{.*}} @test2() |
318 | int test2() { |
319 | // CHECK: load volatile i32, i32* |
320 | // CHECK-NEXT: load volatile i32, i32* |
321 | // CHECK-NEXT: load volatile i32, i32* |
322 | // CHECK-NEXT: add i32 |
323 | // CHECK-NEXT: add i32 |
324 | // CHECK-NEXT: store volatile i32 |
325 | // CHECK-NEXT: ret i32 |
326 | return i += ci; |
327 | } |
328 | |