Index: llvm/lib/Analysis/ScalarEvolution.cpp =================================================================== --- llvm/lib/Analysis/ScalarEvolution.cpp +++ llvm/lib/Analysis/ScalarEvolution.cpp @@ -6569,6 +6569,14 @@ return isSCEVExprNeverPoison(BinOp) ? Flags : SCEV::FlagAnyWrap; } +static bool +isGuaranteedToTransferExecutionToSuccessor(BasicBlock::const_iterator Begin, + BasicBlock::const_iterator End) { + return llvm::all_of( make_range(Begin, End), [](const Instruction &I) { + return isGuaranteedToTransferExecutionToSuccessor(&I); + }); +} + bool ScalarEvolution::isSCEVExprNeverPoison(const Instruction *I) { // Here we check that I is in the header of the innermost loop containing I, // since we only deal with instructions in the loop header. The actual loop we @@ -6604,6 +6612,20 @@ if (auto *AddRecS = dyn_cast(OpS)) { if (isGuaranteedToExecuteForEveryIteration(I, AddRecS->getLoop())) return true; + } else if (auto *U = dyn_cast(OpS)) { + if (auto *DefI = dyn_cast(U->getValue())) { + auto *DefBB = DefI->getParent(); + if (DefBB == InnermostContainingLoop->getHeader() && + DefBB == I->getParent() && + ::isGuaranteedToTransferExecutionToSuccessor(DefI->getIterator(), + I->getIterator())) + return true; + if (DefBB == InnermostContainingLoop->getLoopPreheader() && + ::isGuaranteedToTransferExecutionToSuccessor(DefI->getIterator(), + DefBB->end()) && + isGuaranteedToExecuteForEveryIteration(I, InnermostContainingLoop)) + return true; + } } } return false; Index: llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll =================================================================== --- llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll +++ llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll @@ -203,12 +203,12 @@ ; CHECK-NEXT: Classifying expressions for: @test-add-scope-bound-unkn-preheader-neg1 ; CHECK-NEXT: %offset = load i32, i32* %input, align 4 ; CHECK-NEXT: --> %offset U: full-set S: full-set -; CHECK-NEXT: %i = phi i32 [ %i.next, %loop ], [ 0, %entry ] -; CHECK-NEXT: --> {0,+,%offset}<%loop> U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Computable } +; CHECK-NEXT: %i = phi i32 [ %i.next, %loop ], [ 1, %entry ] +; CHECK-NEXT: --> {1,+,%offset}<%loop> U: [1,0) S: [1,0) Exits: <> LoopDispositions: { %loop: Computable } ; CHECK-NEXT: %i.next = add nuw i32 %i, %offset -; CHECK-NEXT: --> {%offset,+,%offset}<%loop> U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Computable } +; CHECK-NEXT: --> {(1 + %offset),+,%offset}<%loop> U: [1,0) S: [1,0) Exits: <> LoopDispositions: { %loop: Computable } ; CHECK-NEXT: %gep2 = getelementptr i32, i32* %input, i32 %i.next -; CHECK-NEXT: --> ((4 * (sext i32 {%offset,+,%offset}<%loop> to i64)) + %input) U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Computable } +; CHECK-NEXT: --> ((4 * (sext i32 {(1 + %offset),+,%offset}<%loop> to i64)) + %input) U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Computable } ; CHECK-NEXT: Determining loop execution counts for: @test-add-scope-bound-unkn-preheader-neg1 ; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count. ; CHECK-NEXT: Loop %loop: Unpredictable max backedge-taken count. @@ -219,7 +219,7 @@ call void @foo() br label %loop loop: - %i = phi i32 [ %i.next, %loop ], [ 0, %entry ] + %i = phi i32 [ %i.next, %loop ], [ 1, %entry ] %i.next = add nuw i32 %i, %offset %gep2 = getelementptr i32, i32* %input, i32 %i.next store i32 0, i32* %gep2 @@ -235,12 +235,12 @@ ; CHECK-NEXT: Classifying expressions for: @test-add-scope-bound-unkn-preheader-neg2 ; CHECK-NEXT: %offset = load i32, i32* %input, align 4 ; CHECK-NEXT: --> %offset U: full-set S: full-set -; CHECK-NEXT: %i = phi i32 [ %i.next, %loop ], [ 0, %entry ] -; CHECK-NEXT: --> {0,+,%offset}<%loop> U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Computable } +; CHECK-NEXT: %i = phi i32 [ %i.next, %loop ], [ 1, %entry ] +; CHECK-NEXT: --> {1,+,%offset}<%loop> U: [1,0) S: [1,0) Exits: <> LoopDispositions: { %loop: Computable } ; CHECK-NEXT: %i.next = add nuw i32 %i, %offset -; CHECK-NEXT: --> {%offset,+,%offset}<%loop> U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Computable } +; CHECK-NEXT: --> {(1 + %offset),+,%offset}<%loop> U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Computable } ; CHECK-NEXT: %gep2 = getelementptr i32, i32* %input, i32 %i.next -; CHECK-NEXT: --> ((4 * (sext i32 {%offset,+,%offset}<%loop> to i64)) + %input) U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Computable } +; CHECK-NEXT: --> ((4 * (sext i32 {(1 + %offset),+,%offset}<%loop> to i64)) + %input) U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Computable } ; CHECK-NEXT: Determining loop execution counts for: @test-add-scope-bound-unkn-preheader-neg2 ; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count. ; CHECK-NEXT: Loop %loop: Unpredictable max backedge-taken count. @@ -250,7 +250,7 @@ %offset = load i32, i32* %input br label %loop loop: - %i = phi i32 [ %i.next, %loop ], [ 0, %entry ] + %i = phi i32 [ %i.next, %loop ], [ 1, %entry ] call void @foo() %i.next = add nuw i32 %i, %offset %gep2 = getelementptr i32, i32* %input, i32 %i.next @@ -273,9 +273,9 @@ ; CHECK-NEXT: %offset = load i32, i32* %gep, align 4 ; CHECK-NEXT: --> %offset U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Variant } ; CHECK-NEXT: %i.next = add nuw i32 %i, %offset -; CHECK-NEXT: --> (%offset + %i) U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Variant } +; CHECK-NEXT: --> (%offset + %i) U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Variant } ; CHECK-NEXT: %gep2 = getelementptr i32, i32* %input, i32 %i.next -; CHECK-NEXT: --> ((4 * (sext i32 (%offset + %i) to i64)) + %input) U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Variant } +; CHECK-NEXT: --> ((4 * (sext i32 (%offset + %i) to i64)) + %input) U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Variant } ; CHECK-NEXT: Determining loop execution counts for: @test-add-scope-bound-unkn-header ; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count. ; CHECK-NEXT: Loop %loop: Unpredictable max backedge-taken count. @@ -307,9 +307,9 @@ ; CHECK-NEXT: %offset = load i32, i32* %gep, align 4 ; CHECK-NEXT: --> %offset U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Variant } ; CHECK-NEXT: %i.next = add nuw i32 %i, %offset -; CHECK-NEXT: --> (%offset + %i) U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Variant } +; CHECK-NEXT: --> (%offset + %i) U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Variant } ; CHECK-NEXT: %gep2 = getelementptr i32, i32* %input, i32 %i.next -; CHECK-NEXT: --> ((4 * (sext i32 (%offset + %i) to i64)) + %input) U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Variant } +; CHECK-NEXT: --> ((4 * (sext i32 (%offset + %i) to i64)) + %input) U: full-set S: full-set Exits: <> LoopDispositions: { %loop: Variant } ; CHECK-NEXT: Determining loop execution counts for: @test-add-scope-bound-unkn-header2 ; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count. ; CHECK-NEXT: Loop %loop: Unpredictable max backedge-taken count. Index: llvm/test/Analysis/ScalarEvolution/load.ll =================================================================== --- llvm/test/Analysis/ScalarEvolution/load.ll +++ llvm/test/Analysis/ScalarEvolution/load.ll @@ -73,7 +73,7 @@ ; CHECK-NEXT: %n.01 = phi %struct.ListNode* [ bitcast ({ %struct.ListNode*, i32, [4 x i8] }* @node5 to %struct.ListNode*), %entry ], [ %1, %for.body ] ; CHECK-NEXT: --> %n.01 U: full-set S: full-set Exits: @node1 LoopDispositions: { %for.body: Variant } ; CHECK-NEXT: %i = getelementptr inbounds %struct.ListNode, %struct.ListNode* %n.01, i64 0, i32 1 -; CHECK-NEXT: --> (4 + %n.01) U: full-set S: full-set Exits: (4 + @node1) LoopDispositions: { %for.body: Variant } +; CHECK-NEXT: --> (4 + %n.01) U: [4,0) S: [4,0) Exits: (4 + @node1) LoopDispositions: { %for.body: Variant } ; CHECK-NEXT: %0 = load i32, i32* %i, align 4 ; CHECK-NEXT: --> %0 U: full-set S: full-set Exits: 0 LoopDispositions: { %for.body: Variant } ; CHECK-NEXT: %add = add nsw i32 %0, %sum.02 Index: llvm/test/Analysis/ScalarEvolution/ptrtoint.ll =================================================================== --- llvm/test/Analysis/ScalarEvolution/ptrtoint.ll +++ llvm/test/Analysis/ScalarEvolution/ptrtoint.ll @@ -502,7 +502,7 @@ ; X32-NEXT: %i11 = ashr exact i64 %i10, 2 ; X32-NEXT: --> %i11 U: [-2147483648,2147483648) S: [-2147483648,2147483648) Exits: <> LoopDispositions: { %bb6: Variant } ; X32-NEXT: %i12 = getelementptr inbounds i32, i32* %arg2, i64 %i11 -; X32-NEXT: --> ((4 * (trunc i64 %i11 to i32)) + %arg2) U: full-set S: full-set Exits: <> LoopDispositions: { %bb6: Variant } +; X32-NEXT: --> ((4 * (trunc i64 %i11 to i32)) + %arg2) U: full-set S: full-set Exits: <> LoopDispositions: { %bb6: Variant } ; X32-NEXT: %i13 = load i32, i32* %i12, align 4 ; X32-NEXT: --> %i13 U: full-set S: full-set Exits: <> LoopDispositions: { %bb6: Variant } ; X32-NEXT: %i14 = add nsw i32 %i13, %i8