diff options
| -rw-r--r-- | llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp | 64 | ||||
| -rw-r--r-- | llvm/test/Transforms/IRCE/latch-comparison-against-current-value.ll | 245 | 
2 files changed, 13 insertions, 296 deletions
diff --git a/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp b/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp index e625fb463dc..9fa49fdf81f 100644 --- a/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp +++ b/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp @@ -450,20 +450,10 @@ struct LoopStructure {    // equivalent to:    //    // intN_ty inc = IndVarIncreasing ? 1 : -1; -  // pred_ty predicate = IndVarIncreasing -  //                         ? IsSignedPredicate ? ICMP_SLT : ICMP_ULT -  //                         : IsSignedPredicate ? ICMP_SGT : ICMP_UGT; +  // pred_ty predicate = IndVarIncreasing ? ICMP_SLT : ICMP_SGT;    // -  // -  // for (intN_ty iv = IndVarStart; predicate(IndVarBase, LoopExitAt); -  //      iv = IndVarNext) +  // for (intN_ty iv = IndVarStart; predicate(iv, LoopExitAt); iv = IndVarBase)    //   ... body ... -  // -  // Here IndVarBase is either current or next value of the induction variable. -  // in the former case, IsIndVarNext = false and IndVarBase points to the -  // Phi node of the induction variable. Otherwise, IsIndVarNext = true and -  // IndVarBase points to IV increment instruction. -  //    Value *IndVarBase;    Value *IndVarStart; @@ -471,13 +461,12 @@ struct LoopStructure {    Value *LoopExitAt;    bool IndVarIncreasing;    bool IsSignedPredicate; -  bool IsIndVarNext;    LoopStructure()        : Tag(""), Header(nullptr), Latch(nullptr), LatchBr(nullptr),          LatchExit(nullptr), LatchBrExitIdx(-1), IndVarBase(nullptr),          IndVarStart(nullptr), IndVarStep(nullptr), LoopExitAt(nullptr), -        IndVarIncreasing(false), IsSignedPredicate(true), IsIndVarNext(false) {} +        IndVarIncreasing(false), IsSignedPredicate(true) {}    template <typename M> LoopStructure map(M Map) const {      LoopStructure Result; @@ -493,7 +482,6 @@ struct LoopStructure {      Result.LoopExitAt = Map(LoopExitAt);      Result.IndVarIncreasing = IndVarIncreasing;      Result.IsSignedPredicate = IsSignedPredicate; -    Result.IsIndVarNext = IsIndVarNext;      return Result;    } @@ -841,42 +829,21 @@ LoopStructure::parseLoopStructure(ScalarEvolution &SE,      return false;    }; -  // `ICI` can either be a comparison against IV or a comparison of IV.next. -  // Depending on the interpretation, we calculate the start value differently. +  // `ICI` is interpreted as taking the backedge if the *next* value of the +  // induction variable satisfies some constraint. -  // Pair {IndVarBase; IsIndVarNext} semantically designates whether the latch -  // comparisons happens against the IV before or after its value is -  // incremented. Two valid combinations for them are: -  // -  // 1) { phi [ iv.start, preheader ], [ iv.next, latch ]; false }, -  // 2) { iv.next; true }. -  // -  // The latch comparison happens against IndVarBase which can be either current -  // or next value of the induction variable.    const SCEVAddRecExpr *IndVarBase = cast<SCEVAddRecExpr>(LeftSCEV);    bool IsIncreasing = false;    bool IsSignedPredicate = true; -  bool IsIndVarNext = false;    ConstantInt *StepCI;    if (!IsInductionVar(IndVarBase, IsIncreasing, StepCI)) {      FailureReason = "LHS in icmp not induction variable";      return None;    } -  const SCEV *IndVarStart = nullptr; -  // TODO: Currently we only handle comparison against IV, but we can extend -  // this analysis to be able to deal with comparison against sext(iv) and such. -  if (isa<PHINode>(LeftValue) && -      cast<PHINode>(LeftValue)->getParent() == Header) -    // The comparison is made against current IV value. -    IndVarStart = IndVarBase->getStart(); -  else { -    // Assume that the comparison is made against next IV value. -    const SCEV *StartNext = IndVarBase->getStart(); -    const SCEV *Addend = SE.getNegativeSCEV(IndVarBase->getStepRecurrence(SE)); -    IndVarStart = SE.getAddExpr(StartNext, Addend); -    IsIndVarNext = true; -  } +  const SCEV *StartNext = IndVarBase->getStart(); +  const SCEV *Addend = SE.getNegativeSCEV(IndVarBase->getStepRecurrence(SE)); +  const SCEV *IndVarStart = SE.getAddExpr(StartNext, Addend);    const SCEV *Step = SE.getSCEV(StepCI);    ConstantInt *One = ConstantInt::get(IndVarTy, 1); @@ -1060,7 +1027,6 @@ LoopStructure::parseLoopStructure(ScalarEvolution &SE,    Result.IndVarIncreasing = IsIncreasing;    Result.LoopExitAt = RightValue;    Result.IsSignedPredicate = IsSignedPredicate; -  Result.IsIndVarNext = IsIndVarNext;    FailureReason = nullptr; @@ -1350,8 +1316,8 @@ LoopConstrainer::RewrittenRangeInfo LoopConstrainer::changeIterationSpaceEnd(                                        BranchToContinuation);      NewPHI->addIncoming(PN->getIncomingValueForBlock(Preheader), Preheader); -    auto *FixupValue = PN->getIncomingValueForBlock(LS.Latch); -    NewPHI->addIncoming(FixupValue, RRI.ExitSelector); +    NewPHI->addIncoming(PN->getIncomingValueForBlock(LS.Latch), +                        RRI.ExitSelector);      RRI.PHIValuesAtPseudoExit.push_back(NewPHI);    } @@ -1492,6 +1458,7 @@ bool LoopConstrainer::run() {        }        ExitPreLoopAtSCEV = SE.getAddExpr(*SR.HighLimit, MinusOneS);      } +      ExitPreLoopAt = Expander.expandCodeFor(ExitPreLoopAtSCEV, IVTy, InsertPt);      ExitPreLoopAt->setName("exit.preloop.at");    } @@ -1510,9 +1477,7 @@ bool LoopConstrainer::run() {        }        ExitMainLoopAtSCEV = SE.getAddExpr(*SR.LowLimit, MinusOneS);      } -    if (!MainLoopStructure.IsIndVarNext) -      ExitMainLoopAtSCEV = SE.getMinusSCEV( -          ExitMainLoopAtSCEV, SE.getSCEV(MainLoopStructure.IndVarStep)); +      ExitMainLoopAt = Expander.expandCodeFor(ExitMainLoopAtSCEV, IVTy, InsertPt);      ExitMainLoopAt->setName("exit.mainloop.at");    } @@ -1735,10 +1700,7 @@ bool InductiveRangeCheckElimination::runOnLoop(Loop *L, LPPassManager &LPM) {    }    LoopStructure LS = MaybeLoopStructure.getValue();    const SCEVAddRecExpr *IndVar = -      cast<SCEVAddRecExpr>(SE.getSCEV(LS.IndVarBase)); -  if (LS.IsIndVarNext) -    IndVar = cast<SCEVAddRecExpr>(SE.getMinusSCEV(IndVar, -                                                  SE.getSCEV(LS.IndVarStep))); +      cast<SCEVAddRecExpr>(SE.getMinusSCEV(SE.getSCEV(LS.IndVarBase), SE.getSCEV(LS.IndVarStep)));    Optional<InductiveRangeCheck::Range> SafeIterRange;    Instruction *ExprInsertPt = Preheader->getTerminator(); diff --git a/llvm/test/Transforms/IRCE/latch-comparison-against-current-value.ll b/llvm/test/Transforms/IRCE/latch-comparison-against-current-value.ll deleted file mode 100644 index 8ad4e3d3967..00000000000 --- a/llvm/test/Transforms/IRCE/latch-comparison-against-current-value.ll +++ /dev/null @@ -1,245 +0,0 @@ -; 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<header><exiting>,%in.bounds<latch><exiting> -; CHECK: irce: in function test_02: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> -; CHECK-NOT: irce: in function test_03: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> -; CHECK-NOT: irce: in function test_04: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> -; CHECK: irce: in function test_05: constrained Loop at depth 1 containing: %loop<header><exiting>,%in.bounds<latch><exiting> - -; SLT condition for increasing loop from 0 to 100. -define void @test_01(i32* %arr, i32* %a_len_ptr) #0 { - -; CHECK:      test_01 -; CHECK:        entry: -; CHECK-NEXT:     %len = load i32, i32* %a_len_ptr, !range !0 -; CHECK-NEXT:     %exit.mainloop.at = add i32 %len, -1 -; CHECK-NEXT:     [[COND2:%[^ ]+]] = icmp slt i32 0, %exit.mainloop.at -; CHECK-NEXT:     br i1 [[COND2]], label %loop.preheader, label %main.pseudo.exit -; CHECK:        loop: -; CHECK-NEXT:     %idx = phi i32 [ %idx.next, %in.bounds ], [ 0, %loop.preheader ] -; CHECK-NEXT:     %idx.next = add nuw nsw i32 %idx, 1 -; CHECK-NEXT:     %abc = icmp slt i32 %idx, %len -; CHECK-NEXT:     br i1 true, label %in.bounds, label %out.of.bounds.loopexit1 -; CHECK:        in.bounds: -; CHECK-NEXT:     %addr = getelementptr i32, i32* %arr, i32 %idx -; CHECK-NEXT:     store i32 0, i32* %addr -; CHECK-NEXT:     %next = icmp slt i32 %idx, 100 -; CHECK-NEXT:     [[COND3:%[^ ]+]] = icmp slt i32 %idx, %exit.mainloop.at -; CHECK-NEXT:     br i1 [[COND3]], label %loop, label %main.exit.selector -; CHECK:        main.exit.selector: -; CHECK-NEXT:     %idx.lcssa = phi i32 [ %idx, %in.bounds ] -; CHECK-NEXT:     %idx.next.lcssa = phi i32 [ %idx.next, %in.bounds ] -; CHECK-NEXT:     [[COND4:%[^ ]+]] = icmp slt i32 %idx.lcssa, 100 -; CHECK-NEXT:     br i1 [[COND4]], label %main.pseudo.exit, label %exit -; CHECK-NOT: loop.preloop: -; CHECK:        loop.postloop: -; CHECK-NEXT:    %idx.postloop = phi i32 [ %idx.copy, %postloop ], [ %idx.next.postloop, %in.bounds.postloop ] -; CHECK-NEXT:     %idx.next.postloop = add nuw nsw i32 %idx.postloop, 1 -; CHECK-NEXT:     %abc.postloop = icmp slt i32 %idx.postloop, %len -; CHECK-NEXT:     br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds.loopexit - -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 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 0 to 100. -define void @test_02(i32* %arr, i32* %a_len_ptr) #0 { - -; CHECK:      test_02 -; CHECK:        entry: -; CHECK-NEXT:     %len = load i32, i32* %a_len_ptr, !range !0 -; CHECK-NEXT:     %exit.mainloop.at = add i32 %len, -1 -; CHECK-NEXT:     [[COND2:%[^ ]+]] = icmp ult i32 0, %exit.mainloop.at -; CHECK-NEXT:     br i1 [[COND2]], label %loop.preheader, label %main.pseudo.exit -; CHECK:        loop: -; CHECK-NEXT:     %idx = phi i32 [ %idx.next, %in.bounds ], [ 0, %loop.preheader ] -; CHECK-NEXT:     %idx.next = add nuw nsw i32 %idx, 1 -; CHECK-NEXT:     %abc = icmp ult i32 %idx, %len -; CHECK-NEXT:     br i1 true, label %in.bounds, label %out.of.bounds.loopexit1 -; CHECK:        in.bounds: -; CHECK-NEXT:     %addr = getelementptr i32, i32* %arr, i32 %idx -; CHECK-NEXT:     store i32 0, i32* %addr -; CHECK-NEXT:     %next = icmp ult i32 %idx, 100 -; CHECK-NEXT:     [[COND3:%[^ ]+]] = icmp ult i32 %idx, %exit.mainloop.at -; CHECK-NEXT:     br i1 [[COND3]], label %loop, label %main.exit.selector -; CHECK:        main.exit.selector: -; CHECK-NEXT:     %idx.lcssa = phi i32 [ %idx, %in.bounds ] -; CHECK-NEXT:     %idx.next.lcssa = phi i32 [ %idx.next, %in.bounds ] -; CHECK-NEXT:     [[COND4:%[^ ]+]] = icmp ult i32 %idx.lcssa, 100 -; CHECK-NEXT:     br i1 [[COND4]], label %main.pseudo.exit, label %exit -; CHECK-NOT: loop.preloop: -; CHECK:        loop.postloop: -; CHECK-NEXT:    %idx.postloop = phi i32 [ %idx.copy, %postloop ], [ %idx.next.postloop, %in.bounds.postloop ] -; CHECK-NEXT:     %idx.next.postloop = add nuw nsw i32 %idx.postloop, 1 -; CHECK-NEXT:     %abc.postloop = icmp ult i32 %idx.postloop, %len -; CHECK-NEXT:     br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds.loopexit - -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 -} - -; Same as test_01, but comparison happens against IV extended to a wider type. -; This test ensures that IRCE rejects it and does not falsely assume that it was -; a comparison against iv.next. -; TODO: We can actually extend the recognition to cover this case. -define void @test_03(i32* %arr, i64* %a_len_ptr) #0 { - -; CHECK:      test_03 - -entry: -  %len = load i64, i64* %a_len_ptr, !range !1 -  br label %loop - -loop: -  %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] -  %idx.next = add nsw nuw i32 %idx, 1 -  %idx.ext = sext i32 %idx to i64 -  %abc = icmp slt i64 %idx.ext, %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 -} - -; Same as test_02, but comparison happens against IV extended to a wider type. -; This test ensures that IRCE rejects it and does not falsely assume that it was -; a comparison against iv.next. -; TODO: We can actually extend the recognition to cover this case. -define void @test_04(i32* %arr, i64* %a_len_ptr) #0 { - -; CHECK:      test_04 - -entry: -  %len = load i64, i64* %a_len_ptr, !range !1 -  br label %loop - -loop: -  %idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds ] -  %idx.next = add nsw nuw i32 %idx, 1 -  %idx.ext = sext i32 %idx to i64 -  %abc = icmp ult i64 %idx.ext, %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 -} - -define void @test_05(i32* %arr, i32* %a_len_ptr) #0 { - -; CHECK:      test_05 -; CHECK:      entry: -; CHECK-NEXT:     %len = load i32, i32* %a_len_ptr, !range !0 -; CHECK-NEXT:     %exit.mainloop.at = add i32 %len, -1 -; CHECK-NEXT:     br i1 true, label %loop.preloop.preheader, label %preloop.pseudo.exit -; CHECK:      loop.preloop: -; CHECK-NEXT:     %idx.preloop = phi i32 [ %idx.next.preloop, %in.bounds.preloop ], [ -10, %loop.preloop.preheader ] -; CHECK-NEXT:     %idx.next.preloop = add i32 %idx.preloop, 1 -; CHECK-NEXT:     %c1.preloop = icmp sge i32 %idx.preloop, 0 -; CHECK-NEXT:     %c2.preloop = icmp slt i32 %idx.preloop, %len -; CHECK-NEXT:     %abc.preloop = and i1 %c1.preloop, %c2.preloop -; CHECK-NEXT:     br i1 %abc.preloop, label %in.bounds.preloop, label %out.of.bounds.loopexit -; CHECK:      in.bounds.preloop: -; CHECK-NEXT:     %addr.preloop = getelementptr i32, i32* %arr, i32 %idx.preloop -; CHECK-NEXT:     store i32 0, i32* %addr.preloop -; CHECK-NEXT:     %next.preloop = icmp slt i32 %idx.preloop, 100 -; CHECK-NEXT:     [[COND3:%[^ ]+]] = icmp slt i32 %idx.preloop, 0 -; CHECK-NEXT:     br i1 [[COND3]], label %loop.preloop, label %preloop.exit.selector -; CHECK:      loop.postloop: -; CHECK-NEXT:     %idx.postloop = phi i32 [ %idx.copy, %postloop ], [ %idx.next.postloop, %in.bounds.postloop ] -; CHECK-NEXT:     %idx.next.postloop = add i32 %idx.postloop, 1 -; CHECK-NEXT:     %c1.postloop = icmp sge i32 %idx.postloop, 0 -; CHECK-NEXT:     %c2.postloop = icmp slt i32 %idx.postloop, %len -; CHECK-NEXT:     %abc.postloop = and i1 %c1.postloop, %c2.postloop -; CHECK-NEXT:     br i1 %abc.postloop, label %in.bounds.postloop, label %out.of.bounds.loopexit2 -; CHECK:      in.bounds.postloop: -; CHECK-NEXT:     %addr.postloop = getelementptr i32, i32* %arr, i32 %idx.postloop -; CHECK-NEXT:     store i32 0, i32* %addr.postloop -; CHECK-NEXT:     %next.postloop = icmp slt i32 %idx.postloop, 100 -; CHECK-NEXT:     br i1 %next.postloop, label %loop.postloop, label %exit.loopexit - -entry: -  %len = load i32, i32* %a_len_ptr, !range !0 -  br label %loop - -loop: -  %idx = phi i32 [-10, %entry ], [ %idx.next, %in.bounds ] -  %idx.next = add i32 %idx, 1 -  %c1 = icmp sge i32 %idx, 0 -  %c2 = icmp slt i32 %idx, %len -  %abc = and i1 %c1, %c2 -  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 -} - -!0 = !{i32 0, i32 50} -!1 = !{i64 0, i64 50}  | 

