Index: llvm/lib/Transforms/Scalar/IndVarSimplify.cpp =================================================================== --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -2372,6 +2372,27 @@ CmpIndVar = IndVar->getIncomingValueForBlock(L->getExitingBlock()); } + // It may be necessary to drop nowrap flags on the incrementing instruction + // if either LFTR moves from a pre-inc check to a post-inc check (in which + // case the increment might have previously been poison on the last iteration + // only) or if LFTR switches to a different IV that was previously dynamically + // dead (and as such may be arbitrarily poison). We remove any nowrap flags + // that SCEV didn't infer for the post-inc addrec (even if we use a pre-inc + // check), because the pre-inc addrec flags may be adopted from the original + // instruction, while SCEV has to explicitly prove the post-inc nowrap flags. + // TODO: This handling may be inaccurate for one case: If we switch to a + // dynamically dead IV that wraps on the first loop iteration only, which is + // not covered by the post-inc addrec. (If the new IV was not dynamically + // dead, it could not be poison on the first iteration in the first place.) + Value *IncVar = IndVar->getIncomingValueForBlock(L->getLoopLatch()); + if (auto *BO = dyn_cast(IncVar)) { + const SCEVAddRecExpr *AR = cast(SE->getSCEV(IncVar)); + if (BO->hasNoUnsignedWrap()) + BO->setHasNoUnsignedWrap(AR->hasNoUnsignedWrap()); + if (BO->hasNoSignedWrap()) + BO->setHasNoSignedWrap(AR->hasNoSignedWrap()); + } + Value *ExitCnt = genLoopLimit(IndVar, IVCount, L, Rewriter, SE); assert(ExitCnt->getType()->isPointerTy() == IndVar->getType()->isPointerTy() && 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: @@ -155,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: @@ -194,7 +194,7 @@ ; CHECK-NEXT: br label [[ALWAYS_TAKEN]] ; CHECK: always_taken: ; CHECK-NEXT: [[IV_INC]] = add nsw i32 [[IV]], 1 -; CHECK-NEXT: [[IV2_INC]] = add nuw nsw i32 [[IV2]], 1 +; CHECK-NEXT: [[IV2_INC]] = add nuw i32 [[IV2]], 1 ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV2_INC]], -2147483627 ; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND]], label [[FOR_END:%.*]] ; CHECK: for.end: @@ -242,7 +242,7 @@ ; CHECK-NEXT: br label [[ALWAYS_TAKEN]] ; CHECK: always_taken: ; CHECK-NEXT: [[IV_INC]] = add nsw i32 [[IV]], 1 -; CHECK-NEXT: [[IV2_INC]] = add nuw nsw i32 [[IV2]], 1 +; CHECK-NEXT: [[IV2_INC]] = add nuw i32 [[IV2]], 1 ; CHECK-NEXT: br label [[FOR_COND]] ; CHECK: for.end: ; CHECK-NEXT: ret i32 0