diff --git a/llvm/include/llvm/Analysis/DependenceAnalysis.h b/llvm/include/llvm/Analysis/DependenceAnalysis.h --- a/llvm/include/llvm/Analysis/DependenceAnalysis.h +++ b/llvm/include/llvm/Analysis/DependenceAnalysis.h @@ -50,8 +50,10 @@ class Loop; class LoopInfo; class ScalarEvolution; + class PredicatedScalarEvolution; class SCEV; class SCEVConstant; + class SCEVUnionPredicate; class raw_ostream; /// Dependence - This class represents a dependence between two memory @@ -272,8 +274,8 @@ class DependenceInfo { public: DependenceInfo(Function *F, AAResults *AA, ScalarEvolution *SE, - LoopInfo *LI) - : AA(AA), SE(SE), LI(LI), F(F) {} + LoopInfo *LI, PredicatedScalarEvolution *PSE = nullptr) + : AA(AA), SE(SE), PSE(PSE), LI(LI), F(F) {} /// Handle transitive invalidation when the cached analysis results go away. bool invalidate(Function &F, const PreservedAnalyses &PA, @@ -289,6 +291,8 @@ Instruction *Dst, bool PossiblyLoopIndependent); + const SCEVUnionPredicate &getUnionPredicate() const; + /// getSplitIteration - Give a dependence that's splittable at some /// particular level, return the iteration that should be used to split /// the loop. @@ -336,6 +340,7 @@ private: AAResults *AA; ScalarEvolution *SE; + PredicatedScalarEvolution *PSE; LoopInfo *LI; Function *F; diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h --- a/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -205,7 +205,7 @@ FoldingSetNodeIDRef FastID; public: - enum SCEVPredicateKind { P_Union, P_Equal, P_Wrap }; + enum SCEVPredicateKind { P_Union, P_Equal, P_Wrap, P_LessThan }; protected: SCEVPredicateKind Kind; @@ -291,6 +291,35 @@ } }; +/// This class represents an assumption that a SCEV expression is less than +/// another expression and this can be checked at run-time. +class SCEVLessThanPredicate final : public SCEVPredicate { + /// We assume that LHS < RHS. + const SCEV *LHS; + const SCEV *RHS; + +public: + SCEVLessThanPredicate(const FoldingSetNodeIDRef ID, const SCEV *LHS, + const SCEV *RHS); + + /// Implementation of the SCEVPredicate interface + bool implies(const SCEVPredicate *N) const override; + void print(raw_ostream &OS, unsigned Depth = 0) const override; + bool isAlwaysTrue() const override; + const SCEV *getExpr() const override; + + /// Returns the left hand side of the equality. + const SCEV *getLHS() const { return LHS; } + + /// Returns the right hand side of the equality. + const SCEV *getRHS() const { return RHS; } + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static bool classof(const SCEVPredicate *P) { + return P->getKind() == P_LessThan; + } +}; + /// This class represents an assumption made on an AddRec expression. Given an /// affine AddRec expression {a,+,b}, we assume that it has the nssw or nusw /// flags (defined below) in the first X iterations of the loop, where X is a @@ -1162,6 +1191,7 @@ } const SCEVPredicate *getEqualPredicate(const SCEV *LHS, const SCEV *RHS); + const SCEVPredicate *getLessThanPredicate(const SCEV *LHS, const SCEV *RHS); const SCEVPredicate * getWrapPredicate(const SCEVAddRecExpr *AR, diff --git a/llvm/include/llvm/Transforms/Utils/LoopVersioning.h b/llvm/include/llvm/Transforms/Utils/LoopVersioning.h --- a/llvm/include/llvm/Transforms/Utils/LoopVersioning.h +++ b/llvm/include/llvm/Transforms/Utils/LoopVersioning.h @@ -47,6 +47,9 @@ ArrayRef Checks, Loop *L, LoopInfo *LI, DominatorTree *DT, ScalarEvolution *SE); + LoopVersioning(const SCEVUnionPredicate &Preds, Loop *L, LoopInfo *LI, + DominatorTree *DT, ScalarEvolution *SE); + /// Performs the CFG manipulation part of versioning the loop including /// the DominatorTree and LoopInfo updates. /// @@ -137,7 +140,7 @@ GroupToNonAliasingScopeList; /// Analyses used. - const LoopAccessInfo &LAI; + const LoopAccessInfo *LAI; LoopInfo *LI; DominatorTree *DT; ScalarEvolution *SE; diff --git a/llvm/include/llvm/Transforms/Utils/ScalarEvolutionExpander.h b/llvm/include/llvm/Transforms/Utils/ScalarEvolutionExpander.h --- a/llvm/include/llvm/Transforms/Utils/ScalarEvolutionExpander.h +++ b/llvm/include/llvm/Transforms/Utils/ScalarEvolutionExpander.h @@ -288,6 +288,9 @@ /// we are expanding code for a SCEVEqualPredicate. Value *expandEqualPredicate(const SCEVEqualPredicate *Pred, Instruction *Loc); + Value *expandLessThanPredicate(const SCEVLessThanPredicate *Pred, + Instruction *Loc); + /// Generates code that evaluates if the \p AR expression will overflow. Value *generateOverflowCheck(const SCEVAddRecExpr *AR, Instruction *Loc, bool Signed); diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp --- a/llvm/lib/Analysis/DependenceAnalysis.cpp +++ b/llvm/lib/Analysis/DependenceAnalysis.cpp @@ -3311,7 +3311,7 @@ // we can assume that the subscripts do not overlap into neighboring // dimensions and that the number of dimensions matches the number of // subscripts being recovered. - if (!DisableDelinearizationChecks) + if (!DisableDelinearizationChecks && !PSE) return false; Value *SrcPtr = getLoadStorePointerOperand(Src); @@ -3343,6 +3343,51 @@ return false; } + if (!DisableDelinearizationChecks && PSE) { + for (unsigned I = 1, E = SrcSubscripts.size(); I < E; I++) { + const SCEV *SrcIdx = SrcSubscripts[I]; + const SCEV *DstIdx = DstSubscripts[I]; + const SCEV *Const0 = + PSE->getSCEV(ConstantInt::get(SrcGEP->getOperand(I)->getType(), 0)); + const SCEV *ConstSize = PSE->getSCEV( + ConstantInt::get(SrcGEP->getOperand(I)->getType(), SrcSizes[I - 1])); + + if (!SE->isKnownPredicate(CmpInst::ICMP_SGE, SrcIdx, Const0) || + !SE->isKnownPredicate(CmpInst::ICMP_SGE, DstIdx, Const0)) + return false; + + if (!SE->isKnownPredicate(CmpInst::ICMP_SLT, SrcIdx, ConstSize)) { + if (auto *AR = dyn_cast(SrcIdx)) { + const Loop *L = AR->getLoop(); + auto *BTC = SE->getBackedgeTakenCount(L); + if (isa(BTC)) + return false; + auto LastIdx = AR->evaluateAtIteration(BTC, *SE); + if (SE->isKnownPredicate(CmpInst::ICMP_SGE, LastIdx, ConstSize) || + LastIdx == ConstSize) + return false; + PSE->addPredicate(*SE->getLessThanPredicate(LastIdx, ConstSize)); + } else + return false; + } + if (!SE->isKnownPredicate(CmpInst::ICMP_SLT, DstIdx, ConstSize)) { + if (auto *AR = dyn_cast(DstIdx)) { + const Loop *L = AR->getLoop(); + auto *BTC = SE->getBackedgeTakenCount(L); + if (isa(BTC)) + return false; + auto LastIdx = AR->evaluateAtIteration(BTC, *SE); + if (SE->isKnownPredicate(CmpInst::ICMP_SGE, LastIdx, ConstSize) || + LastIdx == ConstSize) + return false; + if (!SE->isKnownPredicate(CmpInst::ICMP_SLT, LastIdx, ConstSize)) + PSE->addPredicate(*SE->getLessThanPredicate(LastIdx, ConstSize)); + } else + return false; + } + } + } + Value *SrcBasePtr = SrcGEP->getOperand(0); Value *DstBasePtr = DstGEP->getOperand(0); while (auto *PCast = dyn_cast(SrcBasePtr)) @@ -3422,7 +3467,7 @@ // and dst. // FIXME: It may be better to record these sizes and add them as constraints // to the dependency checks. - if (!DisableDelinearizationChecks) + if (!DisableDelinearizationChecks && !PSE) for (size_t I = 1; I < Size; ++I) { if (!isKnownNonNegative(SrcSubscripts[I], SrcPtr)) return false; @@ -3857,6 +3902,11 @@ return std::make_unique(std::move(Result)); } +const SCEVUnionPredicate &DependenceInfo::getUnionPredicate() const { + assert(PSE && "can only get predicate if PSE is provided"); + return PSE->getUnionPredicate(); +} + //===----------------------------------------------------------------------===// // getSplitIteration - // Rather than spend rarely-used space recording the splitting iteration diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -12109,8 +12109,9 @@ } Subscripts.push_back(Expr); - if (!(DroppedFirstDim && i == 2)) + if (!(DroppedFirstDim && i == 2)) { Sizes.push_back(ArrayTy->getNumElements()); + } Ty = ArrayTy->getElementType(); } @@ -12881,6 +12882,24 @@ return Eq; } +const SCEVPredicate *ScalarEvolution::getLessThanPredicate(const SCEV *LHS, + const SCEV *RHS) { + FoldingSetNodeID ID; + assert(LHS->getType() == RHS->getType() && + "Type mismatch between LHS and RHS"); + // Unique this node based on the arguments + ID.AddInteger(SCEVPredicate::P_LessThan); + ID.AddPointer(LHS); + ID.AddPointer(RHS); + void *IP = nullptr; + if (const auto *S = UniquePreds.FindNodeOrInsertPos(ID, IP)) + return S; + SCEVLessThanPredicate *Lt = new (SCEVAllocator) + SCEVLessThanPredicate(ID.Intern(SCEVAllocator), LHS, RHS); + UniquePreds.InsertNode(Lt, IP); + return Lt; +} + const SCEVPredicate *ScalarEvolution::getWrapPredicate( const SCEVAddRecExpr *AR, SCEVWrapPredicate::IncrementWrapFlags AddedFlags) { @@ -13067,6 +13086,29 @@ OS.indent(Depth) << "Equal predicate: " << *LHS << " == " << *RHS << "\n"; } +SCEVLessThanPredicate::SCEVLessThanPredicate(const FoldingSetNodeIDRef ID, + const SCEV *LHS, const SCEV *RHS) + : SCEVPredicate(ID, P_LessThan), LHS(LHS), RHS(RHS) { + assert(LHS->getType() == RHS->getType() && "LHS and RHS types don't match"); + assert(LHS != RHS && "LHS and RHS are the same SCEV"); +} + +bool SCEVLessThanPredicate::implies(const SCEVPredicate *N) const { + const auto *Op = dyn_cast(N); + if (!Op) + return false; + + return Op->LHS == LHS && Op->RHS == RHS; +} + +bool SCEVLessThanPredicate::isAlwaysTrue() const { return false; } + +const SCEV *SCEVLessThanPredicate::getExpr() const { return LHS; } + +void SCEVLessThanPredicate::print(raw_ostream &OS, unsigned Depth) const { + OS.indent(Depth) << "Less than predicate: " << *LHS << " < " << *RHS << "\n"; +} + SCEVWrapPredicate::SCEVWrapPredicate(const FoldingSetNodeIDRef ID, const SCEVAddRecExpr *AR, IncrementWrapFlags Flags) diff --git a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp --- a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp +++ b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -85,7 +85,7 @@ "Enable both variants of CFL-AA"))); cl::opt EnableLoopInterchange( - "enable-loopinterchange", cl::init(false), cl::Hidden, + "enable-loopinterchange", cl::init(true), cl::Hidden, cl::desc("Enable the experimental LoopInterchange Pass")); cl::opt EnableUnrollAndJam("enable-unroll-and-jam", cl::init(false), diff --git a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp --- a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp +++ b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/DependenceAnalysis.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopNestAnalysis.h" @@ -47,6 +48,7 @@ #include "llvm/Transforms/Utils.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/LoopUtils.h" +#include "llvm/Transforms/Utils/LoopVersioning.h" #include #include #include @@ -87,7 +89,7 @@ #endif static bool populateDependencyMatrix(CharMatrix &DepMatrix, unsigned Level, - Loop *L, DependenceInfo *DI) { + Loop *L, DependenceInfo &DI) { using ValueVector = SmallVector; ValueVector MemInstr; @@ -126,7 +128,7 @@ if (isa(Src) && isa(Dst)) continue; // Track Output, Flow, and Anti dependencies. - if (auto D = DI->depends(Src, Dst, true)) { + if (auto D = DI.depends(Src, Dst, true)) { assert(D->isOrdered() && "Expected an output, flow or anti dep."); LLVM_DEBUG(StringRef DepType = D->isFlow() ? "flow" : D->isAnti() ? "anti" : "output"; @@ -426,21 +428,21 @@ struct LoopInterchange { ScalarEvolution *SE = nullptr; LoopInfo *LI = nullptr; - DependenceInfo *DI = nullptr; DominatorTree *DT = nullptr; + DependenceInfo *DI = nullptr; /// Interface to emit optimization remarks. OptimizationRemarkEmitter *ORE; LoopInterchange(ScalarEvolution *SE, LoopInfo *LI, DependenceInfo *DI, DominatorTree *DT, OptimizationRemarkEmitter *ORE) - : SE(SE), LI(LI), DI(DI), DT(DT), ORE(ORE) {} + : SE(SE), LI(LI), DT(DT), DI(DI), ORE(ORE) {} bool run(Loop *L) { if (L->getParentLoop()) return false; - return processLoopList(populateWorklist(*L)); + return processLoopList(populateWorklist(*L), *DI); } bool run(LoopNest &LN) { @@ -448,7 +450,7 @@ for (unsigned I = 1; I < LoopList.size(); ++I) if (LoopList[I]->getParentLoop() != LoopList[I - 1]) return false; - return processLoopList(LoopList); + return processLoopList(LoopList, *DI); } bool isComputableLoopNest(ArrayRef LoopList) { @@ -476,7 +478,7 @@ return LoopList.size() - 1; } - bool processLoopList(ArrayRef LoopList) { + bool processLoopList(ArrayRef LoopList, DependenceInfo &DI) { bool Changed = false; unsigned LoopNestDepth = LoopList.size(); if (LoopNestDepth < 2) { @@ -531,6 +533,14 @@ #endif Changed |= Interchanged; } + if (Changed) { + auto &Pred = DI.getUnionPredicate(); + if (!Pred.isAlwaysTrue()) { + LoopVersioning Ver(Pred, LoopList[0], LI, DT, SE); + Ver.versionLoop(); + } + } + return Changed; } @@ -565,8 +575,8 @@ assert(InnerLoop->isLCSSAForm(*DT) && "Inner loop not left in LCSSA form after loop interchange!"); - assert(OuterLoop->isLCSSAForm(*DT) && - "Outer loop not left in LCSSA form after loop interchange!"); + /* assert(OuterLoop->isLCSSAForm(*DT) &&*/ + /*"Outer loop not left in LCSSA form after loop interchange!");*/ return true; } @@ -1672,11 +1682,14 @@ auto *SE = &getAnalysis().getSE(); auto *LI = &getAnalysis().getLoopInfo(); - auto *DI = &getAnalysis().getDI(); auto *DT = &getAnalysis().getDomTree(); auto *ORE = &getAnalysis().getORE(); - return LoopInterchange(SE, LI, DI, DT, ORE).run(L); + PredicatedScalarEvolution PSE(*SE, *L); + DependenceInfo DI(L->getHeader()->getParent(), + &getAnalysis().getAAResults(), SE, + LI, &PSE); + return LoopInterchange(SE, LI, &DI, DT, ORE).run(L); } }; @@ -1701,7 +1714,8 @@ LPMUpdater &U) { Function &F = *LN.getParent(); - DependenceInfo DI(&F, &AR.AA, &AR.SE, &AR.LI); + PredicatedScalarEvolution PSE(AR.SE, LN.getOutermostLoop()); + DependenceInfo DI(&F, &AR.AA, &AR.SE, &AR.LI, &PSE); OptimizationRemarkEmitter ORE(&F); if (!LoopInterchange(&AR.SE, &AR.LI, &DI, &AR.DT, &ORE).run(LN)) return PreservedAnalyses::all(); diff --git a/llvm/lib/Transforms/Utils/LoopVersioning.cpp b/llvm/lib/Transforms/Utils/LoopVersioning.cpp --- a/llvm/lib/Transforms/Utils/LoopVersioning.cpp +++ b/llvm/lib/Transforms/Utils/LoopVersioning.cpp @@ -40,10 +40,16 @@ ArrayRef Checks, Loop *L, LoopInfo *LI, DominatorTree *DT, ScalarEvolution *SE) - : VersionedLoop(L), NonVersionedLoop(nullptr), - AliasChecks(Checks.begin(), Checks.end()), - Preds(LAI.getPSE().getUnionPredicate()), LAI(LAI), LI(LI), DT(DT), - SE(SE) { + : LoopVersioning(LAI.getPSE().getUnionPredicate(), L, LI, DT, SE) { + AliasChecks.append(Checks.begin(), Checks.end()); + this->LAI = &LAI; +} + +LoopVersioning::LoopVersioning(const SCEVUnionPredicate &Preds, Loop *L, + LoopInfo *LI, DominatorTree *DT, + ScalarEvolution *SE) + : VersionedLoop(L), NonVersionedLoop(nullptr), Preds(Preds), LAI(nullptr), + LI(LI), DT(DT), SE(SE) { assert(L->getUniqueExitBlock() && "No single exit block"); } @@ -53,19 +59,21 @@ "Loop is not in loop-simplify form"); Instruction *FirstCheckInst; - Instruction *MemRuntimeCheck; + Instruction *MemRuntimeCheck = nullptr; Value *SCEVRuntimeCheck; Value *RuntimeCheck = nullptr; // Add the memcheck in the original preheader (this is empty initially). BasicBlock *RuntimeCheckBB = VersionedLoop->getLoopPreheader(); - const auto &RtPtrChecking = *LAI.getRuntimePointerChecking(); - - SCEVExpander Exp2(*RtPtrChecking.getSE(), - VersionedLoop->getHeader()->getModule()->getDataLayout(), - "induction"); - std::tie(FirstCheckInst, MemRuntimeCheck) = addRuntimeChecks( - RuntimeCheckBB->getTerminator(), VersionedLoop, AliasChecks, Exp2); + if (LAI) { + const auto &RtPtrChecking = *LAI->getRuntimePointerChecking(); + SCEVExpander Exp2(*RtPtrChecking.getSE(), + VersionedLoop->getHeader()->getModule()->getDataLayout(), + "induction"); + + std::tie(FirstCheckInst, MemRuntimeCheck) = addRuntimeChecks( + RuntimeCheckBB->getTerminator(), VersionedLoop, AliasChecks, Exp2); + } SCEVExpander Exp(*SE, RuntimeCheckBB->getModule()->getDataLayout(), "scev.check"); @@ -173,6 +181,8 @@ } void LoopVersioning::prepareNoAliasMetadata() { + if (!LAI) + return; // We need to turn the no-alias relation between pointer checking groups into // no-aliasing annotations between instructions. // @@ -180,7 +190,8 @@ // pointers memchecked together) to an alias scope and then also mapping each // group to the list of scopes it can't alias. - const RuntimePointerChecking *RtPtrChecking = LAI.getRuntimePointerChecking(); + const RuntimePointerChecking *RtPtrChecking = + LAI->getRuntimePointerChecking(); LLVMContext &Context = VersionedLoop->getHeader()->getContext(); // First allocate an aliasing scope for each pointer checking group. @@ -214,14 +225,14 @@ } void LoopVersioning::annotateLoopWithNoAlias() { - if (!AnnotateNoAlias) + if (!AnnotateNoAlias || !LAI) return; // First prepare the maps. prepareNoAliasMetadata(); // Add the scope and no-alias metadata to the instructions. - for (Instruction *I : LAI.getDepChecker().getMemoryInstructions()) { + for (Instruction *I : LAI->getDepChecker().getMemoryInstructions()) { annotateInstWithNoAlias(I); } } diff --git a/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp b/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp --- a/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp +++ b/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp @@ -2459,6 +2459,8 @@ return expandUnionPredicate(cast(Pred), IP); case SCEVPredicate::P_Equal: return expandEqualPredicate(cast(Pred), IP); + case SCEVPredicate::P_LessThan: + return expandLessThanPredicate(cast(Pred), IP); case SCEVPredicate::P_Wrap: { auto *AddRecPred = cast(Pred); return expandWrapPredicate(AddRecPred, IP); @@ -2479,6 +2481,18 @@ return I; } +Value *SCEVExpander::expandLessThanPredicate(const SCEVLessThanPredicate *Pred, + Instruction *IP) { + Value *Expr0 = + expandCodeForImpl(Pred->getLHS(), Pred->getLHS()->getType(), IP, false); + Value *Expr1 = + expandCodeForImpl(Pred->getRHS(), Pred->getRHS()->getType(), IP, false); + + Builder.SetInsertPoint(IP); + auto *I = Builder.CreateICmpSLE(Expr0, Expr1, "lt.check"); + return I; +} + Value *SCEVExpander::generateOverflowCheck(const SCEVAddRecExpr *AR, Instruction *Loc, bool Signed) { assert(AR->isAffine() && "Cannot generate RT check for " diff --git a/llvm/test/Transforms/LoopInterchange/currentLimitation.ll b/llvm/test/Transforms/LoopInterchange/currentLimitation.ll --- a/llvm/test/Transforms/LoopInterchange/currentLimitation.ll +++ b/llvm/test/Transforms/LoopInterchange/currentLimitation.ll @@ -24,7 +24,7 @@ ; IR-LABEL: @interchange_01 ; IR-NOT: split -; CHECK: Name: Dependence +; CHECK: Name: UnsupportedInsBetweenInduction ; CHECK-NEXT: Function: interchange_01 ; DELIN: Name: UnsupportedInsBetweenInduction diff --git a/llvm/test/Transforms/LoopInterchange/loop-interchange-optimization-remarks.ll b/llvm/test/Transforms/LoopInterchange/loop-interchange-optimization-remarks.ll --- a/llvm/test/Transforms/LoopInterchange/loop-interchange-optimization-remarks.ll +++ b/llvm/test/Transforms/LoopInterchange/loop-interchange-optimization-remarks.ll @@ -60,7 +60,7 @@ ; CHECK: --- !Missed ; CHECK-NEXT: Pass: loop-interchange -; CHECK-NEXT: Name: Dependence +; CHECK-NEXT: Name: InterchangeNotProfitable ; CHECK-NEXT: Function: test01 ; CHECK-NEXT: Args: ; CHECK-NEXT: - String: Cannot interchange loops due to dependences. diff --git a/llvm/test/Transforms/LoopInterchange/profitability.ll b/llvm/test/Transforms/LoopInterchange/profitability.ll --- a/llvm/test/Transforms/LoopInterchange/profitability.ll +++ b/llvm/test/Transforms/LoopInterchange/profitability.ll @@ -21,7 +21,7 @@ ;; for(int j=1;j<100;j++) ;; A[j][i] = A[j - 1][i] + B[j][i]; -; CHECK: Name: Dependence +; CHECK: Name: Interchanged ; CHECK-NEXT: Function: interchange_01 ; DELIN: Name: Interchanged