Don't crash on leaving nested __finally blocks through an EH edge.

The __finally emission block tries to be clever by removing unused continuation
edges if there's an unconditional jump out of the __finally block. With
exception edges, the EH continuation edge isn't always unused though and we'd
crash in a few places.

Just don't be clever. That makes the IR for __finally blocks a bit longer in
some cases (hence small and behavior-preserving changes to existing tests), but
it makes no difference in general and it fixes the last crash from PR22553.

http://reviews.llvm.org/D7918

llvm-svn: 230697
This commit is contained in:
Nico Weber 2015-02-26 22:34:33 +00:00
parent 653773d004
commit ff62a6a0b7
3 changed files with 110 additions and 26 deletions

View File

@ -1684,8 +1684,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
const char *RethrowName = Personality.CatchallRethrowFn;
if (RethrowName != nullptr && !isCleanup) {
EmitRuntimeCall(getCatchallRethrowFn(CGM, RethrowName),
getExceptionFromSlot())
->setDoesNotReturn();
getExceptionFromSlot())->setDoesNotReturn();
Builder.CreateUnreachable();
Builder.restoreIP(SavedIP);
return EHResumeBlock;
@ -1943,23 +1942,17 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {
Builder.SetInsertPoint(FI.FinallyBB);
EmitStmt(Finally->getBlock());
// If the finally block doesn't fall through, we don't need these blocks.
if (!HaveInsertPoint()) {
FI.ContBB->eraseFromParent();
if (FI.ResumeBB)
FI.ResumeBB->eraseFromParent();
return;
}
if (FI.ResumeBB) {
llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot(),
"abnormal.termination");
IsEH = Builder.CreateICmpEQ(IsEH, llvm::ConstantInt::get(Int8Ty, 0));
Builder.CreateCondBr(IsEH, FI.ContBB, FI.ResumeBB);
} else {
// There was nothing exceptional in the try body, so we only have normal
// control flow.
Builder.CreateBr(FI.ContBB);
if (HaveInsertPoint()) {
if (FI.ResumeBB) {
llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot(),
"abnormal.termination");
IsEH = Builder.CreateICmpEQ(IsEH, llvm::ConstantInt::get(Int8Ty, 0));
Builder.CreateCondBr(IsEH, FI.ContBB, FI.ResumeBB);
} else {
// There was nothing exceptional in the try body, so we only have normal
// control flow.
Builder.CreateBr(FI.ContBB);
}
}
Builder.restoreIP(SavedIP);

View File

@ -193,12 +193,99 @@ int nested___finally___finally() {
// CHECK-NEXT: br label %[[finally:[^ ]*]]
//
// CHECK: [[finally]]
// CHECK-NEXT: store i32 1, i32* %
// CHECK-NEXT: store i8 0, i8* %
// CHECK-NEXT: store i32 1, i32* %
// CHECK-NEXT: store i32 1, i32* %
// CHECK-NEXT: br label %[[cleanup:[^ ]*]]
//
// The finally's unreachable continuation block:
// CHECK: store i32 0, i32* %
// CHECK-NEXT: br label %[[cleanup]]
//
// CHECK: [[cleanup]]
// CHECK-NEXT: store i8 0, i8* %
// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]
//
// CHECK: [[outerfinally]]
// CHECK-NEXT: br label %[[finallycont:[^ ]*]]
//
// CHECK: [[finallycont]]
// CHECK-NEXT: ret i32 1
// CHECK-NEXT: %[[dest:[^ ]*]] = load i32* %
// CHECK-NEXT: switch i32 %[[dest]]
// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]]
//
// CHECK: [[cleanupcont]]
// CHECK-NEXT: store i32 0, i32* %
// CHECK-NEXT: br label %[[return:[^ ]*]]
//
// CHECK: [[return]]
// CHECK-NEXT: %[[reg:[^ ]*]] = load i32* %
// CHECK-NEXT: ret i32 %[[reg]]
int nested___finally___finally_with_eh_edge() {
__try {
__try {
might_crash();
} __finally {
return 899;
}
} __finally {
// Intentionally no return here.
}
return 912;
}
// CHECK-LABEL: define i32 @nested___finally___finally_with_eh_edge
// CHECK: invoke void @might_crash() #3
// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
//
// CHECK: [[invokecont]]
// CHECK-NEXT: store i8 0, i8* %[[abnormal:[^ ]*]]
// CHECK-NEXT: br label %[[finally:[^ ]*]]
// CHECK: [[finally]]
// CHECK-NEXT: store i32 899, i32* %
// CHECK-NEXT: store i32 1, i32* %
// CHECK-NEXT: br label %[[cleanup:[^ ]*]]
//
// The inner finally's unreachable continuation block:
// CHECK: store i32 0, i32* %
// CHECK-NEXT: br label %[[cleanup]]
//
// CHECK: [[cleanup]]
// CHECK-NEXT: store i8 0, i8* %
// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]
//
// CHECK: [[outerfinally]]
// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8* %[[abnormal]]
// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0
// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]]
//
// CHECK: [[finallycont]]
// CHECK-NEXT: %[[dest:[^ ]*]] = load i32* %
// CHECK-NEXT: switch i32 %[[dest]]
// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]]
//
// CHECK: [[cleanupcont]]
// CHECK-NEXT: store i32 912, i32* %
// CHECK-NEXT: br label %[[return:[^ ]*]]
//
//
// CHECK: [[lpad]]
// CHECK-NEXT: landingpad
// CHECK-NEXT: cleanup
// CHECK: store i8 1, i8* %[[abnormal]]
// CHECK: br label %[[finally]]
//
// The inner finally's unreachable resume block:
// CHECK: store i8 1, i8* %[[abnormal]]
// CHECK-NEXT: br label %[[outerfinally]]
//
// CHECK: [[finallyresume]]
// CHECK-NEXT: br label %[[ehresume:[^ ]*]]
//
// CHECK: [[return]]
// CHECK-NEXT: %[[reg:[^ ]*]] = load i32* %
// CHECK-NEXT: ret i32 %[[reg]]
//
// The ehresume block, not reachable either.
// CHECK: [[ehresume]]
// CHECK: resume

View File

@ -162,6 +162,13 @@ int nested___except___finally() {
// CHECK-NEXT: br label %[[tryleave:[^ ]*]]
// CHECK-NOT: store i32 23
// Unused __finally continuation block
// CHECK: store i32 51, i32* %
// CHECK-NEXT: br label %[[tryleave]]
// CHECK: [[tryleave]]
// CHECK-NEXT: br label %[[trycont:[^ ]*]]
// CHECK: [[g1_lpad]]
// CHECK: store i8 1, i8* %
// CHECK-NEXT: br label %[[finally]]
@ -171,14 +178,11 @@ int nested___except___finally() {
// CHECK: br label %[[except:[^ ]*]]
// CHECK: [[except]]
// CHECK-NEXT: br label %[[trycont:[^ ]*]]
// CHECK-NEXT: br label %[[trycont]]
// CHECK: [[trycont]]
// CHECK-NEXT: ret i32 1
// CHECK: [[tryleave]]
// CHECK-NEXT: br label %[[trycont]]
int nested___except___except() {
int myres = 0;
__try {