Index: llvm/trunk/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/Attributor.cpp +++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp @@ -1883,8 +1883,20 @@ } } - if (SplitPos == &NormalDestBB->front()) - assumeLive(A, *NormalDestBB); + if (SplitPos == &NormalDestBB->front()) { + // If this is an invoke of a noreturn function the edge to the normal + // destination block is dead but not necessarily the block itself. + // TODO: We need to move to an edge based system during deduction and + // also manifest. + assert(!NormalDestBB->isLandingPad() && + "Expected the normal destination not to be a landingpad!"); + BasicBlock *SplitBB = + SplitBlockPredecessors(NormalDestBB, {BB}, ".dead"); + // The split block is live even if it contains only an unreachable + // instruction at the end. + assumeLive(A, *SplitBB); + SplitPos = SplitBB->getTerminator(); + } } BB = SplitPos->getParent(); Index: llvm/trunk/test/Transforms/FunctionAttrs/liveness.ll =================================================================== --- llvm/trunk/test/Transforms/FunctionAttrs/liveness.ll +++ llvm/trunk/test/Transforms/FunctionAttrs/liveness.ll @@ -177,7 +177,7 @@ %call = invoke i32 @foo_noreturn() to label %continue unwind label %cleanup ; CHECK: %call = invoke i32 @foo_noreturn() - ; CHECK-NEXT: to label %continue unwind label %cleanup + ; CHECK-NEXT: to label %continue.dead unwind label %cleanup cond.false: ; preds = %entry call void @normal_call() @@ -189,7 +189,7 @@ ret i32 %cond continue: - ; CHECK: continue: + ; CHECK: continue.dead: ; CHECK-NEXT: unreachable br label %cond.end @@ -663,3 +663,59 @@ ; CHECK: Function Attrs: nofree nosync nounwind willreturn ; CHECK-NEXT: define internal void @non_dead_d15() ; CHECK-NOT: define internal void @dead_e + + +declare void @blowup() noreturn +define void @live_with_dead_entry() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK: define void @live_with_dead_entry( +; CHECK-NEXT: entry: +; CHECK-NEXT: invoke void @blowup() +; CHECK-NEXT: to label %live_with_dead_entry.dead unwind label %lpad +; CHECK: lpad: ; preds = %entry +; CHECK-NEXT: %0 = landingpad { i8*, i32 } +; CHECK-NEXT: catch i8* null +; CHECK-NEXT: br label %live_with_dead_entry +; CHECK: live_with_dead_entry.dead: ; preds = %entry +; CHECK-NEXT: unreachable +; CHECK: live_with_dead_entry: ; preds = %lpad +; CHECK-NEXT: ret void +entry: + invoke void @blowup() to label %live_with_dead_entry unwind label %lpad +lpad: + %0 = landingpad { i8*, i32 } catch i8* null + br label %live_with_dead_entry +live_with_dead_entry: + ret void +} + +define void @live_with_dead_entry_lp() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK: define void @live_with_dead_entry_lp( +; CHECK-NEXT: entry: +; CHECK-NEXT: invoke void @blowup() +; CHECK-NEXT: to label %live_with_dead_entry.dead unwind label %lp1 +; CHECK: lp1: ; preds = %entry +; CHECK-NEXT: %lp = landingpad { i8*, i32 } +; CHECK-NEXT: catch i8* null +; CHECK-NEXT: invoke void @blowup() +; CHECK-NEXT: to label %live_with_dead_entry.dead1 unwind label %lp2 +; CHECK: lp2: ; preds = %lp1 +; CHECK-NEXT: %0 = landingpad { i8*, i32 } +; CHECK-NEXT: catch i8* null +; CHECK-NEXT: br label %live_with_dead_entry +; CHECK: live_with_dead_entry.dead: ; preds = %entry +; CHECK-NEXT: unreachable +; CHECK: live_with_dead_entry.dead1: ; preds = %lp1 +; CHECK-NEXT: unreachable +; CHECK: live_with_dead_entry: ; preds = %lp2 +; CHECK-NEXT: ret void +entry: + invoke void @blowup() to label %live_with_dead_entry unwind label %lp1 +lp1: + %lp = landingpad { i8*, i32 } catch i8* null + invoke void @blowup() to label %live_with_dead_entry unwind label %lp2 +lp2: + %0 = landingpad { i8*, i32 } catch i8* null + br label %live_with_dead_entry +live_with_dead_entry: + ret void +} Index: llvm/trunk/test/Transforms/FunctionAttrs/noreturn_async.ll =================================================================== --- llvm/trunk/test/Transforms/FunctionAttrs/noreturn_async.ll +++ llvm/trunk/test/Transforms/FunctionAttrs/noreturn_async.ll @@ -42,12 +42,12 @@ %retval = alloca i32, align 4 %__exception_code = alloca i32, align 4 ; CHECK: invoke void @"?overflow@@YAXXZ"() -; CHECK: to label %invoke.cont unwind label %catch.dispatch +; CHECK: to label %invoke.cont.dead unwind label %catch.dispatch invoke void @"?overflow@@YAXXZ"() to label %invoke.cont unwind label %catch.dispatch invoke.cont: ; preds = %entry -; CHECK: invoke.cont: +; CHECK: invoke.cont.dead: ; CHECK-NEXT: unreachable br label %invoke.cont1 @@ -101,12 +101,12 @@ %retval = alloca i32, align 4 %__exception_code = alloca i32, align 4 ; CHECK: invoke void @"?overflow@@YAXXZ_may_throw"() -; CHECK: to label %invoke.cont unwind label %catch.dispatch +; CHECK: to label %invoke.cont.dead unwind label %catch.dispatch invoke void @"?overflow@@YAXXZ_may_throw"() to label %invoke.cont unwind label %catch.dispatch invoke.cont: ; preds = %entry -; CHECK: invoke.cont: +; CHECK: invoke.cont.dead: ; CHECK-NEXT: unreachable br label %invoke.cont1 Index: llvm/trunk/test/Transforms/FunctionAttrs/noreturn_sync.ll =================================================================== --- llvm/trunk/test/Transforms/FunctionAttrs/noreturn_sync.ll +++ llvm/trunk/test/Transforms/FunctionAttrs/noreturn_sync.ll @@ -97,12 +97,12 @@ %retval = alloca i32, align 4 %__exception_code = alloca i32, align 4 ; CHECK: invoke void @"?overflow@@YAXXZ_may_throw"() -; CHECK: to label %invoke.cont unwind label %catch.dispatch +; CHECK: to label %invoke.cont.dead unwind label %catch.dispatch invoke void @"?overflow@@YAXXZ_may_throw"() to label %invoke.cont unwind label %catch.dispatch invoke.cont: ; preds = %entry -; CHECK: invoke.cont: +; CHECK: invoke.cont.dead: ; CHECK-NEXT: unreachable br label %invoke.cont1