From: Johannes Doerfert Date: Mon, 5 Aug 2019 21:35:02 +0000 (+0000) Subject: [Attributor][Fix] Do not remove instructions during manifestation X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b30047122635d84cf90fe478d53c29ad5824c6b3;p=llvm [Attributor][Fix] Do not remove instructions during manifestation When we remove instructions cached references could still be live. This patch avoids removing invoke instructions that are replaced by calls and instead keeps them around but in a dead block. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@367933 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Transforms/Utils/Local.h b/include/llvm/Transforms/Utils/Local.h index ee8df756d72..5c5e0aef34c 100644 --- a/include/llvm/Transforms/Utils/Local.h +++ b/include/llvm/Transforms/Utils/Local.h @@ -271,6 +271,12 @@ inline unsigned getKnownAlignment(Value *V, const DataLayout &DL, return getOrEnforceKnownAlignment(V, 0, DL, CxtI, AC, DT); } +/// Create a call that matches the invoke \p II in terms of arguments, +/// attributes, debug information, etc. The call is not placed in a block and it +/// will not have a name. The invoke instruction is not removed, nor are the +/// uses replaced by the new call. +CallInst *createCallMatchingInvoke(InvokeInst *II); + /// This function converts the specified invoek into a normall call. void changeToCall(InvokeInst *II, DomTreeUpdater *DTU = nullptr); diff --git a/lib/Transforms/IPO/Attributor.cpp b/lib/Transforms/IPO/Attributor.cpp index 1ae8ac77de0..3ecad8b03eb 100644 --- a/lib/Transforms/IPO/Attributor.cpp +++ b/lib/Transforms/IPO/Attributor.cpp @@ -1577,6 +1577,11 @@ struct AAIsDeadFunction : AAIsDead, BooleanState { Instruction *SplitPos = I->getNextNode(); if (auto *II = dyn_cast(I)) { + // If we keep the invoke the split position is at the beginning of the + // normal desitination block (it invokes a noreturn function after all). + BasicBlock *NormalDestBB = II->getNormalDest(); + SplitPos = &NormalDestBB->front(); + /// Invoke is replaced with a call and unreachable is placed after it if /// the callee is nounwind and noreturn. Otherwise, we keep the invoke /// and only place an unreachable in the normal successor. @@ -1587,17 +1592,26 @@ struct AAIsDeadFunction : AAIsDead, BooleanState { (AANoUnw && AANoUnw->isAssumedNoUnwind())) { LLVM_DEBUG(dbgs() << "[AAIsDead] Replace invoke with call inst\n"); - changeToCall(II); - changeToUnreachable(BB->getTerminator(), /* UseLLVMTrap */ false); - 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 + // results. Given that we modify the CFG anyway, we simply keep II + // around but in a new dead block. To avoid II being live through + // a different edge we have to ensure the block we place it in is + // 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(); } } } - - BB = II->getNormalDest(); - SplitPos = &BB->front(); } + BB = SplitPos->getParent(); SplitBlock(BB, SplitPos); changeToUnreachable(BB->getTerminator(), /* UseLLVMTrap */ false); HasChanged = ChangeStatus::CHANGED; diff --git a/lib/Transforms/Utils/Local.cpp b/lib/Transforms/Utils/Local.cpp index 68443c15a78..a1d1b3ec84f 100644 --- a/lib/Transforms/Utils/Local.cpp +++ b/lib/Transforms/Utils/Local.cpp @@ -1933,18 +1933,24 @@ unsigned llvm::changeToUnreachable(Instruction *I, bool UseLLVMTrap, return NumInstrsRemoved; } -/// changeToCall - Convert the specified invoke into a normal call. -void llvm::changeToCall(InvokeInst *II, DomTreeUpdater *DTU) { - SmallVector Args(II->arg_begin(), II->arg_end()); +CallInst *llvm::createCallMatchingInvoke(InvokeInst *II) { + SmallVector Args(II->arg_begin(), II->arg_end()); SmallVector OpBundles; II->getOperandBundlesAsDefs(OpBundles); - CallInst *NewCall = CallInst::Create( - II->getFunctionType(), II->getCalledValue(), Args, OpBundles, "", II); - NewCall->takeName(II); + CallInst *NewCall = CallInst::Create(II->getFunctionType(), + II->getCalledValue(), Args, OpBundles); NewCall->setCallingConv(II->getCallingConv()); NewCall->setAttributes(II->getAttributes()); NewCall->setDebugLoc(II->getDebugLoc()); NewCall->copyMetadata(*II); + return NewCall; +} + +/// changeToCall - Convert the specified invoke into a normal call. +void llvm::changeToCall(InvokeInst *II, DomTreeUpdater *DTU) { + CallInst *NewCall = createCallMatchingInvoke(II); + NewCall->takeName(II); + NewCall->insertBefore(II); II->replaceAllUsesWith(NewCall); // Follow the call by a branch to the normal destination. diff --git a/test/Transforms/FunctionAttrs/liveness.ll b/test/Transforms/FunctionAttrs/liveness.ll index cbf5631e6eb..166b15441e4 100644 --- a/test/Transforms/FunctionAttrs/liveness.ll +++ b/test/Transforms/FunctionAttrs/liveness.ll @@ -184,9 +184,14 @@ cond.true: ; preds = %entry call void @normal_call() %call = invoke i32 @foo_noreturn_nounwind() to label %continue unwind label %cleanup - ; CHECK: call i32 @foo_noreturn_nounwind() + ; CHECK: call void @normal_call() + ; CHECK-NEXT: call i32 @foo_noreturn_nounwind() ; CHECK-NEXT: unreachable + ; We keep the invoke around as other attributes might have references to it. + ; CHECK: cond.true.split: ; No predecessors! + ; CHECK-NEXT: invoke i32 @foo_noreturn_nounwind() + cond.false: ; preds = %entry call void @normal_call() %call1 = call i32 @bar()