diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -156,7 +156,8 @@ bool rewriteNonIntegerIVs(Loop *L); bool simplifyAndExtend(Loop *L, SCEVExpander &Rewriter, LoopInfo *LI); - /// See if we can convert an exit condition from signed to unsigned. + /// Try to improve our exit conditions by converting condition from signed + /// to unsigned or rotating computation out of the loop. /// (See inline comment about why this is duplicated from simplifyAndExtend) bool canonicalizeExitCondition(Loop *L); /// Try to eliminate loop exits based on analyzeable exit counts @@ -1482,6 +1483,83 @@ continue; } } + + // Now that we've canonicalized the condition to match the extend, + // see if we can rotate the extend out of the loop. + for (auto *ExitingBB : ExitingBlocks) { + auto *BI = dyn_cast(ExitingBB->getTerminator()); + if (!BI) + continue; + assert(BI->isConditional() && "exit branch must be conditional"); + + auto *ICmp = dyn_cast(BI->getCondition()); + if (!ICmp || !ICmp->hasOneUse() || !ICmp->isUnsigned()) + continue; + + auto *LHS = ICmp->getOperand(0); + auto *RHS = ICmp->getOperand(1); + if (L->isLoopInvariant(LHS) || !L->isLoopInvariant(RHS)) + // Nothing to rotate + continue; + + if (!LHS->hasOneUse()) + // Can't rotate without increasing instruction count + continue; + + // Match (icmp unsigned-cond zext, RHS) + // TODO: Extend to handle corresponding sext/signed-cmp case + // TODO: Extend to other invertible functions + Value *LHSOp = nullptr; + if (!match(LHS, m_ZExt(m_Value(LHSOp)))) + continue; + + // Given a icmp unsigned-cond zext(Op) where zext(trunc(RHS)) == RHS + // replace with an icmp of the form icmp unsigned-cond Op, trunc(RHS) + // when zext is loop varying and RHS is loop invariant. This converts + // loop varying work to loop-invariant work. + auto doRotateTransform = [&]() { + assert(ICmp->isUnsigned() && "must have proven unsigned already"); + auto *NewRHS = + CastInst::Create(Instruction::Trunc, RHS, LHSOp->getType(), "", + L->getLoopPreheader()->getTerminator()); + ICmp->setOperand(0, LHSOp); + ICmp->setOperand(1, NewRHS); + if (LHS->use_empty()) + DeadInsts.push_back(LHS); + }; + + + const DataLayout &DL = ExitingBB->getModule()->getDataLayout(); + const unsigned InnerBitWidth = DL.getTypeSizeInBits(LHSOp->getType()); + const unsigned OuterBitWidth = DL.getTypeSizeInBits(RHS->getType()); + auto FullCR = ConstantRange::getFull(InnerBitWidth); + FullCR = FullCR.zeroExtend(OuterBitWidth); + if (FullCR.contains(SE->getUnsignedRange(SE->getSCEV(RHS)))) { + doRotateTransform(); + Changed = true; + // Note, we are leaving SCEV in an unfortunately imprecise case here + // as rotation tends to reveal information about trip counts not + // previously visible. + continue; + } + + // If we have a loop which would be undefined if infinite, and it has at + // most one possible dynamic exit, then we can conclude that exit must + // be taken. If that exit must be taken, and we know the LHS can only + // take values in the positive domain, then we can conclude RHS must + // also be in that same range. + if (ExitingBlocks.size() == 1 && SE->loopHasNoAbnormalExits(L) && + SE->loopIsFiniteByAssumption(L)) { + doRotateTransform(); + Changed = true; + // Given we've changed exit counts, notify SCEV. + // Some nested loops may share same folded exit basic block, + // thus we need to notify top most loop. + SE->forgetTopmostLoop(L); + continue; + } + } + return Changed; } @@ -1866,8 +1944,8 @@ // Eliminate redundant IV cycles. NumElimIV += Rewriter.replaceCongruentIVs(L, DT, DeadInsts); - // Try to convert exit conditions to unsigned - // Note: Handles invalidation internally if needed. + // Try to convert exit conditions to unsigned and rotate computation + // out of the loop. Note: Handles invalidation internally if needed. Changed |= canonicalizeExitCondition(L); // Try to eliminate loop exits based on analyzeable exit counts diff --git a/llvm/test/Transforms/IndVarSimplify/finite-exit-comparisons.ll b/llvm/test/Transforms/IndVarSimplify/finite-exit-comparisons.ll --- a/llvm/test/Transforms/IndVarSimplify/finite-exit-comparisons.ll +++ b/llvm/test/Transforms/IndVarSimplify/finite-exit-comparisons.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -indvars -S < %s | FileCheck %s +; RUN: opt -indvars -S < %s -indvars-predicate-loops=0 | FileCheck %s ; A collection of tests which domonstrate cases where we can use properties ; of the loop (i.e. single exit, finite, mustprogress) to optimize conditions @@ -10,12 +10,12 @@ define void @slt_constant_rhs(i16 %n.raw, i8 %start) mustprogress { ; CHECK-LABEL: @slt_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 254 to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ [[START:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i16 [[ZEXT]], 254 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -38,13 +38,13 @@ define void @slt_constant_rhs_maythrow(i16 %n.raw, i8 %start) mustprogress { ; CHECK-LABEL: @slt_constant_rhs_maythrow( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 254 to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ [[START:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 ; CHECK-NEXT: call void @unknown() -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i16 [[ZEXT]], 254 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -68,14 +68,14 @@ define void @slt_constant_rhs_multiexit(i16 %n.raw, i8 %start, i1 %c) mustprogress { ; CHECK-LABEL: @slt_constant_rhs_multiexit( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 254 to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ], [ [[START:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 ; CHECK-NEXT: br i1 [[C:%.*]], label [[LATCH]], label [[FOR_END:%.*]] ; CHECK: latch: -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i16 [[ZEXT]], 254 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -100,13 +100,14 @@ define void @slt_non_constant_rhs(i16 %n) mustprogress { ; CHECK-LABEL: @slt_non_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 [[N:%.*]] to i8 +; CHECK-NEXT: [[UMAX:%.*]] = call i8 @llvm.umax.i8(i8 [[TMP0]], i8 1) ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i16 [[ZEXT]], [[N:%.*]] -; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i8 [[IV_NEXT]], [[UMAX]] +; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void ; @@ -129,12 +130,12 @@ ; CHECK-LABEL: @slt_non_constant_rhs_no_mustprogress( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[N:%.*]] = and i16 [[N_RAW:%.*]], 255 +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 [[N]] to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i16 [[ZEXT]], [[N]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -416,12 +417,12 @@ define void @sgt_constant_rhs(i16 %n.raw, i8 %start) mustprogress { ; CHECK-LABEL: @sgt_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 254 to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ [[START:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i16 [[ZEXT]], 254 +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -443,12 +444,12 @@ define void @sgt_non_constant_rhs(i16 %n) mustprogress { ; CHECK-LABEL: @sgt_non_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 [[N:%.*]] to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i16 [[ZEXT]], [[N:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -470,12 +471,12 @@ define void @sle_constant_rhs(i16 %n.raw, i8 %start) mustprogress { ; CHECK-LABEL: @sle_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 254 to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ [[START:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ule i16 [[ZEXT]], 254 +; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -497,12 +498,12 @@ define void @sle_non_constant_rhs(i16 %n) mustprogress { ; CHECK-LABEL: @sle_non_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 [[N:%.*]] to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ule i16 [[ZEXT]], [[N:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -524,12 +525,12 @@ define void @sge_constant_rhs(i16 %n.raw, i8 %start) mustprogress { ; CHECK-LABEL: @sge_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 254 to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ [[START:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp uge i16 [[ZEXT]], 254 +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -551,12 +552,12 @@ define void @sge_non_constant_rhs(i16 %n) mustprogress { ; CHECK-LABEL: @sge_non_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 [[N:%.*]] to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp uge i16 [[ZEXT]], [[N:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -578,12 +579,12 @@ define void @ult_constant_rhs(i16 %n.raw, i8 %start) mustprogress { ; CHECK-LABEL: @ult_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 254 to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ [[START:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i16 [[ZEXT]], 254 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -605,13 +606,14 @@ define void @ult_non_constant_rhs(i16 %n) mustprogress { ; CHECK-LABEL: @ult_non_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 [[N:%.*]] to i8 +; CHECK-NEXT: [[UMAX:%.*]] = call i8 @llvm.umax.i8(i8 [[TMP0]], i8 1) ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i16 [[ZEXT]], [[N:%.*]] -; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i8 [[IV_NEXT]], [[UMAX]] +; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void ; @@ -632,12 +634,12 @@ define void @ugt_constant_rhs(i16 %n.raw, i8 %start) mustprogress { ; CHECK-LABEL: @ugt_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 254 to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ [[START:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i16 [[ZEXT]], 254 +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -659,12 +661,12 @@ define void @ugt_non_constant_rhs(i16 %n) mustprogress { ; CHECK-LABEL: @ugt_non_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 [[N:%.*]] to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i16 [[ZEXT]], [[N:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -686,12 +688,12 @@ define void @ule_constant_rhs(i16 %n.raw, i8 %start) mustprogress { ; CHECK-LABEL: @ule_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 254 to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ [[START:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ule i16 [[ZEXT]], 254 +; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -713,12 +715,12 @@ define void @ule_non_constant_rhs(i16 %n) mustprogress { ; CHECK-LABEL: @ule_non_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 [[N:%.*]] to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp ule i16 [[ZEXT]], [[N:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -740,12 +742,12 @@ define void @uge_constant_rhs(i16 %n.raw, i8 %start) mustprogress { ; CHECK-LABEL: @uge_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 254 to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ [[START:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp uge i16 [[ZEXT]], 254 +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void @@ -767,12 +769,12 @@ define void @uge_non_constant_rhs(i16 %n) mustprogress { ; CHECK-LABEL: @uge_non_constant_rhs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = trunc i16 [[N:%.*]] to i8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[IV_NEXT]] to i16 -; CHECK-NEXT: [[CMP:%.*]] = icmp uge i16 [[ZEXT]], [[N:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]] ; CHECK: for.end: ; CHECK-NEXT: ret void