Index: include/llvm/Analysis/CFG.h =================================================================== --- include/llvm/Analysis/CFG.h +++ include/llvm/Analysis/CFG.h @@ -89,6 +89,51 @@ BasicBlock *StopBB, const DominatorTree *DT = nullptr, const LoopInfo *LI = nullptr); + +/// \brief Return true if the control flow in \p RPOTraversal is irreducible. +/// +/// This is a generic implementation to detect irreducible control flow by using +/// reducible loop backedges in \p LI. It can be used for any kind of CFG (Loop, +/// MachineLoop, Function, MachineFunction, etc.) by providing a reverse +/// post-order traversal and the loop analysis information for it. +/// Requirements: +/// 1) GraphTraits must be implemented for NodeT type. It is used to access +/// NodeT successors. +// 2) \p RPOTraversal must be a valid reverse post-order traversal of the +/// target CFG with begin()/end() iterator interfaces. +/// 3) \p LI must be a valid LoopInfoBase that contains up-to-date loop +/// analysis information of the CFG. +template > +bool containsIrreducibleCFG(RPOTraversalT &RPOTraversal, const LoopInfoT &LI) { + /// Check whether the edge (\p Src, \p Dst) is a reducible loop backedge + /// according to LI. I.e., check if there exists a loop that contains Src and + /// where Dst is the loop header. + auto isProperBackedge = [&](NodeT Src, NodeT Dst) { + for (const auto *Lp = LI.getLoopFor(Src); Lp; Lp = Lp->getParentLoop()) { + if (Lp->getHeader() == Dst) + return true; + } + return false; + }; + + SmallPtrSet Visited; + for (NodeT Node : RPOTraversal) { + Visited.insert(Node); + for (NodeT Succ : make_range(GT::child_begin(Node), GT::child_end(Node))) { + // Succ hasn't been visited yet + if (!Visited.count(Succ)) + continue; + // We already visited Succ, thus Node->Succ must be a backedge. Check that + // the head matches what we have in the loop information. Otherwise, we + // have an irreducible graph. + if (!isProperBackedge(Node, Succ)) + return true; + } + } + + return false; +} } // End llvm namespace #endif Index: include/llvm/Analysis/LoopIterator.h =================================================================== --- include/llvm/Analysis/LoopIterator.h +++ include/llvm/Analysis/LoopIterator.h @@ -168,6 +168,25 @@ } }; +/// Wrapper class to LoopBlocksDFS that provides a standard begin()/end() +/// interface for the DFS reverse post-order traversal of blocks in a loop body. +class LoopBlocksRPO { +private: + LoopBlocksDFS DFS; + +public: + LoopBlocksRPO(Loop *Container) : DFS(Container) {} + + /// Traverse the loop blocks and store the DFS result. + void perform(LoopInfo *LI) { + DFS.perform(LI); + } + + /// Reverse iterate over the cached postorder blocks. + LoopBlocksDFS::RPOIterator begin() const { return DFS.beginRPO(); } + LoopBlocksDFS::RPOIterator end() const { return DFS.endRPO(); } +}; + /// Specialize po_iterator_storage to record postorder numbers. template<> class po_iterator_storage { LoopBlocksTraversal &LBT; Index: lib/Transforms/Vectorize/LoopVectorize.cpp =================================================================== --- lib/Transforms/Vectorize/LoopVectorize.cpp +++ lib/Transforms/Vectorize/LoopVectorize.cpp @@ -69,6 +69,7 @@ #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Analysis/CFG.h" #include "llvm/Analysis/CodeMetrics.h" #include "llvm/Analysis/DemandedBits.h" #include "llvm/Analysis/GlobalsModRef.h" @@ -283,24 +284,6 @@ } // end anonymous namespace -/// Returns true if the given loop body has a cycle, excluding the loop -/// itself. -static bool hasCyclesInLoopBody(const Loop &L) { - if (!L.empty()) - return true; - - for (const auto &SCC : - make_range(scc_iterator::begin(L), - scc_iterator::end(L))) { - if (SCC.size() > 1) { - DEBUG(dbgs() << "LVL: Detected a cycle in the loop body:\n"); - DEBUG(L.dump()); - return true; - } - } - return false; -} - /// A helper function for converting Scalar types to vector types. /// If the incoming type is void, we return void. If the VF is 1, we return /// the scalar type. @@ -2291,14 +2274,17 @@ } // end anonymous namespace -static void addAcyclicInnerLoop(Loop &L, SmallVectorImpl &V) { +static void addAcyclicInnerLoop(Loop &L, LoopInfo &LI, + SmallVectorImpl &V) { if (L.empty()) { - if (!hasCyclesInLoopBody(L)) + LoopBlocksRPO RPOT(&L); + RPOT.perform(&LI); + if (!containsIrreducibleCFG(RPOT, LI)) V.push_back(&L); return; } for (Loop *InnerL : L) - addAcyclicInnerLoop(*InnerL, V); + addAcyclicInnerLoop(*InnerL, LI, V); } namespace { @@ -8578,7 +8564,7 @@ SmallVector Worklist; for (Loop *L : *LI) - addAcyclicInnerLoop(*L, Worklist); + addAcyclicInnerLoop(*L, *LI, Worklist); LoopsAnalyzed += Worklist.size();