Index: llvm/lib/Transforms/Scalar/LoopPredication.cpp =================================================================== --- llvm/lib/Transforms/Scalar/LoopPredication.cpp +++ llvm/lib/Transforms/Scalar/LoopPredication.cpp @@ -179,6 +179,7 @@ #include "llvm/Transforms/Scalar/LoopPredication.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/GuardUtils.h" #include "llvm/Analysis/LoopInfo.h" @@ -187,7 +188,9 @@ #include "llvm/Analysis/MemorySSAUpdater.h" #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" #include "llvm/IR/PatternMatch.h" @@ -195,6 +198,7 @@ #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/KnownBits.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/GuardUtils.h" #include "llvm/Transforms/Utils/Local.h" @@ -206,6 +210,8 @@ STATISTIC(TotalConsidered, "Number of guards considered"); STATISTIC(TotalWidened, "Number of checks widened"); +STATISTIC(NumWidenedUsingConstantRanges, + "Number of checks widened using constant ranges analysis"); using namespace llvm; @@ -241,6 +247,12 @@ "predicated guards"), cl::init(true)); +static cl::opt WidenChecksUsingConstantRanges( + "loop-predication-widen-checks-using-contant-ranges", cl::Hidden, + cl::desc( + "Whether or not we should widen checks using constant range analysis"), + cl::init(true)); + namespace { /// Represents an induction variable check: /// icmp Pred, , @@ -264,6 +276,7 @@ ScalarEvolution *SE; LoopInfo *LI; MemorySSAUpdater *MSSAU; + AssumptionCache *AC; Loop *L; const DataLayout *DL; @@ -297,6 +310,8 @@ Optional widenICmpRangeCheck(ICmpInst *ICI, SCEVExpander &Expander, Instruction *Guard); + Optional widenRangeCheckUsingConstantRange(ICmpInst *ICI, + Instruction *Guard); Optional widenICmpRangeCheckIncrementingLoop(LoopICmp LatchCheck, LoopICmp RangeCheck, SCEVExpander &Expander, @@ -319,8 +334,8 @@ public: LoopPredication(AliasAnalysis *AA, DominatorTree *DT, ScalarEvolution *SE, - LoopInfo *LI, MemorySSAUpdater *MSSAU) - : AA(AA), DT(DT), SE(SE), LI(LI), MSSAU(MSSAU){}; + LoopInfo *LI, MemorySSAUpdater *MSSAU, AssumptionCache *AC) + : AA(AA), DT(DT), SE(SE), LI(LI), MSSAU(MSSAU), AC(AC){}; bool runOnLoop(Loop *L); }; @@ -340,6 +355,8 @@ bool runOnLoop(Loop *L, LPPassManager &LPM) override { if (skipLoop(L)) return false; + Function &F = *L->getHeader()->getParent(); + auto *SE = &getAnalysis().getSE(); auto *LI = &getAnalysis().getLoopInfo(); auto *DT = &getAnalysis().getDomTree(); @@ -348,7 +365,8 @@ if (MSSAWP) MSSAU = std::make_unique(&MSSAWP->getMSSA()); auto *AA = &getAnalysis().getAAResults(); - LoopPredication LP(AA, DT, SE, LI, MSSAU ? MSSAU.get() : nullptr); + auto *AC = &getAnalysis().getAssumptionCache(F); + LoopPredication LP(AA, DT, SE, LI, MSSAU ? MSSAU.get() : nullptr, AC); return LP.runOnLoop(L); } }; @@ -374,7 +392,7 @@ if (AR.MSSA) MSSAU = std::make_unique(AR.MSSA); LoopPredication LP(&AR.AA, &AR.DT, &AR.SE, &AR.LI, - MSSAU ? MSSAU.get() : nullptr); + MSSAU ? MSSAU.get() : nullptr, &AR.AC); if (!LP.runOnLoop(&L)) return PreservedAnalyses::all(); @@ -752,6 +770,83 @@ } } +Optional +LoopPredication::widenRangeCheckUsingConstantRange(ICmpInst *ICI, + Instruction *Guard) { + if (!WidenChecksUsingConstantRanges || !L->contains(Guard->getParent())) + return None; + LLVM_DEBUG(dbgs() << "Analyzing ICmpInst condition using constant range:\n"); + LLVM_DEBUG(ICI->dump()); + + // We are looking for the range checks of the form: + // x < guardLimit, + // where x and guardLimit have known constant ranges (meaning they are not + // full-set). If they are reasonably small and max(x) <= max(guardLimit), we + // can predicate the loop with the condition max(x) <= guardLimit. + auto Pred = ICI->getPredicate(); + auto *LHS = ICI->getOperand(0); + auto *RHS = ICI->getOperand(1); + + // Both operands are loop variant, bail out. + if (!L->isLoopInvariant(LHS) && !L->isLoopInvariant(RHS)) { + LLVM_DEBUG(dbgs() << "LHS and RHS are loop variant\n"); + return None; + } + + auto ComputeRange = [this](const Value *V, bool IsSigned, + const Instruction *CtxI) { + auto Range = ConstantRange::fromKnownBits( + computeKnownBits(V, *DL, 0, AC, CtxI, DT), IsSigned); + return Range.intersectWith( + computeConstantRange(V, IsSigned, true, AC, CtxI, DT)); + }; + + // We don't support equality predicates currently. + switch (Pred) { + case CmpInst::ICMP_EQ: + case CmpInst::ICMP_NE: + return None; + case CmpInst::ICMP_UGT: + case CmpInst::ICMP_UGE: + case CmpInst::ICMP_SGT: + case CmpInst::ICMP_SGE: + std::swap(LHS, RHS); + Pred = ICmpInst::getSwappedPredicate(Pred); + break; + default: + break; + } + + bool IsSigned = ICmpInst::isSigned(Pred); + auto RHSRange = ComputeRange(RHS, IsSigned, Guard); + if (RHSRange.isFullSet()) { + LLVM_DEBUG(dbgs() << "RHS range is full-set\n"); + return None; + } + + auto LHSRange = ComputeRange(LHS, IsSigned, Guard); + + auto LHSMaxValue = + IsSigned ? LHSRange.getSignedMax() : LHSRange.getUnsignedMax(); + bool LHSMaxIsGreaterThanRHSMax = + IsSigned ? LHSMaxValue.sgt(RHSRange.getSignedMax()) + : LHSMaxValue.ugt(RHSRange.getUnsignedMax()); + + if (LHSMaxIsGreaterThanRHSMax) { + LLVM_DEBUG(dbgs() << "LHS max value is not greater than RHS maximum\n"); + return None; + } + + ICmpInst::Predicate NewPred = ICmpInst::getNonStrictPredicate(Pred); + LLVM_DEBUG(dbgs() << "Speculating " << LHSMaxValue << " " + << ICmpInst::getPredicateName(NewPred) << " " << *RHS + << " because max(LHS) < max(RHS)\n"); + auto *MaxCI = ConstantInt::get(LHS->getType(), LHSMaxValue); + IRBuilder<> Builder(findInsertPt(Guard, {RHS})); + auto *NewICI = Builder.CreateICmp(NewPred, MaxCI, RHS); + return NewICI; +} + unsigned LoopPredication::collectChecks(SmallVectorImpl &Checks, Value *Condition, SCEVExpander &Expander, @@ -792,6 +887,12 @@ NumWidened++; continue; } + if (auto RC = widenRangeCheckUsingConstantRange(ICI, Guard)) { + Checks.push_back(*RC); + NumWidened++; + NumWidenedUsingConstantRanges++; + continue; + } } // Save the condition as is if we can't widen it Index: llvm/test/Transforms/LoopPredication/constant-ranges.ll =================================================================== --- llvm/test/Transforms/LoopPredication/constant-ranges.ll +++ llvm/test/Transforms/LoopPredication/constant-ranges.ll @@ -1,10 +1,11 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -S -passes='loop-mssa(loop-predication)' -loop-predication-insert-assumes-of-predicated-guards-conditions=false < %s 2>&1 | FileCheck %s +; RUN: opt -S -passes='loop-mssa(loop-predication)' -loop-predication-widen-checks-using-contant-ranges=true -loop-predication-insert-assumes-of-predicated-guards-conditions=false < %s 2>&1 | FileCheck %s define i32 @test_ult(ptr noundef %p, i32 noundef %n, ptr noundef %arr, ptr noundef %len_p, i32 noundef %c) { ; CHECK-LABEL: @test_ult( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0:![0-9]+]], !noundef !1 +; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 127, [[LEN]] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] @@ -14,10 +15,9 @@ ; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]] ; CHECK: do_range_check: ; CHECK-NEXT: call void @llvm.assume(i1 [[BOUND_CHECK]]) -; CHECK-NEXT: [[RANGE_CHECK_ULT:%.*]] = icmp ult i32 [[EL]], [[LEN]] ; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition() -; CHECK-NEXT: [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_ULT]], [[WC]] -; CHECK-NEXT: br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[TMP0]], [[WC]] +; CHECK-NEXT: br i1 [[TMP1]], label [[BACKEDGE]], label [[DEOPT:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]] ; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4 @@ -72,6 +72,7 @@ ; CHECK-LABEL: @test_slt( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0]], !noundef !1 +; CHECK-NEXT: [[TMP0:%.*]] = icmp sle i32 127, [[LEN]] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] @@ -81,10 +82,9 @@ ; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]] ; CHECK: do_range_check: ; CHECK-NEXT: call void @llvm.assume(i1 [[BOUND_CHECK]]) -; CHECK-NEXT: [[RANGE_CHECK_SLT:%.*]] = icmp slt i32 [[EL]], [[LEN]] ; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition() -; CHECK-NEXT: [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_SLT]], [[WC]] -; CHECK-NEXT: br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[TMP0]], [[WC]] +; CHECK-NEXT: br i1 [[TMP1]], label [[BACKEDGE]], label [[DEOPT:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]] ; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4 @@ -139,6 +139,7 @@ ; CHECK-LABEL: @test_ule( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0]], !noundef !1 +; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 127, [[LEN]] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] @@ -148,10 +149,9 @@ ; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]] ; CHECK: do_range_check: ; CHECK-NEXT: call void @llvm.assume(i1 [[BOUND_CHECK]]) -; CHECK-NEXT: [[RANGE_CHECK_ULE:%.*]] = icmp ule i32 [[EL]], [[LEN]] ; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition() -; CHECK-NEXT: [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_ULE]], [[WC]] -; CHECK-NEXT: br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[TMP0]], [[WC]] +; CHECK-NEXT: br i1 [[TMP1]], label [[BACKEDGE]], label [[DEOPT:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]] ; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4 @@ -206,6 +206,7 @@ ; CHECK-LABEL: @test_sle( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0]], !noundef !1 +; CHECK-NEXT: [[TMP0:%.*]] = icmp sle i32 127, [[LEN]] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] @@ -215,10 +216,9 @@ ; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]] ; CHECK: do_range_check: ; CHECK-NEXT: call void @llvm.assume(i1 [[BOUND_CHECK]]) -; CHECK-NEXT: [[RANGE_CHECK_SLE:%.*]] = icmp sle i32 [[EL]], [[LEN]] ; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition() -; CHECK-NEXT: [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_SLE]], [[WC]] -; CHECK-NEXT: br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[TMP0]], [[WC]] +; CHECK-NEXT: br i1 [[TMP1]], label [[BACKEDGE]], label [[DEOPT:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]] ; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4 @@ -273,6 +273,7 @@ ; CHECK-LABEL: @test_ugt( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0]], !noundef !1 +; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 127, [[LEN]] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] @@ -282,10 +283,9 @@ ; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]] ; CHECK: do_range_check: ; CHECK-NEXT: call void @llvm.assume(i1 [[BOUND_CHECK]]) -; CHECK-NEXT: [[RANGE_CHECK_SLE:%.*]] = icmp ugt i32 [[LEN]], [[EL]] ; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition() -; CHECK-NEXT: [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_SLE]], [[WC]] -; CHECK-NEXT: br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[TMP0]], [[WC]] +; CHECK-NEXT: br i1 [[TMP1]], label [[BACKEDGE]], label [[DEOPT:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]] ; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4 @@ -340,6 +340,7 @@ ; CHECK-LABEL: @test_uge( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0]], !noundef !1 +; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 127, [[LEN]] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] @@ -349,10 +350,9 @@ ; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]] ; CHECK: do_range_check: ; CHECK-NEXT: call void @llvm.assume(i1 [[BOUND_CHECK]]) -; CHECK-NEXT: [[RANGE_CHECK_SLE:%.*]] = icmp uge i32 [[LEN]], [[EL]] ; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition() -; CHECK-NEXT: [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_SLE]], [[WC]] -; CHECK-NEXT: br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[TMP0]], [[WC]] +; CHECK-NEXT: br i1 [[TMP1]], label [[BACKEDGE]], label [[DEOPT:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]] ; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4 @@ -407,6 +407,7 @@ ; CHECK-LABEL: @test_sgt( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0]], !noundef !1 +; CHECK-NEXT: [[TMP0:%.*]] = icmp sle i32 127, [[LEN]] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] @@ -416,10 +417,9 @@ ; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]] ; CHECK: do_range_check: ; CHECK-NEXT: call void @llvm.assume(i1 [[BOUND_CHECK]]) -; CHECK-NEXT: [[RANGE_CHECK_SLE:%.*]] = icmp sgt i32 [[LEN]], [[EL]] ; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition() -; CHECK-NEXT: [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_SLE]], [[WC]] -; CHECK-NEXT: br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[TMP0]], [[WC]] +; CHECK-NEXT: br i1 [[TMP1]], label [[BACKEDGE]], label [[DEOPT:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]] ; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4 @@ -474,6 +474,7 @@ ; CHECK-LABEL: @test_sge( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[LEN_P:%.*]], align 4, !range [[RNG0]], !noundef !1 +; CHECK-NEXT: [[TMP0:%.*]] = icmp sle i32 127, [[LEN]] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] @@ -483,10 +484,9 @@ ; CHECK-NEXT: br i1 [[BOUND_CHECK]], label [[DO_RANGE_CHECK:%.*]], label [[BOUND_CHECK_FAILED:%.*]] ; CHECK: do_range_check: ; CHECK-NEXT: call void @llvm.assume(i1 [[BOUND_CHECK]]) -; CHECK-NEXT: [[RANGE_CHECK_SLE:%.*]] = icmp sge i32 [[LEN]], [[EL]] ; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition() -; CHECK-NEXT: [[EXPLICIT_GUARD_COND:%.*]] = and i1 [[RANGE_CHECK_SLE]], [[WC]] -; CHECK-NEXT: br i1 [[EXPLICIT_GUARD_COND]], label [[BACKEDGE]], label [[DEOPT:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[TMP0]], [[WC]] +; CHECK-NEXT: br i1 [[TMP1]], label [[BACKEDGE]], label [[DEOPT:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[ARR_PTR:%.*]] = getelementptr i32, ptr [[ARR:%.*]], i32 [[EL]] ; CHECK-NEXT: store i32 [[IV]], ptr [[ARR_PTR]], align 4