[llvm] r351926 - [IRCE] Support narrow latch condition for wide range checks

Max Kazantsev via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 22 23:20:56 PST 2019


Author: mkazantsev
Date: Tue Jan 22 23:20:56 2019
New Revision: 351926

URL: http://llvm.org/viewvc/llvm-project?rev=351926&view=rev
Log:
[IRCE] Support narrow latch condition for wide range checks

This patch relaxes restrictions on types of latch condition and range check.
In current implementation, they should match. This patch allows to handle
wide range checks against narrow condition. The motivating example is the
following:

  int N = ...
  for (long i = 0; (int) i < N; i++) {
    if (i >= length) deopt;
  }

In this patch, the option that enables this support is turned off by
default. We'll wait until it is switched to true.

Differential Revision: https://reviews.llvm.org/D56837
Reviewed By: reames

Added:
    llvm/trunk/test/Transforms/IRCE/wide_indvar.ll
Modified:
    llvm/trunk/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp

Modified: llvm/trunk/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp?rev=351926&r1=351925&r2=351926&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp Tue Jan 22 23:20:56 2019
@@ -115,6 +115,11 @@ static cl::opt<bool> SkipProfitabilityCh
 static cl::opt<bool> AllowUnsignedLatchCondition("irce-allow-unsigned-latch",
                                                  cl::Hidden, cl::init(true));
 
+static cl::opt<bool> AllowNarrowLatchCondition(
+    "irce-allow-narrow-latch", cl::Hidden, cl::init(false),
+    cl::desc("If set to true, IRCE may eliminate wide range checks in loops "
+             "with narrow latch condition."));
+
 static const char *ClonedLoopTag = "irce.loop.clone";
 
 #define DEBUG_TYPE "irce"
@@ -1044,11 +1049,23 @@ LoopStructure::parseLoopStructure(Scalar
   return Result;
 }
 
+/// If the type of \p S matches with \p Ty, return \p S. Otherwise, return
+/// signed or unsigned extension of \p S to type \p Ty.
+static const SCEV *NoopOrExtend(const SCEV *S, Type *Ty, ScalarEvolution &SE,
+                                bool Signed) {
+  return Signed ? SE.getNoopOrSignExtend(S, Ty) : SE.getNoopOrZeroExtend(S, Ty);
+}
+
 Optional<LoopConstrainer::SubRanges>
 LoopConstrainer::calculateSubRanges(bool IsSignedPredicate) const {
   IntegerType *Ty = cast<IntegerType>(LatchTakenCount->getType());
 
-  if (Range.getType() != Ty)
+  auto *RTy = cast<IntegerType>(Range.getType());
+
+  // We only support wide range checks and narrow latches.
+  if (!AllowNarrowLatchCondition && RTy != Ty)
+    return None;
+  if (RTy->getBitWidth() < Ty->getBitWidth())
     return None;
 
   LoopConstrainer::SubRanges Result;
@@ -1056,8 +1073,10 @@ LoopConstrainer::calculateSubRanges(bool
   // I think we can be more aggressive here and make this nuw / nsw if the
   // addition that feeds into the icmp for the latch's terminating branch is nuw
   // / nsw.  In any case, a wrapping 2's complement addition is safe.
-  const SCEV *Start = SE.getSCEV(MainLoopStructure.IndVarStart);
-  const SCEV *End = SE.getSCEV(MainLoopStructure.LoopExitAt);
+  const SCEV *Start = NoopOrExtend(SE.getSCEV(MainLoopStructure.IndVarStart),
+                                   RTy, SE, IsSignedPredicate);
+  const SCEV *End = NoopOrExtend(SE.getSCEV(MainLoopStructure.LoopExitAt), RTy,
+                                 SE, IsSignedPredicate);
 
   bool Increasing = MainLoopStructure.IndVarIncreasing;
 
@@ -1067,7 +1086,7 @@ LoopConstrainer::calculateSubRanges(bool
 
   const SCEV *Smallest = nullptr, *Greatest = nullptr, *GreatestSeen = nullptr;
 
-  const SCEV *One = SE.getOne(Ty);
+  const SCEV *One = SE.getOne(RTy);
   if (Increasing) {
     Smallest = Start;
     Greatest = End;
@@ -1256,6 +1275,13 @@ LoopConstrainer::RewrittenRangeInfo Loop
   bool IsSignedPredicate = LS.IsSignedPredicate;
 
   IRBuilder<> B(PreheaderJump);
+  auto *RangeTy = Range.getBegin()->getType();
+  auto NoopOrExt = [&](Value *V) {
+    if (V->getType() == RangeTy)
+      return V;
+    return IsSignedPredicate ? B.CreateSExt(V, RangeTy, "wide." + V->getName())
+                             : B.CreateZExt(V, RangeTy, "wide." + V->getName());
+  };
 
   // EnterLoopCond - is it okay to start executing this `LS'?
   Value *EnterLoopCond = nullptr;
@@ -1263,9 +1289,7 @@ LoopConstrainer::RewrittenRangeInfo Loop
       Increasing
           ? (IsSignedPredicate ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT)
           : (IsSignedPredicate ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT);
-  Value *IndVarStart = LS.IndVarStart;
-  Value *IndVarBase = LS.IndVarBase;
-  Value *LoopExitAt = LS.LoopExitAt;
+  Value *IndVarStart = NoopOrExt(LS.IndVarStart);
   EnterLoopCond = B.CreateICmp(Pred, IndVarStart, ExitSubloopAt);
 
   B.CreateCondBr(EnterLoopCond, LS.Header, RRI.PseudoExit);
@@ -1273,6 +1297,7 @@ LoopConstrainer::RewrittenRangeInfo Loop
 
   LS.LatchBr->setSuccessor(LS.LatchBrExitIdx, RRI.ExitSelector);
   B.SetInsertPoint(LS.LatchBr);
+  Value *IndVarBase = NoopOrExt(LS.IndVarBase);
   Value *TakeBackedgeLoopCond = B.CreateICmp(Pred, IndVarBase, ExitSubloopAt);
 
   Value *CondForBranch = LS.LatchBrExitIdx == 1
@@ -1286,6 +1311,7 @@ LoopConstrainer::RewrittenRangeInfo Loop
   // IterationsLeft - are there any more iterations left, given the original
   // upper bound on the induction variable?  If not, we branch to the "real"
   // exit.
+  Value *LoopExitAt = NoopOrExt(LS.LoopExitAt);
   Value *IterationsLeft = B.CreateICmp(Pred, IndVarBase, LoopExitAt);
   B.CreateCondBr(IterationsLeft, RRI.PseudoExit, LS.LatchExit);
 
@@ -1394,7 +1420,7 @@ bool LoopConstrainer::run() {
   SubRanges SR = MaybeSR.getValue();
   bool Increasing = MainLoopStructure.IndVarIncreasing;
   IntegerType *IVTy =
-      cast<IntegerType>(MainLoopStructure.IndVarBase->getType());
+      cast<IntegerType>(Range.getBegin()->getType());
 
   SCEVExpander Expander(SE, F.getParent()->getDataLayout(), "irce");
   Instruction *InsertPt = OriginalPreheader->getTerminator();
@@ -1557,6 +1583,12 @@ Optional<InductiveRangeCheck::Range>
 InductiveRangeCheck::computeSafeIterationSpace(
     ScalarEvolution &SE, const SCEVAddRecExpr *IndVar,
     bool IsLatchSigned) const {
+  // We can deal when types of latch check and range checks don't match in case
+  // if latch check is more narrow.
+  auto *IVType = cast<IntegerType>(IndVar->getType());
+  auto *RCType = cast<IntegerType>(getBegin()->getType());
+  if (IVType->getBitWidth() > RCType->getBitWidth())
+    return None;
   // IndVar is of the form "A + B * I" (where "I" is the canonical induction
   // variable, that may or may not exist as a real llvm::Value in the loop) and
   // this inductive range check is a range check on the "C + D * I" ("C" is
@@ -1580,8 +1612,9 @@ InductiveRangeCheck::computeSafeIteratio
   if (!IndVar->isAffine())
     return None;
 
-  const SCEV *A = IndVar->getStart();
-  const SCEVConstant *B = dyn_cast<SCEVConstant>(IndVar->getStepRecurrence(SE));
+  const SCEV *A = NoopOrExtend(IndVar->getStart(), RCType, SE, IsLatchSigned);
+  const SCEVConstant *B = dyn_cast<SCEVConstant>(
+      NoopOrExtend(IndVar->getStepRecurrence(SE), RCType, SE, IsLatchSigned));
   if (!B)
     return None;
   assert(!B->isZero() && "Recurrence with zero step?");
@@ -1592,7 +1625,7 @@ InductiveRangeCheck::computeSafeIteratio
     return None;
 
   assert(!D->getValue()->isZero() && "Recurrence with zero step?");
-  unsigned BitWidth = cast<IntegerType>(IndVar->getType())->getBitWidth();
+  unsigned BitWidth = RCType->getBitWidth();
   const SCEV *SIntMax = SE.getConstant(APInt::getSignedMaxValue(BitWidth));
 
   // Subtract Y from X so that it does not go through border of the IV

Added: llvm/trunk/test/Transforms/IRCE/wide_indvar.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/IRCE/wide_indvar.ll?rev=351926&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/IRCE/wide_indvar.ll (added)
+++ llvm/trunk/test/Transforms/IRCE/wide_indvar.ll Tue Jan 22 23:20:56 2019
@@ -0,0 +1,459 @@
+; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -irce-allow-narrow-latch=true -S < %s 2>&1 | FileCheck %s
+; RUN: opt -verify-loop-info -irce-print-changed-loops -passes='require<branch-prob>,loop(irce)' -irce-allow-narrow-latch=true -S < %s 2>&1 | FileCheck %s
+
+; Check that we can remove trivially non-failing range check.
+define i32 @test_increasing_slt_slt_wide_simple_no_postloop() {
+
+; CHECK-LABEL: @test_increasing_slt_slt_wide_simple_no_postloop(
+; CHECK-NOT:   preloop
+; CHECK-NOT:   postloop
+; CHECK:       loop:
+; CHECK:       br i1 true, label %backedge, label %check_failed
+
+entry:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
+  %rc = icmp slt i64 %iv, 100
+  br i1 %rc, label %backedge, label %check_failed
+
+backedge:
+  %iv.next = add i64 %iv, 1
+  %narrow.iv = trunc i64 %iv.next to i32
+  %latch.cond = icmp slt i32 %narrow.iv, 100
+  br i1 %latch.cond, label %loop, label %exit
+
+exit:
+  ret i32 %narrow.iv
+
+check_failed:
+  ret i32 -1
+}
+
+; This range check fails on the last iteration, so it needs a postloop.
+define i32 @test_increasing_slt_slt_wide_simple_postloop() {
+
+; CHECK-LABEL: @test_increasing_slt_slt_wide_simple_postloop(
+; CHECK-NOT:   preloop
+; CHECK:       loop:
+; CHECK:       br i1 true, label %backedge, label %check_failed
+; CHECK:       backedge
+; CHECK:       [[COND:%[^ ]+]] = icmp slt i64 %wide.narrow.iv, 99
+; CHECK:       br i1 [[COND]], label %loop, label %main.exit.selector
+; CHECK:       postloop
+
+entry:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
+  %rc = icmp slt i64 %iv, 99
+  br i1 %rc, label %backedge, label %check_failed
+
+backedge:
+  %iv.next = add i64 %iv, 1
+  %narrow.iv = trunc i64 %iv.next to i32
+  %latch.cond = icmp slt i32 %narrow.iv, 100
+  br i1 %latch.cond, label %loop, label %exit
+
+exit:
+  ret i32 %narrow.iv
+
+check_failed:
+  ret i32 -1
+}
+
+; General case. If both %N and %M are non-negative, we do not need a preloop.
+define i32 @test_increasing_slt_slt_wide_non-negative(i32* %n_ptr, i64* %m_ptr) {
+
+; CHECK-LABEL: @test_increasing_slt_slt_wide_non-negative(
+; CHECK-NOT:   preloop
+; CHECK:       loop:
+; CHECK:       br i1 true, label %backedge, label %check_failed
+; CHECK:       backedge
+; CHECK:       [[COND:%[^ ]+]] = icmp slt i64 %wide.narrow.iv, %exit.mainloop.at
+; CHECK:       br i1 [[COND]], label %loop, label %main.exit.selector
+; CHECK:       postloop
+
+entry:
+  %N = load i32, i32* %n_ptr, !range !2
+  %M = load i64, i64* %m_ptr, !range !1
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
+  %rc = icmp slt i64 %iv, %M
+  br i1 %rc, label %backedge, label %check_failed
+
+backedge:
+  %iv.next = add i64 %iv, 1
+  %narrow.iv = trunc i64 %iv.next to i32
+  %latch.cond = icmp slt i32 %narrow.iv, %N
+  br i1 %latch.cond, label %loop, label %exit
+
+exit:
+  ret i32 %narrow.iv
+
+check_failed:
+  ret i32 -1
+}
+
+; General case. Even though %M may be negative, we do not need a preloop because
+; we make a non-negativity runtime check against M and do not go to main loop if
+; M was negative.
+define i32 @test_increasing_slt_slt_wide_general(i32* %n_ptr, i64* %m_ptr) {
+
+; CHECK-LABEL: @test_increasing_slt_slt_wide_general(
+; CHECK-NOT:   preloop
+; CHECK:       loop:
+; CHECK:       br i1 true, label %backedge, label %check_failed
+; CHECK:       backedge
+; CHECK:       [[COND:%[^ ]+]] = icmp slt i64
+; CHECK:       br i1 [[COND]], label %loop, label %main.exit.selector
+; CHECK:       postloop
+
+entry:
+  %N = load i32, i32* %n_ptr, !range !2
+  %M = load i64, i64* %m_ptr
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
+  %rc = icmp slt i64 %iv, %M
+  br i1 %rc, label %backedge, label %check_failed
+
+backedge:
+  %iv.next = add i64 %iv, 1
+  %narrow.iv = trunc i64 %iv.next to i32
+  %latch.cond = icmp slt i32 %narrow.iv, %N
+  br i1 %latch.cond, label %loop, label %exit
+
+exit:
+  ret i32 %narrow.iv
+
+check_failed:
+  ret i32 -1
+}
+
+; General case with preloop.
+define i32 @test_increasing_slt_slt_wide_general_preloop(i32* %n_ptr, i64* %m_ptr) {
+
+; CHECK-LABEL: @test_increasing_slt_slt_wide_general_preloop(
+; CHECK:       loop:
+; CHECK:       br i1 true, label %backedge, label %check_failed
+; CHECK:       backedge
+; CHECK:       [[COND:%[^ ]+]] = icmp slt i64
+; CHECK:       br i1 [[COND]], label %loop, label %main.exit.selector
+; CHECK:       preloop
+; CHECK:       postloop
+
+entry:
+  %N = load i32, i32* %n_ptr, !range !2
+  %M = load i64, i64* %m_ptr
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
+  %rc = icmp slt i64 %iv, %M
+  br i1 %rc, label %backedge, label %check_failed
+
+backedge:
+  %iv.next = add i64 %iv, 1
+  %narrow.iv = trunc i64 %iv to i32
+  %latch.cond = icmp slt i32 %narrow.iv, %N
+  br i1 %latch.cond, label %loop, label %exit
+
+exit:
+  ret i32 %narrow.iv
+
+check_failed:
+  ret i32 -1
+}
+
+; Same as above, multiple checks.
+define i32 @test_increasing_slt_slt_wide_multiple_checks(i32* %n_ptr, i64* %m1_ptr, i64* %m2_ptr, i64* %m3_ptr, i64* %m4_ptr) {
+; CHECK-LABEL: @test_increasing_slt_slt_wide_multiple_checks(
+; CHECK-NOT:   preloop
+; CHECK:       loop:
+; CHECK:       %c1 = and i1 true, true
+; CHECK:       %c2 = and i1 %c1, true
+; CHECK:       %rc = and i1 %c2, true
+; CHECK:       br i1 %rc, label %backedge, label %check_failed.loopexit
+; CHECK:       backedge
+; CHECK:       [[COND:%[^ ]+]] = icmp slt i64
+; CHECK:       br i1 [[COND]], label %loop, label %main.exit.selector
+; CHECK:       postloop
+
+entry:
+  %N = load i32, i32* %n_ptr, !range !2
+  %M1 = load i64, i64* %m1_ptr
+  %M2 = load i64, i64* %m2_ptr
+  %M3 = load i64, i64* %m3_ptr
+  %M4 = load i64, i64* %m4_ptr
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
+  %rc1 = icmp slt i64 %iv, %M1
+  %rc2 = icmp slt i64 %iv, %M2
+  %rc3 = icmp slt i64 %iv, %M3
+  %rc4 = icmp slt i64 %iv, %M4
+  %c1 = and i1 %rc1, %rc2
+  %c2 = and i1 %c1, %rc3
+  %rc = and i1 %c2, %rc4
+  br i1 %rc, label %backedge, label %check_failed
+
+backedge:
+  %iv.next = add i64 %iv, 1
+  %narrow.iv = trunc i64 %iv.next to i32
+  %latch.cond = icmp slt i32 %narrow.iv, %N
+  br i1 %latch.cond, label %loop, label %exit
+
+exit:
+  ret i32 %narrow.iv
+
+check_failed:
+  ret i32 -1
+}
+
+; Wide IV against narrow range check. We don't currently support it.
+define i32 @test_increasing_slt_slt_wide_simple_negtest_narrow_rc() {
+
+; CHECK-LABEL: @test_increasing_slt_slt_wide_simple_negtest_narrow_rc(
+; CHECK-NOT:   i1 true
+; CHECK-NOT:   main
+
+entry:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
+  %narrow.iv = trunc i64 %iv to i32
+  %rc = icmp slt i32 %narrow.iv, 101
+  br i1 %rc, label %backedge, label %check_failed
+
+backedge:
+  %iv.next = add i64 %iv, 1
+  %latch.cond = icmp slt i64 %iv, 100
+  br i1 %latch.cond, label %loop, label %exit
+
+exit:
+  ret i32 %narrow.iv
+
+check_failed:
+  ret i32 -1
+}
+
+; Check that we can remove trivially non-failing range check.
+define i32 @test_increasing_ult_ult_wide_simple_no_postloop() {
+
+; CHECK-LABEL: @test_increasing_ult_ult_wide_simple_no_postloop(
+; CHECK-NOT:   preloop
+; CHECK-NOT:   postloop
+; CHECK:       loop:
+; CHECK:       br i1 true, label %backedge, label %check_failed
+
+entry:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
+  %rc = icmp ult i64 %iv, 100
+  br i1 %rc, label %backedge, label %check_failed
+
+backedge:
+  %iv.next = add i64 %iv, 1
+  %narrow.iv = trunc i64 %iv.next to i32
+  %latch.cond = icmp ult i32 %narrow.iv, 100
+  br i1 %latch.cond, label %loop, label %exit
+
+exit:
+  ret i32 %narrow.iv
+
+check_failed:
+  ret i32 -1
+}
+
+; This range check fails on the last iteration, so it needs a postloop.
+define i32 @test_increasing_ult_ult_wide_simple_postloop() {
+
+; CHECK-LABEL: @test_increasing_ult_ult_wide_simple_postloop(
+; CHECK-NOT:   preloop
+; CHECK:       loop:
+; CHECK:       br i1 true, label %backedge, label %check_failed
+; CHECK:       backedge
+; CHECK:       [[COND:%[^ ]+]] = icmp ult i64 %wide.narrow.iv, 99
+; CHECK:       br i1 [[COND]], label %loop, label %main.exit.selector
+; CHECK:       postloop
+
+entry:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
+  %rc = icmp ult i64 %iv, 99
+  br i1 %rc, label %backedge, label %check_failed
+
+backedge:
+  %iv.next = add i64 %iv, 1
+  %narrow.iv = trunc i64 %iv.next to i32
+  %latch.cond = icmp ult i32 %narrow.iv, 100
+  br i1 %latch.cond, label %loop, label %exit
+
+exit:
+  ret i32 %narrow.iv
+
+check_failed:
+  ret i32 -1
+}
+
+; General case. If both %N and %M are non-negative, we do not need a preloop.
+define i32 @test_increasing_ult_ult_wide_non-negative(i32* %n_ptr, i64* %m_ptr) {
+
+; CHECK-LABEL: @test_increasing_ult_ult_wide_non-negative(
+; CHECK-NOT:   preloop
+; CHECK:       loop:
+; CHECK:       br i1 true, label %backedge, label %check_failed
+; CHECK:       backedge
+; CHECK:       [[COND:%[^ ]+]] = icmp ult i64 %wide.narrow.iv, %exit.mainloop.at
+; CHECK:       br i1 [[COND]], label %loop, label %main.exit.selector
+; CHECK:       postloop
+
+entry:
+  %N = load i32, i32* %n_ptr, !range !2
+  %M = load i64, i64* %m_ptr, !range !1
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
+  %rc = icmp ult i64 %iv, %M
+  br i1 %rc, label %backedge, label %check_failed
+
+backedge:
+  %iv.next = add i64 %iv, 1
+  %narrow.iv = trunc i64 %iv.next to i32
+  %latch.cond = icmp ult i32 %narrow.iv, %N
+  br i1 %latch.cond, label %loop, label %exit
+
+exit:
+  ret i32 %narrow.iv
+
+check_failed:
+  ret i32 -1
+}
+
+; General case. Even though %M may be negative, we do not need a preloop because
+; we make a non-negativity runtime check against M and do not go to main loop if
+; M was negative.
+define i32 @test_increasing_ult_ult_wide_general(i32* %n_ptr, i64* %m_ptr) {
+
+; CHECK-LABEL: @test_increasing_ult_ult_wide_general(
+; CHECK-NOT:   preloop
+; CHECK:       loop:
+; CHECK:       br i1 true, label %backedge, label %check_failed
+; CHECK:       backedge
+; CHECK:       [[COND:%[^ ]+]] = icmp ult i64
+; CHECK:       br i1 [[COND]], label %loop, label %main.exit.selector
+; CHECK:       postloop
+
+entry:
+  %N = load i32, i32* %n_ptr, !range !2
+  %M = load i64, i64* %m_ptr
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
+  %rc = icmp ult i64 %iv, %M
+  br i1 %rc, label %backedge, label %check_failed
+
+backedge:
+  %iv.next = add i64 %iv, 1
+  %narrow.iv = trunc i64 %iv.next to i32
+  %latch.cond = icmp ult i32 %narrow.iv, %N
+  br i1 %latch.cond, label %loop, label %exit
+
+exit:
+  ret i32 %narrow.iv
+
+check_failed:
+  ret i32 -1
+}
+
+; Same as above, multiple checks.
+define i32 @test_increasing_ult_ult_wide_multiple_checks(i32* %n_ptr, i64* %m1_ptr, i64* %m2_ptr, i64* %m3_ptr, i64* %m4_ptr) {
+; CHECK-LABEL: @test_increasing_ult_ult_wide_multiple_checks(
+; CHECK-NOT:   preloop
+; CHECK:       loop:
+; CHECK:       %c1 = and i1 true, true
+; CHECK:       %c2 = and i1 %c1, true
+; CHECK:       %rc = and i1 %c2, true
+; CHECK:       br i1 %rc, label %backedge, label %check_failed.loopexit
+; CHECK:       backedge
+; CHECK:       [[COND:%[^ ]+]] = icmp ult i64
+; CHECK:       br i1 [[COND]], label %loop, label %main.exit.selector
+; CHECK:       postloop
+
+entry:
+  %N = load i32, i32* %n_ptr, !range !2
+  %M1 = load i64, i64* %m1_ptr
+  %M2 = load i64, i64* %m2_ptr
+  %M3 = load i64, i64* %m3_ptr
+  %M4 = load i64, i64* %m4_ptr
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
+  %rc1 = icmp ult i64 %iv, %M1
+  %rc2 = icmp ult i64 %iv, %M2
+  %rc3 = icmp ult i64 %iv, %M3
+  %rc4 = icmp ult i64 %iv, %M4
+  %c1 = and i1 %rc1, %rc2
+  %c2 = and i1 %c1, %rc3
+  %rc = and i1 %c2, %rc4
+  br i1 %rc, label %backedge, label %check_failed
+
+backedge:
+  %iv.next = add i64 %iv, 1
+  %narrow.iv = trunc i64 %iv.next to i32
+  %latch.cond = icmp ult i32 %narrow.iv, %N
+  br i1 %latch.cond, label %loop, label %exit
+
+exit:
+  ret i32 %narrow.iv
+
+check_failed:
+  ret i32 -1
+}
+
+; Wide IV against narrow range check. We don't currently support it.
+define i32 @test_increasing_ult_ult_wide_simple_negtest_narrow_rc() {
+
+; CHECK-LABEL: @test_increasing_ult_ult_wide_simple_negtest_narrow_rc(
+; CHECK-NOT:   i1 true
+; CHECK-NOT:   main
+
+entry:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %backedge ]
+  %narrow.iv = trunc i64 %iv to i32
+  %rc = icmp ult i32 %narrow.iv, 101
+  br i1 %rc, label %backedge, label %check_failed
+
+backedge:
+  %iv.next = add i64 %iv, 1
+  %latch.cond = icmp ult i64 %iv, 100
+  br i1 %latch.cond, label %loop, label %exit
+
+exit:
+  ret i32 %narrow.iv
+
+check_failed:
+  ret i32 -1
+}
+
+!0 = !{i32 0, i32 2147483647}
+!1 = !{i64 0, i64 9223372036854775807}
+!2 = !{i32 1, i32 2147483647}




More information about the llvm-commits mailing list