Index: llvm/lib/Transforms/Scalar/IndVarSimplify.cpp =================================================================== --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -2375,6 +2375,23 @@ // backedge branches to the loop header. This is one less than the // number of times the loop executes, so use the incremented indvar. CmpIndVar = IndVar->getIncomingValueForBlock(L->getExitingBlock()); + + // It may be that the result of the increment is poison (due to nuw/nsw + // flags) on the last iterations only, in which case moving the comparison + // after the increment may invalidate the nuw/nsw flags. We combine the + // computed SCEV nowrap flags from the pre-increment and the post-increment + // AddRecs. The former covers all but the last iteration, while the former + // covers all but the first. If a nowrap flag is set on both, it implies + // that the operation is non-wrapping for all iterations. + if (auto *BO = dyn_cast(CmpIndVar)) { + const SCEVAddRecExpr *PreAR = cast(SE->getSCEV(IndVar)); + const SCEVAddRecExpr *PostAR = + cast(SE->getSCEV(CmpIndVar)); + BO->setHasNoUnsignedWrap( + PreAR->hasNoUnsignedWrap() && PostAR->hasNoUnsignedWrap()); + BO->setHasNoSignedWrap( + PreAR->hasNoSignedWrap() && PostAR->hasNoSignedWrap()); + } } Value *ExitCnt = genLoopLimit(IndVar, IVCount, L, Rewriter, SE); Index: llvm/test/Transforms/IndVarSimplify/pr31181.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/pr31181.ll +++ llvm/test/Transforms/IndVarSimplify/pr31181.ll @@ -15,7 +15,7 @@ ; CHECK: loop: ; CHECK-NEXT: [[STOREMERGE:%.*]] = phi i32 [ -2, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LOOP]] ] ; CHECK-NEXT: store i32 [[STOREMERGE]], i32* @a -; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[STOREMERGE]], 1 +; CHECK-NEXT: [[INC]] = add nsw i32 [[STOREMERGE]], 1 ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], 0 ; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: @@ -42,7 +42,7 @@ ; CHECK: loop: ; CHECK-NEXT: [[STOREMERGE:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LOOP]] ] ; CHECK-NEXT: store i32 [[STOREMERGE]], i32* @a -; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[STOREMERGE]], 1 +; CHECK-NEXT: [[INC]] = add nuw i32 [[STOREMERGE]], 1 ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], -2147483648 ; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: @@ -117,6 +117,33 @@ ret i32 0 } +define i32 @test_no_add_nuw() { +; CHECK-LABEL: @test_no_add_nuw( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[STOREMERGE:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LOOP]] ] +; CHECK-NEXT: store i32 [[STOREMERGE]], i32* @a +; CHECK-NEXT: [[INC]] = add nsw i32 [[STOREMERGE]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], 10 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i32 0 +; +entry: + br label %loop + +loop: + %storemerge = phi i32 [ -1, %entry ], [ %inc, %loop ] + store i32 %storemerge, i32* @a + %cmp = icmp slt i32 %storemerge, 9 + %inc = add i32 %storemerge, 1 + br i1 %cmp, label %loop, label %exit + +exit: + ret i32 0 +} + define i32 @test_drop_nsw_var_lim(i32 %lim) { ; CHECK-LABEL: @test_drop_nsw_var_lim( ; CHECK-NEXT: entry: @@ -128,7 +155,7 @@ ; CHECK: loop: ; CHECK-NEXT: [[STOREMERGE:%.*]] = phi i32 [ [[INC:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ] ; CHECK-NEXT: store i32 [[STOREMERGE]], i32* @a -; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[STOREMERGE]], 1 +; CHECK-NEXT: [[INC]] = add nuw i32 [[STOREMERGE]], 1 ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], [[TMP0]] ; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]] ; CHECK: exit.loopexit: