cl::init(true));
namespace {
-class LoopPredication {
- /// Represents an induction variable check:
- /// icmp Pred, <induction variable>, <loop invariant limit>
- struct LoopICmp {
- ICmpInst::Predicate Pred;
- const SCEVAddRecExpr *IV;
- const SCEV *Limit;
- LoopICmp(ICmpInst::Predicate Pred, const SCEVAddRecExpr *IV,
- const SCEV *Limit)
- : Pred(Pred), IV(IV), Limit(Limit) {}
- LoopICmp() {}
- void dump() {
- dbgs() << "LoopICmp Pred = " << Pred << ", IV = " << *IV
- << ", Limit = " << *Limit << "\n";
- }
- };
+/// Represents an induction variable check:
+/// icmp Pred, <induction variable>, <loop invariant limit>
+struct LoopICmp {
+ ICmpInst::Predicate Pred;
+ const SCEVAddRecExpr *IV;
+ const SCEV *Limit;
+ LoopICmp(ICmpInst::Predicate Pred, const SCEVAddRecExpr *IV,
+ const SCEV *Limit)
+ : Pred(Pred), IV(IV), Limit(Limit) {}
+ LoopICmp() {}
+ void dump() {
+ dbgs() << "LoopICmp Pred = " << Pred << ", IV = " << *IV
+ << ", Limit = " << *Limit << "\n";
+ }
+};
+class LoopPredication {
AliasAnalysis *AA;
ScalarEvolution *SE;
BranchProbabilityInfo *BPI;
return getLoopPassPreservedAnalyses();
}
-Optional<LoopPredication::LoopICmp>
+Optional<LoopICmp>
LoopPredication::parseLoopICmp(ICmpInst::Predicate Pred, Value *LHS,
Value *RHS) {
const SCEV *LHSS = SE->getSCEV(LHS);
return Builder.CreateICmp(Pred, LHSV, RHSV);
}
-Optional<LoopPredication::LoopICmp>
+Optional<LoopICmp>
LoopPredication::generateLoopLatchCheck(Type *RangeCheckType) {
auto *LatchType = LatchCheck.IV->getType();
}
Optional<Value *> LoopPredication::widenICmpRangeCheckIncrementingLoop(
- LoopPredication::LoopICmp LatchCheck, LoopPredication::LoopICmp RangeCheck,
+ LoopICmp LatchCheck, LoopICmp RangeCheck,
SCEVExpander &Expander, Instruction *Guard) {
auto *Ty = RangeCheck.IV->getType();
// Generate the widened condition for the forward loop:
}
Optional<Value *> LoopPredication::widenICmpRangeCheckDecrementingLoop(
- LoopPredication::LoopICmp LatchCheck, LoopPredication::LoopICmp RangeCheck,
+ LoopICmp LatchCheck, LoopICmp RangeCheck,
SCEVExpander &Expander, Instruction *Guard) {
auto *Ty = RangeCheck.IV->getType();
const SCEV *GuardStart = RangeCheck.IV->getStart();
return Builder.CreateAnd(FirstIterationCheck, LimitCheck);
}
+static void normalizePredicate(ScalarEvolution *SE, Loop *L,
+ LoopICmp& RC) {
+ // LFTR canonicalizes checks to the ICMP_NE form instead of an ULT/SLT form.
+ // Normalize back to the ULT/SLT form for ease of handling.
+ if (RC.Pred == ICmpInst::ICMP_NE &&
+ RC.IV->getStepRecurrence(*SE)->isOne() &&
+ SE->isKnownPredicate(ICmpInst::ICMP_ULE, RC.IV->getStart(), RC.Limit))
+ RC.Pred = ICmpInst::ICMP_ULT;
+}
+
+
/// If ICI can be widened to a loop invariant condition emits the loop
/// invariant condition in the loop preheader and return it, otherwise
/// returns None.
return true;
}
-Optional<LoopPredication::LoopICmp> LoopPredication::parseLoopLatchICmp() {
+Optional<LoopICmp> LoopPredication::parseLoopLatchICmp() {
using namespace PatternMatch;
BasicBlock *LoopLatch = L->getLoopLatch();
}
};
+ normalizePredicate(SE, L, *Result);
if (IsUnsupportedPredicate(Step, Result->Pred)) {
LLVM_DEBUG(dbgs() << "Unsupported loop latch predicate(" << Result->Pred
<< ")!\n");
; CHECK-NEXT: loop.preheader:
; CHECK-NEXT: [[N:%.*]] = zext i16 [[N16:%.*]] to i32
; CHECK-NEXT: [[NPLUS1:%.*]] = add nuw nsw i32 [[N]], 1
+; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 [[NPLUS1]], [[LENGTH:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 0, [[LENGTH]]
+; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
-; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH:%.*]]
-; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP2]], i32 9) [ "deopt"() ]
; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i32 [[I]], 1
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I_NEXT]], [[NPLUS1]]
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK-LABEL: @ne_latch_zext_preinc(
; CHECK-NEXT: loop.preheader:
; CHECK-NEXT: [[N:%.*]] = zext i16 [[N16:%.*]] to i32
+; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[LENGTH:%.*]], -1
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ule i32 [[N]], [[TMP0]]
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 0, [[LENGTH]]
+; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER:%.*]] ]
-; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH:%.*]]
-; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I]], [[N]]
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[N:%.*]], 0
; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
; CHECK: loop.preheader:
+; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[LENGTH:%.*]], -1
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ule i32 [[N]], [[TMP0]]
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 0, [[LENGTH]]
+; CHECK-NEXT: [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
-; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LENGTH:%.*]]
-; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP3]], i32 9) [ "deopt"() ]
; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ne i32 [[I]], [[N]]
; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]