1 // RUN: %clang_cc1 -Wno-return-type -Wno-unused-value -emit-llvm %s -w -o - | FileCheck %s
2
3 // CHECK: @i = {{(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 = {{(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()
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()
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()
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