[PATCH] D127754: [ValueTracking] recognize sub X, (X -nsw Y) as not overflowing

Sanjay Patel via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 14 08:41:36 PDT 2022


spatel created this revision.
spatel added reviewers: nikic, RKSimon, xgupta.
Herald added subscribers: hiraditya, mcrosier.
Herald added a project: All.
spatel requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

This extends a similar pattern from D125500 <https://reviews.llvm.org/D125500>. If we know that operand 1 of a subtract is itself a non-overflowing subtract from operand 0, 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 the motivating case from issue #48013 <https://github.com/llvm/llvm-project/issues/48013>. In that example, we determine 'nsw' on the first sub from the srem, then we determine that the 2nd sub can be narrowed, and that leads to eliminating both subtracts.

This works for unsigned sub too, but I left that out to keep the patch minimal. If this looks ok, I will follow up with that change. There are also 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.


https://reviews.llvm.org/D127754

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


Index: llvm/test/Transforms/InstCombine/sub.ll
===================================================================
--- llvm/test/Transforms/InstCombine/sub.ll
+++ llvm/test/Transforms/InstCombine/sub.ll
@@ -1847,10 +1847,7 @@
 
 define i16 @sext_nsw_noundef(i8 noundef %x, i8 %y) {
 ; CHECK-LABEL: @sext_nsw_noundef(
-; CHECK-NEXT:    [[D:%.*]] = sub nsw i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[EX:%.*]] = sext i8 [[X]] to i16
-; CHECK-NEXT:    [[ED:%.*]] = sext i8 [[D]] to i16
-; CHECK-NEXT:    [[Z:%.*]] = sub nsw i16 [[EX]], [[ED]]
+; CHECK-NEXT:    [[Z:%.*]] = sext i8 [[Y:%.*]] to i16
 ; CHECK-NEXT:    ret i16 [[Z]]
 ;
   %d = sub nsw i8 %x, %y
@@ -1860,6 +1857,8 @@
   ret i16 %z
 }
 
+; negative test - requires noundef
+
 define i16 @sext_nsw(i8 %x, i8 %y) {
 ; CHECK-LABEL: @sext_nsw(
 ; CHECK-NEXT:    [[D:%.*]] = sub nsw i8 [[X:%.*]], [[Y:%.*]]
@@ -1875,6 +1874,8 @@
   ret i16 %z
 }
 
+; negative test - requires nsw
+
 define i16 @sext_noundef(i8 noundef %x, i8 %y) {
 ; CHECK-LABEL: @sext_noundef(
 ; CHECK-NEXT:    [[D:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]]
@@ -1890,6 +1891,8 @@
   ret i16 %z
 }
 
+; negative test - must have common operand
+
 define i16 @sext_nsw_noundef_wrong_val(i8 noundef %x, i8 noundef %y, i8 noundef %q) {
 ; CHECK-LABEL: @sext_nsw_noundef_wrong_val(
 ; CHECK-NEXT:    [[D:%.*]] = sub nsw i8 [[X:%.*]], [[Y:%.*]]
@@ -1905,13 +1908,12 @@
   ret i16 %z
 }
 
+; two no-wrap analyses combine to allow reduction
+
 define i16 @srem_sext_noundef(i8 noundef %x, i8 %y) {
 ; CHECK-LABEL: @srem_sext_noundef(
 ; CHECK-NEXT:    [[R:%.*]] = srem i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[D:%.*]] = sub nsw i8 [[X]], [[R]]
-; CHECK-NEXT:    [[SD:%.*]] = sext i8 [[D]] to i16
-; CHECK-NEXT:    [[SX:%.*]] = sext i8 [[X]] to i16
-; CHECK-NEXT:    [[Z:%.*]] = sub nsw i16 [[SX]], [[SD]]
+; CHECK-NEXT:    [[Z:%.*]] = sext i8 [[R]] to i16
 ; CHECK-NEXT:    ret i16 [[Z]]
 ;
   %r = srem i8 %x, %y
Index: llvm/lib/Analysis/ValueTracking.cpp
===================================================================
--- llvm/lib/Analysis/ValueTracking.cpp
+++ llvm/lib/Analysis/ValueTracking.cpp
@@ -4987,9 +4987,15 @@
   // X - (X % ?)
   // The remainder of a value can't have greater magnitude than itself,
   // so the subtraction can't overflow.
-  if (match(RHS, m_SRem(m_Specific(LHS), m_Value())) &&
-      isGuaranteedNotToBeUndefOrPoison(LHS, AC, CxtI, DT))
-    return OverflowResult::NeverOverflows;
+
+  // X - (X -nsw ?)
+  // 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.
+  if (match(RHS, m_SRem(m_Specific(LHS), m_Value())) ||
+      match(RHS, m_NSWSub(m_Specific(LHS), m_Value())))
+    if (isGuaranteedNotToBeUndefOrPoison(LHS, AC, CxtI, DT))
+      return OverflowResult::NeverOverflows;
 
   // If LHS and RHS each have at least two sign bits, the subtraction
   // cannot overflow.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D127754.436780.patch
Type: text/x-patch
Size: 2995 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20220614/0472fa44/attachment.bin>


More information about the llvm-commits mailing list