diff --git a/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp b/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp index 8384d46837a7e..989ccafadb1ad 100644 --- a/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp +++ b/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp @@ -28,68 +28,6 @@ STATISTIC(MayThrowException, "Cannot move across instructions that may throw"); STATISTIC(NotMovedPHINode, "Movement of PHINodes are not supported"); STATISTIC(NotMovedTerminator, "Movement of Terminator are not supported"); -namespace { -/// Represent a control condition. A control condition is a condition of a -/// terminator to decide which successors to execute. The pointer field -/// represents the address of the condition of the terminator. The integer field -/// is a bool, it is true when the basic block is executed when V is true. For -/// example, `br %cond, bb0, bb1` %cond is a control condition of bb0 with the -/// integer field equals to true, while %cond is a control condition of bb1 with -/// the integer field equals to false. -using ControlCondition = PointerIntPair; -#ifndef NDEBUG -raw_ostream &operator<<(raw_ostream &OS, const ControlCondition &C) { - OS << "[" << *C.getPointer() << ", " << (C.getInt() ? "true" : "false") - << "]"; - return OS; -} -#endif - -/// Represent a set of control conditions required to execute ToBB from FromBB. -class ControlConditions { - using ConditionVectorTy = SmallVector; - - /// A SmallVector of control conditions. - ConditionVectorTy Conditions; - -public: - /// Return a ControlConditions which stores all conditions required to execute - /// \p BB from \p Dominator. If \p MaxLookup is non-zero, it limits the - /// number of conditions to collect. Return std::nullopt if not all conditions - /// are collected successfully, or we hit the limit. - static const std::optional - collectControlConditions(const BasicBlock &BB, const BasicBlock &Dominator, - const DominatorTree &DT, - const PostDominatorTree &PDT, - unsigned MaxLookup = 6); - - /// Return true if there exists no control conditions required to execute ToBB - /// from FromBB. - bool isUnconditional() const { return Conditions.empty(); } - - /// Return a constant reference of Conditions. - const ConditionVectorTy &getControlConditions() const { return Conditions; } - - /// Add \p V as one of the ControlCondition in Condition with IsTrueCondition - /// equals to \p True. Return true if inserted successfully. - bool addControlCondition(ControlCondition C); - - /// Return true if for all control conditions in Conditions, there exists an - /// equivalent control condition in \p Other.Conditions. - bool isEquivalent(const ControlConditions &Other) const; - - /// Return true if \p C1 and \p C2 are equivalent. - static bool isEquivalent(const ControlCondition &C1, - const ControlCondition &C2); - -private: - ControlConditions() = default; - - static bool isEquivalent(const Value &V1, const Value &V2); - static bool isInverse(const Value &V1, const Value &V2); -}; -} // namespace - static bool domTreeLevelBefore(DominatorTree *DT, const Instruction *InstA, const Instruction *InstB) { // Use ordered basic block in case the 2 instructions are in the same @@ -102,130 +40,6 @@ static bool domTreeLevelBefore(DominatorTree *DT, const Instruction *InstA, return DA->getLevel() < DB->getLevel(); } -const std::optional -ControlConditions::collectControlConditions(const BasicBlock &BB, - const BasicBlock &Dominator, - const DominatorTree &DT, - const PostDominatorTree &PDT, - unsigned MaxLookup) { - assert(DT.dominates(&Dominator, &BB) && "Expecting Dominator to dominate BB"); - - ControlConditions Conditions; - unsigned NumConditions = 0; - - // BB is executed unconditional from itself. - if (&Dominator == &BB) - return Conditions; - - const BasicBlock *CurBlock = &BB; - // Walk up the dominator tree from the associated DT node for BB to the - // associated DT node for Dominator. - do { - assert(DT.getNode(CurBlock) && "Expecting a valid DT node for CurBlock"); - BasicBlock *IDom = DT.getNode(CurBlock)->getIDom()->getBlock(); - assert(DT.dominates(&Dominator, IDom) && - "Expecting Dominator to dominate IDom"); - - // Limitation: can only handle branch instruction currently. - const BranchInst *BI = dyn_cast(IDom->getTerminator()); - if (!BI) - return std::nullopt; - - bool Inserted = false; - if (PDT.dominates(CurBlock, IDom)) { - LLVM_DEBUG(dbgs() << CurBlock->getName() - << " is executed unconditionally from " - << IDom->getName() << "\n"); - } else if (PDT.dominates(CurBlock, BI->getSuccessor(0))) { - LLVM_DEBUG(dbgs() << CurBlock->getName() << " is executed when \"" - << *BI->getCondition() << "\" is true from " - << IDom->getName() << "\n"); - Inserted = Conditions.addControlCondition( - ControlCondition(BI->getCondition(), true)); - } else if (PDT.dominates(CurBlock, BI->getSuccessor(1))) { - LLVM_DEBUG(dbgs() << CurBlock->getName() << " is executed when \"" - << *BI->getCondition() << "\" is false from " - << IDom->getName() << "\n"); - Inserted = Conditions.addControlCondition( - ControlCondition(BI->getCondition(), false)); - } else - return std::nullopt; - - if (Inserted) - ++NumConditions; - - if (MaxLookup != 0 && NumConditions > MaxLookup) - return std::nullopt; - - CurBlock = IDom; - } while (CurBlock != &Dominator); - - return Conditions; -} - -bool ControlConditions::addControlCondition(ControlCondition C) { - bool Inserted = false; - if (none_of(Conditions, [&](ControlCondition &Exists) { - return ControlConditions::isEquivalent(C, Exists); - })) { - Conditions.push_back(C); - Inserted = true; - } - - LLVM_DEBUG(dbgs() << (Inserted ? "Inserted " : "Not inserted ") << C << "\n"); - return Inserted; -} - -bool ControlConditions::isEquivalent(const ControlConditions &Other) const { - if (Conditions.empty() && Other.Conditions.empty()) - return true; - - if (Conditions.size() != Other.Conditions.size()) - return false; - - return all_of(Conditions, [&](const ControlCondition &C) { - return any_of(Other.Conditions, [&](const ControlCondition &OtherC) { - return ControlConditions::isEquivalent(C, OtherC); - }); - }); -} - -bool ControlConditions::isEquivalent(const ControlCondition &C1, - const ControlCondition &C2) { - if (C1.getInt() == C2.getInt()) { - if (isEquivalent(*C1.getPointer(), *C2.getPointer())) - return true; - } else if (isInverse(*C1.getPointer(), *C2.getPointer())) - return true; - - return false; -} - -// FIXME: Use SCEV and reuse GVN/CSE logic to check for equivalence between -// Values. -// Currently, isEquivalent rely on other passes to ensure equivalent conditions -// have the same value, e.g. GVN. -bool ControlConditions::isEquivalent(const Value &V1, const Value &V2) { - return &V1 == &V2; -} - -bool ControlConditions::isInverse(const Value &V1, const Value &V2) { - if (const CmpInst *Cmp1 = dyn_cast(&V1)) - if (const CmpInst *Cmp2 = dyn_cast(&V2)) { - if (Cmp1->getPredicate() == Cmp2->getInversePredicate() && - Cmp1->getOperand(0) == Cmp2->getOperand(0) && - Cmp1->getOperand(1) == Cmp2->getOperand(1)) - return true; - - if (Cmp1->getPredicate() == - CmpInst::getSwappedPredicate(Cmp2->getInversePredicate()) && - Cmp1->getOperand(0) == Cmp2->getOperand(1) && - Cmp1->getOperand(1) == Cmp2->getOperand(0)) - return true; - } - return false; -} - static bool reportInvalidCandidate(const Instruction &I, llvm::Statistic &Stat) { ++Stat;