brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.0 KiB · 6e19ce8 Raw
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