Skip to content

Commit

Permalink
[ValueTracking] recognize sub X, (X -nsw Y) as not overflowing
Browse files Browse the repository at this point in the history
This extends a similar pattern from D125500.
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 the motivating case from issue #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.

Differential Revision: https://reviews.llvm.org/D127754
  • Loading branch information
rotateright committed Jun 14, 2022
1 parent 87b8b37 commit 8605b4d
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 11 deletions.
12 changes: 9 additions & 3 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4987,9 +4987,15 @@ OverflowResult llvm::computeOverflowForSignedSub(const Value *LHS,
// 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.
Expand Down
18 changes: 10 additions & 8 deletions llvm/test/Transforms/InstCombine/sub.ll
Original file line number Diff line number Diff line change
Expand Up @@ -1847,10 +1847,7 @@ define i32 @nuw_zext_zext_different_width(i8 %x, i7 %y) {

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
Expand All @@ -1860,6 +1857,8 @@ define i16 @sext_nsw_noundef(i8 noundef %x, i8 %y) {
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:%.*]]
Expand All @@ -1875,6 +1874,8 @@ define i16 @sext_nsw(i8 %x, i8 %y) {
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:%.*]]
Expand All @@ -1890,6 +1891,8 @@ define i16 @sext_noundef(i8 noundef %x, i8 %y) {
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:%.*]]
Expand All @@ -1905,13 +1908,12 @@ define i16 @sext_nsw_noundef_wrong_val(i8 noundef %x, i8 noundef %y, i8 noundef
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
Expand Down

0 comments on commit 8605b4d

Please sign in to comment.