Index: include/llvm/Analysis/ScalarEvolution.h =================================================================== --- include/llvm/Analysis/ScalarEvolution.h +++ include/llvm/Analysis/ScalarEvolution.h @@ -1489,6 +1489,11 @@ /// bool isKnownNonZero(const SCEV *S); + /// Test if first iteration of a loop exits it. + bool isLoopFirstIterationExit(const Loop *L, bool ExitOperand, + ICmpInst::Predicate Pred, + const SCEV *LHS, const SCEV *RHS); + /// Test if the given expression is known to satisfy the condition described /// by Pred, LHS, and RHS. /// Index: lib/Analysis/ScalarEvolution.cpp =================================================================== --- lib/Analysis/ScalarEvolution.cpp +++ lib/Analysis/ScalarEvolution.cpp @@ -7735,6 +7735,32 @@ return false; } +/// True if we exit on the first loop iteration +bool +ScalarEvolution::isLoopFirstIterationExit(const Loop *L, bool ExitOperand, + ICmpInst::Predicate Pred, + const SCEV *LHS, const SCEV *RHS) { + if (!L) + return false; + BasicBlock *Header = L->getHeader(); + const BranchInst *BI = dyn_cast(Header->getTerminator()); + if (!BI || BI->isUnconditional()) + return false; + CmpInst *CmpI = dyn_cast(BI->getCondition()); + if (!CmpI || CmpI->getPredicate() != Pred) + return false; + if (!HasSameValue(LHS, getSCEV(CmpI->getOperand(0))) || + !HasSameValue(RHS, getSCEV(CmpI->getOperand(1)))) + return false; + if (ICmpInst::isTrueWhenEqual(Pred) && ExitOperand && + !L->contains(BI->getSuccessor(0)) && L->contains(BI->getSuccessor(1))) + return true; + if (ICmpInst::isFalseWhenEqual(Pred) && !ExitOperand && + L->contains(BI->getSuccessor(0)) && !L->contains(BI->getSuccessor(1))) + return true; + return false; +} + bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred, const SCEV *&LHS, const SCEV *&RHS, unsigned Depth) { @@ -7744,6 +7770,24 @@ if (Depth >= 3) return false; + if (const SCEVAddRecExpr *LAR = dyn_cast(LHS)) { + const Loop *L = LAR->getLoop(); + if (isLoopInvariant(RHS, L) && HasSameValue(LAR->getStart(), RHS)) { + if (isLoopFirstIterationExit(L, true, Pred, LHS, RHS)) + goto trivially_true; + else if (isLoopFirstIterationExit(L, false, Pred, LHS, RHS)) + goto trivially_false; + } + } + if (const SCEVAddRecExpr *RAR = dyn_cast(RHS)) { + const Loop *L = RAR->getLoop(); + if (isLoopInvariant(LHS, L) && HasSameValue(RAR->getStart(), LHS)) { + if (isLoopFirstIterationExit(L, true, Pred, LHS, RHS)) + goto trivially_true; + else if (isLoopFirstIterationExit(L, false, Pred, LHS, RHS)) + goto trivially_false; + } + } // Canonicalize a constant to the right side. if (const SCEVConstant *LHSC = dyn_cast(LHS)) { // Check for both operands constant. Index: test/Transforms/IndVarSimplify/first_iter_exit.ll =================================================================== --- test/Transforms/IndVarSimplify/first_iter_exit.ll +++ test/Transforms/IndVarSimplify/first_iter_exit.ll @@ -0,0 +1,61 @@ +; RUN: opt < %s -S -indvars | FileCheck %s + +; The test checks if we can remove first iteration exit compare: +; for (i = 84; i > 1; i--) +; for (j = i; j < i; j++) +; ... + +; CHECK: for.cond1: +; CHECK-NEXT: br i1 false + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +@b = common global [100 x i32] zeroinitializer, align 16 +@a = common global [100 x i32] zeroinitializer, align 16 + +; Function Attrs: nounwind uwtable +define void @foo() local_unnamed_addr { +entry: + br label %for.cond + +for.cond: ; preds = %for.inc12, %entry + %i.0 = phi i32 [ 84, %entry ], [ %dec, %for.inc12 ] + %cmp = icmp ugt i32 %i.0, 1 + br i1 %cmp, label %for.cond1.preheader, label %for.end13 + +for.cond1.preheader: ; preds = %for.cond + br label %for.cond1 + +for.cond1: ; preds = %for.cond1.preheader, %for.inc9 + %j.0 = phi i32 [ %inc10, %for.inc9 ], [ %i.0, %for.cond1.preheader ] + %cmp2 = icmp ult i32 %j.0, %i.0 + br i1 %cmp2, label %for.cond4.preheader, label %for.inc12 + +for.cond4.preheader: ; preds = %for.cond1 + br label %for.cond4 + +for.cond4: ; preds = %for.cond4.preheader, %for.body6 + %k.0 = phi i32 [ %inc, %for.body6 ], [ 1, %for.cond4.preheader ] + %cmp5 = icmp ult i32 %k.0, 7 + br i1 %cmp5, label %for.body6, label %for.inc9 + +for.body6: ; preds = %for.cond4 + %idxprom = zext i32 %k.0 to i64 + %arrayidx = getelementptr inbounds [100 x i32], [100 x i32]* @b, i64 0, i64 %idxprom + %0 = load i32, i32* %arrayidx, align 4 + %idxprom7 = zext i32 %i.0 to i64 + %arrayidx8 = getelementptr inbounds [100 x i32], [100 x i32]* @a, i64 0, i64 %idxprom7 + store i32 %0, i32* %arrayidx8, align 4 + %inc = add nuw nsw i32 %k.0, 1 + br label %for.cond4 + +for.inc9: ; preds = %for.cond4 + %inc10 = add i32 %j.0, 1 + br label %for.cond1 + +for.inc12: ; preds = %for.cond1 + %dec = add i32 %i.0, -1 + br label %for.cond + +for.end13: ; preds = %for.cond + ret void +}