[llvm] 4022551 - [ValueTracking] recognize sub X, (X -nuw Y) as not overflowing

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Sun Jun 19 12:12:32 PDT 2022


Author: Sanjay Patel
Date: 2022-06-19T15:12:19-04:00
New Revision: 4022551a154e01ca5347629fd429ca04b36801e0

URL: https://github.com/llvm/llvm-project/commit/4022551a154e01ca5347629fd429ca04b36801e0
DIFF: https://github.com/llvm/llvm-project/commit/4022551a154e01ca5347629fd429ca04b36801e0.diff

LOG: [ValueTracking] recognize sub X, (X -nuw Y) as not overflowing

This extends a similar pattern from D125500 and D127754.
If we know that operand 1 (RHS) of a subtract is itself a
non-overflowing subtract from operand 0 (LHS), then the
final/outer subtract is also non-overflowing:
https://alive2.llvm.org/ce/z/Bqan8v

InstCombine uses this analysis to trigger a narrowing
optimization, so that is what the first changed test shows.

The last test models a motivating case from issue #48013.
In that example, we determine 'nuw' on the first sub from
the urem, then we determine that the 2nd sub can be narrowed,
and that leads to eliminating both subtracts.

here are still several missing subtract narrowing optimizations
demonstrated in the tests above the diffs shown here - those
should be handled in InstCombine with another set of patches.

Added: 
    

Modified: 
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/test/Transforms/InstCombine/sub.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index a6c256f32dfa..4ae1c6d5bfbd 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -4955,11 +4955,18 @@ OverflowResult llvm::computeOverflowForUnsignedSub(const Value *LHS,
   // X - (X % ?)
   // The remainder of a value can't have greater magnitude than itself,
   // so the subtraction can't overflow.
+
+  // X - (X -nuw ?)
+  // In the minimal case, this would simplify to "?", so there's no subtract
+  // at all. But if this analysis is used to peek through casts, for example,
+  // then determining no-overflow may allow other transforms.
+
   // TODO: There are other patterns like this.
   //       See simplifyICmpWithBinOpOnLHS() for candidates.
-  if (match(RHS, m_URem(m_Specific(LHS), m_Value())) &&
-      isGuaranteedNotToBeUndefOrPoison(LHS, AC, CxtI, DT))
-    return OverflowResult::NeverOverflows;
+  if (match(RHS, m_URem(m_Specific(LHS), m_Value())) ||
+      match(RHS, m_NUWSub(m_Specific(LHS), m_Value())))
+    if (isGuaranteedNotToBeUndefOrPoison(LHS, AC, CxtI, DT))
+      return OverflowResult::NeverOverflows;
 
   // Checking for conditions implied by dominating conditions may be expensive.
   // Limit it to usub_with_overflow calls for now.

diff  --git a/llvm/test/Transforms/InstCombine/sub.ll b/llvm/test/Transforms/InstCombine/sub.ll
index 039441f9188a..f7d99a084176 100644
--- a/llvm/test/Transforms/InstCombine/sub.ll
+++ b/llvm/test/Transforms/InstCombine/sub.ll
@@ -1926,10 +1926,7 @@ define i16 @srem_sext_noundef(i8 noundef %x, i8 %y) {
 
 define i16 @zext_nuw_noundef(i8 noundef %x, i8 %y) {
 ; CHECK-LABEL: @zext_nuw_noundef(
-; CHECK-NEXT:    [[D:%.*]] = sub nuw i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[EX:%.*]] = zext i8 [[X]] to i16
-; CHECK-NEXT:    [[ED:%.*]] = zext i8 [[D]] to i16
-; CHECK-NEXT:    [[Z:%.*]] = sub nsw i16 [[EX]], [[ED]]
+; CHECK-NEXT:    [[Z:%.*]] = zext i8 [[Y:%.*]] to i16
 ; CHECK-NEXT:    ret i16 [[Z]]
 ;
   %d = sub nuw i8 %x, %y
@@ -1939,6 +1936,8 @@ define i16 @zext_nuw_noundef(i8 noundef %x, i8 %y) {
   ret i16 %z
 }
 
+; negative test - requires noundef
+
 define i16 @zext_nuw(i8 %x, i8 %y) {
 ; CHECK-LABEL: @zext_nuw(
 ; CHECK-NEXT:    [[D:%.*]] = sub nuw i8 [[X:%.*]], [[Y:%.*]]
@@ -1954,6 +1953,8 @@ define i16 @zext_nuw(i8 %x, i8 %y) {
   ret i16 %z
 }
 
+; negative test - requires nuw
+
 define i16 @zext_noundef(i8 noundef %x, i8 %y) {
 ; CHECK-LABEL: @zext_noundef(
 ; CHECK-NEXT:    [[D:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]]
@@ -1969,6 +1970,8 @@ define i16 @zext_noundef(i8 noundef %x, i8 %y) {
   ret i16 %z
 }
 
+; negative test - must have common operand
+
 define i16 @zext_nsw_noundef_wrong_val(i8 noundef %x, i8 noundef %y, i8 noundef %q) {
 ; CHECK-LABEL: @zext_nsw_noundef_wrong_val(
 ; CHECK-NEXT:    [[D:%.*]] = sub nuw i8 [[X:%.*]], [[Y:%.*]]
@@ -1984,13 +1987,12 @@ define i16 @zext_nsw_noundef_wrong_val(i8 noundef %x, i8 noundef %y, i8 noundef
   ret i16 %z
 }
 
-define i16 @srem_zext_noundef(i8 noundef %x, i8 %y) {
-; CHECK-LABEL: @srem_zext_noundef(
+; two no-wrap analyses combine to allow reduction
+
+define i16 @urem_zext_noundef(i8 noundef %x, i8 %y) {
+; CHECK-LABEL: @urem_zext_noundef(
 ; CHECK-NEXT:    [[R:%.*]] = urem i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[D:%.*]] = sub nuw i8 [[X]], [[R]]
-; CHECK-NEXT:    [[ED:%.*]] = zext i8 [[D]] to i16
-; CHECK-NEXT:    [[EX:%.*]] = zext i8 [[X]] to i16
-; CHECK-NEXT:    [[Z:%.*]] = sub nsw i16 [[EX]], [[ED]]
+; CHECK-NEXT:    [[Z:%.*]] = zext i8 [[R]] to i16
 ; CHECK-NEXT:    ret i16 [[Z]]
 ;
   %r = urem i8 %x, %y


        


More information about the llvm-commits mailing list