Index: llvm/include/llvm/Transforms/IPO/Attributor.h =================================================================== --- llvm/include/llvm/Transforms/IPO/Attributor.h +++ llvm/include/llvm/Transforms/IPO/Attributor.h @@ -2646,6 +2646,13 @@ return F.hasPersonalityFn() && !canSimplifyInvokeNoUnwind(&F); } + /// Return assumed live successors of a given basic block. + /// This is specifically useful in AAReachability. + virtual SetVector + getAssumedLiveOutEdges(Attributor &A, const BasicBlock &BB) const { + return SetVector(succ_begin(&BB), succ_end(&BB)); + } + /// See AbstractAttribute::getName() const std::string getName() const override { return "AAIsDead"; } Index: llvm/lib/Transforms/IPO/AttributorAttributes.cpp =================================================================== --- llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -3094,6 +3094,13 @@ /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override; + /// Returns assumed live successors of a given basic block. + /// Note: Even if there is a branch instruction that jumps to the entry node + /// of the given basic block, the returned set will not contain the + /// given basic block. + SetVector + getAssumedLiveOutEdges(Attributor &A, const BasicBlock &BB) const override; + /// See AbstractAttribute::trackStatistics() void trackStatistics() const override {} @@ -3177,7 +3184,7 @@ static bool identifyAliveSuccessors(Attributor &A, const CallBase &CB, - AbstractAttribute &AA, + const AbstractAttribute &AA, SmallVectorImpl &AliveSuccessors) { const IRPosition &IPos = IRPosition::callsite_function(CB); @@ -3194,7 +3201,7 @@ static bool identifyAliveSuccessors(Attributor &A, const InvokeInst &II, - AbstractAttribute &AA, + const AbstractAttribute &AA, SmallVectorImpl &AliveSuccessors) { bool UsedAssumedInformation = identifyAliveSuccessors(A, cast(II), AA, AliveSuccessors); @@ -3219,7 +3226,7 @@ static bool identifyAliveSuccessors(Attributor &A, const BranchInst &BI, - AbstractAttribute &AA, + const AbstractAttribute &AA, SmallVectorImpl &AliveSuccessors) { bool UsedAssumedInformation = false; if (BI.getNumSuccessors() == 1) { @@ -3244,7 +3251,7 @@ static bool identifyAliveSuccessors(Attributor &A, const SwitchInst &SI, - AbstractAttribute &AA, + const AbstractAttribute &AA, SmallVectorImpl &AliveSuccessors) { bool UsedAssumedInformation = false; Optional CI = @@ -3267,6 +3274,74 @@ return UsedAssumedInformation; } +static bool identifyAliveSuccessorsForInstruction( + Attributor &A, const Instruction &I, const AbstractAttribute &AA, + SmallVectorImpl &AliveSuccessors) { + bool UsedAssumedInformation = false; + switch (I.getOpcode()) { + // TODO: look for (assumed) UB to backwards propagate "deadness". + default: + if (I.isTerminator()) { + for (const BasicBlock *SuccBB : successors(I.getParent())) + AliveSuccessors.push_back(&SuccBB->front()); + } else { + AliveSuccessors.push_back(I.getNextNode()); + } + break; + case Instruction::Call: + UsedAssumedInformation = + identifyAliveSuccessors(A, cast(I), AA, AliveSuccessors); + break; + case Instruction::Invoke: + UsedAssumedInformation = + identifyAliveSuccessors(A, cast(I), AA, AliveSuccessors); + break; + case Instruction::Br: + UsedAssumedInformation = + identifyAliveSuccessors(A, cast(I), AA, AliveSuccessors); + break; + case Instruction::Switch: + UsedAssumedInformation = + identifyAliveSuccessors(A, cast(I), AA, AliveSuccessors); + break; + } + return UsedAssumedInformation; +} + +SetVector +AAIsDeadFunction::getAssumedLiveOutEdges(Attributor &A, + const BasicBlock &BB) const { + // Explore from the entry node of the given basic block. + SmallVector Worklist; + DenseSet ExploredInsts; + SmallVector AliveSuccessors; + SetVector AliveSuccessorBBs; + + Worklist.push_back(&BB.front()); + ExploredInsts.insert(&BB.front()); + + while (!Worklist.empty()) { + const Instruction *I = Worklist.pop_back_val(); + AliveSuccessors.clear(); + identifyAliveSuccessorsForInstruction(A, *I, *this, AliveSuccessors); + + for (const Instruction *AliveSuccessor : AliveSuccessors) { + const BasicBlock *AliveSuccessorBB = AliveSuccessor->getParent(); + // If a successor is outside of the basic block, add it to the assumed + // live successor set. Otherwise, If we have not explore the successor + // yet, add it to the worklist. + if (AliveSuccessorBB != &BB) + AliveSuccessorBBs.insert(AliveSuccessorBB); + else if (!ExploredInsts.count(AliveSuccessor)) { + Worklist.push_back(AliveSuccessor); + ExploredInsts.insert(AliveSuccessor); + } + } + } + + return AliveSuccessorBBs; +} + ChangeStatus AAIsDeadFunction::updateImpl(Attributor &A) { ChangeStatus Change = ChangeStatus::UNCHANGED; @@ -3288,34 +3363,8 @@ AliveSuccessors.clear(); - bool UsedAssumedInformation = false; - switch (I->getOpcode()) { - // TODO: look for (assumed) UB to backwards propagate "deadness". - default: - if (I->isTerminator()) { - for (const BasicBlock *SuccBB : successors(I->getParent())) - AliveSuccessors.push_back(&SuccBB->front()); - } else { - AliveSuccessors.push_back(I->getNextNode()); - } - break; - case Instruction::Call: - UsedAssumedInformation = identifyAliveSuccessors(A, cast(*I), - *this, AliveSuccessors); - break; - case Instruction::Invoke: - UsedAssumedInformation = identifyAliveSuccessors(A, cast(*I), - *this, AliveSuccessors); - break; - case Instruction::Br: - UsedAssumedInformation = identifyAliveSuccessors(A, cast(*I), - *this, AliveSuccessors); - break; - case Instruction::Switch: - UsedAssumedInformation = identifyAliveSuccessors(A, cast(*I), - *this, AliveSuccessors); - break; - } + bool UsedAssumedInformation = + identifyAliveSuccessorsForInstruction(A, *I, *this, AliveSuccessors); if (UsedAssumedInformation) { NewToBeExploredFrom.insert(I);