diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp index fa0ea7e0ff14..448a2d4b6c1e 100644 --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -2338,7 +2338,8 @@ struct AAIsDeadFunction : public AAIsDead { continue; const auto &NoReturnAA = A.getAAFor(*this, IRPosition::callsite_function(*CB)); - if (!NoReturnAA.isAssumedNoReturn()) + bool MayReturn = !NoReturnAA.isAssumedNoReturn(); + if (MayReturn && (!Invoke2CallAllowed || !isa(CB))) continue; Instruction *I = const_cast(DeadEndI); BasicBlock *BB = I->getParent(); @@ -2361,6 +2362,26 @@ struct AAIsDeadFunction : public AAIsDead { if (AANoUnw.isAssumedNoUnwind()) { LLVM_DEBUG(dbgs() << "[AAIsDead] Replace invoke with call inst\n"); + CallInst *CI = createCallMatchingInvoke(II); + CI->insertBefore(II); + CI->takeName(II); + II->replaceAllUsesWith(CI); + + // If this is a nounwind + mayreturn invoke we only remove the unwind edge. + // This is done by moving the invoke into a new and dead block and connecting + // the normal destination of the invoke with a branch that follows the call + // replacement we created above. + if (MayReturn) { + BasicBlock *NewDeadBB = SplitBlock(BB, II, nullptr, nullptr, nullptr, ".i2c"); + assert(isa(BB->getTerminator()) && + BB->getTerminator()->getNumSuccessors() == 1 && + BB->getTerminator()->getSuccessor(0) == NewDeadBB); + new UnreachableInst(I->getContext(), NewDeadBB); + BB->getTerminator()->setOperand(0, NormalDestBB); + A.deleteAfterManifest(*II); + continue; + } + // We do not need an invoke (II) but instead want a call followed // by an unreachable. However, we do not remove II as other // abstract attributes might have it cached as part of their @@ -2370,10 +2391,6 @@ struct AAIsDeadFunction : public AAIsDead { // only reached from the current block of II and then not reached // at all when we insert the unreachable. SplitBlockPredecessors(NormalDestBB, {BB}, ".i2c"); - CallInst *CI = createCallMatchingInvoke(II); - CI->insertBefore(II); - CI->takeName(II); - II->replaceAllUsesWith(CI); SplitPos = CI->getNextNode(); } } diff --git a/llvm/test/Transforms/FunctionAttrs/liveness.ll b/llvm/test/Transforms/FunctionAttrs/liveness.ll index e16677dc158f..eef674b53eca 100644 --- a/llvm/test/Transforms/FunctionAttrs/liveness.ll +++ b/llvm/test/Transforms/FunctionAttrs/liveness.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes ; RUN: opt -attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s ; UTC_ARGS: --turn off @@ -8,6 +8,8 @@ declare void @normal_call() readnone declare i32 @foo() +declare i32 @foo_nounwind() nounwind + declare i32 @foo_noreturn_nounwind() noreturn nounwind declare i32 @foo_noreturn() noreturn @@ -162,7 +164,7 @@ cond.end: ; preds = %cond.false, %cond.t ret i32 %cond } -; TEST 5 noreturn invoke instruction with a unreachable normal successor block. +; TEST 5.1 noreturn invoke instruction with a unreachable normal successor block. ; CHECK: define i32 @invoke_noreturn(i32 %a) define i32 @invoke_noreturn(i32 %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { @@ -197,7 +199,7 @@ cleanup: ret i32 0 } -; TEST 4.1 noreturn invoke instruction replaced by a call and an unreachable instruction +; TEST 5.2 noreturn invoke instruction replaced by a call and an unreachable instruction ; put after it. ; CHECK: define i32 @invoke_noreturn_nounwind(i32 %a) @@ -234,6 +236,45 @@ cleanup: ret i32 0 } +; TEST 5.3 unounwind invoke instruction replaced by a call and a branch instruction put after it. +define i32 @invoke_nounwind(i32 %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK-LABEL: define {{[^@]+}}@invoke_nounwind +; CHECK: cond.true: +; CHECK-NEXT: call void @normal_call() +; CHECK-NEXT: [[CALL:%.*]] = call i32 @foo_nounwind() +; CHECK-NEXT: br label [[CONTINUE:%.*]] +; CHECK: continue: +; CHECK-NEXT: br label [[COND_END:%.*]] +; +entry: + %cmp = icmp eq i32 %a, 0 + br i1 %cmp, label %cond.true, label %cond.false + +cond.true: ; preds = %entry + call void @normal_call() + %call = invoke i32 @foo_nounwind() to label %continue + unwind label %cleanup + +cond.false: ; preds = %entry + call void @normal_call() + %call1 = call i32 @bar() + br label %cond.end + +cond.end: ; preds = %cond.false, %continue + %cond = phi i32 [ %call, %continue ], [ %call1, %cond.false ] + ret i32 %cond + +continue: + br label %cond.end + +cleanup: + %res = landingpad { i8*, i32 } + catch i8* null + ret i32 0 +} + +; UTC_ARGS: --turn off + ; TEST 6: Undefined behvior, taken from LangRef. ; FIXME: Should be able to detect undefined behavior.