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 @@ -656,6 +656,65 @@ return false; } } + + // TODO: Handle triangular loops of another form. + // e.g. for(int i=0;igetLoopLatch(); + BranchInst *InnerLoopLatchBI = + dyn_cast(InnerLoopLatch->getTerminator()); + if (!InnerLoopLatchBI->isConditional()) + return false; + if (CmpInst *InnerLoopCmp = + dyn_cast(InnerLoopLatchBI->getCondition())) { + 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 IsPathToIndVar; + IsPathToIndVar = [&InnerInduction, &IsPathToIndVar](Value *V) -> bool { + if (V == InnerInduction) + return true; + if (isa(V)) + return true; + Instruction *I = dyn_cast(V); + if (!I) + return false; + if (isa(I)) + return IsPathToIndVar(I->getOperand(0)); + if (isa(I)) + return IsPathToIndVar(I->getOperand(0)) && + IsPathToIndVar(I->getOperand(1)); + return false; + }; + + if (IsPathToIndVar(Op0) && !isa(Op0)) { + Left = Op0; + Right = Op1; + } else if (IsPathToIndVar(Op1) && !isa(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; } diff --git a/llvm/test/Transforms/LoopInterchange/inner-indvar-depend-on-outer-indvar.ll b/llvm/test/Transforms/LoopInterchange/inner-indvar-depend-on-outer-indvar.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/LoopInterchange/inner-indvar-depend-on-outer-indvar.ll @@ -0,0 +1,78 @@ +; RUN: opt < %s -basic-aa -loop-interchange -verify-dom-info -verify-loop-info \ +; RUN: -S -debug 2>&1 | FileCheck %s + +@A = common global [100 x [100 x i64]] zeroinitializer + +;; for(int i=0;i<100;i++) +;; for(int j=0;j