266 lines · cpp
1// RUN: %clang_cc1 -Wno-unused-value -triple i686-linux-gnu -emit-llvm -o - %s | FileCheck %s2extern "C" int printf(...);3extern "C" void abort();4 5struct A6{7 int i;8 A (int j) : i(j) {printf("this = %p A(%d)\n", this, j);}9 A (const A &j) : i(j.i) {printf("this = %p const A&(%d)\n", this, i);}10 A& operator= (const A &j) { i = j.i; abort(); return *this; }11 ~A() { printf("this = %p ~A(%d)\n", this, i); }12};13 14struct B15{16 int i;17 B (const A& a) { i = a.i; }18 B() {printf("this = %p B()\n", this);}19 B (const B &j) : i(j.i) {printf("this = %p const B&(%d)\n", this, i);}20 ~B() { printf("this = %p ~B(%d)\n", this, i); }21};22 23A foo(int j)24{25 return ({ j ? A(1) : A(0); });26}27 28 29void 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 39void foo3()40{41 const A &b = ({ A a(1); a; });42 if (b.i != 1)43 abort();44}45 46void foo4()47{48// CHECK: call {{.*}} @_ZN1AC1Ei49// CHECK: call {{.*}} @_ZN1AC1ERKS_50// CHECK: call {{.*}} @_ZN1AD1Ev51// CHECK: call {{.*}} @_ZN1BC1ERK1A52// CHECK: call {{.*}} @_ZN1AD1Ev53 const B &b = ({ A a(1); a; });54 if (b.i != 1)55 abort();56}57 58int main()59{60 foo2();61 foo3();62 foo4();63 return foo(1).i-1;64}65 66int a[128];67int* foo5() {68// CHECK-NOT: memcpy69 // Check that array-to-pointer conversion occurs in a70 // statement-expression.71 return (({ a; }));72}73 74// Make sure this doesn't crash.75int 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 of82// the full expression, the result of the inner expression (the call to83// call_with_cleanups in this case) may not dominate the fallthrough destination84// of the shared cleanup block.85//86// In this case the CFG will be a sequence of two diamonds, but the only87// dynamically possible execution paths are both left hand branches and both88// right hand branches. The first diamond LHS will call bar, and the second89// diamond LHS will assign the result to v, but the call to bar does not90// dominate the assignment.91int bar(A, int);92extern "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 {{.*}} @_ZN1AC1Ei99// Spill after bar.100// CHECK: %[[v:[^ ]*]] = call{{.*}} i32 @_Z3bar1Ai({{.*}})101// CHECK-NEXT: store i32 %[[v]], ptr %[[tmp:[^, ]*]]102// Do cleanup.103// CHECK: call {{.*}} @_ZN1AD1Ev104// CHECK: switch105// Reload before v assignment.106// CHECK: %[[v:[^ ]*]] = load i32, ptr %[[tmp]]107// CHECK-NEXT: store i32 %[[v]], ptr %v108 109// No need to spill when the expression result is a constant, constants don't110// have dominance problems.111extern "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 %v118 119// Check for the same bug for lvalue expression evaluation kind.120// FIXME: What about non-reference lvalues, like bitfield lvalues and vector121// lvalues?122int &getref();123extern "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 {{.*}} @_ZN1AC1Ei129// 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 {{.*}} @_ZN1AD1Ev134// CHECK: switch135// Reload before v assignment.136// CHECK: %[[v:[^ ]*]] = load ptr, ptr %[[tmp]]137// CHECK-NEXT: store ptr %[[v]], ptr %r138 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.141struct ByVal { int x[3]; };142extern "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 {{.*}} @_ZN1AC1Ei148// CHECK: call {{.*}} @_ZN1AD1Ev149// CHECK: switch150// CHECK: store ptr %arg, ptr %r151 152// Bind the reference to a local variable. We don't need to spill it. Binding a153// reference to it doesn't generate any instructions.154extern "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 i32161// CHECK: store i32 42, ptr %local162// CHECK: call {{.*}} @_ZN1AC1Ei163// CHECK-NOT: store ptr %local164// CHECK: call {{.*}} @_ZN1AD1Ev165// CHECK: switch166// CHECK: store ptr %local, ptr %r, align 4167 168// We handle ExprWithCleanups for complex evaluation type separately, and it had169// the same bug.170_Complex float bar_complex(A, int);171extern "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 {{.*}} @_ZN1AC1Ei178// 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 {{.*}} @_ZN1AD1Ev184// CHECK: switch185// 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.realp189// CHECK: store float %[[v2]], ptr %v.imagp190 191extern "C" void then(int);192 193// CHECK-LABEL: @{{.*}}volatile_load194void volatile_load() {195 volatile int n;196 197 // CHECK-NOT: load volatile198 // CHECK: load volatile199 // CHECK-NOT: load volatile200 ({n;});201 202 // CHECK-LABEL: @then(i32 noundef 1)203 then(1);204 205 // CHECK-NOT: load volatile206 // CHECK: load volatile207 // CHECK-NOT: load volatile208 ({goto lab; lab: n;});209 210 // CHECK-LABEL: @then(i32 noundef 2)211 then(2);212 213 // CHECK-NOT: load volatile214 // CHECK: load volatile215 // CHECK-NOT: load volatile216 ({[[gsl::suppress("foo")]] n;});217 218 // CHECK-LABEL: @then(i32 noundef 3)219 then(3);220 221 // CHECK-NOT: load volatile222 // CHECK: load volatile223 // CHECK-NOT: load volatile224 ({if (true) n;});225 226 // CHECK: }227}228 229// CHECK-LABEL: @{{.*}}volatile_load_template230template<typename T>231void volatile_load_template() {232 volatile T n;233 234 // CHECK-NOT: load volatile235 // CHECK: load volatile236 // CHECK-NOT: load volatile237 ({n;});238 239 // CHECK-LABEL: @then(i32 noundef 1)240 then(1);241 242 // CHECK-NOT: load volatile243 // CHECK: load volatile244 // CHECK-NOT: load volatile245 ({goto lab; lab: n;});246 247 // CHECK-LABEL: @then(i32 noundef 2)248 then(2);249 250 // CHECK-NOT: load volatile251 // CHECK: load volatile252 // CHECK-NOT: load volatile253 ({[[gsl::suppress("foo")]] n;});254 255 // CHECK-LABEL: @then(i32 noundef 3)256 then(3);257 258 // CHECK-NOT: load volatile259 // CHECK: load volatile260 // CHECK-NOT: load volatile261 ({if (true) n;});262 263 // CHECK: }264}265template void volatile_load_template<int>();266