| //===- LoopInterchange.cpp - Loop interchange pass-------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This Pass handles loop interchange transform. |
| // This pass interchanges loops to provide a more cache-friendly memory access |
| // patterns. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/Transforms/Scalar/LoopInterchange.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/SmallSet.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/Statistic.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/Analysis/DependenceAnalysis.h" |
| #include "llvm/Analysis/LoopCacheAnalysis.h" |
| #include "llvm/Analysis/LoopInfo.h" |
| #include "llvm/Analysis/LoopNestAnalysis.h" |
| #include "llvm/Analysis/LoopPass.h" |
| #include "llvm/Analysis/OptimizationRemarkEmitter.h" |
| #include "llvm/Analysis/ScalarEvolution.h" |
| #include "llvm/Analysis/ScalarEvolutionExpressions.h" |
| #include "llvm/IR/BasicBlock.h" |
| #include "llvm/IR/DiagnosticInfo.h" |
| #include "llvm/IR/Dominators.h" |
| #include "llvm/IR/Function.h" |
| #include "llvm/IR/IRBuilder.h" |
| #include "llvm/IR/InstrTypes.h" |
| #include "llvm/IR/Instruction.h" |
| #include "llvm/IR/Instructions.h" |
| #include "llvm/IR/User.h" |
| #include "llvm/IR/Value.h" |
| #include "llvm/Support/Casting.h" |
| #include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/Debug.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include "llvm/Transforms/Scalar/LoopPassManager.h" |
| #include "llvm/Transforms/Utils/BasicBlockUtils.h" |
| #include "llvm/Transforms/Utils/Local.h" |
| #include "llvm/Transforms/Utils/LoopUtils.h" |
| #include <cassert> |
| #include <utility> |
| #include <vector> |
| |
| using namespace llvm; |
| |
| #define DEBUG_TYPE "loop-interchange" |
| |
| STATISTIC(LoopsInterchanged, "Number of loops interchanged"); |
| |
| static cl::opt<int> LoopInterchangeCostThreshold( |
| "loop-interchange-threshold", cl::init(0), cl::Hidden, |
| cl::desc("Interchange if you gain more than this number")); |
| |
| static cl::opt<unsigned int> MaxMemInstrRatio( |
| "loop-interchange-max-mem-instr-ratio", cl::init(4), cl::Hidden, |
| cl::desc("Maximum number of load/store instructions squared in relation to " |
| "the total number of instructions. Higher value may lead to more " |
| "interchanges at the cost of compile-time")); |
| |
| namespace { |
| |
| using LoopVector = SmallVector<Loop *, 8>; |
| |
| /// A list of direction vectors. Each entry represents a direction vector |
| /// corresponding to one or more dependencies existing in the loop nest. The |
| /// length of all direction vectors is equal and is N + 1, where N is the depth |
| /// of the loop nest. The first N elements correspond to the dependency |
| /// direction of each N loops. The last one indicates whether this entry is |
| /// forward dependency ('<') or not ('*'). The term "forward" aligns with what |
| /// is defined in LoopAccessAnalysis. |
| // TODO: Check if we can use a sparse matrix here. |
| using CharMatrix = std::vector<std::vector<char>>; |
| |
| /// Types of rules used in profitability check. |
| enum class RuleTy { |
| PerLoopCacheAnalysis, |
| PerInstrOrderCost, |
| ForVectorization, |
| Ignore |
| }; |
| |
| } // end anonymous namespace |
| |
| // Minimum loop depth supported. |
| static cl::opt<unsigned int> MinLoopNestDepth( |
| "loop-interchange-min-loop-nest-depth", cl::init(2), cl::Hidden, |
| cl::desc("Minimum depth of loop nest considered for the transform")); |
| |
| // Maximum loop depth supported. |
| static cl::opt<unsigned int> MaxLoopNestDepth( |
| "loop-interchange-max-loop-nest-depth", cl::init(10), cl::Hidden, |
| cl::desc("Maximum depth of loop nest considered for the transform")); |
| |
| // We prefer cache cost to vectorization by default. |
| static cl::list<RuleTy> Profitabilities( |
| "loop-interchange-profitabilities", cl::MiscFlags::CommaSeparated, |
| cl::Hidden, |
| cl::desc("List of profitability heuristics to be used. They are applied in " |
| "the given order"), |
| cl::list_init<RuleTy>({RuleTy::PerInstrOrderCost, |
| RuleTy::ForVectorization}), |
| cl::values(clEnumValN(RuleTy::PerLoopCacheAnalysis, "cache", |
| "Prioritize loop cache cost"), |
| clEnumValN(RuleTy::PerInstrOrderCost, "instorder", |
| "Prioritize the IVs order of each instruction"), |
| clEnumValN(RuleTy::ForVectorization, "vectorize", |
| "Prioritize vectorization"), |
| clEnumValN(RuleTy::Ignore, "ignore", |
| "Ignore profitability, force interchange (does not " |
| "work with other options)"))); |
| |
| // Support for the inner-loop reduction pattern. |
| static cl::opt<bool> EnableReduction2Memory( |
| "loop-interchange-reduction-to-mem", cl::init(false), cl::Hidden, |
| cl::desc("Support for the inner-loop reduction pattern.")); |
| |
| #ifndef NDEBUG |
| static bool noDuplicateRulesAndIgnore(ArrayRef<RuleTy> Rules) { |
| SmallSet<RuleTy, 4> Set; |
| for (RuleTy Rule : Rules) { |
| if (!Set.insert(Rule).second) |
| return false; |
| if (Rule == RuleTy::Ignore) |
| return false; |
| } |
| return true; |
| } |
| |
| static void printDepMatrix(CharMatrix &DepMatrix) { |
| for (auto &Row : DepMatrix) { |
| // Drop the last element because it is a flag indicating whether this is |
| // forward dependency or not, which doesn't affect the legality check. |
| for (char D : drop_end(Row)) |
| LLVM_DEBUG(dbgs() << D << " "); |
| LLVM_DEBUG(dbgs() << "\n"); |
| } |
| } |
| |
| /// Return true if \p Src appears before \p Dst in the same basic block. |
| /// Precondition: \p Src and \Dst are distinct instructions within the same |
| /// basic block. |
| static bool inThisOrder(const Instruction *Src, const Instruction *Dst) { |
| assert(Src->getParent() == Dst->getParent() && Src != Dst && |
| "Expected Src and Dst to be different instructions in the same BB"); |
| |
| bool FoundSrc = false; |
| for (const Instruction &I : *(Src->getParent())) { |
| if (&I == Src) { |
| FoundSrc = true; |
| continue; |
| } |
| if (&I == Dst) |
| return FoundSrc; |
| } |
| |
| llvm_unreachable("Dst not found"); |
| } |
| #endif |
| |
| static bool populateDependencyMatrix(CharMatrix &DepMatrix, unsigned Level, |
| Loop *L, DependenceInfo *DI, |
| ScalarEvolution *SE, |
| OptimizationRemarkEmitter *ORE) { |
| using ValueVector = SmallVector<Value *, 16>; |
| |
| ValueVector MemInstr; |
| unsigned NumInsts = 0; |
| |
| // For each block. |
| for (BasicBlock *BB : L->blocks()) { |
| // Scan the BB and collect legal loads and stores. |
| for (Instruction &I : *BB) { |
| NumInsts++; |
| if (auto *Ld = dyn_cast<LoadInst>(&I)) { |
| if (!Ld->isSimple()) |
| return false; |
| MemInstr.push_back(&I); |
| } else if (auto *St = dyn_cast<StoreInst>(&I)) { |
| if (!St->isSimple()) |
| return false; |
| MemInstr.push_back(&I); |
| } |
| } |
| } |
| |
| // To populate the dependence matrix, we perform dependence test for each pair |
| // of memory instructions, which has O(NumMemInstr^2) complexity. This implies |
| // that even if the number of memory instructions is small, the analysis can |
| // still be expensive if the most of the instructions in the loop are memory |
| // instructions. On the other hand, if the number of memory instructions is |
| // not small, but the loop is large (i.e., it contains many non-memory |
| // instructions), the analysis can still be affordable. |
| unsigned NumMemInstr = MemInstr.size(); |
| LLVM_DEBUG(dbgs() << "Found " << NumMemInstr |
| << " Loads and Stores to analyze\n"); |
| if (MaxMemInstrRatio * NumInsts < NumMemInstr * NumMemInstr) { |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedLoop", |
| L->getStartLoc(), L->getHeader()) |
| << "Number of loads/stores exceeded, the supported maximum can be " |
| "increased with option -loop-interchange-max-mem-instr-ratio."; |
| }); |
| return false; |
| } |
| ValueVector::iterator I, IE, J, JE; |
| |
| // Manage direction vectors that are already seen. Map each direction vector |
| // to an index of DepMatrix at which it is stored. |
| StringMap<unsigned> Seen; |
| |
| for (I = MemInstr.begin(), IE = MemInstr.end(); I != IE; ++I) { |
| for (J = I, JE = MemInstr.end(); J != JE; ++J) { |
| std::vector<char> Dep; |
| Instruction *Src = cast<Instruction>(*I); |
| Instruction *Dst = cast<Instruction>(*J); |
| // Ignore Input dependencies. |
| if (isa<LoadInst>(Src) && isa<LoadInst>(Dst)) |
| continue; |
| // Track Output, Flow, and Anti dependencies. |
| if (auto D = DI->depends(Src, Dst)) { |
| assert(D->isOrdered() && "Expected an output, flow or anti dep."); |
| // If the direction vector is negative, normalize it to |
| // make it non-negative. |
| if (D->normalize(SE)) |
| LLVM_DEBUG(dbgs() << "Negative dependence vector normalized.\n"); |
| LLVM_DEBUG(StringRef DepType = |
| D->isFlow() ? "flow" : D->isAnti() ? "anti" : "output"; |
| dbgs() << "Found " << DepType |
| << " dependency between Src and Dst\n" |
| << " Src:" << *Src << "\n Dst:" << *Dst << '\n'); |
| unsigned Levels = D->getLevels(); |
| char Direction; |
| for (unsigned II = 1; II <= Levels; ++II) { |
| // `DVEntry::LE` is converted to `*`. This is because `LE` means `<` |
| // or `=`, for which we don't have an equivalent representation, so |
| // that the conservative approximation is necessary. The same goes for |
| // `DVEntry::GE`. |
| // TODO: Use of fine-grained expressions allows for more accurate |
| // analysis. |
| unsigned Dir = D->getDirection(II); |
| if (Dir == Dependence::DVEntry::LT) |
| Direction = '<'; |
| else if (Dir == Dependence::DVEntry::GT) |
| Direction = '>'; |
| else if (Dir == Dependence::DVEntry::EQ) |
| Direction = '='; |
| else |
| Direction = '*'; |
| Dep.push_back(Direction); |
| } |
| |
| // If the Dependence object doesn't have any information, fill the |
| // dependency vector with '*'. |
| if (D->isConfused()) { |
| assert(Dep.empty() && "Expected empty dependency vector"); |
| Dep.assign(Level, '*'); |
| } |
| |
| while (Dep.size() != Level) { |
| Dep.push_back('I'); |
| } |
| |
| // If all the elements of any direction vector have only '*', legality |
| // can't be proven. Exit early to save compile time. |
| if (all_of(Dep, equal_to('*'))) { |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "Dependence", |
| L->getStartLoc(), L->getHeader()) |
| << "All loops have dependencies in all directions."; |
| }); |
| return false; |
| } |
| |
| // Test whether the dependency is forward or not. |
| bool IsKnownForward = true; |
| if (Src->getParent() != Dst->getParent()) { |
| // In general, when Src and Dst are in different BBs, the execution |
| // order of them within a single iteration is not guaranteed. Treat |
| // conservatively as not-forward dependency in this case. |
| IsKnownForward = false; |
| } else { |
| // Src and Dst are in the same BB. If they are the different |
| // instructions, Src should appear before Dst in the BB as they are |
| // stored to MemInstr in that order. |
| assert((Src == Dst || inThisOrder(Src, Dst)) && |
| "Unexpected instructions"); |
| |
| // If the Dependence object is reversed (due to normalization), it |
| // represents the dependency from Dst to Src, meaning it is a backward |
| // dependency. Otherwise it should be a forward dependency. |
| bool IsReversed = D->getSrc() != Src; |
| if (IsReversed) |
| IsKnownForward = false; |
| } |
| |
| // Initialize the last element. Assume forward dependencies only; it |
| // will be updated later if there is any non-forward dependency. |
| Dep.push_back('<'); |
| |
| // The last element should express the "summary" among one or more |
| // direction vectors whose first N elements are the same (where N is |
| // the depth of the loop nest). Hence we exclude the last element from |
| // the Seen map. |
| auto [Ite, Inserted] = Seen.try_emplace( |
| StringRef(Dep.data(), Dep.size() - 1), DepMatrix.size()); |
| |
| // Make sure we only add unique entries to the dependency matrix. |
| if (Inserted) |
| DepMatrix.push_back(Dep); |
| |
| // If we cannot prove that this dependency is forward, change the last |
| // element of the corresponding entry. Since a `[... *]` dependency |
| // includes a `[... <]` dependency, we do not need to keep both and |
| // change the existing entry instead. |
| if (!IsKnownForward) |
| DepMatrix[Ite->second].back() = '*'; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| // A loop is moved from index 'from' to an index 'to'. Update the Dependence |
| // matrix by exchanging the two columns. |
| static void interChangeDependencies(CharMatrix &DepMatrix, unsigned FromIndx, |
| unsigned ToIndx) { |
| for (auto &Row : DepMatrix) |
| std::swap(Row[ToIndx], Row[FromIndx]); |
| } |
| |
| // Check if a direction vector is lexicographically positive. Return true if it |
| // is positive, nullopt if it is "zero", otherwise false. |
| // [Theorem] A permutation of the loops in a perfect nest is legal if and only |
| // if the direction matrix, after the same permutation is applied to its |
| // columns, has no ">" direction as the leftmost non-"=" direction in any row. |
| static std::optional<bool> |
| isLexicographicallyPositive(ArrayRef<char> DV, unsigned Begin, unsigned End) { |
| for (unsigned char Direction : DV.slice(Begin, End - Begin)) { |
| if (Direction == '<') |
| return true; |
| if (Direction == '>' || Direction == '*') |
| return false; |
| } |
| return std::nullopt; |
| } |
| |
| // Checks if it is legal to interchange 2 loops. |
| static bool isLegalToInterChangeLoops(CharMatrix &DepMatrix, |
| unsigned InnerLoopId, |
| unsigned OuterLoopId) { |
| unsigned NumRows = DepMatrix.size(); |
| std::vector<char> Cur; |
| // For each row check if it is valid to interchange. |
| for (unsigned Row = 0; Row < NumRows; ++Row) { |
| // Create temporary DepVector check its lexicographical order |
| // before and after swapping OuterLoop vs InnerLoop |
| Cur = DepMatrix[Row]; |
| |
| // If the surrounding loops already ensure that the direction vector is |
| // lexicographically positive, nothing within the loop will be able to break |
| // the dependence. In such a case we can skip the subsequent check. |
| if (isLexicographicallyPositive(Cur, 0, OuterLoopId) == true) |
| continue; |
| |
| // Check if the direction vector is lexicographically positive (or zero) |
| // for both before/after exchanged. Ignore the last element because it |
| // doesn't affect the legality. |
| if (isLexicographicallyPositive(Cur, OuterLoopId, Cur.size() - 1) == false) |
| return false; |
| std::swap(Cur[InnerLoopId], Cur[OuterLoopId]); |
| if (isLexicographicallyPositive(Cur, OuterLoopId, Cur.size() - 1) == false) |
| return false; |
| } |
| return true; |
| } |
| |
| static void populateWorklist(Loop &L, LoopVector &LoopList) { |
| LLVM_DEBUG(dbgs() << "Calling populateWorklist on Func: " |
| << L.getHeader()->getParent()->getName() << " Loop: %" |
| << L.getHeader()->getName() << '\n'); |
| assert(LoopList.empty() && "LoopList should initially be empty!"); |
| Loop *CurrentLoop = &L; |
| const std::vector<Loop *> *Vec = &CurrentLoop->getSubLoops(); |
| while (!Vec->empty()) { |
| // The current loop has multiple subloops in it hence it is not tightly |
| // nested. |
| // Discard all loops above it added into Worklist. |
| if (Vec->size() != 1) { |
| LoopList = {}; |
| return; |
| } |
| |
| LoopList.push_back(CurrentLoop); |
| CurrentLoop = Vec->front(); |
| Vec = &CurrentLoop->getSubLoops(); |
| } |
| LoopList.push_back(CurrentLoop); |
| } |
| |
| static bool hasSupportedLoopDepth(ArrayRef<Loop *> LoopList, |
| OptimizationRemarkEmitter &ORE) { |
| unsigned LoopNestDepth = LoopList.size(); |
| if (LoopNestDepth < MinLoopNestDepth || LoopNestDepth > MaxLoopNestDepth) { |
| LLVM_DEBUG(dbgs() << "Unsupported depth of loop nest " << LoopNestDepth |
| << ", the supported range is [" << MinLoopNestDepth |
| << ", " << MaxLoopNestDepth << "].\n"); |
| Loop *OuterLoop = LoopList.front(); |
| ORE.emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedLoopNestDepth", |
| OuterLoop->getStartLoc(), |
| OuterLoop->getHeader()) |
| << "Unsupported depth of loop nest, the supported range is [" |
| << std::to_string(MinLoopNestDepth) << ", " |
| << std::to_string(MaxLoopNestDepth) << "].\n"; |
| }); |
| return false; |
| } |
| return true; |
| } |
| |
| static bool isComputableLoopNest(ScalarEvolution *SE, |
| ArrayRef<Loop *> LoopList) { |
| for (Loop *L : LoopList) { |
| const SCEV *ExitCountOuter = SE->getBackedgeTakenCount(L); |
| if (isa<SCEVCouldNotCompute>(ExitCountOuter)) { |
| LLVM_DEBUG(dbgs() << "Couldn't compute backedge count\n"); |
| return false; |
| } |
| if (L->getNumBackEdges() != 1) { |
| LLVM_DEBUG(dbgs() << "NumBackEdges is not equal to 1\n"); |
| return false; |
| } |
| if (!L->getExitingBlock()) { |
| LLVM_DEBUG(dbgs() << "Loop doesn't have unique exit block\n"); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| namespace { |
| |
| /// LoopInterchangeLegality checks if it is legal to interchange the loop. |
| class LoopInterchangeLegality { |
| public: |
| LoopInterchangeLegality(Loop *Outer, Loop *Inner, ScalarEvolution *SE, |
| OptimizationRemarkEmitter *ORE, DominatorTree *DT) |
| : OuterLoop(Outer), InnerLoop(Inner), SE(SE), DT(DT), ORE(ORE) {} |
| |
| /// Check if the loops can be interchanged. |
| bool canInterchangeLoops(unsigned InnerLoopId, unsigned OuterLoopId, |
| CharMatrix &DepMatrix); |
| |
| /// Check if the loop structure is understood. We do not handle triangular |
| /// loops for now. |
| bool isLoopStructureUnderstood(); |
| |
| bool currentLimitations(); |
| |
| const SmallPtrSetImpl<PHINode *> &getOuterInnerReductions() const { |
| return OuterInnerReductions; |
| } |
| |
| const ArrayRef<PHINode *> getInnerLoopInductions() const { |
| return InnerLoopInductions; |
| } |
| |
| ArrayRef<Instruction *> getHasNoWrapReductions() const { |
| return HasNoWrapReductions; |
| } |
| |
| ArrayRef<Instruction *> getHasNoInfInsts() const { return HasNoInfInsts; } |
| |
| /// Record reductions in the inner loop. Currently supported reductions: |
| /// - initialized from a constant. |
| /// - reduction PHI node has only one user. |
| /// - located in the innermost loop. |
| struct InnerReduction { |
| /// The reduction itself. |
| PHINode *Reduction; |
| Value *Init; |
| Value *Next; |
| /// The Lcssa PHI. |
| PHINode *LcssaPhi; |
| /// Store reduction result into memory object. |
| StoreInst *LcssaStore; |
| /// The memory Location. |
| Value *MemRef; |
| Type *ElemTy; |
| }; |
| |
| ArrayRef<InnerReduction> getInnerReductions() const { |
| return InnerReductions; |
| } |
| |
| private: |
| bool tightlyNested(Loop *Outer, Loop *Inner); |
| bool containsUnsafeInstructions(BasicBlock *BB, Instruction *Skip); |
| |
| /// Traverse all PHI nodes in the header of each loop in the loop nest |
| /// starting from \p OuterLoop, and perform the following checks: |
| /// |
| /// - Identify induction variables in the child loop of \p OuterLoop. |
| /// - Check for reductions across the inner loop and \p OuterLoop. |
| /// - Detect unsupported PHI nodes. |
| /// |
| /// Return false if any unsupported PHI node is found or if no induction |
| /// variable is found in the child loop of \p OuterLoop. Otherwise return |
| /// true. |
| bool checkInductionsAndReductions(Loop *OuterLoop); |
| |
| /// Detect and record the reduction of the inner loop. Add them to |
| /// InnerReductions. |
| /// |
| /// innerloop: |
| /// Re = phi<0.0, Next> |
| /// Next = Re op ... |
| /// OuterLoopLatch: |
| /// Lcssa = phi<Next> ; lcssa phi |
| /// store Lcssa, MemRef ; LcssaStore |
| /// |
| bool isInnerReduction(Loop *L, PHINode *Phi, |
| SmallVectorImpl<Instruction *> &HasNoWrapInsts); |
| |
| Loop *OuterLoop; |
| Loop *InnerLoop; |
| |
| ScalarEvolution *SE; |
| DominatorTree *DT; |
| |
| /// Interface to emit optimization remarks. |
| OptimizationRemarkEmitter *ORE; |
| |
| /// Set of reduction PHIs taking part of a reduction across the inner and |
| /// outer loop. |
| SmallPtrSet<PHINode *, 4> OuterInnerReductions; |
| |
| /// Set of inner loop induction PHIs |
| SmallVector<PHINode *, 8> InnerLoopInductions; |
| |
| /// Hold instructions that have nuw/nsw flags and involved in reductions, |
| /// like integer addition/multiplication. Those flags must be dropped when |
| /// interchanging the loops. |
| SmallVector<Instruction *, 4> HasNoWrapReductions; |
| |
| /// Hold instructions that have ninf flags and involved in reductions. Those |
| /// flags must be dropped when interchanging the loops. |
| SmallVector<Instruction *, 4> HasNoInfInsts; |
| |
| /// Vector of reductions in the inner loop. |
| SmallVector<InnerReduction, 8> InnerReductions; |
| }; |
| |
| /// Manages information utilized by the profitability check for cache. The main |
| /// purpose of this class is to delay the computation of CacheCost until it is |
| /// actually needed. |
| class CacheCostManager { |
| Loop *OutermostLoop; |
| LoopStandardAnalysisResults *AR; |
| DependenceInfo *DI; |
| |
| /// CacheCost for \ref OutermostLoop. Once it is computed, it is cached. Note |
| /// that the result can be nullptr. |
| std::optional<std::unique_ptr<CacheCost>> CC; |
| |
| /// Maps each loop to an index representing the optimal position within the |
| /// loop-nest, as determined by the cache cost analysis. |
| DenseMap<const Loop *, unsigned> CostMap; |
| |
| void computeIfUnitinialized(); |
| |
| public: |
| CacheCostManager(Loop *OutermostLoop, LoopStandardAnalysisResults *AR, |
| DependenceInfo *DI) |
| : OutermostLoop(OutermostLoop), AR(AR), DI(DI) {} |
| CacheCost *getCacheCost(); |
| const DenseMap<const Loop *, unsigned> &getCostMap(); |
| }; |
| |
| /// LoopInterchangeProfitability checks if it is profitable to interchange the |
| /// loop. |
| class LoopInterchangeProfitability { |
| public: |
| LoopInterchangeProfitability(Loop *Outer, Loop *Inner, ScalarEvolution *SE, |
| OptimizationRemarkEmitter *ORE) |
| : OuterLoop(Outer), InnerLoop(Inner), SE(SE), ORE(ORE) {} |
| |
| /// Check if the loop interchange is profitable. |
| bool isProfitable(const Loop *InnerLoop, const Loop *OuterLoop, |
| unsigned InnerLoopId, unsigned OuterLoopId, |
| CharMatrix &DepMatrix, CacheCostManager &CCM); |
| |
| private: |
| int getInstrOrderCost(); |
| std::optional<bool> isProfitablePerLoopCacheAnalysis( |
| const DenseMap<const Loop *, unsigned> &CostMap, CacheCost *CC); |
| std::optional<bool> isProfitablePerInstrOrderCost(); |
| std::optional<bool> isProfitableForVectorization(unsigned InnerLoopId, |
| unsigned OuterLoopId, |
| CharMatrix &DepMatrix); |
| Loop *OuterLoop; |
| Loop *InnerLoop; |
| |
| /// Scev analysis. |
| ScalarEvolution *SE; |
| |
| /// Interface to emit optimization remarks. |
| OptimizationRemarkEmitter *ORE; |
| }; |
| |
| /// LoopInterchangeTransform interchanges the loop. |
| class LoopInterchangeTransform { |
| public: |
| LoopInterchangeTransform(Loop *Outer, Loop *Inner, ScalarEvolution *SE, |
| LoopInfo *LI, DominatorTree *DT, |
| const LoopInterchangeLegality &LIL) |
| : OuterLoop(Outer), InnerLoop(Inner), SE(SE), LI(LI), DT(DT), LIL(LIL) {} |
| |
| /// Interchange OuterLoop and InnerLoop. |
| void transform(ArrayRef<Instruction *> DropNoWrapInsts, |
| ArrayRef<Instruction *> DropNoInfInsts); |
| void reduction2Memory(); |
| void restructureLoops(Loop *NewInner, Loop *NewOuter, |
| BasicBlock *OrigInnerPreHeader, |
| BasicBlock *OrigOuterPreHeader); |
| void removeChildLoop(Loop *OuterLoop, Loop *InnerLoop); |
| |
| private: |
| void adjustLoopLinks(); |
| void adjustLoopBranches(); |
| |
| Loop *OuterLoop; |
| Loop *InnerLoop; |
| |
| /// Scev analysis. |
| ScalarEvolution *SE; |
| |
| LoopInfo *LI; |
| DominatorTree *DT; |
| |
| const LoopInterchangeLegality &LIL; |
| }; |
| |
| struct LoopInterchange { |
| ScalarEvolution *SE = nullptr; |
| LoopInfo *LI = nullptr; |
| DependenceInfo *DI = nullptr; |
| DominatorTree *DT = nullptr; |
| LoopStandardAnalysisResults *AR = nullptr; |
| |
| /// Interface to emit optimization remarks. |
| OptimizationRemarkEmitter *ORE; |
| |
| LoopInterchange(ScalarEvolution *SE, LoopInfo *LI, DependenceInfo *DI, |
| DominatorTree *DT, LoopStandardAnalysisResults *AR, |
| OptimizationRemarkEmitter *ORE) |
| : SE(SE), LI(LI), DI(DI), DT(DT), AR(AR), ORE(ORE) {} |
| |
| bool run(Loop *L) { |
| if (L->getParentLoop()) |
| return false; |
| SmallVector<Loop *, 8> LoopList; |
| populateWorklist(*L, LoopList); |
| return processLoopList(LoopList); |
| } |
| |
| bool run(LoopNest &LN) { |
| SmallVector<Loop *, 8> LoopList(LN.getLoops()); |
| for (unsigned I = 1; I < LoopList.size(); ++I) |
| if (LoopList[I]->getParentLoop() != LoopList[I - 1]) |
| return false; |
| return processLoopList(LoopList); |
| } |
| |
| unsigned selectLoopForInterchange(ArrayRef<Loop *> LoopList) { |
| // TODO: Add a better heuristic to select the loop to be interchanged based |
| // on the dependence matrix. Currently we select the innermost loop. |
| return LoopList.size() - 1; |
| } |
| |
| bool processLoopList(SmallVectorImpl<Loop *> &LoopList) { |
| bool Changed = false; |
| |
| // Ensure proper loop nest depth. |
| assert(hasSupportedLoopDepth(LoopList, *ORE) && |
| "Unsupported depth of loop nest."); |
| |
| unsigned LoopNestDepth = LoopList.size(); |
| |
| LLVM_DEBUG({ |
| dbgs() << "Processing LoopList of size = " << LoopNestDepth |
| << " containing the following loops:\n"; |
| for (auto *L : LoopList) { |
| dbgs() << " - "; |
| L->print(dbgs()); |
| } |
| }); |
| |
| CharMatrix DependencyMatrix; |
| Loop *OuterMostLoop = *(LoopList.begin()); |
| if (!populateDependencyMatrix(DependencyMatrix, LoopNestDepth, |
| OuterMostLoop, DI, SE, ORE)) { |
| LLVM_DEBUG(dbgs() << "Populating dependency matrix failed\n"); |
| return false; |
| } |
| |
| LLVM_DEBUG(dbgs() << "Dependency matrix before interchange:\n"; |
| printDepMatrix(DependencyMatrix)); |
| |
| // Get the Outermost loop exit. |
| BasicBlock *LoopNestExit = OuterMostLoop->getExitBlock(); |
| if (!LoopNestExit) { |
| LLVM_DEBUG(dbgs() << "OuterMostLoop '" << OuterMostLoop->getName() |
| << "' needs an unique exit block"); |
| return false; |
| } |
| |
| unsigned SelecLoopId = selectLoopForInterchange(LoopList); |
| CacheCostManager CCM(LoopList[0], AR, DI); |
| // We try to achieve the globally optimal memory access for the loopnest, |
| // and do interchange based on a bubble-sort fasion. We start from |
| // the innermost loop, move it outwards to the best possible position |
| // and repeat this process. |
| for (unsigned j = SelecLoopId; j > 0; j--) { |
| bool ChangedPerIter = false; |
| for (unsigned i = SelecLoopId; i > SelecLoopId - j; i--) { |
| bool Interchanged = |
| processLoop(LoopList, i, i - 1, DependencyMatrix, CCM); |
| ChangedPerIter |= Interchanged; |
| Changed |= Interchanged; |
| } |
| // Early abort if there was no interchange during an entire round of |
| // moving loops outwards. |
| if (!ChangedPerIter) |
| break; |
| } |
| return Changed; |
| } |
| |
| bool processLoop(SmallVectorImpl<Loop *> &LoopList, unsigned InnerLoopId, |
| unsigned OuterLoopId, |
| std::vector<std::vector<char>> &DependencyMatrix, |
| CacheCostManager &CCM) { |
| Loop *OuterLoop = LoopList[OuterLoopId]; |
| Loop *InnerLoop = LoopList[InnerLoopId]; |
| LLVM_DEBUG(dbgs() << "Processing InnerLoopId = " << InnerLoopId |
| << " and OuterLoopId = " << OuterLoopId << "\n"); |
| LoopInterchangeLegality LIL(OuterLoop, InnerLoop, SE, ORE, DT); |
| if (!LIL.canInterchangeLoops(InnerLoopId, OuterLoopId, DependencyMatrix)) { |
| LLVM_DEBUG(dbgs() << "Cannot prove legality, not interchanging loops '" |
| << OuterLoop->getName() << "' and '" |
| << InnerLoop->getName() << "'\n"); |
| return false; |
| } |
| LLVM_DEBUG(dbgs() << "Loops '" << OuterLoop->getName() << "' and '" |
| << InnerLoop->getName() |
| << "' are legal to interchange\n"); |
| LoopInterchangeProfitability LIP(OuterLoop, InnerLoop, SE, ORE); |
| if (!LIP.isProfitable(InnerLoop, OuterLoop, InnerLoopId, OuterLoopId, |
| DependencyMatrix, CCM)) { |
| LLVM_DEBUG(dbgs() << "Interchanging loops '" << OuterLoop->getName() |
| << "' and '" << InnerLoop->getName() |
| << "' not profitable.\n"); |
| return false; |
| } |
| |
| ORE->emit([&]() { |
| return OptimizationRemark(DEBUG_TYPE, "Interchanged", |
| InnerLoop->getStartLoc(), |
| InnerLoop->getHeader()) |
| << "Loop interchanged with enclosing loop."; |
| }); |
| |
| LoopInterchangeTransform LIT(OuterLoop, InnerLoop, SE, LI, DT, LIL); |
| LIT.transform(LIL.getHasNoWrapReductions(), LIL.getHasNoInfInsts()); |
| LLVM_DEBUG(dbgs() << "Loops interchanged: outer loop '" |
| << OuterLoop->getName() << "' and inner loop '" |
| << InnerLoop->getName() << "'\n"); |
| LoopsInterchanged++; |
| |
| llvm::formLCSSARecursively(*OuterLoop, *DT, LI, SE); |
| |
| // Loops interchanged, update LoopList accordingly. |
| std::swap(LoopList[OuterLoopId], LoopList[InnerLoopId]); |
| // Update the DependencyMatrix |
| interChangeDependencies(DependencyMatrix, InnerLoopId, OuterLoopId); |
| |
| LLVM_DEBUG(dbgs() << "Dependency matrix after interchange:\n"; |
| printDepMatrix(DependencyMatrix)); |
| |
| return true; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| bool LoopInterchangeLegality::containsUnsafeInstructions(BasicBlock *BB, |
| Instruction *Skip) { |
| return any_of(*BB, [Skip](const Instruction &I) { |
| if (&I == Skip) |
| return false; |
| return I.mayHaveSideEffects() || I.mayReadFromMemory(); |
| }); |
| } |
| |
| bool LoopInterchangeLegality::tightlyNested(Loop *OuterLoop, Loop *InnerLoop) { |
| BasicBlock *OuterLoopHeader = OuterLoop->getHeader(); |
| BasicBlock *InnerLoopPreHeader = InnerLoop->getLoopPreheader(); |
| BasicBlock *OuterLoopLatch = OuterLoop->getLoopLatch(); |
| |
| LLVM_DEBUG(dbgs() << "Checking if loops '" << OuterLoop->getName() |
| << "' and '" << InnerLoop->getName() |
| << "' are tightly nested\n"); |
| |
| // In a perfectly nested loop the outer header branches only into the inner |
| // loop. If it can also reach the outer latch, it conditionally guards the |
| // inner loop (an imperfect nest), so the inner loop runs on only a subset of |
| // the outer iterations. Interchanging such a nest would run the inner loop on |
| // every outer iteration, including the guarded-off ones, which is illegal |
| // when the inner loop relies on the guard to terminate (e.g. an eq/ne exit |
| // whose trip count is degenerate once the guard is false). Reject by allowing |
| // the outer header to branch only into the inner loop. |
| // |
| // TODO: This is conservative. A guarded nest is still safe to interchange |
| // when the inner loop has a computable trip count that is empty exactly when |
| // the guard is false, e.g.: |
| // for (i = 0; i < N; i++) |
| // if (M > 0) // loop-invariant guard |
| // for (j = 0; j < M; j++) // empty when M <= 0 |
| // A[j][i] = ...; |
| // Interchanging is legal here because the inner loop runs zero times on the |
| // guarded-off iterations. |
| for (BasicBlock *Succ : successors(OuterLoopHeader)) |
| if (Succ != InnerLoopPreHeader && Succ != InnerLoop->getHeader()) |
| return false; |
| |
| LLVM_DEBUG(dbgs() << "Checking instructions in Loop header and Loop latch\n"); |
| |
| // The inner loop reduction pattern requires storing the LCSSA PHI in |
| // the OuterLoop Latch. Therefore, when reduction2Memory is enabled, skip |
| // that store during checks. |
| Instruction *Skip = nullptr; |
| assert(InnerReductions.size() <= 1 && |
| "So far we only support at most one reduction."); |
| if (InnerReductions.size() == 1) |
| Skip = InnerReductions[0].LcssaStore; |
| |
| // We do not have any basic block in between now make sure the outer header |
| // and outer loop latch doesn't contain any unsafe instructions. |
| if (containsUnsafeInstructions(OuterLoopHeader, Skip) || |
| containsUnsafeInstructions(OuterLoopLatch, Skip)) |
| return false; |
| |
| // Also make sure the inner loop preheader does not contain any unsafe |
| // instructions. Note that all instructions in the preheader will be moved to |
| // the outer loop header when interchanging. |
| if (InnerLoopPreHeader != OuterLoopHeader && |
| containsUnsafeInstructions(InnerLoopPreHeader, Skip)) |
| return false; |
| |
| BasicBlock *InnerLoopExit = InnerLoop->getExitBlock(); |
| // Ensure the inner loop exit block flows to the outer loop latch possibly |
| // through empty blocks. |
| const BasicBlock &SuccInner = |
| LoopNest::skipEmptyBlockUntil(InnerLoopExit, OuterLoopLatch); |
| if (&SuccInner != OuterLoopLatch) { |
| LLVM_DEBUG(dbgs() << "Inner loop exit block " << *InnerLoopExit |
| << " does not lead to the outer loop latch.\n";); |
| return false; |
| } |
| // The inner loop exit block does flow to the outer loop latch and not some |
| // other BBs, now make sure it contains safe instructions, since it will be |
| // moved into the (new) inner loop after interchange. |
| if (containsUnsafeInstructions(InnerLoopExit, Skip)) |
| return false; |
| |
| LLVM_DEBUG(dbgs() << "Loops are perfectly nested\n"); |
| // We have a perfect loop nest. |
| return true; |
| } |
| |
| bool LoopInterchangeLegality::isLoopStructureUnderstood() { |
| BasicBlock *InnerLoopPreheader = InnerLoop->getLoopPreheader(); |
| for (PHINode *InnerInduction : InnerLoopInductions) { |
| unsigned Num = InnerInduction->getNumOperands(); |
| for (unsigned i = 0; i < Num; ++i) { |
| Value *Val = InnerInduction->getOperand(i); |
| if (isa<Constant>(Val)) |
| continue; |
| Instruction *I = dyn_cast<Instruction>(Val); |
| if (!I) |
| return false; |
| // TODO: Handle triangular loops. |
| // e.g. for(int i=0;i<N;i++) |
| // for(int j=i;j<N;j++) |
| unsigned IncomBlockIndx = PHINode::getIncomingValueNumForOperand(i); |
| if (InnerInduction->getIncomingBlock(IncomBlockIndx) == |
| InnerLoopPreheader && |
| !OuterLoop->isLoopInvariant(I)) { |
| return false; |
| } |
| } |
| } |
| |
| // TODO: Handle triangular loops of another form. |
| // e.g. for(int i=0;i<N;i++) |
| // for(int j=0;j<i;j++) |
| // or, |
| // for(int i=0;i<N;i++) |
| // for(int j=0;j*i<N;j++) |
| BasicBlock *InnerLoopLatch = InnerLoop->getLoopLatch(); |
| CondBrInst *InnerLoopLatchBI = |
| dyn_cast<CondBrInst>(InnerLoopLatch->getTerminator()); |
| if (!InnerLoopLatchBI) |
| return false; |
| |
| CmpInst *InnerLoopCmp = dyn_cast<CmpInst>(InnerLoopLatchBI->getCondition()); |
| if (!InnerLoopCmp) |
| return false; |
| |
| Value *Op0 = InnerLoopCmp->getOperand(0); |
| Value *Op1 = InnerLoopCmp->getOperand(1); |
| |
| // LHS and RHS of the inner loop exit condition, e.g., |
| // in "for(int j=0;j<i;j++)", LHS is j and RHS is i. |
| Value *Left = nullptr; |
| Value *Right = nullptr; |
| |
| // Check if V only involves inner loop induction variable. |
| // Return true if V is InnerInduction, or a cast from |
| // InnerInduction, or a binary operator that involves |
| // InnerInduction and a constant. |
| std::function<bool(Value *)> IsPathToInnerIndVar; |
| IsPathToInnerIndVar = [this, &IsPathToInnerIndVar](const Value *V) -> bool { |
| if (llvm::is_contained(InnerLoopInductions, V)) |
| return true; |
| if (isa<Constant>(V)) |
| return true; |
| const Instruction *I = dyn_cast<Instruction>(V); |
| if (!I) |
| return false; |
| if (isa<CastInst>(I)) |
| return IsPathToInnerIndVar(I->getOperand(0)); |
| if (isa<BinaryOperator>(I)) |
| return IsPathToInnerIndVar(I->getOperand(0)) && |
| IsPathToInnerIndVar(I->getOperand(1)); |
| return false; |
| }; |
| |
| // In case of multiple inner loop indvars, it is okay if LHS and RHS |
| // are both inner indvar related variables. |
| if (IsPathToInnerIndVar(Op0) && IsPathToInnerIndVar(Op1)) |
| return true; |
| |
| // Otherwise we check if the cmp instruction compares an inner indvar |
| // related variable (Left) with a outer loop invariant (Right). |
| if (IsPathToInnerIndVar(Op0) && !isa<Constant>(Op0)) { |
| Left = Op0; |
| Right = Op1; |
| } else if (IsPathToInnerIndVar(Op1) && !isa<Constant>(Op1)) { |
| Left = Op1; |
| Right = Op0; |
| } |
| |
| if (Left == nullptr) |
| return false; |
| |
| const SCEV *S = SE->getSCEV(Right); |
| if (!SE->isLoopInvariant(S, OuterLoop)) |
| return false; |
| |
| return true; |
| } |
| |
| // If SV is a LCSSA PHI node with a single incoming value, return the incoming |
| // value. |
| static Value *followLCSSA(Value *SV) { |
| PHINode *PHI = dyn_cast<PHINode>(SV); |
| if (!PHI) |
| return SV; |
| |
| if (PHI->getNumIncomingValues() != 1) |
| return SV; |
| return followLCSSA(PHI->getIncomingValue(0)); |
| } |
| |
| static bool checkReductionKind(Loop *L, PHINode *PHI, |
| SmallVectorImpl<Instruction *> &HasNoWrapInsts, |
| SmallVectorImpl<Instruction *> &HasNoInfInsts) { |
| RecurrenceDescriptor RD; |
| if (RecurrenceDescriptor::isReductionPHI(PHI, L, RD)) { |
| // Detect floating point reduction only when it can be reordered. |
| if (RD.getExactFPMathInst() != nullptr) |
| return false; |
| |
| RecurKind RK = RD.getRecurrenceKind(); |
| switch (RK) { |
| case RecurKind::Or: |
| case RecurKind::And: |
| case RecurKind::Xor: |
| case RecurKind::SMin: |
| case RecurKind::SMax: |
| case RecurKind::UMin: |
| case RecurKind::UMax: |
| return true; |
| |
| // Interchanging the loops that contain AnyOf reduction is not always legal. |
| // Especially, when the result value of the AnyOf is not loop-invariant with |
| // respect to the outer loop, interchanging may change the semantics. The |
| // following is an example of such case: |
| // int A = {{ 1, 0 }, { 0, 1 }}; |
| // int red = 0; |
| // for (int i = 0; i < 2; i++) |
| // for (int j = 0; j < 2; j++) |
| // red = (A[j][i] == 0) ? i + 1 : red; |
| // |
| // TODO: We may be able to support interchanging loops with AnyOf reduction |
| // by checking the operand of the reduction is loop-invariant with respect |
| // to the outer loop as well. |
| case RecurKind::AnyOf: |
| return false; |
| |
| // Changing the order of floating-point operations may alter the results. If |
| // a certain instruction has the ninf flag, it means that reordering can |
| // produce a poison value, which may lead to undefined behavior. To prevent |
| // this, we must drop the ninf flags if we decide to apply the |
| // transformation. |
| case RecurKind::FAdd: |
| case RecurKind::FMul: |
| case RecurKind::FMin: |
| case RecurKind::FMax: |
| case RecurKind::FMinimum: |
| case RecurKind::FMaximum: |
| case RecurKind::FMinimumNum: |
| case RecurKind::FMaximumNum: |
| case RecurKind::FMulAdd: |
| for (Instruction *I : RD.getReductionOpChain(PHI, L)) |
| if (isa<FPMathOperator>(I) && I->hasNoInfs()) |
| HasNoInfInsts.push_back(I); |
| return true; |
| |
| // Change the order of integer addition/multiplication may change the |
| // semantics. Consider the following case: |
| // |
| // int A[2][2] = {{ INT_MAX, INT_MAX }, { INT_MIN, INT_MIN }}; |
| // int sum = 0; |
| // for (int i = 0; i < 2; i++) |
| // for (int j = 0; j < 2; j++) |
| // sum += A[j][i]; |
| // |
| // If the above loops are exchanged, the addition will cause an |
| // overflow. To prevent this, we must drop the nuw/nsw flags from the |
| // addition/multiplication instructions when we actually exchanges the |
| // loops. |
| case RecurKind::Add: |
| case RecurKind::Mul: { |
| unsigned OpCode = RecurrenceDescriptor::getOpcode(RK); |
| SmallVector<Instruction *, 4> Ops = RD.getReductionOpChain(PHI, L); |
| |
| // Bail out when we fail to collect reduction instructions chain. |
| if (Ops.empty()) |
| return false; |
| |
| for (Instruction *I : Ops) { |
| assert(I->getOpcode() == OpCode && |
| "Expected the instruction to be the reduction operation"); |
| (void)OpCode; |
| |
| // If the instruction has nuw/nsw flags, we must drop them when the |
| // transformation is actually performed. |
| if (I->hasNoSignedWrap() || I->hasNoUnsignedWrap()) |
| HasNoWrapInsts.push_back(I); |
| } |
| return true; |
| } |
| |
| default: |
| return false; |
| } |
| } else |
| return false; |
| } |
| |
| // Check V's users to see if it is involved in a reduction in L. |
| static PHINode * |
| findInnerReductionPhi(Loop *L, Value *V, |
| SmallVectorImpl<Instruction *> &HasNoWrapInsts, |
| SmallVectorImpl<Instruction *> &HasNoInfInsts) { |
| // Reduction variables cannot be constants. |
| if (isa<Constant>(V)) |
| return nullptr; |
| |
| for (Value *User : V->users()) { |
| if (PHINode *PHI = dyn_cast<PHINode>(User)) { |
| if (PHI->getNumIncomingValues() == 1) |
| continue; |
| |
| if (checkReductionKind(L, PHI, HasNoWrapInsts, HasNoInfInsts)) |
| return PHI; |
| else |
| return nullptr; |
| } |
| } |
| |
| return nullptr; |
| } |
| |
| bool LoopInterchangeLegality::isInnerReduction( |
| Loop *L, PHINode *Phi, SmallVectorImpl<Instruction *> &HasNoWrapInsts) { |
| |
| // Only support reduction2Mem when the loop nest to be interchanged is |
| // the innermost two loops. |
| if (!L->isInnermost()) { |
| LLVM_DEBUG(dbgs() << "Only supported when the loop is the innermost.\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedInnerReduction", |
| L->getStartLoc(), L->getHeader()) |
| << "Only supported when the loop is the innermost."; |
| }); |
| return false; |
| } |
| |
| if (Phi->getNumIncomingValues() != 2) |
| return false; |
| |
| Value *Init = Phi->getIncomingValueForBlock(L->getLoopPreheader()); |
| Value *Next = Phi->getIncomingValueForBlock(L->getLoopLatch()); |
| |
| // So far only supports constant initial value. |
| if (!isa<Constant>(Init)) { |
| LLVM_DEBUG( |
| dbgs() |
| << "Only supported for the reduction with a constant initial value.\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedInnerReduction", |
| L->getStartLoc(), L->getHeader()) |
| << "Only supported for the reduction with a constant initial " |
| "value."; |
| }); |
| return false; |
| } |
| |
| // The reduction result must live in the inner loop. |
| if (Instruction *I = dyn_cast<Instruction>(Next)) { |
| BasicBlock *BB = I->getParent(); |
| if (!L->contains(BB)) |
| return false; |
| } |
| |
| // The reduction should have only one user. |
| if (!Phi->hasOneUser()) |
| return false; |
| |
| // Check the reduction kind. |
| if (!checkReductionKind(L, Phi, HasNoWrapInsts, HasNoInfInsts)) |
| return false; |
| |
| // Find lcssa_phi in OuterLoop's Latch |
| BasicBlock *ExitBlock = L->getExitBlock(); |
| if (!ExitBlock) |
| return false; |
| |
| PHINode *Lcssa = NULL; |
| for (auto *U : Next->users()) { |
| if (auto *P = dyn_cast<PHINode>(U)) { |
| if (P == Phi) |
| continue; |
| |
| if (Lcssa == NULL && P->getParent() == ExitBlock && |
| P->getIncomingValueForBlock(L->getLoopLatch()) == Next) |
| Lcssa = P; |
| else |
| return false; |
| } else |
| return false; |
| } |
| if (!Lcssa) |
| return false; |
| |
| if (!Lcssa->hasOneUser()) { |
| LLVM_DEBUG(dbgs() << "Only supported when the reduction is used once in " |
| "the outer loop.\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedInnerReduction", |
| L->getStartLoc(), L->getHeader()) |
| << "Only supported when the reduction is used once in the outer " |
| "loop."; |
| }); |
| return false; |
| } |
| |
| StoreInst *LcssaStore = |
| dyn_cast<StoreInst>(Lcssa->getUniqueUndroppableUser()); |
| if (!LcssaStore || LcssaStore->getParent() != ExitBlock) |
| return false; |
| |
| Value *MemRef = LcssaStore->getOperand(1); |
| Type *ElemTy = LcssaStore->getOperand(0)->getType(); |
| |
| // LcssaStore stores the reduction result in BB. |
| // When the reduction is initialized from a constant value, we need to load |
| // from the memory object into the target basic block of the inner loop. This |
| // means the memory reference was used prematurely. So we must ensure that the |
| // memory reference does not dominate the target basic block. |
| // TODO: Move the memory reference definition into the loop header. |
| if (!DT->dominates(dyn_cast<Instruction>(MemRef), L->getHeader())) { |
| LLVM_DEBUG(dbgs() << "Only supported when memory reference dominate " |
| "the inner loop.\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedInnerReduction", |
| L->getStartLoc(), L->getHeader()) |
| << "Only supported when memory reference dominate the inner " |
| "loop."; |
| }); |
| return false; |
| } |
| |
| // Found a reduction in the inner loop. |
| InnerReduction SR; |
| SR.Reduction = Phi; |
| SR.Init = Init; |
| SR.Next = Next; |
| SR.LcssaPhi = Lcssa; |
| SR.LcssaStore = LcssaStore; |
| SR.MemRef = MemRef; |
| SR.ElemTy = ElemTy; |
| |
| InnerReductions.push_back(SR); |
| return true; |
| } |
| |
| bool LoopInterchangeLegality::checkInductionsAndReductions(Loop *OuterLoop) { |
| auto ChildLoop = [](Loop *L) { |
| assert(L->getSubLoops().size() <= 1 && |
| "Expect at most one child loop for now."); |
| return L->getSubLoops().empty() ? nullptr : L->getSubLoops().front(); |
| }; |
| |
| Loop *InnerLoop = ChildLoop(OuterLoop); |
| for (Loop *CurLoop = OuterLoop; CurLoop; CurLoop = ChildLoop(CurLoop)) { |
| for (PHINode &PHI : CurLoop->getHeader()->phis()) { |
| InductionDescriptor ID; |
| if (InductionDescriptor::isInductionPHI(&PHI, CurLoop, SE, ID)) { |
| if (CurLoop == InnerLoop) { |
| const SCEV *Step = ID.getStep(); |
| if (!SE->isLoopInvariant(Step, OuterLoop)) |
| return false; |
| InnerLoopInductions.push_back(&PHI); |
| } |
| continue; |
| } |
| |
| if (CurLoop == OuterLoop) { |
| // PHIs in inner loops need to be part of a reduction in the outer loop, |
| if (PHI.getNumIncomingValues() != 2) { |
| LLVM_DEBUG(dbgs() << "Only PHI nodes in the outer loop header with 2 " |
| "incoming values are supported.\n"); |
| return false; |
| } |
| // Check if we have a PHI node in the outer loop that has a reduction |
| // result from the inner loop as an incoming value. |
| Value *V = followLCSSA( |
| PHI.getIncomingValueForBlock(OuterLoop->getLoopLatch())); |
| PHINode *InnerRedPhi = findInnerReductionPhi( |
| InnerLoop, V, HasNoWrapReductions, HasNoInfInsts); |
| |
| // Reject if PHI has users other than InnerRedPhi. The typical case is |
| // as follows: |
| // |
| // o.header: |
| // %red.o = phi [ 0, ... ], [ %red.next, %o.latch ] |
| // br label %i.header |
| // |
| // i.header: |
| // %red.i = phi [ %red.o, %o.header ], [ %red.next, %i.latch ] |
| // br label %i.body |
| // |
| // i.body: |
| // store %red.o to %mem |
| // ... |
| // |
| if (!InnerRedPhi || |
| !llvm::is_contained(InnerRedPhi->incoming_values(), &PHI) || |
| !all_of(PHI.users(), |
| [InnerRedPhi](User *U) { return U == InnerRedPhi; })) { |
| LLVM_DEBUG( |
| dbgs() |
| << "Failed to recognize PHI as an induction or reduction.\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedPHIOuter", |
| OuterLoop->getStartLoc(), |
| OuterLoop->getHeader()) |
| << "Only outer loops with induction or reduction PHI nodes " |
| "can be interchanged currently."; |
| }); |
| return false; |
| } |
| |
| OuterInnerReductions.insert(&PHI); |
| OuterInnerReductions.insert(InnerRedPhi); |
| } else { |
| if (OuterInnerReductions.count(&PHI)) { |
| LLVM_DEBUG(dbgs() << "Found a reduction across the outer loop.\n"); |
| } else if (EnableReduction2Memory && |
| isInnerReduction(CurLoop, &PHI, HasNoWrapReductions)) { |
| LLVM_DEBUG(dbgs() << "Found a reduction in the inner loop: \n" |
| << PHI << '\n'); |
| } else { |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedPHIInner", |
| CurLoop->getStartLoc(), |
| CurLoop->getHeader()) |
| << "Only inner loops with induction or reduction PHI nodes " |
| "can be interchanged currently."; |
| }); |
| return false; |
| } |
| } |
| } |
| |
| // For now we only support at most one reduction. |
| if (InnerReductions.size() > 1) { |
| LLVM_DEBUG(dbgs() << "Only supports at most one reduction.\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedInnerReduction", |
| CurLoop->getStartLoc(), |
| CurLoop->getHeader()) |
| << "Only supports at most one reduction."; |
| }); |
| return false; |
| } |
| } |
| |
| return !InnerLoopInductions.empty(); |
| } |
| |
| // This function indicates the current limitations in the transform as a result |
| // of which we do not proceed. |
| bool LoopInterchangeLegality::currentLimitations() { |
| BasicBlock *InnerLoopLatch = InnerLoop->getLoopLatch(); |
| |
| // transform currently expects the loop latches to also be the exiting |
| // blocks. |
| if (InnerLoop->getExitingBlock() != InnerLoopLatch || |
| OuterLoop->getExitingBlock() != OuterLoop->getLoopLatch() || |
| !isa<CondBrInst>(InnerLoopLatch->getTerminator()) || |
| !isa<CondBrInst>(OuterLoop->getLoopLatch()->getTerminator())) { |
| LLVM_DEBUG( |
| dbgs() << "Loops where the latch is not the exiting block are not" |
| << " supported currently.\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "ExitingNotLatch", |
| OuterLoop->getStartLoc(), |
| OuterLoop->getHeader()) |
| << "Loops where the latch is not the exiting block cannot be" |
| " interchange currently."; |
| }); |
| return true; |
| } |
| |
| // TODO: Triangular loops are not handled for now. |
| if (!isLoopStructureUnderstood()) { |
| LLVM_DEBUG(dbgs() << "Loop structure not understood by pass\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedStructureInner", |
| InnerLoop->getStartLoc(), |
| InnerLoop->getHeader()) |
| << "Inner loop structure not understood currently."; |
| }); |
| return true; |
| } |
| |
| // Currently, we do not support loops that have a predecessor entering the |
| // loop via an indirectbr. |
| for (Loop *L : {OuterLoop, InnerLoop}) { |
| BasicBlock *Header = L->getHeader(); |
| for (BasicBlock *Pred : predecessors(Header)) { |
| if (L->contains(Pred)) |
| continue; |
| if (isa<IndirectBrInst>(Pred->getTerminator())) { |
| LLVM_DEBUG( |
| dbgs() << "Indirect branch found in the loop predecessor.\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "IndirectBranchPreheader", |
| L->getStartLoc(), L->getHeader()) |
| << "Indirect branch found in the loop predecessor."; |
| }); |
| return true; |
| } |
| } |
| } |
| |
| // Currently, we do not support loops where the inner loop header has |
| // duplicate successors. |
| SmallPtrSet<BasicBlock *, 2> InnerLoopHeaderSuccs; |
| for (BasicBlock *Succ : successors(InnerLoop->getHeader())) |
| if (!InnerLoopHeaderSuccs.insert(Succ).second) |
| return true; |
| |
| return false; |
| } |
| |
| /// We currently only support LCSSA PHI nodes in the inner loop exit if their |
| /// users are either of the following: |
| /// |
| /// - Reduction PHIs |
| /// - PHIs outside the outer loop |
| /// - PHIs belonging to the latch of the outer loop |
| /// |
| /// These conditions mean that we are only interested in the final value after |
| /// the inner loop. |
| static bool |
| areInnerLoopExitPHIsSupported(Loop *OuterL, Loop *InnerL, |
| SmallPtrSetImpl<PHINode *> &Reductions, |
| PHINode *LcssaReduction) { |
| BasicBlock *InnerExit = InnerL->getUniqueExitBlock(); |
| for (PHINode &PHI : InnerExit->phis()) { |
| // The reduction LCSSA PHI will have only one incoming block, which comes |
| // from the loop latch. |
| if (PHI.getNumIncomingValues() > 1) |
| return false; |
| // The reduction LCSSA PHI's store user is rewritten by reduction2Memory(); |
| // skip its user-check but keep validating the remaining LCSSA PHIs. |
| if (&PHI == LcssaReduction) |
| continue; |
| if (any_of(PHI.users(), [&Reductions, OuterL](User *U) { |
| PHINode *PN = dyn_cast<PHINode>(U); |
| if (!PN) |
| return true; |
| if (Reductions.count(PN)) |
| return false; |
| BasicBlock *PB = PN->getParent(); |
| if (!OuterL->contains(PB)) |
| return false; |
| return PB != OuterL->getLoopLatch(); |
| })) |
| return false; |
| } |
| return true; |
| } |
| |
| // We currently support LCSSA PHI nodes in the outer loop exit, if their |
| // incoming values do not come from the outer loop latch or if the |
| // outer loop latch has a single predecessor. In that case, the value will |
| // be available if both the inner and outer loop conditions are true, which |
| // will still be true after interchanging. If we have multiple predecessor, |
| // that may not be the case, e.g. because the outer loop latch may be executed |
| // if the inner loop is not executed. |
| static bool areOuterLoopExitPHIsSupported(Loop *OuterLoop, Loop *InnerLoop) { |
| BasicBlock *LoopNestExit = OuterLoop->getUniqueExitBlock(); |
| for (PHINode &PHI : LoopNestExit->phis()) { |
| for (Value *Incoming : PHI.incoming_values()) { |
| Instruction *IncomingI = dyn_cast<Instruction>(Incoming); |
| if (!IncomingI || IncomingI->getParent() != OuterLoop->getLoopLatch()) |
| continue; |
| |
| // The incoming value is defined in the outer loop latch. Currently we |
| // only support that in case the outer loop latch has a single predecessor. |
| // This guarantees that the outer loop latch is executed if and only if |
| // the inner loop is executed (because tightlyNested() guarantees that the |
| // outer loop header only branches to the inner loop or the outer loop |
| // latch). |
| // FIXME: We could weaken this logic and allow multiple predecessors, |
| // if the values are produced outside the loop latch. We would need |
| // additional logic to update the PHI nodes in the exit block as |
| // well. |
| if (OuterLoop->getLoopLatch()->getUniquePredecessor() == nullptr) |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /// The transform clones the inner latch's exit condition into the new latch |
| /// (see MoveInstructions in LoopInterchangeTransform::transform), but it does |
| /// not relocate PHI nodes. So if a PHI in the inner latch feeds that condition, |
| /// a later interchange can leave the cloned PHI with a stale incoming block, |
| /// producing invalid IR. Reject that case here. |
| /// |
| /// For example, %p is a PHI in the inner latch and the inner loop's exit test |
| /// reads %p, so %p feeds the condition that would be cloned: |
| /// |
| /// inner.latch: |
| /// %p = phi i64 [ %v, %subloop.latch ] |
| /// %ec = icmp eq i64 %iv, %p ; inner exit test reads %p |
| /// br i1 %ec, label %exit, label %inner.header |
| /// |
| /// TODO: Handle transformation of lcssa phis in the InnerLoop latch in case of |
| /// multi-level loop nests. |
| static bool areInnerLoopLatchPHIsSupported(Loop *InnerLoop) { |
| if (InnerLoop->getSubLoops().empty()) |
| return true; |
| |
| BasicBlock *InnerLoopLatch = InnerLoop->getLoopLatch(); |
| auto *LatchBI = dyn_cast<CondBrInst>(InnerLoopLatch->getTerminator()); |
| if (!LatchBI) |
| return true; |
| auto *CondI = dyn_cast<Instruction>(LatchBI->getCondition()); |
| if (!CondI) |
| return true; |
| |
| // Bail if a phi in the inner latch feeds the exit condition, walking operands |
| // within the inner loop. |
| SmallSetVector<Instruction *, 8> Worklist; |
| Worklist.insert(CondI); |
| for (unsigned I = 0; I < Worklist.size(); ++I) { |
| Instruction *Cur = Worklist[I]; |
| if (isa<PHINode>(Cur) && Cur->getParent() == InnerLoopLatch) |
| return false; |
| for (Value *Op : Cur->operands()) |
| if (auto *OpI = dyn_cast<Instruction>(Op)) |
| if (InnerLoop->contains(OpI)) |
| Worklist.insert(OpI); |
| } |
| return true; |
| } |
| |
| bool LoopInterchangeLegality::canInterchangeLoops(unsigned InnerLoopId, |
| unsigned OuterLoopId, |
| CharMatrix &DepMatrix) { |
| if (!isLegalToInterChangeLoops(DepMatrix, InnerLoopId, OuterLoopId)) { |
| LLVM_DEBUG(dbgs() << "Failed interchange InnerLoopId = " << InnerLoopId |
| << " and OuterLoopId = " << OuterLoopId |
| << " due to dependence\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "Dependence", |
| InnerLoop->getStartLoc(), |
| InnerLoop->getHeader()) |
| << "Cannot interchange loops due to dependences."; |
| }); |
| return false; |
| } |
| // Check if outer and inner loop contain legal instructions only. |
| for (auto *BB : OuterLoop->blocks()) |
| for (Instruction &I : *BB) { |
| // Loads and stores are checked separately, so we can skip them here. |
| if (isa<LoadInst, StoreInst, PseudoProbeInst>(&I)) |
| continue; |
| |
| // We cannot ignore potential memory reads, e.g., loads inside the called |
| // function. |
| if (!I.mayHaveSideEffects() && !I.mayReadFromMemory()) |
| continue; |
| |
| LLVM_DEBUG( |
| dbgs() |
| << "Loops contain instructions that cannot be safely interchanged\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsafeInst", |
| I.getDebugLoc(), I.getParent()) |
| << "Cannot interchange loops due to instruction that is " |
| "potentially unsafe to interchange."; |
| }); |
| |
| return false; |
| } |
| |
| if (!checkInductionsAndReductions(OuterLoop)) { |
| LLVM_DEBUG(dbgs() << "Failed to find inner loop inductions or found " |
| "unsupported reductions.\n"); |
| return false; |
| } |
| |
| if (!areInnerLoopLatchPHIsSupported(InnerLoop)) { |
| LLVM_DEBUG(dbgs() << "Found unsupported PHI nodes in inner loop latch.\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedInnerLatchPHI", |
| InnerLoop->getStartLoc(), |
| InnerLoop->getHeader()) |
| << "Cannot interchange loops because unsupported PHI nodes found " |
| "in inner loop latch."; |
| }); |
| return false; |
| } |
| |
| // TODO: The loops could not be interchanged due to current limitations in the |
| // transform module. |
| if (currentLimitations()) { |
| LLVM_DEBUG(dbgs() << "Not legal because of current transform limitation\n"); |
| return false; |
| } |
| |
| // Check if the loops are tightly nested. |
| if (!tightlyNested(OuterLoop, InnerLoop)) { |
| LLVM_DEBUG(dbgs() << "Loops not tightly nested\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "NotTightlyNested", |
| InnerLoop->getStartLoc(), |
| InnerLoop->getHeader()) |
| << "Cannot interchange loops because they are not tightly " |
| "nested."; |
| }); |
| return false; |
| } |
| |
| // The LCSSA PHI for the reduction has passed checks before; its user |
| // is a store instruction. |
| PHINode *LcssaReduction = nullptr; |
| assert(InnerReductions.size() <= 1 && |
| "So far we only support at most one reduction."); |
| if (InnerReductions.size() == 1) |
| LcssaReduction = InnerReductions[0].LcssaPhi; |
| |
| if (!areInnerLoopExitPHIsSupported(OuterLoop, InnerLoop, OuterInnerReductions, |
| LcssaReduction)) { |
| LLVM_DEBUG(dbgs() << "Found unsupported PHI nodes in inner loop exit.\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedExitPHI", |
| InnerLoop->getStartLoc(), |
| InnerLoop->getHeader()) |
| << "Found unsupported PHI node in loop exit."; |
| }); |
| return false; |
| } |
| |
| if (!areOuterLoopExitPHIsSupported(OuterLoop, InnerLoop)) { |
| LLVM_DEBUG(dbgs() << "Found unsupported PHI nodes in outer loop exit.\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedExitPHI", |
| OuterLoop->getStartLoc(), |
| OuterLoop->getHeader()) |
| << "Found unsupported PHI node in loop exit."; |
| }); |
| return false; |
| } |
| |
| if (any_of(OuterLoop->getLoopLatch()->phis(), |
| [](PHINode &PHI) { return PHI.getNumIncomingValues() != 1; })) { |
| LLVM_DEBUG(dbgs() << "Only outer loop latch PHI nodes with one incoming " |
| "value are supported.\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedLatchPHI", |
| OuterLoop->getStartLoc(), |
| OuterLoop->getHeader()) |
| << "Only outer loop latch PHI nodes with one incoming value are " |
| "supported."; |
| }); |
| return false; |
| } |
| |
| // Regarding def-use chains that begin at an LCSSA PHI in the inner loop exit |
| // and end at any instruction in the outer loop latch, we currently support |
| // only the case where the chain contains only PHI nodes. Since we already |
| // call `tightlyNested()`, we know that if there is a def-use chain that we |
| // don't support (i.e., a chain that contains a non-PHI user), then the |
| // non-PHI user must be in the outer loop latch. |
| if (InnerLoop->getExitBlock() != OuterLoop->getLoopLatch()) |
| for (PHINode &PHI : OuterLoop->getLoopLatch()->phis()) |
| if (any_of(PHI.users(), [](const User *U) { return !isa<PHINode>(U); })) { |
| LLVM_DEBUG(dbgs() << "Outer loop latch PHI has a non-PHI user.\n"); |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedLatchPHI", |
| OuterLoop->getStartLoc(), |
| OuterLoop->getHeader()) |
| << "Cannot interchange loops because an outer loop latch PHI " |
| "node has a non-PHI user."; |
| }); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void CacheCostManager::computeIfUnitinialized() { |
| if (CC.has_value()) |
| return; |
| |
| LLVM_DEBUG(dbgs() << "Compute CacheCost.\n"); |
| CC = CacheCost::getCacheCost(*OutermostLoop, *AR, *DI); |
| // Obtain the loop vector returned from loop cache analysis beforehand, |
| // and put each <Loop, index> pair into a map for constant time query |
| // later. Indices in loop vector reprsent the optimal order of the |
| // corresponding loop, e.g., given a loopnest with depth N, index 0 |
| // indicates the loop should be placed as the outermost loop and index N |
| // indicates the loop should be placed as the innermost loop. |
| // |
| // For the old pass manager CacheCost would be null. |
| if (*CC != nullptr) |
| for (const auto &[Idx, Cost] : enumerate((*CC)->getLoopCosts())) |
| CostMap[Cost.first] = Idx; |
| } |
| |
| CacheCost *CacheCostManager::getCacheCost() { |
| computeIfUnitinialized(); |
| return CC->get(); |
| } |
| |
| const DenseMap<const Loop *, unsigned> &CacheCostManager::getCostMap() { |
| computeIfUnitinialized(); |
| return CostMap; |
| } |
| |
| /// If \S contains an affine addrec for \p L, return the step recurrence of it. |
| /// If \S is loop invariant with respect to \p L, return nullptr. Otherwise, |
| /// return std::nullopt, which indicates we cannot determine the coefficient of |
| /// the addrec for \p L in \S. |
| /// TODO: Handle more complex cases. Maybe using SCEVTraversal is a good way to |
| /// do that. |
| static std::optional<const SCEV *> |
| getAddRecCoefficient(ScalarEvolution &SE, const SCEV *S, const Loop *L) { |
| const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(S); |
| if (!AR) { |
| if (SE.isLoopInvariant(S, L)) |
| return nullptr; |
| return std::nullopt; |
| } |
| |
| if (!AR->isAffine()) { |
| LLVM_DEBUG(dbgs() << "Unexpected non-affine addrec\n"); |
| return std::nullopt; |
| } |
| |
| std::optional<const SCEV *> Coeff = |
| getAddRecCoefficient(SE, AR->getStart(), L); |
| if (!Coeff.has_value()) |
| return std::nullopt; |
| |
| if (AR->getLoop() == L) { |
| assert(!*Coeff && "Found more than one addrec for the same loop"); |
| Coeff = AR->getStepRecurrence(SE); |
| } |
| return Coeff; |
| } |
| |
| int LoopInterchangeProfitability::getInstrOrderCost() { |
| SmallPtrSet<const SCEV *, 4> GoodBasePtrs, BadBasePtrs; |
| for (BasicBlock *BB : InnerLoop->blocks()) { |
| for (Instruction &Ins : *BB) { |
| if (!isa<LoadInst, StoreInst>(&Ins)) |
| continue; |
| const SCEV *Access = SE->getSCEV(getLoadStorePointerOperand(&Ins)); |
| const SCEV *BasePtr = SE->getPointerBase(Access); |
| std::optional<const SCEV *> OuterCoeff = |
| getAddRecCoefficient(*SE, Access, OuterLoop); |
| std::optional<const SCEV *> InnerCoeff = |
| getAddRecCoefficient(*SE, Access, InnerLoop); |
| |
| if (!OuterCoeff.has_value() || !*OuterCoeff || !InnerCoeff.has_value() || |
| !*InnerCoeff) |
| continue; |
| |
| // This heuristic assumes that a smaller step recurrence implies that the |
| // induction variable corresponding to the loop is used in the inner |
| // dimension of the array. Placing such a loop in the inner position would |
| // be beneficial in terms of locality. If the array access is of the form |
| // like `A[3*i + 2*j]`, this heuristic may lead to an unprofitable |
| // interchange, but we expect such cases to be rare. |
| const SCEV *OuterStep = SE->getAbsExpr(*OuterCoeff, /*IsNSW=*/false); |
| const SCEV *InnerStep = SE->getAbsExpr(*InnerCoeff, /*IsNSW=*/false); |
| // If we find the inner induction after an outer induction e.g. |
| // |
| // for(int i=0;i<N;i++) |
| // for(int j=0;j<N;j++) |
| // A[i][j] = A[i-1][j-1]+k; |
| // |
| // |
| // then it is a good order. If we find the outer induction after an inner |
| // induction e.g. |
| // |
| // for(int i=0;i<N;i++) |
| // for(int j=0;j<N;j++) |
| // A[j][i] = A[j-1][i-1]+k; |
| // |
| // then it is a bad order. |
| // |
| // To avoid counting the same base pointers multiple times, we deduplicate |
| // them by using a set of base pointers. |
| if (SE->isKnownPredicate(ICmpInst::ICMP_SLT, InnerStep, OuterStep)) |
| GoodBasePtrs.insert(BasePtr); |
| else if (SE->isKnownPredicate(ICmpInst::ICMP_SLT, OuterStep, InnerStep)) |
| BadBasePtrs.insert(BasePtr); |
| } |
| } |
| |
| int GoodOrder = GoodBasePtrs.size(); |
| int BadOrder = BadBasePtrs.size(); |
| return GoodOrder - BadOrder; |
| } |
| |
| std::optional<bool> |
| LoopInterchangeProfitability::isProfitablePerLoopCacheAnalysis( |
| const DenseMap<const Loop *, unsigned> &CostMap, CacheCost *CC) { |
| // This is the new cost model returned from loop cache analysis. |
| // A smaller index means the loop should be placed an outer loop, and vice |
| // versa. |
| auto InnerLoopIt = CostMap.find(InnerLoop); |
| if (InnerLoopIt == CostMap.end()) |
| return std::nullopt; |
| auto OuterLoopIt = CostMap.find(OuterLoop); |
| if (OuterLoopIt == CostMap.end()) |
| return std::nullopt; |
| |
| if (CC->getLoopCost(*OuterLoop) == CC->getLoopCost(*InnerLoop)) |
| return std::nullopt; |
| unsigned InnerIndex = InnerLoopIt->second; |
| unsigned OuterIndex = OuterLoopIt->second; |
| LLVM_DEBUG(dbgs() << "InnerIndex = " << InnerIndex |
| << ", OuterIndex = " << OuterIndex << "\n"); |
| assert(InnerIndex != OuterIndex && "CostMap should assign unique " |
| "numbers to each loop"); |
| return std::optional<bool>(InnerIndex < OuterIndex); |
| } |
| |
| std::optional<bool> |
| LoopInterchangeProfitability::isProfitablePerInstrOrderCost() { |
| // Legacy cost model: this is rough cost estimation algorithm. It counts the |
| // good and bad order of induction variables in the instruction and allows |
| // reordering if number of bad orders is more than good. |
| int Cost = getInstrOrderCost(); |
| LLVM_DEBUG(dbgs() << "Cost = " << Cost << "\n"); |
| if (Cost < 0 && Cost < LoopInterchangeCostThreshold) |
| return std::optional<bool>(true); |
| |
| return std::nullopt; |
| } |
| |
| /// Return true if we can vectorize the loop specified by \p LoopId. |
| static bool canVectorize(const CharMatrix &DepMatrix, unsigned LoopId) { |
| for (const auto &Dep : DepMatrix) { |
| char Dir = Dep[LoopId]; |
| char DepType = Dep.back(); |
| assert((DepType == '<' || DepType == '*') && |
| "Unexpected element in dependency vector"); |
| |
| // There are no loop-carried dependencies. |
| if (Dir == '=' || Dir == 'I') |
| continue; |
| |
| // DepType being '<' means that this direction vector represents a forward |
| // dependency. In principle, a loop with '<' direction can be vectorized in |
| // this case. |
| if (Dir == '<' && DepType == '<') |
| continue; |
| |
| // We cannot prove that the loop is vectorizable. |
| return false; |
| } |
| return true; |
| } |
| |
| std::optional<bool> LoopInterchangeProfitability::isProfitableForVectorization( |
| unsigned InnerLoopId, unsigned OuterLoopId, CharMatrix &DepMatrix) { |
| // If the outer loop cannot be vectorized, it is not profitable to move this |
| // to inner position. |
| if (!canVectorize(DepMatrix, OuterLoopId)) |
| return false; |
| |
| // If the inner loop cannot be vectorized but the outer loop can be, then it |
| // is profitable to interchange to enable inner loop parallelism. |
| if (!canVectorize(DepMatrix, InnerLoopId)) |
| return true; |
| |
| // If both the inner and the outer loop can be vectorized, it is necessary to |
| // check the cost of each vectorized loop for profitability decision. At this |
| // time we do not have a cost model to estimate them, so return nullopt. |
| // TODO: Estimate the cost of vectorized loop when both the outer and the |
| // inner loop can be vectorized. |
| return std::nullopt; |
| } |
| |
| bool LoopInterchangeProfitability::isProfitable( |
| const Loop *InnerLoop, const Loop *OuterLoop, unsigned InnerLoopId, |
| unsigned OuterLoopId, CharMatrix &DepMatrix, CacheCostManager &CCM) { |
| // Do not consider loops with a backedge that isn't taken, e.g. an |
| // unconditional branch true/false, as candidates for interchange. |
| // TODO: when interchange is forced, we should probably also allow |
| // interchange for these loops, and thus this logic should be moved just |
| // below the cost-model ignore check below. But this check is done first |
| // to avoid the issue in #163954. |
| const SCEV *InnerBTC = SE->getBackedgeTakenCount(InnerLoop); |
| const SCEV *OuterBTC = SE->getBackedgeTakenCount(OuterLoop); |
| if (InnerBTC && InnerBTC->isZero()) { |
| LLVM_DEBUG(dbgs() << "Inner loop back-edge isn't taken, rejecting " |
| "single iteration loop\n"); |
| return false; |
| } |
| if (OuterBTC && OuterBTC->isZero()) { |
| LLVM_DEBUG(dbgs() << "Outer loop back-edge isn't taken, rejecting " |
| "single iteration loop\n"); |
| return false; |
| } |
| |
| // Return true if interchange is forced and the cost-model ignored. |
| if (Profitabilities.size() == 1 && Profitabilities[0] == RuleTy::Ignore) |
| return true; |
| assert(noDuplicateRulesAndIgnore(Profitabilities) && |
| "Duplicate rules and option 'ignore' are not allowed"); |
| |
| // isProfitable() is structured to avoid endless loop interchange. If the |
| // highest priority rule (isProfitablePerLoopCacheAnalysis by default) could |
| // decide the profitability then, profitability check will stop and return the |
| // analysis result. If it failed to determine it (e.g., cache analysis failed |
| // to analyze the loopnest due to delinearization issues) then go ahead the |
| // second highest priority rule (isProfitablePerInstrOrderCost by default). |
| // Likewise, if it failed to analysis the profitability then only, the last |
| // rule (isProfitableForVectorization by default) will decide. |
| std::optional<bool> shouldInterchange; |
| for (RuleTy RT : Profitabilities) { |
| switch (RT) { |
| case RuleTy::PerLoopCacheAnalysis: { |
| CacheCost *CC = CCM.getCacheCost(); |
| const DenseMap<const Loop *, unsigned> &CostMap = CCM.getCostMap(); |
| shouldInterchange = isProfitablePerLoopCacheAnalysis(CostMap, CC); |
| break; |
| } |
| case RuleTy::PerInstrOrderCost: |
| shouldInterchange = isProfitablePerInstrOrderCost(); |
| break; |
| case RuleTy::ForVectorization: |
| shouldInterchange = |
| isProfitableForVectorization(InnerLoopId, OuterLoopId, DepMatrix); |
| break; |
| case RuleTy::Ignore: |
| llvm_unreachable("Option 'ignore' is not supported with other options"); |
| break; |
| } |
| |
| // If this rule could determine the profitability, don't call subsequent |
| // rules. |
| if (shouldInterchange.has_value()) |
| break; |
| } |
| |
| if (!shouldInterchange.has_value()) { |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "InterchangeNotProfitable", |
| InnerLoop->getStartLoc(), |
| InnerLoop->getHeader()) |
| << "Insufficient information to calculate the cost of loop for " |
| "interchange."; |
| }); |
| return false; |
| } else if (!shouldInterchange.value()) { |
| ORE->emit([&]() { |
| return OptimizationRemarkMissed(DEBUG_TYPE, "InterchangeNotProfitable", |
| InnerLoop->getStartLoc(), |
| InnerLoop->getHeader()) |
| << "Interchanging loops is not considered to improve cache " |
| "locality nor vectorization."; |
| }); |
| return false; |
| } |
| return true; |
| } |
| |
| void LoopInterchangeTransform::removeChildLoop(Loop *OuterLoop, |
| Loop *InnerLoop) { |
| for (Loop *L : *OuterLoop) |
| if (L == InnerLoop) { |
| OuterLoop->removeChildLoop(L); |
| return; |
| } |
| llvm_unreachable("Couldn't find loop"); |
| } |
| |
| /// Update LoopInfo, after interchanging. NewInner and NewOuter refer to the |
| /// new inner and outer loop after interchanging: NewInner is the original |
| /// outer loop and NewOuter is the original inner loop. |
| /// |
| /// Before interchanging, we have the following structure |
| /// Outer preheader |
| // Outer header |
| // Inner preheader |
| // Inner header |
| // Inner body |
| // Inner latch |
| // outer bbs |
| // Outer latch |
| // |
| // After interchanging: |
| // Inner preheader |
| // Inner header |
| // Outer preheader |
| // Outer header |
| // Inner body |
| // outer bbs |
| // Outer latch |
| // Inner latch |
| void LoopInterchangeTransform::restructureLoops( |
| Loop *NewInner, Loop *NewOuter, BasicBlock *OrigInnerPreHeader, |
| BasicBlock *OrigOuterPreHeader) { |
| Loop *OuterLoopParent = OuterLoop->getParentLoop(); |
| // The original inner loop preheader moves from the new inner loop to |
| // the parent loop, if there is one. |
| NewInner->removeBlockFromLoop(OrigInnerPreHeader); |
| LI->changeLoopFor(OrigInnerPreHeader, OuterLoopParent); |
| |
| // Switch the loop levels. |
| if (OuterLoopParent) { |
| // Remove the loop from its parent loop. |
| removeChildLoop(OuterLoopParent, NewInner); |
| removeChildLoop(NewInner, NewOuter); |
| OuterLoopParent->addChildLoop(NewOuter); |
| } else { |
| removeChildLoop(NewInner, NewOuter); |
| LI->changeTopLevelLoop(NewInner, NewOuter); |
| } |
| while (!NewOuter->isInnermost()) |
| NewInner->addChildLoop(NewOuter->removeChildLoop(NewOuter->begin())); |
| NewOuter->addChildLoop(NewInner); |
| |
| // BBs from the original inner loop. |
| SmallVector<BasicBlock *, 8> OrigInnerBBs(NewOuter->blocks()); |
| |
| // Add BBs from the original outer loop to the original inner loop (excluding |
| // BBs already in inner loop) |
| for (BasicBlock *BB : NewInner->blocks()) |
| if (LI->getLoopFor(BB) == NewInner) |
| NewOuter->addBlockEntry(BB); |
| |
| // Now remove inner loop header and latch from the new inner loop and move |
| // other BBs (the loop body) to the new inner loop. |
| BasicBlock *OuterHeader = NewOuter->getHeader(); |
| BasicBlock *OuterLatch = NewOuter->getLoopLatch(); |
| for (BasicBlock *BB : OrigInnerBBs) { |
| // Nothing will change for BBs in child loops. |
| if (LI->getLoopFor(BB) != NewOuter) |
| continue; |
| // Remove the new outer loop header and latch from the new inner loop. |
| if (BB == OuterHeader || BB == OuterLatch) |
| NewInner->removeBlockFromLoop(BB); |
| else |
| LI->changeLoopFor(BB, NewInner); |
| } |
| |
| // The preheader of the original outer loop becomes part of the new |
| // outer loop. |
| NewOuter->addBlockEntry(OrigOuterPreHeader); |
| LI->changeLoopFor(OrigOuterPreHeader, NewOuter); |
| |
| // Tell SE that we move the loops around. |
| SE->forgetLoop(NewOuter); |
| } |
| |
| /// User can write, or optimizers can generate the reduction for inner loop. |
| /// To make the interchange valid, apply Reduction2Mem by moving the |
| /// initializer and store instructions into the inner loop. So far we only |
| /// handle cases where the reduction variable is initialized to a constant. |
| /// For example, below code: |
| /// |
| /// loop: |
| /// re = phi<0.0, next> |
| /// next = re op ... |
| /// endloop |
| /// reduc_sum = phi<next> // lcssa phi |
| /// MEM_REF[idx] = reduc_sum // LcssaStore |
| /// |
| /// is transformed into: |
| /// |
| /// loop: |
| /// tmp = MEM_REF[idx]; |
| /// new_var = !first_iteration ? tmp : 0.0; |
| /// next = new_var op ... |
| /// MEM_REF[idx] = next; // after moving |
| /// endloop |
| /// |
| /// In this way the initial const is used in the first iteration of loop. |
| void LoopInterchangeTransform::reduction2Memory() { |
| ArrayRef<LoopInterchangeLegality::InnerReduction> InnerReductions = |
| LIL.getInnerReductions(); |
| |
| assert(InnerReductions.size() == 1 && |
| "So far we only support at most one reduction."); |
| |
| LoopInterchangeLegality::InnerReduction SR = InnerReductions[0]; |
| BasicBlock *InnerLoopHeader = InnerLoop->getHeader(); |
| IRBuilder<> Builder(InnerLoopHeader, InnerLoopHeader->getFirstNonPHIIt()); |
| |
| // Check if it's the first iteration. |
| LLVMContext &Context = InnerLoopHeader->getContext(); |
| PHINode *FirstIter = |
| Builder.CreatePHI(Type::getInt1Ty(Context), 2, "first.iter"); |
| FirstIter->addIncoming(ConstantInt::get(Type::getInt1Ty(Context), 1), |
| InnerLoop->getLoopPreheader()); |
| FirstIter->addIncoming(ConstantInt::get(Type::getInt1Ty(Context), 0), |
| InnerLoop->getLoopLatch()); |
| assert(FirstIter->isComplete() && "The FirstIter PHI node is not complete."); |
| |
| // When the reduction is initialized from a constant value, we need to add |
| // a stmt loading from the memory object to target basic block in inner |
| // loop. |
| Instruction *LoadMem = Builder.CreateLoad(SR.ElemTy, SR.MemRef); |
| |
| // Init new_var to MEM_REF or CONST depending on if it is the first iteration. |
| Value *NewVar = Builder.CreateSelect(FirstIter, SR.Init, LoadMem, "new.var"); |
| |
| // Replace all uses of the reduction variable with a new variable. |
| SR.Reduction->replaceAllUsesWith(NewVar); |
| |
| // Move store instruction into inner loop, just after reduction next's |
| // definition. |
| SR.LcssaStore->setOperand(0, SR.Next); |
| SR.LcssaStore->moveAfter(dyn_cast<Instruction>(SR.Next)); |
| } |
| |
| void LoopInterchangeTransform::transform( |
| ArrayRef<Instruction *> DropNoWrapInsts, |
| ArrayRef<Instruction *> DropNoInfInsts) { |
| |
| ArrayRef<LoopInterchangeLegality::InnerReduction> InnerReductions = |
| LIL.getInnerReductions(); |
| if (InnerReductions.size() == 1) |
| reduction2Memory(); |
| |
| LLVM_DEBUG(dbgs() << "Splitting the inner loop latch\n"); |
| auto &InductionPHIs = LIL.getInnerLoopInductions(); |
| assert(!InductionPHIs.empty() && |
| "Expected at least one induction variable in the inner loop"); |
| |
| SmallVector<Instruction *, 8> InnerIndexVarList; |
| for (PHINode *CurInductionPHI : InductionPHIs) { |
| Instruction *IncomingValue = dyn_cast<Instruction>( |
| CurInductionPHI->getIncomingValueForBlock(InnerLoop->getLoopLatch())); |
| assert(IncomingValue && |
| "Incoming value from loop latch isn't an instruction"); |
| if (is_contained(InductionPHIs, IncomingValue)) |
| continue; |
| InnerIndexVarList.push_back(IncomingValue); |
| } |
| |
| // Create a new latch block for the inner loop. We split at the |
| // current latch's terminator and then move the condition and all |
| // operands that are not either loop-invariant or the induction PHI into the |
| // new latch block. |
| BasicBlock *NewLatch = |
| SplitBlock(InnerLoop->getLoopLatch(), |
| InnerLoop->getLoopLatch()->getTerminator(), DT, LI); |
| |
| SmallSetVector<Instruction *, 4> WorkList; |
| unsigned i = 0; |
| auto MoveInstructions = [&i, &WorkList, this, &InductionPHIs, NewLatch]() { |
| for (; i < WorkList.size(); i++) { |
| // PHI nodes cannot be cloned and moved here; the legality check |
| // (areInnerLoopLatchPHIsSupported) ensures none reach the worklist. |
| assert(!isa<PHINode>(WorkList[i]) && |
| "MoveInstructions does not support PHI nodes"); |
| // Duplicate instruction and move it to the new latch. Update uses that |
| // have been moved. |
| Instruction *NewI = WorkList[i]->clone(); |
| NewI->insertBefore(NewLatch->getFirstNonPHIIt()); |
| assert(!NewI->mayHaveSideEffects() && |
| "Moving instructions with side-effects may change behavior of " |
| "the loop nest!"); |
| for (Use &U : llvm::make_early_inc_range(WorkList[i]->uses())) { |
| Instruction *UserI = cast<Instruction>(U.getUser()); |
| if (!InnerLoop->contains(UserI->getParent()) || |
| UserI->getParent() == NewLatch || |
| llvm::is_contained(InductionPHIs, UserI)) |
| U.set(NewI); |
| } |
| // Add operands of moved instruction to the worklist, except if they are |
| // outside the inner loop or are the induction PHI. |
| for (Value *Op : WorkList[i]->operands()) { |
| Instruction *OpI = dyn_cast<Instruction>(Op); |
| if (!OpI || this->LI->getLoopFor(OpI->getParent()) != this->InnerLoop || |
| llvm::is_contained(InductionPHIs, OpI)) |
| continue; |
| WorkList.insert(OpI); |
| } |
| } |
| }; |
| |
| // FIXME: Should we interchange when we have a constant condition? |
| Instruction *CondI = dyn_cast<Instruction>( |
| cast<CondBrInst>(InnerLoop->getLoopLatch()->getTerminator()) |
| ->getCondition()); |
| if (CondI) |
| WorkList.insert(CondI); |
| MoveInstructions(); |
| for (Instruction *InnerIndexVar : InnerIndexVarList) |
| WorkList.insert(cast<Instruction>(InnerIndexVar)); |
| MoveInstructions(); |
| |
| // Split the inner header so that it has a unique successor. |
| BasicBlock *InnerLoopHeader = InnerLoop->getHeader(); |
| SplitBlock(InnerLoopHeader, InnerLoopHeader->getFirstNonPHIIt(), DT, LI); |
| LLVM_DEBUG(dbgs() << "splitting InnerLoopHeader done\n"); |
| |
| // Instructions in the original inner loop preheader may depend on values |
| // defined in the outer loop header. Move them there, because the original |
| // inner loop preheader will become the entry into the interchanged loop nest. |
| // Currently we move all instructions and rely on LICM to move invariant |
| // instructions outside the loop nest. |
| BasicBlock *InnerLoopPreHeader = InnerLoop->getLoopPreheader(); |
| BasicBlock *OuterLoopHeader = OuterLoop->getHeader(); |
| |
| if (InnerLoopPreHeader != OuterLoopHeader) { |
| // Eliminate PHIs in the inner-loop preheader. |
| for (PHINode &P : make_early_inc_range(InnerLoopPreHeader->phis())) { |
| assert(all_equal(P.incoming_values()) && |
| "Expected equivalent incoming values in inner loop preheader"); |
| P.replaceAllUsesWith(P.getIncomingValue(0)); |
| P.eraseFromParent(); |
| } |
| for (Instruction &I : |
| make_early_inc_range(make_range(InnerLoopPreHeader->begin(), |
| std::prev(InnerLoopPreHeader->end())))) |
| I.moveBeforePreserving(OuterLoopHeader->getTerminator()->getIterator()); |
| } |
| |
| adjustLoopLinks(); |
| |
| // Finally, drop the nsw/nuw/ninf flags from the instructions for reduction |
| // calculations. |
| for (Instruction *Reduction : DropNoWrapInsts) { |
| Reduction->setHasNoSignedWrap(false); |
| Reduction->setHasNoUnsignedWrap(false); |
| } |
| for (Instruction *I : DropNoInfInsts) |
| I->setHasNoInfs(false); |
| } |
| |
| /// \brief Move all instructions except the terminator from FromBB right before |
| /// InsertBefore |
| static void moveBBContents(BasicBlock *FromBB, Instruction *InsertBefore) { |
| BasicBlock *ToBB = InsertBefore->getParent(); |
| |
| ToBB->splice(InsertBefore->getIterator(), FromBB, FromBB->begin(), |
| FromBB->getTerminator()->getIterator()); |
| } |
| |
| /// Swap instructions between \p BB1 and \p BB2 but keep terminators intact. |
| static void swapBBContents(BasicBlock *BB1, BasicBlock *BB2) { |
| // Save all non-terminator instructions of BB1 into TempInstrs and unlink them |
| // from BB1 afterwards. |
| auto Iter = map_range(*BB1, [](Instruction &I) { return &I; }); |
| SmallVector<Instruction *, 4> TempInstrs(Iter.begin(), std::prev(Iter.end())); |
| for (Instruction *I : TempInstrs) |
| I->removeFromParent(); |
| |
| // Move instructions from BB2 to BB1. |
| moveBBContents(BB2, BB1->getTerminator()); |
| |
| // Move instructions from TempInstrs to BB2. |
| for (Instruction *I : TempInstrs) |
| I->insertBefore(BB2->getTerminator()->getIterator()); |
| } |
| |
| // Update BI to jump to NewBB instead of OldBB. Records updates to the |
| // dominator tree in DTUpdates. If \p MustUpdateOnce is true, assert that |
| // \p OldBB is exactly once in BI's successor list. |
| static void updateSuccessor(Instruction *Term, BasicBlock *OldBB, |
| BasicBlock *NewBB, |
| std::vector<DominatorTree::UpdateType> &DTUpdates, |
| bool MustUpdateOnce = true) { |
| assert((!MustUpdateOnce || llvm::count(successors(Term), OldBB) == 1) && |
| "BI must jump to OldBB exactly once."); |
| bool Changed = false; |
| for (Use &Op : Term->operands()) |
| if (Op == OldBB) { |
| Op.set(NewBB); |
| Changed = true; |
| } |
| |
| if (Changed) { |
| DTUpdates.push_back( |
| {DominatorTree::UpdateKind::Insert, Term->getParent(), NewBB}); |
| DTUpdates.push_back( |
| {DominatorTree::UpdateKind::Delete, Term->getParent(), OldBB}); |
| } |
| assert(Changed && "Expected a successor to be updated"); |
| } |
| |
| // Move Lcssa PHIs to the right place. |
| static void moveLCSSAPhis(BasicBlock *InnerExit, BasicBlock *InnerHeader, |
| BasicBlock *InnerLatch, BasicBlock *OuterHeader, |
| BasicBlock *OuterLatch, BasicBlock *OuterExit, |
| Loop *InnerLoop, LoopInfo *LI) { |
| |
| // Deal with LCSSA PHI nodes in the exit block of the inner loop, that are |
| // defined either in the header or latch. Those blocks will become header and |
| // latch of the new outer loop, and the only possible users can PHI nodes |
| // in the exit block of the loop nest or the outer loop header (reduction |
| // PHIs, in that case, the incoming value must be defined in the inner loop |
| // header). We can just substitute the user with the incoming value and remove |
| // the PHI. |
| for (PHINode &P : make_early_inc_range(InnerExit->phis())) { |
| assert(P.getNumIncomingValues() == 1 && |
| "Only loops with a single exit are supported!"); |
| |
| Value *IncomingValue = P.getIncomingValueForBlock(InnerLatch); |
| auto *IncI = dyn_cast<Instruction>(IncomingValue); |
| if (!IncI) { |
| // If the incoming value is not an instruction, it must be loop invariant. |
| // In that case, we can just replace the PHI with the incoming value and |
| // remove the PHI. |
| assert(InnerLoop->isLoopInvariant(IncomingValue) && |
| "Expected non-instruction incoming value to be loop invariant"); |
| P.replaceAllUsesWith(IncomingValue); |
| P.eraseFromParent(); |
| continue; |
| } |
| |
| // In case of multi-level nested loops, follow LCSSA to find the incoming |
| // value defined from the innermost loop. |
| auto *IncIInnerMost = dyn_cast<Instruction>(followLCSSA(IncI)); |
| // Skip phis when: |
| // - they are not an instruction, e.g. incoming values are constants. |
| // - Incomming values from the inner loop body, excluding the header and |
| // latch. |
| if (!IncIInnerMost || (IncIInnerMost->getParent() != InnerLatch && |
| IncIInnerMost->getParent() != InnerHeader)) |
| continue; |
| |
| assert(all_of(P.users(), |
| [OuterHeader, OuterExit, IncI, InnerHeader](User *U) { |
| return (cast<PHINode>(U)->getParent() == OuterHeader && |
| IncI->getParent() == InnerHeader) || |
| cast<PHINode>(U)->getParent() == OuterExit; |
| }) && |
| "Can only replace phis iff the uses are in the loop nest exit or " |
| "the incoming value is defined in the inner header (it will " |
| "dominate all loop blocks after interchanging)"); |
| P.replaceAllUsesWith(IncI); |
| P.eraseFromParent(); |
| } |
| |
| SmallVector<PHINode *, 8> LcssaInnerExit( |
| llvm::make_pointer_range(InnerExit->phis())); |
| |
| SmallVector<PHINode *, 8> LcssaInnerLatch( |
| llvm::make_pointer_range(InnerLatch->phis())); |
| |
| // Lcssa PHIs for values used outside the inner loop are in InnerExit. |
| // If a PHI node has users outside of InnerExit, it has a use outside the |
| // interchanged loop and we have to preserve it. We move these to |
| // InnerLatch, which will become the new exit block for the innermost |
| // loop after interchanging. |
| for (PHINode *P : LcssaInnerExit) |
| P->moveBefore(InnerLatch->getFirstNonPHIIt()); |
| |
| // If the inner loop latch contains LCSSA PHIs, those come from a child loop |
| // and we have to move them to the new inner latch. |
| for (PHINode *P : LcssaInnerLatch) |
| P->moveBefore(InnerExit->getFirstNonPHIIt()); |
| |
| // Deal with LCSSA PHI nodes in the loop nest exit block. For PHIs that have |
| // incoming values defined in the outer loop, we have to add a new PHI |
| // in the inner loop latch, which became the exit block of the outer loop, |
| // after interchanging. |
| if (OuterExit) { |
| for (PHINode &P : OuterExit->phis()) { |
| if (P.getNumIncomingValues() != 1) |
| continue; |
| // Skip Phis with incoming values defined in the inner loop. Those should |
| // already have been updated. |
| auto I = dyn_cast<Instruction>(P.getIncomingValue(0)); |
| if (!I || LI->getLoopFor(I->getParent()) == InnerLoop) |
| continue; |
| |
| PHINode *NewPhi = dyn_cast<PHINode>(P.clone()); |
| NewPhi->setIncomingValue(0, P.getIncomingValue(0)); |
| NewPhi->setIncomingBlock(0, OuterLatch); |
| // We might have incoming edges from other BBs, i.e., the original outer |
| // header. |
| for (auto *Pred : predecessors(InnerLatch)) { |
| if (Pred == OuterLatch) |
| continue; |
| NewPhi->addIncoming(P.getIncomingValue(0), Pred); |
| } |
| NewPhi->insertBefore(InnerLatch->getFirstNonPHIIt()); |
| P.setIncomingValue(0, NewPhi); |
| } |
| } |
| |
| // Now adjust the incoming blocks for the LCSSA PHIs. |
| // For PHIs moved from Inner's exit block, we need to replace Inner's latch |
| // with the new latch. |
| InnerLatch->replacePhiUsesWith(InnerLatch, OuterLatch); |
| } |
| |
| /// This deals with a corner case when a LCSSA phi node appears in a non-exit |
| /// block: the outer loop latch block does not need to be exit block of the |
| /// inner loop. Consider a loop that was in LCSSA form, but then some |
| /// transformation like loop-unswitch comes along and creates an empty block, |
| /// where BB5 in this example is the outer loop latch block: |
| /// |
| /// BB4: |
| /// br label %BB5 |
| /// BB5: |
| /// %old.cond.lcssa = phi i16 [ %cond, %BB4 ] |
| /// br outer.header |
| /// |
| /// Interchange then brings it in LCSSA form again resulting in this chain of |
| /// single-input phi nodes: |
| /// |
| /// BB4: |
| /// %new.cond.lcssa = phi i16 [ %cond, %BB3 ] |
| /// br label %BB5 |
| /// BB5: |
| /// %old.cond.lcssa = phi i16 [ %new.cond.lcssa, %BB4 ] |
| /// |
| /// The problem is that interchange can reoder blocks BB4 and BB5 placing the |
| /// use before the def if we don't check this. The solution is to simplify |
| /// lcssa phi nodes (remove) if they appear in non-exit blocks. |
| /// |
| static void simplifyLCSSAPhis(Loop *OuterLoop, Loop *InnerLoop) { |
| BasicBlock *InnerLoopExit = InnerLoop->getExitBlock(); |
| BasicBlock *OuterLoopLatch = OuterLoop->getLoopLatch(); |
| |
| // Do not modify lcssa phis where they actually belong, i.e. in exit blocks. |
| if (OuterLoopLatch == InnerLoopExit) |
| return; |
| |
| // Collect and remove phis in non-exit blocks if they have 1 input. |
| SmallVector<PHINode *, 8> Phis( |
| llvm::make_pointer_range(OuterLoopLatch->phis())); |
| for (PHINode *Phi : Phis) { |
| assert(Phi->getNumIncomingValues() == 1 && "Single input phi expected"); |
| LLVM_DEBUG(dbgs() << "Removing 1-input phi in non-exit block: " << *Phi |
| << "\n"); |
| Phi->replaceAllUsesWith(Phi->getIncomingValue(0)); |
| Phi->eraseFromParent(); |
| } |
| } |
| |
| void LoopInterchangeTransform::adjustLoopBranches() { |
| LLVM_DEBUG(dbgs() << "adjustLoopBranches called\n"); |
| std::vector<DominatorTree::UpdateType> DTUpdates; |
| |
| BasicBlock *OuterLoopPreHeader = OuterLoop->getLoopPreheader(); |
| BasicBlock *InnerLoopPreHeader = InnerLoop->getLoopPreheader(); |
| |
| assert(OuterLoopPreHeader != OuterLoop->getHeader() && |
| InnerLoopPreHeader != InnerLoop->getHeader() && OuterLoopPreHeader && |
| InnerLoopPreHeader && "Guaranteed by loop-simplify form"); |
| |
| simplifyLCSSAPhis(OuterLoop, InnerLoop); |
| |
| // Ensure that both preheaders do not contain PHI nodes and have single |
| // predecessors. This allows us to move them easily. We use |
| // InsertPreHeaderForLoop to create an 'extra' preheader, if the existing |
| // preheaders do not satisfy those conditions. |
| if (isa<PHINode>(OuterLoopPreHeader->begin()) || |
| !OuterLoopPreHeader->getUniquePredecessor()) |
| OuterLoopPreHeader = |
| InsertPreheaderForLoop(OuterLoop, DT, LI, nullptr, true); |
| if (InnerLoopPreHeader == OuterLoop->getHeader()) |
| InnerLoopPreHeader = |
| InsertPreheaderForLoop(InnerLoop, DT, LI, nullptr, true); |
| |
| // Adjust the loop preheader |
| BasicBlock *InnerLoopHeader = InnerLoop->getHeader(); |
| BasicBlock *OuterLoopHeader = OuterLoop->getHeader(); |
| BasicBlock *InnerLoopLatch = InnerLoop->getLoopLatch(); |
| BasicBlock *OuterLoopLatch = OuterLoop->getLoopLatch(); |
| BasicBlock *OuterLoopPredecessor = OuterLoopPreHeader->getUniquePredecessor(); |
| BasicBlock *InnerLoopLatchPredecessor = |
| InnerLoopLatch->getUniquePredecessor(); |
| BasicBlock *InnerLoopLatchSuccessor; |
| BasicBlock *OuterLoopLatchSuccessor; |
| |
| CondBrInst *OuterLoopLatchBI = |
| dyn_cast<CondBrInst>(OuterLoopLatch->getTerminator()); |
| CondBrInst *InnerLoopLatchBI = |
| dyn_cast<CondBrInst>(InnerLoopLatch->getTerminator()); |
| Instruction *OuterLoopHeaderBI = OuterLoopHeader->getTerminator(); |
| Instruction *InnerLoopHeaderBI = InnerLoopHeader->getTerminator(); |
| |
| assert(OuterLoopPredecessor && InnerLoopLatchPredecessor && |
| "Failed to find a unique predecessor"); |
| assert(OuterLoopLatchBI && InnerLoopLatchBI && |
| "Failed to find a conditional branch"); |
| |
| Instruction *InnerLoopLatchPredecessorBI = |
| InnerLoopLatchPredecessor->getTerminator(); |
| Instruction *OuterLoopPredecessorBI = OuterLoopPredecessor->getTerminator(); |
| |
| BasicBlock *InnerLoopHeaderSuccessor = InnerLoopHeader->getUniqueSuccessor(); |
| assert(InnerLoopHeaderSuccessor && |
| "Failed to find a unique successor for the inner loop header"); |
| |
| // Adjust Loop Preheader and headers. |
| // The branches in the outer loop predecessor and the outer loop header can |
| // be unconditional branches or conditional branches with duplicates. Consider |
| // this when updating the successors. |
| updateSuccessor(OuterLoopPredecessorBI, OuterLoopPreHeader, |
| InnerLoopPreHeader, DTUpdates, /*MustUpdateOnce=*/false); |
| // The outer loop header might or might not branch to the outer latch. |
| // We are guaranteed to branch to the inner loop preheader. |
| if (llvm::is_contained(successors(OuterLoopHeaderBI), OuterLoopLatch)) { |
| // In this case the outerLoopHeader should branch to the InnerLoopLatch. |
| updateSuccessor(OuterLoopHeaderBI, OuterLoopLatch, InnerLoopLatch, |
| DTUpdates, |
| /*MustUpdateOnce=*/false); |
| } |
| updateSuccessor(OuterLoopHeaderBI, InnerLoopPreHeader, |
| InnerLoopHeaderSuccessor, DTUpdates, |
| /*MustUpdateOnce=*/false); |
| |
| // Adjust reduction PHI's now that the incoming block has changed. |
| InnerLoopHeaderSuccessor->replacePhiUsesWith(InnerLoopHeader, |
| OuterLoopHeader); |
| |
| updateSuccessor(InnerLoopHeaderBI, InnerLoopHeaderSuccessor, |
| OuterLoopPreHeader, DTUpdates); |
| |
| // -------------Adjust loop latches----------- |
| if (InnerLoopLatchBI->getSuccessor(0) == InnerLoopHeader) |
| InnerLoopLatchSuccessor = InnerLoopLatchBI->getSuccessor(1); |
| else |
| InnerLoopLatchSuccessor = InnerLoopLatchBI->getSuccessor(0); |
| |
| updateSuccessor(InnerLoopLatchPredecessorBI, InnerLoopLatch, |
| InnerLoopLatchSuccessor, DTUpdates); |
| |
| if (OuterLoopLatchBI->getSuccessor(0) == OuterLoopHeader) |
| OuterLoopLatchSuccessor = OuterLoopLatchBI->getSuccessor(1); |
| else |
| OuterLoopLatchSuccessor = OuterLoopLatchBI->getSuccessor(0); |
| |
| updateSuccessor(InnerLoopLatchBI, InnerLoopLatchSuccessor, |
| OuterLoopLatchSuccessor, DTUpdates); |
| updateSuccessor(OuterLoopLatchBI, OuterLoopLatchSuccessor, InnerLoopLatch, |
| DTUpdates); |
| |
| DT->applyUpdates(DTUpdates); |
| restructureLoops(OuterLoop, InnerLoop, InnerLoopPreHeader, |
| OuterLoopPreHeader); |
| |
| moveLCSSAPhis(InnerLoopLatchSuccessor, InnerLoopHeader, InnerLoopLatch, |
| OuterLoopHeader, OuterLoopLatch, InnerLoop->getExitBlock(), |
| InnerLoop, LI); |
| // For PHIs in the exit block of the outer loop, outer's latch has been |
| // replaced by Inners'. |
| OuterLoopLatchSuccessor->replacePhiUsesWith(OuterLoopLatch, InnerLoopLatch); |
| |
| auto &OuterInnerReductions = LIL.getOuterInnerReductions(); |
| // Now update the reduction PHIs in the inner and outer loop headers. |
| SmallVector<PHINode *, 4> InnerLoopPHIs, OuterLoopPHIs; |
| for (PHINode &PHI : InnerLoopHeader->phis()) |
| if (OuterInnerReductions.contains(&PHI)) |
| InnerLoopPHIs.push_back(&PHI); |
| |
| for (PHINode &PHI : OuterLoopHeader->phis()) |
| if (OuterInnerReductions.contains(&PHI)) |
| OuterLoopPHIs.push_back(&PHI); |
| |
| // Now move the remaining reduction PHIs from outer to inner loop header and |
| // vice versa. The PHI nodes must be part of a reduction across the inner and |
| // outer loop and all the remains to do is and updating the incoming blocks. |
| for (PHINode *PHI : OuterLoopPHIs) { |
| LLVM_DEBUG(dbgs() << "Outer loop reduction PHIs:\n"; PHI->dump();); |
| PHI->moveBefore(InnerLoopHeader->getFirstNonPHIIt()); |
| assert(OuterInnerReductions.count(PHI) && "Expected a reduction PHI node"); |
| } |
| for (PHINode *PHI : InnerLoopPHIs) { |
| LLVM_DEBUG(dbgs() << "Inner loop reduction PHIs:\n"; PHI->dump();); |
| PHI->moveBefore(OuterLoopHeader->getFirstNonPHIIt()); |
| assert(OuterInnerReductions.count(PHI) && "Expected a reduction PHI node"); |
| } |
| |
| // Update the incoming blocks for moved PHI nodes. |
| OuterLoopHeader->replacePhiUsesWith(InnerLoopPreHeader, OuterLoopPreHeader); |
| OuterLoopHeader->replacePhiUsesWith(InnerLoopLatch, OuterLoopLatch); |
| InnerLoopHeader->replacePhiUsesWith(OuterLoopPreHeader, InnerLoopPreHeader); |
| InnerLoopHeader->replacePhiUsesWith(OuterLoopLatch, InnerLoopLatch); |
| |
| // Values defined in the outer loop header could be used in the inner loop |
| // latch. In that case, we need to create LCSSA phis for them, because after |
| // interchanging they will be defined in the new inner loop and used in the |
| // new outer loop. |
| SmallVector<Instruction *, 4> MayNeedLCSSAPhis; |
| for (Instruction &I : |
| make_range(OuterLoopHeader->begin(), std::prev(OuterLoopHeader->end()))) |
| MayNeedLCSSAPhis.push_back(&I); |
| formLCSSAForInstructions(MayNeedLCSSAPhis, *DT, *LI, SE); |
| } |
| |
| void LoopInterchangeTransform::adjustLoopLinks() { |
| // Adjust all branches in the inner and outer loop. |
| adjustLoopBranches(); |
| |
| // We have interchanged the preheaders so we need to interchange the data in |
| // the preheaders as well. This is because the content of the inner |
| // preheader was previously executed inside the outer loop. |
| BasicBlock *OuterLoopPreHeader = OuterLoop->getLoopPreheader(); |
| BasicBlock *InnerLoopPreHeader = InnerLoop->getLoopPreheader(); |
| swapBBContents(OuterLoopPreHeader, InnerLoopPreHeader); |
| } |
| |
| PreservedAnalyses LoopInterchangePass::run(LoopNest &LN, |
| LoopAnalysisManager &AM, |
| LoopStandardAnalysisResults &AR, |
| LPMUpdater &U) { |
| Function &F = *LN.getParent(); |
| SmallVector<Loop *, 8> LoopList(LN.getLoops()); |
| |
| OptimizationRemarkEmitter ORE(&F); |
| |
| // Ensure minimum depth of the loop nest to do the interchange. |
| if (!hasSupportedLoopDepth(LoopList, ORE)) |
| return PreservedAnalyses::all(); |
| // Ensure computable loop nest. |
| if (!isComputableLoopNest(&AR.SE, LoopList)) { |
| LLVM_DEBUG(dbgs() << "Not valid loop candidate for interchange\n"); |
| return PreservedAnalyses::all(); |
| } |
| |
| ORE.emit([&]() { |
| return OptimizationRemarkAnalysis(DEBUG_TYPE, "Dependence", |
| LN.getOutermostLoop().getStartLoc(), |
| LN.getOutermostLoop().getHeader()) |
| << "Computed dependence info, invoking the transform."; |
| }); |
| |
| DependenceInfo DI(&F, &AR.AA, &AR.SE, &AR.LI); |
| if (!LoopInterchange(&AR.SE, &AR.LI, &DI, &AR.DT, &AR, &ORE).run(LN)) |
| return PreservedAnalyses::all(); |
| U.markLoopNestChanged(true); |
| return getLoopPassPreservedAnalyses(); |
| } |