[PATCH] D148322: [SCEV] Infer NSW when subtracting expressions with the same signs

Dmitry Makogon via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 14 03:32:25 PDT 2023


dmakogon created this revision.
dmakogon added reviewers: mkazantsev, nikic, fhahn, aleksandr.popov.
Herald added subscribers: StephenFan, javed.absar, hiraditya.
Herald added a project: All.
dmakogon requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

When creating a SCEV for `X - Y` infer NSW for the resulting expression if X and Y are either both non-positive or non-negative.
In these cases there can be no signed overflow.


https://reviews.llvm.org/D148322

Files:
  llvm/lib/Analysis/ScalarEvolution.cpp
  llvm/test/Analysis/ScalarEvolution/addrec-sub-nsw.ll
  llvm/test/Analysis/ScalarEvolution/decrementing_addrecs.ll


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}<nsw><%loop> U: full-set S: full-set Exits: 0 LoopDispositions: { %loop: Computable }
 ; DEFAULT-NEXT:    %a = sub i32 %n, %i
-; DEFAULT-NEXT:    --> {%n,+,-1}<nw><%loop> U: full-set S: full-set Exits: 1 LoopDispositions: { %loop: Computable }
+; DEFAULT-NEXT:    --> {%n,+,-1}<nsw><%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}<nsw><%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}<nsw><%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}<nw><%loop> U: [1,-2147483648) S: [1,-2147483648) Exits: 1 LoopDispositions: { %loop: Computable }
+; EXPENSIVE_SHARPENING-NEXT:    --> {%n,+,-1}<nsw><%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}<nsw><%loop> U: [0,2147483647) S: [0,2147483647) Exits: 0 LoopDispositions: { %loop: Computable }
 ; EXPENSIVE_SHARPENING-NEXT:    %c = sub i32 2147483647, %i
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}<nuw><nsw><%loop> U: [0,2147483647) S: [0,2147483647) Exits: (-1 + (1 smax %n))<nsw> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %a = sub i32 %n, %i
-; CHECK-NEXT:    --> {%n,+,-1}<nw><%loop> U: full-set S: full-set Exits: (1 + (-1 * (1 smax %n))<nsw> + %n) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {%n,+,-1}<nsw><%loop> U: full-set S: full-set Exits: (1 + (-1 * (1 smax %n))<nsw> + %n) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %i.next = add nuw nsw i32 %i, 1
 ; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%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}<nuw><nsw><%loop> U: [0,2147483647) S: [0,2147483647) Exits: (-1 + (1 smax %n))<nsw> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %minus.i = mul i32 %i, -1
-; CHECK-NEXT:    --> {0,+,-1}<nw><%loop> U: [-2147483646,1) S: [-2147483646,1) Exits: (1 + (-1 * (1 smax %n))<nsw>)<nsw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {0,+,-1}<nsw><%loop> U: [-2147483646,1) S: [-2147483646,1) Exits: (1 + (-1 * (1 smax %n))<nsw>)<nsw> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %a = sub i32 %minus.n, %minus.i
 ; CHECK-NEXT:    --> {(-1 * %n),+,1}<nsw><%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/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 <algorithm>
 #include <cassert>
 #include <climits>
@@ -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<SCEVAddRecExpr>(LHS))
+          L = AR->getLoop();
+        if (!L)
+          if (auto *AR = dyn_cast<SCEVAddRecExpr>(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:


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D148322.513519.patch
Type: text/x-patch
Size: 5803 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20230414/245f4735/attachment.bin>


More information about the llvm-commits mailing list