1 // RUN: %clang_cc1 -Wno-unused-value -triple i686-linux-gnu -emit-llvm -o - %s | FileCheck %s
2 extern "C" int printf(...);
3 extern "C" void abort();
4
5 struct A
6 {
7 int i;
AA8 A (int j) : i(j) {printf("this = %p A(%d)\n", this, j);}
AA9 A (const A &j) : i(j.i) {printf("this = %p const A&(%d)\n", this, i);}
operator =A10 A& operator= (const A &j) { i = j.i; abort(); return *this; }
~AA11 ~A() { printf("this = %p ~A(%d)\n", this, i); }
12 };
13
14 struct B
15 {
16 int i;
BB17 B (const A& a) { i = a.i; }
BB18 B() {printf("this = %p B()\n", this);}
BB19 B (const B &j) : i(j.i) {printf("this = %p const B&(%d)\n", this, i);}
~BB20 ~B() { printf("this = %p ~B(%d)\n", this, i); }
21 };
22
foo(int j)23 A foo(int j)
24 {
25 return ({ j ? A(1) : A(0); });
26 }
27
28
foo2()29 void foo2()
30 {
31 A b = ({ A a(1); A a1(2); A a2(3); a1; a2; a; });
32 if (b.i != 1)
33 abort();
34 A c = ({ A a(1); A a1(2); A a2(3); a1; a2; a; A a3(4); a2; a3; });
35 if (c.i != 4)
36 abort();
37 }
38
foo3()39 void foo3()
40 {
41 const A &b = ({ A a(1); a; });
42 if (b.i != 1)
43 abort();
44 }
45
foo4()46 void foo4()
47 {
48 // CHECK: call {{.*}} @_ZN1AC1Ei
49 // CHECK: call {{.*}} @_ZN1AC1ERKS_
50 // CHECK: call {{.*}} @_ZN1AD1Ev
51 // CHECK: call {{.*}} @_ZN1BC1ERK1A
52 // CHECK: call {{.*}} @_ZN1AD1Ev
53 const B &b = ({ A a(1); a; });
54 if (b.i != 1)
55 abort();
56 }
57
main()58 int main()
59 {
60 foo2();
61 foo3();
62 foo4();
63 return foo(1).i-1;
64 }
65
66 int a[128];
foo5()67 int* foo5() {
68 // CHECK-NOT: memcpy
69 // Check that array-to-pointer conversion occurs in a
70 // statement-expression.
71 return (({ a; }));
72 }
73
74 // Make sure this doesn't crash.
foo5(bool b)75 int foo5(bool b) {
76 int y = 0;
77 y = ({ A a(1); if (b) goto G; a.i; });
78 G: return y;
79 }
80
81 // When we emit a full expression with cleanups that contains branches out of
82 // the full expression, the result of the inner expression (the call to
83 // call_with_cleanups in this case) may not dominate the fallthrough destination
84 // of the shared cleanup block.
85 //
86 // In this case the CFG will be a sequence of two diamonds, but the only
87 // dynamically possible execution paths are both left hand branches and both
88 // right hand branches. The first diamond LHS will call bar, and the second
89 // diamond LHS will assign the result to v, but the call to bar does not
90 // dominate the assignment.
91 int bar(A, int);
cleanup_exit_scalar(bool b)92 extern "C" int cleanup_exit_scalar(bool b) {
93 int v = bar(A(1), ({ if (b) return 42; 13; }));
94 return v;
95 }
96
97 // CHECK-LABEL: define{{.*}} i32 @cleanup_exit_scalar({{.*}})
98 // CHECK: call {{.*}} @_ZN1AC1Ei
99 // Spill after bar.
100 // CHECK: %[[v:[^ ]*]] = call{{.*}} i32 @_Z3bar1Ai({{.*}})
101 // CHECK-NEXT: store i32 %[[v]], ptr %[[tmp:[^, ]*]]
102 // Do cleanup.
103 // CHECK: call {{.*}} @_ZN1AD1Ev
104 // CHECK: switch
105 // Reload before v assignment.
106 // CHECK: %[[v:[^ ]*]] = load i32, ptr %[[tmp]]
107 // CHECK-NEXT: store i32 %[[v]], ptr %v
108
109 // No need to spill when the expression result is a constant, constants don't
110 // have dominance problems.
cleanup_exit_scalar_constant(bool b)111 extern "C" int cleanup_exit_scalar_constant(bool b) {
112 int v = (A(1), (void)({ if (b) return 42; 0; }), 13);
113 return v;
114 }
115
116 // CHECK-LABEL: define{{.*}} i32 @cleanup_exit_scalar_constant({{.*}})
117 // CHECK: store i32 13, ptr %v
118
119 // Check for the same bug for lvalue expression evaluation kind.
120 // FIXME: What about non-reference lvalues, like bitfield lvalues and vector
121 // lvalues?
122 int &getref();
cleanup_exit_lvalue(bool cond)123 extern "C" int cleanup_exit_lvalue(bool cond) {
124 int &r = (A(1), ({ if (cond) return 0; (void)0; }), getref());
125 return r;
126 }
127 // CHECK-LABEL: define{{.*}} i32 @cleanup_exit_lvalue({{.*}})
128 // CHECK: call {{.*}} @_ZN1AC1Ei
129 // Spill after bar.
130 // CHECK: %[[v:[^ ]*]] = call noundef nonnull align 4 dereferenceable(4) ptr @_Z6getrefv({{.*}})
131 // CHECK-NEXT: store ptr %[[v]], ptr %[[tmp:[^, ]*]]
132 // Do cleanup.
133 // CHECK: call {{.*}} @_ZN1AD1Ev
134 // CHECK: switch
135 // Reload before v assignment.
136 // CHECK: %[[v:[^ ]*]] = load ptr, ptr %[[tmp]]
137 // CHECK-NEXT: store ptr %[[v]], ptr %r
138
139 // Bind the reference to a byval argument. It is not an instruction or Constant,
140 // so it's a bit of a corner case.
141 struct ByVal { int x[3]; };
cleanup_exit_lvalue_byval(bool cond,ByVal arg)142 extern "C" int cleanup_exit_lvalue_byval(bool cond, ByVal arg) {
143 ByVal &r = (A(1), ({ if (cond) return 0; (void)ByVal(); }), arg);
144 return r.x[0];
145 }
146 // CHECK-LABEL: define{{.*}} i32 @cleanup_exit_lvalue_byval({{.*}}, ptr noundef byval(%struct.ByVal) align 4 %arg)
147 // CHECK: call {{.*}} @_ZN1AC1Ei
148 // CHECK: call {{.*}} @_ZN1AD1Ev
149 // CHECK: switch
150 // CHECK: store ptr %arg, ptr %r
151
152 // Bind the reference to a local variable. We don't need to spill it. Binding a
153 // reference to it doesn't generate any instructions.
cleanup_exit_lvalue_local(bool cond)154 extern "C" int cleanup_exit_lvalue_local(bool cond) {
155 int local = 42;
156 int &r = (A(1), ({ if (cond) return 0; (void)0; }), local);
157 return r;
158 }
159 // CHECK-LABEL: define{{.*}} i32 @cleanup_exit_lvalue_local({{.*}})
160 // CHECK: %local = alloca i32
161 // CHECK: store i32 42, ptr %local
162 // CHECK: call {{.*}} @_ZN1AC1Ei
163 // CHECK-NOT: store ptr %local
164 // CHECK: call {{.*}} @_ZN1AD1Ev
165 // CHECK: switch
166 // CHECK: store ptr %local, ptr %r, align 4
167
168 // We handle ExprWithCleanups for complex evaluation type separately, and it had
169 // the same bug.
170 _Complex float bar_complex(A, int);
cleanup_exit_complex(bool b)171 extern "C" int cleanup_exit_complex(bool b) {
172 _Complex float v = bar_complex(A(1), ({ if (b) return 42; 13; }));
173 return (float)v;
174 }
175
176 // CHECK-LABEL: define{{.*}} i32 @cleanup_exit_complex({{.*}})
177 // CHECK: call {{.*}} @_ZN1AC1Ei
178 // Spill after bar.
179 // CHECK: call {{.*}} @_Z11bar_complex1Ai({{.*}})
180 // CHECK: store float %{{.*}}, ptr %[[tmp1:[^, ]*]]
181 // CHECK: store float %{{.*}}, ptr %[[tmp2:[^, ]*]]
182 // Do cleanup.
183 // CHECK: call {{.*}} @_ZN1AD1Ev
184 // CHECK: switch
185 // Reload before v assignment.
186 // CHECK: %[[v1:[^ ]*]] = load float, ptr %[[tmp1]]
187 // CHECK: %[[v2:[^ ]*]] = load float, ptr %[[tmp2]]
188 // CHECK: store float %[[v1]], ptr %v.realp
189 // CHECK: store float %[[v2]], ptr %v.imagp
190
191 extern "C" void then(int);
192
193 // CHECK-LABEL: @{{.*}}volatile_load
volatile_load()194 void volatile_load() {
195 volatile int n;
196
197 // CHECK-NOT: load volatile
198 // CHECK: load volatile
199 // CHECK-NOT: load volatile
200 ({n;});
201
202 // CHECK-LABEL: @then(i32 noundef 1)
203 then(1);
204
205 // CHECK-NOT: load volatile
206 // CHECK: load volatile
207 // CHECK-NOT: load volatile
208 ({goto lab; lab: n;});
209
210 // CHECK-LABEL: @then(i32 noundef 2)
211 then(2);
212
213 // CHECK-NOT: load volatile
214 // CHECK: load volatile
215 // CHECK-NOT: load volatile
216 ({[[gsl::suppress("foo")]] n;});
217
218 // CHECK-LABEL: @then(i32 noundef 3)
219 then(3);
220
221 // CHECK-NOT: load volatile
222 // CHECK: load volatile
223 // CHECK-NOT: load volatile
224 ({if (true) n;});
225
226 // CHECK: }
227 }
228
229 // CHECK-LABEL: @{{.*}}volatile_load_template
230 template<typename T>
volatile_load_template()231 void volatile_load_template() {
232 volatile T n;
233
234 // CHECK-NOT: load volatile
235 // CHECK: load volatile
236 // CHECK-NOT: load volatile
237 ({n;});
238
239 // CHECK-LABEL: @then(i32 noundef 1)
240 then(1);
241
242 // CHECK-NOT: load volatile
243 // CHECK: load volatile
244 // CHECK-NOT: load volatile
245 ({goto lab; lab: n;});
246
247 // CHECK-LABEL: @then(i32 noundef 2)
248 then(2);
249
250 // CHECK-NOT: load volatile
251 // CHECK: load volatile
252 // CHECK-NOT: load volatile
253 ({[[gsl::suppress("foo")]] n;});
254
255 // CHECK-LABEL: @then(i32 noundef 3)
256 then(3);
257
258 // CHECK-NOT: load volatile
259 // CHECK: load volatile
260 // CHECK-NOT: load volatile
261 ({if (true) n;});
262
263 // CHECK: }
264 }
265 template void volatile_load_template<int>();
266