Files
clang-p2996/clang/test/CodeGenCXX/condition.cpp
John McCall 2b7fc3828e Teach IR generation how to lazily emit cleanups. This has a lot of advantages,
mostly in avoiding unnecessary work at compile time but also in producing more
sensible block orderings.

Move the destructor cleanups for local variables over to use lazy cleanups.
Eventually all cleanups will do this;  for now we have some awkward code
duplication.

Tell IR generation just to never produce landing pads in -fno-exceptions.
This is a much more comprehensive solution to a problem which previously was
half-solved by checks in most cleanup-generation spots.

llvm-svn: 108270
2010-07-13 20:32:21 +00:00

318 lines
6.5 KiB
C++

// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
void *f();
template <typename T> T* g() {
if (T* t = f())
return t;
return 0;
}
void h() {
void *a = g<void>();
}
struct X {
X();
X(const X&);
~X();
operator bool();
};
struct Y {
Y();
~Y();
};
X getX();
// CHECK: define void @_Z11if_destructi(
void if_destruct(int z) {
// Verify that the condition variable is destroyed at the end of the
// "if" statement.
// CHECK: call void @_ZN1XC1Ev
// CHECK: call zeroext i1 @_ZN1XcvbEv
if (X x = X()) {
// CHECK: store i32 18
z = 18;
}
// CHECK: call void @_ZN1XD1Ev
// CHECK: store i32 17
z = 17;
// CHECK: call void @_ZN1XC1Ev
if (X x = X())
Y y;
// CHECK: br
// CHECK: call void @_ZN1YC1Ev
// CHECK: call void @_ZN1YD1Ev
// CHECK: br
// CHECK: call void @_ZN1XD1Ev
// CHECK: call void @_Z4getXv
// CHECK: call zeroext i1 @_ZN1XcvbEv
// CHECK: call void @_ZN1XD1Ev
// CHECK: br
if (getX()) { }
// CHECK: ret
}
struct ConvertibleToInt {
ConvertibleToInt();
~ConvertibleToInt();
operator int();
};
ConvertibleToInt getConvToInt();
void switch_destruct(int z) {
// CHECK: call void @_ZN16ConvertibleToIntC1Ev
switch (ConvertibleToInt conv = ConvertibleToInt()) {
case 0:
break;
default:
// CHECK: store i32 19
z = 19;
break;
}
// CHECK: call void @_ZN16ConvertibleToIntD1Ev
// CHECK: store i32 20
z = 20;
// CHECK: call void @_Z12getConvToIntv
// CHECK: call i32 @_ZN16ConvertibleToIntcviEv
// CHECK: call void @_ZN16ConvertibleToIntD1Ev
switch(getConvToInt()) {
case 0:
break;
}
// CHECK: store i32 27
z = 27;
// CHECK: ret
}
int foo();
// CHECK: define void @_Z14while_destructi
void while_destruct(int z) {
// CHECK: [[Z:%.*]] = alloca i32
// CHECK: [[CLEANUPDEST:%.*]] = alloca i32
while (X x = X()) {
// CHECK: call void @_ZN1XC1Ev
// CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN1XcvbEv
// CHECK-NEXT: br i1 [[COND]]
// Loop-exit staging block.
// CHECK: store i32 1, i32* [[CLEANUPDEST]]
// CHECK-NEXT: br
// While body.
// CHECK: store i32 21, i32* [[Z]]
// CHECK: store i32 2, i32* [[CLEANUPDEST]]
// CHECK-NEXT: br
z = 21;
// Cleanup.
// CHECK: call void @_ZN1XD1Ev
// CHECK-NEXT: [[DEST:%.*]] = load i32* [[CLEANUPDEST]]
// CHECK-NEXT: switch i32 [[DEST]]
}
// CHECK: store i32 22, i32* [[Z]]
z = 22;
// CHECK: call void @_Z4getXv
// CHECK-NEXT: call zeroext i1 @_ZN1XcvbEv
// CHECK-NEXT: call void @_ZN1XD1Ev
// CHECK-NEXT: br
while(getX()) { }
// CHECK: store i32 25, i32* [[Z]]
z = 25;
// CHECK: ret
}
// CHECK: define void @_Z12for_destructi(
void for_destruct(int z) {
// CHECK: [[Z:%.*]] = alloca i32
// CHECK: [[XDEST:%.*]] = alloca i32
// CHECK: [[I:%.*]] = alloca i32
// CHECK: call void @_ZN1YC1Ev
// CHECK-NEXT: br
// -> %for.cond
for(Y y = Y(); X x = X(); ++z) {
// %for.cond: The loop condition.
// CHECK: call void @_ZN1XC1Ev
// CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN1XcvbEv(
// CHECK-NEXT: br i1 [[COND]]
// -> %for.body, %for.cond.cleanup
// %for.cond.cleanup: Exit cleanup staging.
// CHECK: store i32 1, i32* [[XDEST]]
// CHECK-NEXT: br
// -> %cleanup
// %for.body:
// CHECK: store i32 23, i32* [[Z]]
// CHECK-NEXT: br
// -> %for.inc
z = 23;
// %for.inc:
// CHECK: [[TMP:%.*]] = load i32* [[Z]]
// CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP]], 1
// CHECK-NEXT: store i32 [[INC]], i32* [[Z]]
// CHECK-NEXT: store i32 2, i32* [[XDEST]]
// CHECK-NEXT: br
// -> %cleanup
// %cleanup: Destroys X.
// CHECK: call void @_ZN1XD1Ev
// CHECK-NEXT: [[YDESTTMP:%.*]] = load i32* [[XDEST]]
// CHECK-NEXT: switch i32 [[YDESTTMP]]
// 1 -> %cleanup4, 2 -> %cleanup.cont
// %cleanup.cont: (eliminable)
// CHECK: br
// -> %for.cond
// %cleanup4: Destroys Y.
// CHECK: call void @_ZN1YD1Ev(
// CHECK-NEXT: br
// -> %for.end
}
// %for.end:
// CHECK: store i32 24
z = 24;
// CHECK-NEXT: store i32 0, i32* [[I]]
// CHECK-NEXT: br
// -> %for.cond6
// %for.cond6:
// CHECK: call void @_Z4getXv
// CHECK-NEXT: call zeroext i1 @_ZN1XcvbEv
// CHECK-NEXT: call void @_ZN1XD1Ev
// CHECK-NEXT: br
// -> %for.body10, %for.end16
// %for.body10:
// CHECK: br
// -> %for.inc11
// %for.inc11:
// CHECK: call void @_Z4getXv
// CHECK-NEXT: load i32* [[I]]
// CHECK-NEXT: add
// CHECK-NEXT: store
// CHECK-NEXT: call void @_ZN1XD1Ev
// CHECK-NEXT: br
// -> %for.cond6
int i = 0;
for(; getX(); getX(), ++i) { }
// %for.end16
// CHECK: store i32 26
z = 26;
// CHECK-NEXT: ret void
}
void do_destruct(int z) {
// CHECK: define void @_Z11do_destruct
do {
// CHECK: store i32 77
z = 77;
// CHECK: call void @_Z4getXv
// CHECK: call zeroext i1 @_ZN1XcvbEv
// CHECK: call void @_ZN1XD1Ev
// CHECK: br
} while (getX());
// CHECK: store i32 99
z = 99;
// CHECK: ret
}
int f(X);
template<typename T>
int instantiated(T x) {
int result;
// CHECK: call void @_ZN1XC1ERKS_
// CHECK: call i32 @_Z1f1X
// CHECK: call void @_ZN1XD1Ev
// CHECK: br
// CHECK: store i32 2
// CHECK: br
// CHECK: store i32 3
if (f(x)) { result = 2; } else { result = 3; }
// CHECK: call void @_ZN1XC1ERKS_
// CHECK: call i32 @_Z1f1X
// CHECK: call void @_ZN1XD1Ev
// CHECK: br
// CHECK: store i32 4
// CHECK: br
while (f(x)) { result = 4; }
// CHECK: call void @_ZN1XC1ERKS_
// CHECK: call i32 @_Z1f1X
// CHECK: call void @_ZN1XD1Ev
// CHECK: br
// CHECK: store i32 6
// CHECK: br
// CHECK: call void @_ZN1XC1ERKS_
// CHECK: call i32 @_Z1f1X
// CHECK: store i32 5
// CHECK: call void @_ZN1XD1Ev
// CHECK: br
for (; f(x); f(x), result = 5) {
result = 6;
}
// CHECK: call void @_ZN1XC1ERKS_
// CHECK: call i32 @_Z1f1X
// CHECK: call void @_ZN1XD1Ev
// CHECK: switch i32
// CHECK: store i32 7
// CHECK: store i32 8
switch (f(x)) {
case 0:
result = 7;
break;
case 1:
result = 8;
}
// CHECK: store i32 9
// CHECK: br
// CHECK: call void @_ZN1XC1ERKS_
// CHECK: call i32 @_Z1f1X
// CHECK: call void @_ZN1XD1Ev
// CHECK: br
do {
result = 9;
} while (f(x));
// CHECK: store i32 10
// CHECK: call void @_ZN1XC1ERKS_
// CHECK: call zeroext i1 @_ZN1XcvbEv
// CHECK: call void @_ZN1XD1Ev
// CHECK: br
do {
result = 10;
} while (X(x));
// CHECK: ret i32
return result;
}
template int instantiated(X);