Index: lib/Transforms/Scalar/IndVarSimplify.cpp =================================================================== --- lib/Transforms/Scalar/IndVarSimplify.cpp +++ lib/Transforms/Scalar/IndVarSimplify.cpp @@ -2196,15 +2196,12 @@ // have originally had a concrete definition. if (!hasConcreteDef(Phi)) { // We explicitly allow unknown phis as long as they are already used by - // the loop test. In this case we assume that performing LFTR could not - // increase the number of undef users. - // TODO: Generalize this to allow *any* loop exit which is known to - // execute on each iteration - if (L->getExitingBlock()) - if (ICmpInst *Cond = getLoopTest(L, ExitingBB)) - if (Phi != getLoopPhiForCounter(Cond->getOperand(0), L) && - Phi != getLoopPhiForCounter(Cond->getOperand(1), L)) - continue; + // the loop exit test. This is legal since performing LFTR could not + // increase the number of undef users. + if (ICmpInst *Cond = getLoopTest(L, ExitingBB)) + if (Phi != getLoopPhiForCounter(Cond->getOperand(0), L) && + Phi != getLoopPhiForCounter(Cond->getOperand(1), L)) + continue; } const SCEV *Init = AR->getStart(); @@ -2621,12 +2618,8 @@ // If we have a trip count expression, rewrite the loop's exit condition // using it. if (!DisableLFTR) { - // For the moment, we only do LFTR for single exit loops. The code is - // structured as it is in the expectation of generalization to multi-exit - // loops in the near future. See D62625 for context. SmallVector ExitingBlocks; - if (auto *ExitingBB = L->getExitingBlock()) - ExitingBlocks.push_back(ExitingBB); + L->getExitingBlocks(ExitingBlocks); for (BasicBlock *ExitingBB : ExitingBlocks) { // Can't rewrite non-branch yet. if (!isa(ExitingBB->getTerminator())) Index: test/Transforms/IndVarSimplify/lftr-multi-exit.ll =================================================================== --- test/Transforms/IndVarSimplify/lftr-multi-exit.ll +++ test/Transforms/IndVarSimplify/lftr-multi-exit.ll @@ -15,13 +15,13 @@ ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] -; CHECK-NEXT: [[EARLYCND:%.*]] = icmp ult i32 [[IV]], [[N:%.*]] -; CHECK-NEXT: br i1 [[EARLYCND]], label [[LATCH]], label [[EXIT:%.*]] +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]] +; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]] ; CHECK: latch: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: store i32 [[IV]], i32* @A -; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV_NEXT]], 1000 -; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT]] +; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 1000 +; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; @@ -55,8 +55,8 @@ ; CHECK: latch: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: store i32 [[IV]], i32* @A -; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV_NEXT]], 1000 -; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT]] +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV_NEXT]], 1000 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; @@ -86,17 +86,17 @@ ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] -; CHECK-NEXT: [[EARLYCND:%.*]] = icmp ult i32 [[IV]], [[N:%.*]] -; CHECK-NEXT: br i1 [[EARLYCND]], label [[CONTINUE:%.*]], label [[EXIT:%.*]] +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]] +; CHECK-NEXT: br i1 [[EXITCOND]], label [[CONTINUE:%.*]], label [[EXIT:%.*]] ; CHECK: continue: ; CHECK-NEXT: store volatile i32 [[IV]], i32* @A -; CHECK-NEXT: [[EARLYCND2:%.*]] = icmp ult i32 [[IV]], [[M:%.*]] -; CHECK-NEXT: br i1 [[EARLYCND2]], label [[LATCH]], label [[EXIT]] +; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV]], [[M:%.*]] +; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LATCH]], label [[EXIT]] ; CHECK: latch: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: store volatile i32 [[IV]], i32* @A -; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV_NEXT]], 1000 -; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT]] +; CHECK-NEXT: [[EXITCOND2:%.*]] = icmp ne i32 [[IV_NEXT]], 1000 +; CHECK-NEXT: br i1 [[EXITCOND2]], label [[LOOP]], label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; @@ -138,8 +138,8 @@ ; CHECK: latch: ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: store volatile i32 [[IV]], i32* @A -; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV_NEXT]], 1000 -; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT]] +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV_NEXT]], 1000 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; @@ -170,8 +170,8 @@ ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] -; CHECK-NEXT: [[EARLYCND:%.*]] = icmp ult i32 [[IV]], [[N:%.*]] -; CHECK-NEXT: br i1 [[EARLYCND]], label [[LATCH]], label [[EXIT:%.*]] +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]] +; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]] ; CHECK: latch: ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 ; CHECK-NEXT: store i32 [[IV]], i32* @A @@ -240,12 +240,12 @@ ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] -; CHECK-NEXT: [[EARLYCND:%.*]] = icmp ult i32 [[IV]], [[N:%.*]] -; CHECK-NEXT: br i1 [[EARLYCND]], label [[CONTINUE:%.*]], label [[EXIT:%.*]] +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]] +; CHECK-NEXT: br i1 [[EXITCOND]], label [[CONTINUE:%.*]], label [[EXIT:%.*]] ; CHECK: continue: ; CHECK-NEXT: store volatile i32 [[IV]], i32* @A -; CHECK-NEXT: [[EARLYCND2:%.*]] = icmp ult i32 [[IV]], [[M:%.*]] -; CHECK-NEXT: br i1 [[EARLYCND2]], label [[LATCH]], label [[EXIT]] +; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV]], [[M:%.*]] +; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LATCH]], label [[EXIT]] ; CHECK: latch: ; CHECK-NEXT: store volatile i32 [[IV]], i32* @A ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1