Index: lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp =================================================================== --- lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp +++ lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp @@ -829,21 +829,32 @@ return false; }; - // `ICI` is interpreted as taking the backedge if the *next* value of the - // induction variable satisfies some constraint. + // `ICI` can either be a comparison against IV or a comparison of IV.next. + // Depending on the interpretation, we calculate the start value differently. - const SCEVAddRecExpr *IndVarNext = cast(LeftSCEV); + const SCEVAddRecExpr *IVRec = cast(LeftSCEV); bool IsIncreasing = false; bool IsSignedPredicate = true; ConstantInt *StepCI; - if (!IsInductionVar(IndVarNext, IsIncreasing, StepCI)) { + if (!IsInductionVar(IVRec, IsIncreasing, StepCI)) { FailureReason = "LHS in icmp not induction variable"; return None; } - const SCEV *StartNext = IndVarNext->getStart(); - const SCEV *Addend = SE.getNegativeSCEV(IndVarNext->getStepRecurrence(SE)); - const SCEV *IndVarStart = SE.getAddExpr(StartNext, Addend); + const SCEV *IndVarStart; + Value *IndVarNext; + if (isa(LeftValue) && + cast(LeftValue)->getParent() == Header) { + // The comparison is made against IV. + IndVarStart = IVRec->getStart(); + IndVarNext = cast(LeftValue)->getIncomingValueForBlock(Latch); + } else { + // Assume that the comparison is made against IV.next. + const SCEV *StartNext = IVRec->getStart(); + const SCEV *Addend = SE.getNegativeSCEV(IVRec->getStepRecurrence(SE)); + IndVarStart = SE.getAddExpr(StartNext, Addend); + IndVarNext = LeftValue; + } const SCEV *Step = SE.getSCEV(StepCI); ConstantInt *One = ConstantInt::get(IndVarTy, 1); @@ -1023,7 +1034,7 @@ Result.LatchBrExitIdx = LatchBrExitIdx; Result.IndVarStart = IndVarStartV; Result.IndVarStep = StepCI; - Result.IndVarNext = LeftValue; + Result.IndVarNext = IndVarNext; Result.IndVarIncreasing = IsIncreasing; Result.LoopExitAt = RightValue; Result.IsSignedPredicate = IsSignedPredicate; Index: test/Transforms/IRCE/latch-comparison-against-current-value.ll =================================================================== --- /dev/null +++ test/Transforms/IRCE/latch-comparison-against-current-value.ll @@ -0,0 +1,73 @@ +; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -S < %s 2>&1 | FileCheck %s + +; Check that IRCE is able to deal with loops where the latch comparison is +; done against current value of the IV, not the IV.next. + +; CHECK: irce: in function test_01: constrained Loop at depth 1 containing: %loop
,%in.bounds +; CHECK: irce: in function test_02: constrained Loop at depth 1 containing: %loop
,%in.bounds + +; SLT condition for increasing loop from MIN_SINT to 100. +define void @test_01(i32* %arr, i32* %a_len_ptr) #0 { + +; CHECK: test_01 +; CHECK: main.exit.selector: +; CHECK-NEXT: [[PSEUDO_PHI:%[^ ]+]] = phi i32 [ %idx.next, %in.bounds ] +; CHECK-NEXT: [[COND:%[^ ]+]] = icmp slt i32 [[PSEUDO_PHI]], 100 +; CHECK-NEXT: br i1 [[COND]] + +entry: + %len = load i32, i32* %a_len_ptr, !range !0 + br label %loop + +loop: + %idx = phi i32 [ -2147483648, %entry ], [ %idx.next, %in.bounds ] + %idx.next = add nsw nuw i32 %idx, 1 + %abc = icmp slt i32 %idx, %len + br i1 %abc, label %in.bounds, label %out.of.bounds + +in.bounds: + %addr = getelementptr i32, i32* %arr, i32 %idx + store i32 0, i32* %addr + %next = icmp slt i32 %idx, 100 + br i1 %next, label %loop, label %exit + +out.of.bounds: + ret void + +exit: + ret void +} + +; ULT condition for increasing loop from MIN_UINT to 100. +define void @test_02(i32* %arr, i32* %a_len_ptr) #0 { + +; CHECK: test_02 +; CHECK: main.exit.selector: +; CHECK-NEXT: [[PSEUDO_PHI:%[^ ]+]] = phi i32 [ %idx.next, %in.bounds ] +; CHECK-NEXT: [[COND:%[^ ]+]] = icmp ult i32 [[PSEUDO_PHI]], 100 +; CHECK-NEXT: br i1 [[COND]] + +entry: + %len = load i32, i32* %a_len_ptr, !range !0 + br label %loop + +loop: + %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] + %idx.next = add nsw nuw i32 %idx, 1 + %abc = icmp ult i32 %idx, %len + br i1 %abc, label %in.bounds, label %out.of.bounds + +in.bounds: + %addr = getelementptr i32, i32* %arr, i32 %idx + store i32 0, i32* %addr + %next = icmp ult i32 %idx, 100 + br i1 %next, label %loop, label %exit + +out.of.bounds: + ret void + +exit: + ret void +} + +!0 = !{i32 0, i32 50}