Index: llvm/lib/Analysis/ScalarEvolution.cpp =================================================================== --- llvm/lib/Analysis/ScalarEvolution.cpp +++ llvm/lib/Analysis/ScalarEvolution.cpp @@ -116,6 +116,7 @@ #include "llvm/Support/KnownBits.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/LoopUtils.h" #include #include #include @@ -7712,6 +7713,35 @@ Flags = getNoWrapFlagsFromUB(BO->Op); LHS = getSCEV(BO->LHS); RHS = getSCEV(BO->RHS); + + // Try to prove NSW based on operands signs. Subtracting non-negative + // values cannot overflow, as well as subtracting non-positives ones. + if (!hasFlags(Flags, SCEV::FlagNSW)) { + // If one of the operands is an AddRec, then the resulting expression + // makes sense only in the loop of that AddRec, so we can safely use the + // loop as context to get facts about operands signs. + const Loop *L = nullptr; + if (auto *AR = dyn_cast(LHS)) + L = AR->getLoop(); + if (!L) + if (auto *AR = dyn_cast(RHS)) + L = AR->getLoop(); + enum class SCEVExprSign { NonNegative, NonPositive, Unknown }; + auto GetExprSign = [&](const SCEV *S) -> SCEVExprSign { + if (isKnownNonNegative(S) || + (L && isKnownNonNegativeInLoop(S, L, *this))) + return SCEVExprSign::NonNegative; + if (isKnownNonPositive(S) || + (L && isKnownNonPositiveInLoop(S, L, *this))) + return SCEVExprSign::NonPositive; + return SCEVExprSign::Unknown; + }; + auto LHSSign = GetExprSign(LHS); + auto RHSSign = GetExprSign(RHS); + if (LHSSign != SCEVExprSign::Unknown && LHSSign == RHSSign) + Flags = setFlags(Flags, SCEV::FlagNSW); + } + return getMinusSCEV(LHS, RHS, Flags); } case Instruction::And: Index: llvm/test/Analysis/ScalarEvolution/addrec-sub-nsw.ll =================================================================== --- llvm/test/Analysis/ScalarEvolution/addrec-sub-nsw.ll +++ llvm/test/Analysis/ScalarEvolution/addrec-sub-nsw.ll @@ -7,7 +7,7 @@ ; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ] ; CHECK-NEXT: --> {0,+,1}<%loop> U: [0,2147483647) S: [0,2147483647) Exits: (-1 + (1 smax %n)) LoopDispositions: { %loop: Computable } ; CHECK-NEXT: %a = sub i32 %n, %i -; CHECK-NEXT: --> {%n,+,-1}<%loop> U: full-set S: full-set Exits: (1 + (-1 * (1 smax %n)) + %n) LoopDispositions: { %loop: Computable } +; CHECK-NEXT: --> {%n,+,-1}<%loop> U: full-set S: full-set Exits: (1 + (-1 * (1 smax %n)) + %n) LoopDispositions: { %loop: Computable } ; CHECK-NEXT: %i.next = add nuw nsw i32 %i, 1 ; CHECK-NEXT: --> {1,+,1}<%loop> U: [1,-2147483648) S: [1,-2147483648) Exits: (1 smax %n) LoopDispositions: { %loop: Computable } ; CHECK-NEXT: Determining loop execution counts for: @test_1_non_negative @@ -44,7 +44,7 @@ ; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ] ; CHECK-NEXT: --> {0,+,1}<%loop> U: [0,2147483647) S: [0,2147483647) Exits: (-1 + (1 smax %n)) LoopDispositions: { %loop: Computable } ; CHECK-NEXT: %minus.i = mul i32 %i, -1 -; CHECK-NEXT: --> {0,+,-1}<%loop> U: [-2147483646,1) S: [-2147483646,1) Exits: (1 + (-1 * (1 smax %n))) LoopDispositions: { %loop: Computable } +; CHECK-NEXT: --> {0,+,-1}<%loop> U: [-2147483646,1) S: [-2147483646,1) Exits: (1 + (-1 * (1 smax %n))) LoopDispositions: { %loop: Computable } ; CHECK-NEXT: %a = sub i32 %minus.n, %minus.i ; CHECK-NEXT: --> {(-1 * %n),+,1}<%loop> U: full-set S: full-set Exits: (-1 + (-1 * %n) + (1 smax %n)) LoopDispositions: { %loop: Computable } ; CHECK-NEXT: %i.next = add nuw nsw i32 %i, 1 Index: llvm/test/Analysis/ScalarEvolution/decrementing_addrecs.ll =================================================================== --- llvm/test/Analysis/ScalarEvolution/decrementing_addrecs.ll +++ llvm/test/Analysis/ScalarEvolution/decrementing_addrecs.ll @@ -36,7 +36,7 @@ ; DEFAULT-NEXT: %j = phi i32 [ %n.minus.1, %entry ], [ %j.next, %loop ] ; DEFAULT-NEXT: --> {(-1 + %n),+,-1}<%loop> U: full-set S: full-set Exits: 0 LoopDispositions: { %loop: Computable } ; DEFAULT-NEXT: %a = sub i32 %n, %i -; DEFAULT-NEXT: --> {%n,+,-1}<%loop> U: full-set S: full-set Exits: 1 LoopDispositions: { %loop: Computable } +; DEFAULT-NEXT: --> {%n,+,-1}<%loop> U: full-set S: full-set Exits: 1 LoopDispositions: { %loop: Computable } ; DEFAULT-NEXT: %b = sub i32 %n.minus.1, %i ; DEFAULT-NEXT: --> {(-1 + %n),+,-1}<%loop> U: full-set S: full-set Exits: 0 LoopDispositions: { %loop: Computable } ; DEFAULT-NEXT: %c = sub i32 2147483647, %i @@ -62,7 +62,7 @@ ; EXPENSIVE_SHARPENING-NEXT: %j = phi i32 [ %n.minus.1, %entry ], [ %j.next, %loop ] ; EXPENSIVE_SHARPENING-NEXT: --> {(-1 + %n),+,-1}<%loop> U: [0,2147483647) S: [0,2147483647) Exits: 0 LoopDispositions: { %loop: Computable } ; EXPENSIVE_SHARPENING-NEXT: %a = sub i32 %n, %i -; EXPENSIVE_SHARPENING-NEXT: --> {%n,+,-1}<%loop> U: [1,-2147483648) S: [1,-2147483648) Exits: 1 LoopDispositions: { %loop: Computable } +; EXPENSIVE_SHARPENING-NEXT: --> {%n,+,-1}<%loop> U: [1,-2147483648) S: [1,-2147483648) Exits: 1 LoopDispositions: { %loop: Computable } ; EXPENSIVE_SHARPENING-NEXT: %b = sub i32 %n.minus.1, %i ; EXPENSIVE_SHARPENING-NEXT: --> {(-1 + %n),+,-1}<%loop> U: [0,2147483647) S: [0,2147483647) Exits: 0 LoopDispositions: { %loop: Computable } ; EXPENSIVE_SHARPENING-NEXT: %c = sub i32 2147483647, %i