Skip to content

Commit 4022551

Browse files
committed
[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 llvm#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.
1 parent bfb915e commit 4022551

File tree

2 files changed

+22
-13
lines changed

2 files changed

+22
-13
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4955,11 +4955,18 @@ OverflowResult llvm::computeOverflowForUnsignedSub(const Value *LHS,
49554955
// X - (X % ?)
49564956
// The remainder of a value can't have greater magnitude than itself,
49574957
// so the subtraction can't overflow.
4958+
4959+
// X - (X -nuw ?)
4960+
// In the minimal case, this would simplify to "?", so there's no subtract
4961+
// at all. But if this analysis is used to peek through casts, for example,
4962+
// then determining no-overflow may allow other transforms.
4963+
49584964
// TODO: There are other patterns like this.
49594965
// See simplifyICmpWithBinOpOnLHS() for candidates.
4960-
if (match(RHS, m_URem(m_Specific(LHS), m_Value())) &&
4961-
isGuaranteedNotToBeUndefOrPoison(LHS, AC, CxtI, DT))
4962-
return OverflowResult::NeverOverflows;
4966+
if (match(RHS, m_URem(m_Specific(LHS), m_Value())) ||
4967+
match(RHS, m_NUWSub(m_Specific(LHS), m_Value())))
4968+
if (isGuaranteedNotToBeUndefOrPoison(LHS, AC, CxtI, DT))
4969+
return OverflowResult::NeverOverflows;
49634970

49644971
// Checking for conditions implied by dominating conditions may be expensive.
49654972
// Limit it to usub_with_overflow calls for now.

llvm/test/Transforms/InstCombine/sub.ll

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,10 +1926,7 @@ define i16 @srem_sext_noundef(i8 noundef %x, i8 %y) {
19261926

19271927
define i16 @zext_nuw_noundef(i8 noundef %x, i8 %y) {
19281928
; CHECK-LABEL: @zext_nuw_noundef(
1929-
; CHECK-NEXT: [[D:%.*]] = sub nuw i8 [[X:%.*]], [[Y:%.*]]
1930-
; CHECK-NEXT: [[EX:%.*]] = zext i8 [[X]] to i16
1931-
; CHECK-NEXT: [[ED:%.*]] = zext i8 [[D]] to i16
1932-
; CHECK-NEXT: [[Z:%.*]] = sub nsw i16 [[EX]], [[ED]]
1929+
; CHECK-NEXT: [[Z:%.*]] = zext i8 [[Y:%.*]] to i16
19331930
; CHECK-NEXT: ret i16 [[Z]]
19341931
;
19351932
%d = sub nuw i8 %x, %y
@@ -1939,6 +1936,8 @@ define i16 @zext_nuw_noundef(i8 noundef %x, i8 %y) {
19391936
ret i16 %z
19401937
}
19411938

1939+
; negative test - requires noundef
1940+
19421941
define i16 @zext_nuw(i8 %x, i8 %y) {
19431942
; CHECK-LABEL: @zext_nuw(
19441943
; CHECK-NEXT: [[D:%.*]] = sub nuw i8 [[X:%.*]], [[Y:%.*]]
@@ -1954,6 +1953,8 @@ define i16 @zext_nuw(i8 %x, i8 %y) {
19541953
ret i16 %z
19551954
}
19561955

1956+
; negative test - requires nuw
1957+
19571958
define i16 @zext_noundef(i8 noundef %x, i8 %y) {
19581959
; CHECK-LABEL: @zext_noundef(
19591960
; CHECK-NEXT: [[D:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]]
@@ -1969,6 +1970,8 @@ define i16 @zext_noundef(i8 noundef %x, i8 %y) {
19691970
ret i16 %z
19701971
}
19711972

1973+
; negative test - must have common operand
1974+
19721975
define i16 @zext_nsw_noundef_wrong_val(i8 noundef %x, i8 noundef %y, i8 noundef %q) {
19731976
; CHECK-LABEL: @zext_nsw_noundef_wrong_val(
19741977
; 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
19841987
ret i16 %z
19851988
}
19861989

1987-
define i16 @srem_zext_noundef(i8 noundef %x, i8 %y) {
1988-
; CHECK-LABEL: @srem_zext_noundef(
1990+
; two no-wrap analyses combine to allow reduction
1991+
1992+
define i16 @urem_zext_noundef(i8 noundef %x, i8 %y) {
1993+
; CHECK-LABEL: @urem_zext_noundef(
19891994
; CHECK-NEXT: [[R:%.*]] = urem i8 [[X:%.*]], [[Y:%.*]]
1990-
; CHECK-NEXT: [[D:%.*]] = sub nuw i8 [[X]], [[R]]
1991-
; CHECK-NEXT: [[ED:%.*]] = zext i8 [[D]] to i16
1992-
; CHECK-NEXT: [[EX:%.*]] = zext i8 [[X]] to i16
1993-
; CHECK-NEXT: [[Z:%.*]] = sub nsw i16 [[EX]], [[ED]]
1995+
; CHECK-NEXT: [[Z:%.*]] = zext i8 [[R]] to i16
19941996
; CHECK-NEXT: ret i16 [[Z]]
19951997
;
19961998
%r = urem i8 %x, %y

0 commit comments

Comments
 (0)