Index: llvm/include/llvm/Analysis/ScalarEvolution.h =================================================================== --- llvm/include/llvm/Analysis/ScalarEvolution.h +++ llvm/include/llvm/Analysis/ScalarEvolution.h @@ -1552,8 +1552,9 @@ /// SCEVUnknowns and thus don't use this mechanism. ConstantRange getRangeForUnknownRecurrence(const SCEVUnknown *U); - /// Sharpen range of entire SCEVUnknown Phi strongly connected component that - /// includes \p Phi. On output, \p ConservativeResult is the sharpened range. + /// Sharpen range of a strongly connected component that includes \p Phi and + /// is composed of Phis and nuw+nsw binops. On output, \p ConservativeResult + /// is the sharpened range. void sharpenPhiSCCRange(const PHINode *Phi, ConstantRange &ConservativeResult, ScalarEvolution::RangeSignHint SignHint); Index: llvm/lib/Analysis/ScalarEvolution.cpp =================================================================== --- llvm/lib/Analysis/ScalarEvolution.cpp +++ llvm/lib/Analysis/ScalarEvolution.cpp @@ -6284,15 +6284,22 @@ ScalarEvolution::sharpenPhiSCCRange(const PHINode *Phi, ConstantRange &ConservativeResult, ScalarEvolution::RangeSignHint SignHint) { - // Collect strongly connected component (further on - SCC ) composed of Phis. + // Collect strongly connected component (further on - SCC ) composed of Phis + // and nuw+nsw binary operators. // Analyze all values that are incoming to this SCC (we call them roots). - // All SCC elements have range that is not wider than union of ranges of - // roots. - SmallVector Worklist; - SmallPtrSet Reachable; + // There are two possible cases: + // 1. SCC fully consists of Phis. Then all SCC elements have range that is + // not wider than union of ranges of roots. + // 2. SCC contains at least one nuw+nsw BinOp. In this case, we are dealing + // with loop that gets incremented on each iteration. The best we can do + // is to prove that all incoming values of this SCC are non-negative. + // In this case, the entire SCC is also non-negative, because neither a + // Phi translation nor nuw+nsw BinOp can break this invariant. + SmallVector Worklist; + SmallPtrSet Reachable; Reachable.insert(Phi); Worklist.push_back(Phi); - // First, find all PHI nodes that are reachable from Phi. + // First, find all PHI nodes and nuw+nsw binops that are reachable from Phi. while (!Worklist.empty()) { if (Reachable.size() > MaxPhiSCCAnalysisSize) { // Too many nodes to process. Assume that SCC is composed of Phi alone. @@ -6301,26 +6308,44 @@ } auto *Curr = Worklist.pop_back_val(); for (auto &Op : Curr->operands()) { - if (auto *PhiOp = dyn_cast(&*Op)) { + auto *I = dyn_cast(&*Op); + if (!I) + continue; + if (auto *PhiOp = dyn_cast(I)) { if (PendingPhiRanges.count(PhiOp)) continue; if (Reachable.insert(PhiOp).second) Worklist.push_back(PhiOp); - } + } else if (auto *BO = dyn_cast(I)) + // TODO: Handle nuw and nsw separately? + if (BO->hasNoSignedWrap() && BO->hasNoUnsignedWrap()) + if (Reachable.insert(I).second) + Worklist.push_back(I); } } - SmallPtrSet SCC; + SmallPtrSet SCC; SCC.insert(Phi); Worklist.push_back(Phi); + bool SCCContainsOnlyPhis = true; // Out of reachable nodes, find those from which Phi is also reachable. // This defines a SCC. while (!Worklist.empty()) { auto *Curr = Worklist.pop_back_val(); for (auto *User : Curr->users()) { - auto *PN = dyn_cast(User); - if (PN && Reachable.count(PN) && SCC.insert(PN).second) - Worklist.push_back(PN); + auto *I = cast(User); + if (Reachable.count(I)) { + if (!isa(I)) { + auto *BO = dyn_cast(I); + (void)BO; + assert(BO && "Only phis and binary operators are allowed!"); + assert(BO->hasNoSignedWrap() && BO->hasNoUnsignedWrap() && + "Only non-wrapping BOs are allowed!"); + SCCContainsOnlyPhis = false; + } + if (SCC.insert(I).second) + Worklist.push_back(I); + } } } Reachable.clear(); @@ -6329,52 +6354,73 @@ SmallPtrSet Roots; for (auto *PN : SCC) for (auto &Op : PN->operands()) { - auto *PhiInput = dyn_cast(Op); - if (!PhiInput || !SCC.count(PhiInput)) + auto *InsnInput = dyn_cast(Op); + if (!InsnInput || !SCC.count(InsnInput)) Roots.insert(Op); } // Mark SCC elements as pending to avoid infinite recursion if there is a // cyclic dependency through some instruction that is not a PHI. - for (auto *PN : SCC) { - bool Inserted = PendingPhiRanges.insert(PN).second; - assert(Inserted && "PHI is already pending?"); - (void)Inserted; - } + for (auto *I : SCC) + if (auto *PN = dyn_cast(I)) { + bool Inserted = PendingPhiRanges.insert(PN).second; + assert(Inserted && "PHI is already pending?"); + (void)Inserted; + } - auto BitWidth = ConservativeResult.getBitWidth(); - ConstantRange RangeFromRoots(BitWidth, /*isFullSet=*/false); - for (auto *Root : Roots) { - auto OpRange = getRangeRef(getSCEV(Root), SignHint); - RangeFromRoots = RangeFromRoots.unionWith(OpRange); - // No point to continue if we already have a full set. - if (RangeFromRoots.isFullSet()) - break; - } ConstantRange::PreferredRangeType RangeType = SignHint == ScalarEvolution::HINT_RANGE_UNSIGNED ? ConstantRange::Unsigned : ConstantRange::Signed; - ConservativeResult = - ConservativeResult.intersectWith(RangeFromRoots, RangeType); + auto BitWidth = ConservativeResult.getBitWidth(); + if (SCCContainsOnlyPhis) { + // If SCC consists only of Phis, then its range is union of all incoming + // roots. + ConstantRange RangeFromRoots(BitWidth, /*isFullSet=*/false); + for (auto *Root : Roots) { + auto OpRange = getRangeRef(getSCEV(Root), SignHint); + RangeFromRoots = RangeFromRoots.unionWith(OpRange); + // No point to continue if we already have a full set. + if (RangeFromRoots.isFullSet()) + break; + } + ConservativeResult = + ConservativeResult.intersectWith(RangeFromRoots, RangeType); + } else { + // If SCC includes binary operators, the best we can do is to prove that all + // roots are non-negative. In this case, Phi-translations and nuw+nsw + // operations will not violate this invariant. + bool ProvedNonNegative = all_of(Roots, [&](Value *Root) { + auto OpRange = getRangeRef(getSCEV(Root), SignHint); + return OpRange.isAllNonNegative(); + }); + if (ProvedNonNegative) { + auto SignedMaxPlus1 = APInt::getSignedMinValue(BitWidth); + auto RangeFromRoots = + ConstantRange::getNonEmpty(APInt::getZero(BitWidth), SignedMaxPlus1); + ConservativeResult = + ConservativeResult.intersectWith(RangeFromRoots, RangeType); + } + } DenseMap &Cache = SignHint == ScalarEvolution::HINT_RANGE_UNSIGNED ? UnsignedRanges : SignedRanges; // Entire SCC has the same range. - for (auto *PN : SCC) { - bool Erased = PendingPhiRanges.erase(PN); - assert(Erased && "Failed to erase Phi properly?"); - (void)Erased; - auto *PNSCEV = getSCEV(const_cast(PN)); - auto I = Cache.find(PNSCEV); - if (I == Cache.end()) - setRange(PNSCEV, SignHint, ConservativeResult); - else { - auto SharpenedRange = - I->second.intersectWith(ConservativeResult, RangeType); - setRange(PNSCEV, SignHint, SharpenedRange); + for (auto *I : SCC) + if (auto *PN = dyn_cast(I)) { + bool Erased = PendingPhiRanges.erase(PN); + assert(Erased && "Failed to erase Phi properly?"); + (void)Erased; + auto *PNSCEV = getSCEV(const_cast(PN)); + auto I = Cache.find(PNSCEV); + if (I == Cache.end()) + setRange(PNSCEV, SignHint, ConservativeResult); + else { + auto SharpenedRange = + I->second.intersectWith(ConservativeResult, RangeType); + setRange(PNSCEV, SignHint, SharpenedRange); + } } - } } // Given a StartRange, Step and MaxBECount for an expression compute a range of Index: llvm/test/Analysis/ScalarEvolution/outer_phi.ll =================================================================== --- llvm/test/Analysis/ScalarEvolution/outer_phi.ll +++ llvm/test/Analysis/ScalarEvolution/outer_phi.ll @@ -65,20 +65,20 @@ ; CHECK-LABEL: 'test_02' ; CHECK-NEXT: Classifying expressions for: @test_02 ; CHECK-NEXT: %outer.iv = phi i32 [ 0, %entry ], [ %iv.next, %outer.backedge ] -; CHECK-NEXT: --> %outer.iv U: full-set S: full-set Exits: <> LoopDispositions: { %outer: Variant, %inner: Invariant } +; CHECK-NEXT: --> %outer.iv U: [0,-2147483648) S: [0,-2147483648) Exits: <> LoopDispositions: { %outer: Variant, %inner: Invariant } ; CHECK-NEXT: %iv = phi i32 [ %outer.iv, %outer ], [ %iv.next, %inner.backedge ] -; CHECK-NEXT: --> {%outer.iv,+,1}<%inner> U: full-set S: full-set Exits: <> LoopDispositions: { %inner: Computable, %outer: Variant } +; CHECK-NEXT: --> {%outer.iv,+,1}<%inner> U: [0,-2147483648) S: [0,-2147483648) Exits: <> LoopDispositions: { %inner: Computable, %outer: Variant } ; CHECK-NEXT: %iv.next = add nuw nsw i32 %iv, 1 -; CHECK-NEXT: --> {(1 + %outer.iv),+,1}<%inner> U: full-set S: full-set Exits: <> LoopDispositions: { %inner: Computable, %outer: Variant } +; CHECK-NEXT: --> {(1 + %outer.iv),+,1}<%inner> U: [1,0) S: [1,0) Exits: <> LoopDispositions: { %inner: Computable, %outer: Variant } ; CHECK-NEXT: %inner.loop.cond = call i1 @cond() ; CHECK-NEXT: --> %inner.loop.cond U: full-set S: full-set Exits: <> LoopDispositions: { %inner: Variant, %outer: Variant } ; CHECK-NEXT: %outer.loop.cond = call i1 @cond() ; CHECK-NEXT: --> %outer.loop.cond U: full-set S: full-set Exits: <> LoopDispositions: { %outer: Variant, %inner: Invariant } ; CHECK-NEXT: Determining loop execution counts for: @test_02 ; CHECK-NEXT: Loop %inner: Unpredictable backedge-taken count. -; CHECK-NEXT: exit count for inner: ((-1 * %outer.iv) + (%b smax %outer.iv)) +; CHECK-NEXT: exit count for inner: ((-1 * %outer.iv) + (%b smax %outer.iv)) ; CHECK-NEXT: exit count for inner.backedge: ***COULDNOTCOMPUTE*** -; CHECK-NEXT: Loop %inner: max backedge-taken count is -1 +; CHECK-NEXT: Loop %inner: max backedge-taken count is 2147483647 ; CHECK-NEXT: Loop %inner: Unpredictable predicated backedge-taken count. ; CHECK-NEXT: Loop %outer: Unpredictable backedge-taken count. ; CHECK-NEXT: exit count for inner: ***COULDNOTCOMPUTE*** Index: llvm/test/Analysis/ScalarEvolution/pr49856.ll =================================================================== --- llvm/test/Analysis/ScalarEvolution/pr49856.ll +++ llvm/test/Analysis/ScalarEvolution/pr49856.ll @@ -5,7 +5,7 @@ ; CHECK-LABEL: 'test' ; CHECK-NEXT: Classifying expressions for: @test ; CHECK-NEXT: %tmp = phi i32 [ 2, %bb ], [ %tmp2, %bb3 ] -; CHECK-NEXT: --> %tmp U: [1,-2147483648) S: [0,-2147483648) +; CHECK-NEXT: --> %tmp U: [0,-2147483648) S: [0,-2147483648) ; CHECK-NEXT: %tmp2 = add nuw nsw i32 %tmp, 1 ; CHECK-NEXT: --> (1 + %tmp) U: [1,-2147483647) S: [1,-2147483647) ; CHECK-NEXT: Determining loop execution counts for: @test Index: llvm/test/Analysis/ScalarEvolution/shift-recurrences.ll =================================================================== --- llvm/test/Analysis/ScalarEvolution/shift-recurrences.ll +++ llvm/test/Analysis/ScalarEvolution/shift-recurrences.ll @@ -446,7 +446,7 @@ ; CHECK-LABEL: 'nonloop_recurrence' ; CHECK-NEXT: Classifying expressions for: @nonloop_recurrence ; CHECK-NEXT: %tmp = phi i32 [ 2, %bb ], [ %tmp2, %bb3 ] -; CHECK-NEXT: --> %tmp U: [1,-2147483648) S: [0,-2147483648) +; CHECK-NEXT: --> %tmp U: [0,-2147483648) S: [0,-2147483648) ; CHECK-NEXT: %tmp2 = add nuw nsw i32 %tmp, 1 ; CHECK-NEXT: --> (1 + %tmp) U: [1,-2147483647) S: [1,-2147483647) ; CHECK-NEXT: Determining loop execution counts for: @nonloop_recurrence @@ -470,7 +470,7 @@ ; CHECK-LABEL: 'nonloop_recurrence_2' ; CHECK-NEXT: Classifying expressions for: @nonloop_recurrence_2 ; CHECK-NEXT: %tmp = phi i32 [ 2, %loop ], [ %tmp2, %bb3 ] -; CHECK-NEXT: --> %tmp U: [1,-2147483648) S: [0,-2147483648) Exits: <> LoopDispositions: { %loop: Variant } +; CHECK-NEXT: --> %tmp U: [0,-2147483648) S: [0,-2147483648) Exits: <> LoopDispositions: { %loop: Variant } ; CHECK-NEXT: %tmp2 = add nuw nsw i32 %tmp, 1 ; CHECK-NEXT: --> (1 + %tmp) U: [1,-2147483647) S: [1,-2147483647) Exits: <> LoopDispositions: { %loop: Variant } ; CHECK-NEXT: Determining loop execution counts for: @nonloop_recurrence_2 Index: llvm/test/Analysis/ScalarEvolution/trivial-phis.ll =================================================================== --- llvm/test/Analysis/ScalarEvolution/trivial-phis.ll +++ llvm/test/Analysis/ScalarEvolution/trivial-phis.ll @@ -24,7 +24,7 @@ ; CHECK-LABEL @test2 ; CHECK: %tmp24 = phi i64 [ %tmp14, %bb22 ], [ %tmp14, %bb13 ] -; CHECK-NEXT: --> %tmp24 U: full-set S: full-set Exits: <> LoopDispositions: { %bb13: Variant, %bb8: Variant, %bb17: Invariant, %bb27: Invariant } +; CHECK-NEXT: --> %tmp24 U: [0,-9223372036854775808) S: [0,-9223372036854775808) Exits: <> LoopDispositions: { %bb13: Variant, %bb8: Variant, %bb17: Invariant, %bb27: Invariant } define void @test2(i64 %arg, i32* noalias %arg1) { bb: Index: llvm/test/Transforms/IndVarSimplify/outer_phi.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/outer_phi.ll +++ llvm/test/Transforms/IndVarSimplify/outer_phi.ll @@ -398,7 +398,6 @@ } ; Same as test_01, but non-negativity of %b is known without context. -; FIXME: We can remove 2nd check in loop. define i32 @test_05(i32 %a, i32* %bp) { ; CHECK-LABEL: @test_05( ; CHECK-NEXT: entry: @@ -409,11 +408,10 @@ ; CHECK-NEXT: br label [[INNER:%.*]] ; CHECK: inner: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[OUTER_IV]], [[OUTER]] ], [ [[IV_NEXT:%.*]], [[INNER_BACKEDGE:%.*]] ] -; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]] +; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]] ; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] ; CHECK: inner.1: -; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]] -; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]] +; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]] ; CHECK: inner.backedge: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: [[INNER_LOOP_COND:%.*]] = call i1 @cond() @@ -590,15 +588,13 @@ define i32 @test_05c(i32 %a, i32* %bp) { ; CHECK-LABEL: @test_05c( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[B:%.*]] = load i32, i32* [[BP:%.*]], align 4, !range [[RNG1:![0-9]+]] ; CHECK-NEXT: br label [[OUTER:%.*]] ; CHECK: outer: ; CHECK-NEXT: [[OUTER_IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA:%.*]], [[OUTER_BACKEDGE:%.*]] ] ; CHECK-NEXT: br label [[INNER:%.*]] ; CHECK: inner: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[OUTER_IV]], [[OUTER]] ], [ [[IV_NEXT:%.*]], [[INNER_BACKEDGE:%.*]] ] -; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]] -; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] +; CHECK-NEXT: br i1 false, label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] ; CHECK: inner.1: ; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]] ; CHECK: inner.backedge: @@ -652,15 +648,13 @@ define i32 @test_05d(i32 %a, i32* %bp) { ; CHECK-LABEL: @test_05d( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[B:%.*]] = load i32, i32* [[BP:%.*]], align 4, !range [[RNG1]] ; CHECK-NEXT: br label [[OUTER:%.*]] ; CHECK: outer: ; CHECK-NEXT: [[OUTER_IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA:%.*]], [[OUTER_BACKEDGE:%.*]] ] ; CHECK-NEXT: br label [[INNER:%.*]] ; CHECK: inner: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[OUTER_IV]], [[OUTER]] ], [ [[IV_NEXT:%.*]], [[INNER_BACKEDGE:%.*]] ] -; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]] -; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] +; CHECK-NEXT: br i1 false, label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] ; CHECK: inner.1: ; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]] ; CHECK: inner.backedge: @@ -839,15 +833,13 @@ define i32 @test_05g(i32 %a, i32* %bp) { ; CHECK-LABEL: @test_05g( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[B:%.*]] = load i32, i32* [[BP:%.*]], align 4, !range [[RNG1]] ; CHECK-NEXT: br label [[OUTER:%.*]] ; CHECK: outer: ; CHECK-NEXT: [[OUTER_IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA:%.*]], [[OUTER_BACKEDGE:%.*]] ] ; CHECK-NEXT: br label [[INNER:%.*]] ; CHECK: inner: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[OUTER_IV]], [[OUTER]] ], [ [[IV_NEXT:%.*]], [[INNER_BACKEDGE:%.*]] ] -; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp sgt i32 [[B]], [[IV]] -; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] +; CHECK-NEXT: br i1 false, label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] ; CHECK: inner.1: ; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]] ; CHECK: inner.backedge: @@ -901,15 +893,13 @@ define i32 @test_05h(i32 %a, i32* %bp) { ; CHECK-LABEL: @test_05h( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[B:%.*]] = load i32, i32* [[BP:%.*]], align 4, !range [[RNG1]] ; CHECK-NEXT: br label [[OUTER:%.*]] ; CHECK: outer: ; CHECK-NEXT: [[OUTER_IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_LCSSA:%.*]], [[OUTER_BACKEDGE:%.*]] ] ; CHECK-NEXT: br label [[INNER:%.*]] ; CHECK: inner: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[OUTER_IV]], [[OUTER]] ], [ [[IV_NEXT:%.*]], [[INNER_BACKEDGE:%.*]] ] -; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp sgt i32 [[B]], [[IV]] -; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] +; CHECK-NEXT: br i1 false, label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] ; CHECK: inner.1: ; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]] ; CHECK: inner.backedge: @@ -960,7 +950,6 @@ } ; Same as test_02, but non-negativity of %b is known without context. -; FIXME: We can remove 2nd check in loop. define i32 @test_06(i32 %a, i32* %bp) { ; CHECK-LABEL: @test_06( ; CHECK-NEXT: entry: @@ -971,11 +960,10 @@ ; CHECK-NEXT: br label [[INNER:%.*]] ; CHECK: inner: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[OUTER_IV]], [[OUTER]] ], [ [[IV_NEXT:%.*]], [[INNER_BACKEDGE:%.*]] ] -; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]] +; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]] ; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] ; CHECK: inner.1: -; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]] -; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]] +; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]] ; CHECK: inner.backedge: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: [[INNER_LOOP_COND:%.*]] = call i1 @cond() @@ -1025,7 +1013,6 @@ } ; Same as test_03, but non-negativity of %b is known without context. -; FIXME: We can remove 2nd check in loop. define i32 @test_07(i32 %a, i32* %bp) { ; CHECK-LABEL: @test_07( ; CHECK-NEXT: entry: @@ -1042,11 +1029,10 @@ ; CHECK-NEXT: br label [[OUTER_BACKEDGE]] ; CHECK: inner: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT:%.*]], [[INNER_BACKEDGE:%.*]] ], [ [[OUTER_IV]], [[INNER_PREHEADER]] ] -; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]] +; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]] ; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]] ; CHECK: inner.1: -; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]] -; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]] +; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]] ; CHECK: inner.backedge: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: [[INNER_LOOP_COND:%.*]] = call i1 @cond()