Index: llvm/include/llvm/Analysis/ScalarEvolution.h =================================================================== --- llvm/include/llvm/Analysis/ScalarEvolution.h +++ llvm/include/llvm/Analysis/ScalarEvolution.h @@ -529,9 +529,11 @@ bool containsAddRecurrence(const SCEV *S); /// Is operation \p BinOp between \p LHS and \p RHS provably does not have - /// a signed/unsigned overflow (\p Signed)? + /// a signed/unsigned overflow (\p Signed)? If \p CtxI is specified, the + /// no-overflow fact should be true in the context of this instruction. bool willNotOverflow(Instruction::BinaryOps BinOp, bool Signed, - const SCEV *LHS, const SCEV *RHS); + const SCEV *LHS, const SCEV *RHS, + const Instruction *CtxI = nullptr); /// Parse NSW/NUW flags from add/sub/mul IR binary operation \p Op into /// SCEV no-wrap flags, and deduce flag[s] that aren't known yet. Index: llvm/lib/Analysis/ScalarEvolution.cpp =================================================================== --- llvm/lib/Analysis/ScalarEvolution.cpp +++ llvm/lib/Analysis/ScalarEvolution.cpp @@ -242,6 +242,11 @@ cl::desc("Handle <= and >= in finite loops"), cl::init(true)); +static cl::opt UseContextForNoWrapFlagInference( + "scalar-evolution-use-context-for-no-wrap-flag-strenghening", cl::Hidden, + cl::desc("Infer nuw/nsw flags using context where suitable"), + cl::init(true)); + //===----------------------------------------------------------------------===// // SCEV class definitions //===----------------------------------------------------------------------===// @@ -2285,7 +2290,8 @@ } bool ScalarEvolution::willNotOverflow(Instruction::BinaryOps BinOp, bool Signed, - const SCEV *LHS, const SCEV *RHS) { + const SCEV *LHS, const SCEV *RHS, + const Instruction *CtxI) { const SCEV *(ScalarEvolution::*Operation)(const SCEV *, const SCEV *, SCEV::NoWrapFlags, unsigned); switch (BinOp) { @@ -2316,7 +2322,28 @@ const SCEV *LHSB = (this->*Extension)(LHS, WideTy, 0); const SCEV *RHSB = (this->*Extension)(RHS, WideTy, 0); const SCEV *B = (this->*Operation)(LHSB, RHSB, SCEV::FlagAnyWrap, 0); - return A == B; + if (A == B) + return true; + // Can we use context to prove the fact we need? + if (!CtxI) + return false; + // TODO: Support other operations. + if (BinOp != Instruction::Add) + return false; + auto *RHSC = dyn_cast(RHS); + // TODO: Lift this limitation. + if (!RHSC) + return false; + APInt C = RHSC->getAPInt(); + // TODO: Also lift this limitation. + if (Signed && C.isNegative()) + return false; + unsigned NumBits = C.getBitWidth(); + APInt Max = + Signed ? APInt::getSignedMaxValue(NumBits) : APInt::getMaxValue(NumBits); + APInt Limit = Max - C; + ICmpInst::Predicate Pred = Signed ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE; + return isKnownPredicateAt(Pred, LHS, getConstant(Limit), CtxI); } Optional @@ -2343,16 +2370,18 @@ const SCEV *LHS = getSCEV(OBO->getOperand(0)); const SCEV *RHS = getSCEV(OBO->getOperand(1)); + const Instruction *CtxI = + UseContextForNoWrapFlagInference ? dyn_cast(OBO) : nullptr; if (!OBO->hasNoUnsignedWrap() && willNotOverflow((Instruction::BinaryOps)OBO->getOpcode(), - /* Signed */ false, LHS, RHS)) { + /* Signed */ false, LHS, RHS, CtxI)) { Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW); Deduced = true; } if (!OBO->hasNoSignedWrap() && willNotOverflow((Instruction::BinaryOps)OBO->getOpcode(), - /* Signed */ true, LHS, RHS)) { + /* Signed */ true, LHS, RHS, CtxI)) { Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNSW); Deduced = true; } Index: llvm/test/Transforms/IndVarSimplify/AArch64/widen-loop-comp.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/AArch64/widen-loop-comp.ll +++ llvm/test/Transforms/IndVarSimplify/AArch64/widen-loop-comp.ll @@ -275,7 +275,7 @@ ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[A:%.*]], i64 [[INDVARS_IV]] ; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[ARRAYIDX]], align 4 ; CHECK-NEXT: [[ADD]] = add nsw i32 [[SUM_0]], [[TMP1]] -; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 ; CHECK-NEXT: br label [[FOR_COND]] ; CHECK: for.end: ; CHECK-NEXT: [[SUM_0_LCSSA:%.*]] = phi i32 [ [[SUM_0]], [[FOR_COND]] ] @@ -410,7 +410,7 @@ ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[A:%.*]], i64 [[INDVARS_IV]] ; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[ARRAYIDX]], align 4 ; CHECK-NEXT: [[ADD]] = add nsw i32 [[SUM_0]], [[TMP2]] -; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 ; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i64 0, [[INDVARS_IV_NEXT]] ; CHECK-NEXT: br i1 [[CMP2]], label [[FOR_COND]], label [[FOR_END]] ; CHECK: for.end: Index: llvm/test/Transforms/IndVarSimplify/X86/iv-widen.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/X86/iv-widen.ll +++ llvm/test/Transforms/IndVarSimplify/X86/iv-widen.ll @@ -75,7 +75,7 @@ ; CHECK-NEXT: br label [[B18:%.*]] ; CHECK: B18: ; CHECK-NEXT: [[DOT02:%.*]] = phi i32 [ [[TMP33:%.*]], [[B24:%.*]] ], [ 0, [[B18_PREHEADER]] ] -; CHECK-NEXT: [[TMP33]] = add nuw i32 [[DOT02]], 1 +; CHECK-NEXT: [[TMP33]] = add nuw nsw i32 [[DOT02]], 1 ; CHECK-NEXT: [[O:%.*]] = getelementptr i32, i32* [[A:%.*]], i32 [[DOT02]] ; CHECK-NEXT: [[V:%.*]] = load i32, i32* [[O]], align 4 ; CHECK-NEXT: [[T:%.*]] = icmp eq i32 [[V]], 0 @@ -167,11 +167,11 @@ ; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[SIZE]] to i64 ; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[HSIZE:%.*]] to i64 ; CHECK-NEXT: [[SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[NSTEPS:%.*]], i32 1) -; CHECK-NEXT: [[WIDE_TRIP_COUNT11:%.*]] = zext i32 [[SMAX]] to i64 +; CHECK-NEXT: [[WIDE_TRIP_COUNT14:%.*]] = zext i32 [[SMAX]] to i64 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: -; CHECK-NEXT: [[INDVARS_IV7:%.*]] = phi i64 [ [[INDVARS_IV_NEXT8:%.*]], [[FOR_INC:%.*]] ], [ 0, [[ENTRY:%.*]] ] -; CHECK-NEXT: [[TMP2:%.*]] = mul nsw i64 [[INDVARS_IV7]], [[TMP0]] +; CHECK-NEXT: [[INDVARS_IV9:%.*]] = phi i64 [ [[INDVARS_IV_NEXT10:%.*]], [[FOR_INC:%.*]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[TMP2:%.*]] = mul nsw i64 [[INDVARS_IV9]], [[TMP0]] ; CHECK-NEXT: [[TMP3:%.*]] = add nsw i64 [[TMP2]], [[TMP1]] ; CHECK-NEXT: br i1 [[CMP215]], label [[FOR_BODY2_PREHEADER:%.*]], label [[FOR_INC]] ; CHECK: for.body2.preheader: @@ -188,22 +188,22 @@ ; CHECK: for.body3.preheader: ; CHECK-NEXT: [[TMP5:%.*]] = trunc i64 [[TMP3]] to i32 ; CHECK-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 -; CHECK-NEXT: [[WIDE_TRIP_COUNT5:%.*]] = zext i32 [[SIZE]] to i64 +; CHECK-NEXT: [[WIDE_TRIP_COUNT7:%.*]] = zext i32 [[SIZE]] to i64 ; CHECK-NEXT: br label [[FOR_BODY3:%.*]] ; CHECK: for.body3: -; CHECK-NEXT: [[INDVARS_IV2:%.*]] = phi i64 [ 1, [[FOR_BODY3_PREHEADER]] ], [ [[INDVARS_IV_NEXT3:%.*]], [[FOR_BODY3]] ] -; CHECK-NEXT: [[TMP7:%.*]] = add nuw nsw i64 [[TMP6]], [[INDVARS_IV2]] +; CHECK-NEXT: [[INDVARS_IV3:%.*]] = phi i64 [ 1, [[FOR_BODY3_PREHEADER]] ], [ [[INDVARS_IV_NEXT4:%.*]], [[FOR_BODY3]] ] +; CHECK-NEXT: [[TMP7:%.*]] = add nuw nsw i64 [[TMP6]], [[INDVARS_IV3]] ; CHECK-NEXT: [[ADD_PTR2:%.*]] = getelementptr inbounds i8, i8* [[BC0]], i64 [[TMP7]] ; CHECK-NEXT: store i8 [[TMP1]], i8* [[ADD_PTR2]], align 1 -; CHECK-NEXT: [[INDVARS_IV_NEXT3]] = add nuw nsw i64 [[INDVARS_IV2]], 1 -; CHECK-NEXT: [[EXITCOND6:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT3]], [[WIDE_TRIP_COUNT5]] -; CHECK-NEXT: br i1 [[EXITCOND6]], label [[FOR_BODY3]], label [[FOR_INC_LOOPEXIT:%.*]] +; CHECK-NEXT: [[INDVARS_IV_NEXT4]] = add nuw nsw i64 [[INDVARS_IV3]], 1 +; CHECK-NEXT: [[EXITCOND8:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT4]], [[WIDE_TRIP_COUNT7]] +; CHECK-NEXT: br i1 [[EXITCOND8]], label [[FOR_BODY3]], label [[FOR_INC_LOOPEXIT:%.*]] ; CHECK: for.inc.loopexit: ; CHECK-NEXT: br label [[FOR_INC]] ; CHECK: for.inc: -; CHECK-NEXT: [[INDVARS_IV_NEXT8]] = add nuw nsw i64 [[INDVARS_IV7]], 1 -; CHECK-NEXT: [[EXITCOND12:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT8]], [[WIDE_TRIP_COUNT11]] -; CHECK-NEXT: br i1 [[EXITCOND12]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]] +; CHECK-NEXT: [[INDVARS_IV_NEXT10]] = add nuw nsw i64 [[INDVARS_IV9]], 1 +; CHECK-NEXT: [[EXITCOND15:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT10]], [[WIDE_TRIP_COUNT14]] +; CHECK-NEXT: br i1 [[EXITCOND15]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]] ; CHECK: for.end.loopexit: ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IndVarSimplify/X86/pr35406.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/X86/pr35406.ll +++ llvm/test/Transforms/IndVarSimplify/X86/pr35406.ll @@ -77,17 +77,10 @@ ; CHECK: general_case24: ; CHECK-NEXT: br i1 false, label [[LOOP2_PREHEADER:%.*]], label [[LOOP2_EXIT]] ; CHECK: loop2.preheader: -; CHECK-NEXT: [[TMP0:%.*]] = udiv i32 14, [[LOCAL_0_]] -; CHECK-NEXT: [[TMP1:%.*]] = udiv i32 60392, [[TMP0]] -; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[TMP1]], -1 -; CHECK-NEXT: [[TMP3:%.*]] = mul i32 [[TMP2]], [[TMP0]] -; CHECK-NEXT: [[TMP4:%.*]] = sext i32 [[TMP3]] to i64 -; CHECK-NEXT: [[TMP5:%.*]] = add nsw i64 [[TMP4]], 60392 ; CHECK-NEXT: br label [[LOOP2:%.*]] ; CHECK: loop2: -; CHECK-NEXT: [[INDVARS_IV_NEXT:%.*]] = add nsw i64 [[TMP5]], -1 ; CHECK-NEXT: [[I4:%.*]] = load atomic i64, i64* [[P1:%.*]] unordered, align 8 -; CHECK-NEXT: [[I6:%.*]] = sub i64 [[I4]], [[INDVARS_IV_NEXT]] +; CHECK-NEXT: [[I6:%.*]] = sub i64 [[I4]], -1 ; CHECK-NEXT: store atomic i64 [[I6]], i64* [[P1]] unordered, align 8 ; CHECK-NEXT: br i1 true, label [[LOOP2_EXIT_LOOPEXIT:%.*]], label [[LOOP2]] ; CHECK: loop2.exit.loopexit: Index: llvm/test/Transforms/IndVarSimplify/bbi-63564.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/bbi-63564.ll +++ llvm/test/Transforms/IndVarSimplify/bbi-63564.ll @@ -19,7 +19,7 @@ ; CHECK-NEXT: br label [[FOR_BODY2:%.*]] ; CHECK: for.body2: ; CHECK-NEXT: [[INC2:%.*]] = phi i16 [ undef, [[FOR_BODY]] ], [ [[INC:%.*]], [[FOR_BODY2]] ] -; CHECK-NEXT: [[INC]] = add nsw i16 [[INC2]], 1 +; CHECK-NEXT: [[INC]] = add nuw nsw i16 [[INC2]], 1 ; CHECK-NEXT: store i16 [[INC]], i16* undef, align 1 ; CHECK-NEXT: br i1 true, label [[FOR_BODY2]], label [[CRIT_EDGE:%.*]] ; CHECK: crit_edge: Index: llvm/test/Transforms/IndVarSimplify/cycled_phis.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/cycled_phis.ll +++ llvm/test/Transforms/IndVarSimplify/cycled_phis.ll @@ -85,7 +85,7 @@ ; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]] ; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]] ; CHECK: backedge: -; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 +; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: [[COND:%.*]] = call i1 @cond() ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[DONE:%.*]] ; CHECK: failed.signed: @@ -161,7 +161,7 @@ ; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]] ; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]] ; CHECK: backedge: -; CHECK-NEXT: [[IV_NEXT]] = add nuw i32 [[IV]], 1 +; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: [[COND:%.*]] = call i1 @cond() ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[DONE:%.*]] ; CHECK: failed.signed: @@ -252,7 +252,7 @@ ; CHECK: signed.passed: ; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]] ; CHECK: backedge: -; CHECK-NEXT: [[IV_NEXT]] = add nuw i32 [[IV]], 1 +; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: [[COND:%.*]] = call i1 @cond() ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[DONE:%.*]] ; CHECK: failed.signed: @@ -352,7 +352,7 @@ ; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]] ; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]] ; CHECK: backedge: -; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 +; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: [[COND:%.*]] = call i1 @cond() ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[OUTER_LOOP_BACKEDGE]] ; CHECK: outer.loop.backedge: @@ -470,7 +470,7 @@ ; CHECK-NEXT: [[UNSIGNED_CMP:%.*]] = icmp ult i32 [[IV]], [[LEN]] ; CHECK-NEXT: br i1 [[UNSIGNED_CMP]], label [[BACKEDGE]], label [[FAILED_UNSIGNED:%.*]] ; CHECK: backedge: -; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 +; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: [[COND:%.*]] = call i1 @cond() ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[OUTER_LOOP_SELECTION:%.*]] ; CHECK: outer.loop.selection: Index: llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll +++ llvm/test/Transforms/IndVarSimplify/eliminate-comparison.ll @@ -638,7 +638,7 @@ ; CHECK-NEXT: [[TMP29:%.*]] = icmp eq i16 [[TMP26]], 0 ; CHECK-NEXT: br i1 [[TMP29]], label [[BB1]], label [[BB2_LOOPEXIT]] ; CHECK: bb1: -; CHECK-NEXT: [[TMP30]] = add nuw i32 [[VAR_1]], 1 +; CHECK-NEXT: [[TMP30]] = add nuw nsw i32 [[VAR_1]], 1 ; CHECK-NEXT: [[TMP31:%.*]] = icmp eq i32 [[VAR_0]], 0 ; CHECK-NEXT: br i1 [[TMP31]], label [[BB3:%.*]], label [[BB0]] ; CHECK: bb2.loopexit: @@ -1003,7 +1003,7 @@ ; CHECK: checked.2: ; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAIL]] ; CHECK: backedge: -; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 758394 +; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 758394 ; CHECK-NEXT: [[LOOP_COND:%.*]] = call i1 @cond_func() ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: fail: @@ -1055,7 +1055,7 @@ ; CHECK: checked.2: ; CHECK-NEXT: br i1 [[C3]], label [[BACKEDGE]], label [[FAIL]] ; CHECK: backedge: -; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 758394 +; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 758394 ; CHECK-NEXT: [[LOOP_COND:%.*]] = call i1 @cond_func() ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: fail: Index: llvm/test/Transforms/IndVarSimplify/finite-exit-comparisons.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/finite-exit-comparisons.ll +++ llvm/test/Transforms/IndVarSimplify/finite-exit-comparisons.ll @@ -1029,7 +1029,7 @@ ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ [[IV_NEXT:%.*]], [[FOR_BODY]] ], [ 0, [[FOR_BODY_PREHEADER]] ] -; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 1 +; CHECK-NEXT: [[IV_NEXT]] = add nuw i8 [[IV]], 1 ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[IV_NEXT]], [[TMP0]] ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]] ; CHECK: for.end.loopexit: Index: llvm/test/Transforms/IndVarSimplify/loop-predication.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/loop-predication.ll +++ llvm/test/Transforms/IndVarSimplify/loop-predication.ll @@ -611,7 +611,7 @@ ; CHECK-NEXT: ret i32 -1 ; CHECK: guarded: ; CHECK-NEXT: store volatile i32 0, i32* [[A:%.*]], align 4 -; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1 +; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1 ; CHECK-NEXT: br label [[LOOP]] ; loop.preheader: Index: llvm/test/Transforms/IndVarSimplify/trivial-guard.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/trivial-guard.ll +++ llvm/test/Transforms/IndVarSimplify/trivial-guard.ll @@ -17,7 +17,7 @@ ; CHECK-NEXT: [[CHECK_1:%.*]] = icmp slt i32 [[IV_1]], [[X:%.*]] ; CHECK-NEXT: br i1 [[CHECK_1]], label [[GUARDED_1]], label [[FAIL_LOOPEXIT:%.*]] ; CHECK: guarded.1: -; CHECK-NEXT: [[IV_NEXT_1]] = add nuw i32 [[IV_1]], 1 +; CHECK-NEXT: [[IV_NEXT_1]] = add nuw nsw i32 [[IV_1]], 1 ; CHECK-NEXT: [[LOOP_COND_1:%.*]] = call i1 @cond() ; CHECK-NEXT: br i1 [[LOOP_COND_1]], label [[LOOP_1]], label [[EXIT_LOOPEXIT:%.*]] ; CHECK: loop.2: @@ -86,7 +86,7 @@ ; CHECK-NEXT: [[CHECK_2:%.*]] = icmp slt i32 [[IV_2]], [[X:%.*]] ; CHECK-NEXT: br i1 [[CHECK_2]], label [[GUARDED_2]], label [[FAIL_LOOPEXIT1:%.*]] ; CHECK: guarded.2: -; CHECK-NEXT: [[IV_NEXT_2]] = add nuw i32 [[IV_2]], 1 +; CHECK-NEXT: [[IV_NEXT_2]] = add nuw nsw i32 [[IV_2]], 1 ; CHECK-NEXT: [[LOOP_COND_2:%.*]] = call i1 @cond() ; CHECK-NEXT: br i1 [[LOOP_COND_2]], label [[LOOP_2]], label [[EXIT_LOOPEXIT2:%.*]] ; CHECK: exit.loopexit: Index: llvm/test/Transforms/LoopUnroll/runtime-loop-multiple-exits.ll =================================================================== --- llvm/test/Transforms/LoopUnroll/runtime-loop-multiple-exits.ll +++ llvm/test/Transforms/LoopUnroll/runtime-loop-multiple-exits.ll @@ -3147,7 +3147,7 @@ ; EPILOG-NEXT: %cmp1.7 = icmp ult i32 %inc.7, %N ; EPILOG-NEXT: br i1 %cmp1.7, label %latch.7, label %latchExit.epilog-lcssa.loopexit ; EPILOG: latch.7: -; EPILOG-NEXT: %niter.next.7 = add i32 %niter.next.6, 1 +; EPILOG-NEXT: %niter.next.7 = add nuw i32 %niter.next.6, 1 ; EPILOG-NEXT: %niter.ncmp.7 = icmp ne i32 %niter.next.7, %unroll_iter ; EPILOG-NEXT: br i1 %niter.ncmp.7, label %header, label %latchExit.unr-lcssa.loopexit ; EPILOG: latchExit.unr-lcssa.loopexit: @@ -3209,7 +3209,7 @@ ; EPILOG-BLOCK-NEXT: %cmp1.1 = icmp ult i32 %inc.1, %N ; EPILOG-BLOCK-NEXT: br i1 %cmp1.1, label %latch.1, label %latchExit.epilog-lcssa.loopexit ; EPILOG-BLOCK: latch.1: -; EPILOG-BLOCK-NEXT: %niter.next.1 = add i32 %niter.next, 1 +; EPILOG-BLOCK-NEXT: %niter.next.1 = add nuw i32 %niter.next, 1 ; EPILOG-BLOCK-NEXT: %niter.ncmp.1 = icmp ne i32 %niter.next.1, %unroll_iter ; EPILOG-BLOCK-NEXT: br i1 %niter.ncmp.1, label %header, label %latchExit.unr-lcssa.loopexit, !llvm.loop !8 ; EPILOG-BLOCK: latchExit.unr-lcssa.loopexit: