diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -8316,6 +8316,32 @@ if (!isa(Ret)) return Ret; } + // If this loop must exit based on this condition (or execute undefined + // behaviour), and we can prove the test sequence produced must repeat + // the same values on self-wrap of the IV, then we can infer that IV + // doesn't self wrap because if it did, we'd have an infinite (undefined) + // loop. + if (ControlsExit && isLoopInvariant(RHS, L) && loopHasNoAbnormalExits(L) && + loopIsFiniteByAssumption(L)) { + + // TODO: We can peel off any functions which are invertible *in L*. Loop + // invariant terms are effectively constants for our purposes here. + auto *InnerLHS = LHS; + if (auto *ZExt = dyn_cast(LHS)) + InnerLHS = ZExt->getOperand(); + if (const SCEVAddRecExpr *AR = dyn_cast(InnerLHS)) { + auto *StrideC = dyn_cast(AR->getStepRecurrence(*this)); + if (!AR->hasNoSelfWrap() && AR->getLoop() == L && AR->isAffine() && + StrideC && StrideC->getAPInt().isPowerOf2()) { + auto Flags = AR->getNoWrapFlags(); + Flags = setFlags(Flags, SCEV::FlagNW); + SmallVector Operands{AR->operands()}; + Flags = StrengthenNoWrapFlags(this, scAddRecExpr, Operands, Flags); + setNoWrapFlags(const_cast(AR), Flags); + } + } + } + switch (Pred) { case ICmpInst::ICMP_NE: { // while (X != Y) // Convert to: while (X-Y != 0) @@ -11821,14 +11847,6 @@ if (auto *ZExt = dyn_cast(LHS)) { const SCEVAddRecExpr *AR = dyn_cast(ZExt->getOperand()); if (AR && AR->getLoop() == L && AR->isAffine()) { - auto Flags = AR->getNoWrapFlags(); - if (!hasFlags(Flags, SCEV::FlagNW) && canAssumeNoSelfWrap(AR)) { - Flags = setFlags(Flags, SCEV::FlagNW); - - SmallVector Operands{AR->operands()}; - Flags = StrengthenNoWrapFlags(this, scAddRecExpr, Operands, Flags); - } - auto canProveNUW = [&]() { if (!isLoopInvariant(RHS, L)) return false; @@ -11851,6 +11869,7 @@ Limit = Limit.zext(OuterBitWidth); return getUnsignedRangeMax(applyLoopGuards(RHS, L)).ule(Limit); }; + auto Flags = AR->getNoWrapFlags(); if (!hasFlags(Flags, SCEV::FlagNUW) && canProveNUW()) Flags = setFlags(Flags, SCEV::FlagNUW); diff --git a/llvm/test/Analysis/ScalarEvolution/ne-overflow.ll b/llvm/test/Analysis/ScalarEvolution/ne-overflow.ll --- a/llvm/test/Analysis/ScalarEvolution/ne-overflow.ll +++ b/llvm/test/Analysis/ScalarEvolution/ne-overflow.ll @@ -10,9 +10,11 @@ define void @test(i32 %N) mustprogress { ; CHECK-LABEL: 'test' ; CHECK-NEXT: Determining loop execution counts for: @test -; CHECK-NEXT: Loop %for.body: Unpredictable backedge-taken count. -; CHECK-NEXT: Loop %for.body: Unpredictable max backedge-taken count. -; CHECK-NEXT: Loop %for.body: Unpredictable predicated backedge-taken count. +; CHECK-NEXT: Loop %for.body: backedge-taken count is ((-2 + %N) /u 2) +; CHECK-NEXT: Loop %for.body: max backedge-taken count is 2147483647 +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is ((-2 + %N) /u 2) +; CHECK-NEXT: Predicates: +; CHECK: Loop %for.body: Trip multiple is 1 ; entry: br label %for.body @@ -30,9 +32,11 @@ define void @test_preinc(i32 %N) mustprogress { ; CHECK-LABEL: 'test_preinc' ; CHECK-NEXT: Determining loop execution counts for: @test_preinc -; CHECK-NEXT: Loop %for.body: Unpredictable backedge-taken count. -; CHECK-NEXT: Loop %for.body: Unpredictable max backedge-taken count. -; CHECK-NEXT: Loop %for.body: Unpredictable predicated backedge-taken count. +; CHECK-NEXT: Loop %for.body: backedge-taken count is (%N /u 2) +; CHECK-NEXT: Loop %for.body: max backedge-taken count is 2147483647 +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (%N /u 2) +; CHECK-NEXT: Predicates: +; CHECK: Loop %for.body: Trip multiple is 1 ; entry: br label %for.body @@ -117,9 +121,11 @@ define void @test_1024(i32 %N) mustprogress { ; CHECK-LABEL: 'test_1024' ; CHECK-NEXT: Determining loop execution counts for: @test_1024 -; CHECK-NEXT: Loop %for.body: Unpredictable backedge-taken count. -; CHECK-NEXT: Loop %for.body: Unpredictable max backedge-taken count. -; CHECK-NEXT: Loop %for.body: Unpredictable predicated backedge-taken count. +; CHECK-NEXT: Loop %for.body: backedge-taken count is ((-1024 + %N) /u 1024) +; CHECK-NEXT: Loop %for.body: max backedge-taken count is 4194303 +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is ((-1024 + %N) /u 1024) +; CHECK-NEXT: Predicates: +; CHECK: Loop %for.body: Trip multiple is 1 ; entry: br label %for.body @@ -232,7 +238,9 @@ ; CHECK-NEXT: Determining loop execution counts for: @test_zext ; CHECK-NEXT: Loop %for.body: Unpredictable backedge-taken count. ; CHECK-NEXT: Loop %for.body: Unpredictable max backedge-taken count. -; CHECK-NEXT: Loop %for.body: Unpredictable predicated backedge-taken count. +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (%N /u 2) +; CHECK-NEXT: Predicates: +; CHECK-NEXT: {0,+,2}<%for.body> Added Flags: ; entry: br label %for.body diff --git a/llvm/test/Analysis/ScalarEvolution/trip-count-negative-stride.ll b/llvm/test/Analysis/ScalarEvolution/trip-count-negative-stride.ll --- a/llvm/test/Analysis/ScalarEvolution/trip-count-negative-stride.ll +++ b/llvm/test/Analysis/ScalarEvolution/trip-count-negative-stride.ll @@ -56,9 +56,11 @@ define void @ult_infinite_ub() mustprogress { ; CHECK-LABEL: 'ult_infinite_ub' ; CHECK-NEXT: Determining loop execution counts for: @ult_infinite_ub -; CHECK-NEXT: Loop %for.body: Unpredictable backedge-taken count. -; CHECK-NEXT: Loop %for.body: Unpredictable max backedge-taken count. -; CHECK-NEXT: Loop %for.body: Unpredictable predicated backedge-taken count. +; CHECK-NEXT: Loop %for.body: backedge-taken count is 1 +; CHECK-NEXT: Loop %for.body: max backedge-taken count is 1 +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is 1 +; CHECK-NEXT: Predicates: +; CHECK: Loop %for.body: Trip multiple is 2 ; entry: br label %for.body @@ -340,9 +342,11 @@ define void @slt_infinite_ub() mustprogress { ; CHECK-LABEL: 'slt_infinite_ub' ; CHECK-NEXT: Determining loop execution counts for: @slt_infinite_ub -; CHECK-NEXT: Loop %for.body: Unpredictable backedge-taken count. -; CHECK-NEXT: Loop %for.body: Unpredictable max backedge-taken count. -; CHECK-NEXT: Loop %for.body: Unpredictable predicated backedge-taken count. +; CHECK-NEXT: Loop %for.body: backedge-taken count is 0 +; CHECK-NEXT: Loop %for.body: max backedge-taken count is 0 +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is 0 +; CHECK-NEXT: Predicates: +; CHECK: Loop %for.body: Trip multiple is 1 ; entry: br label %for.body