diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/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. diff --git a/llvm/test/Transforms/InstCombine/sub.ll b/llvm/test/Transforms/InstCombine/sub.ll --- a/llvm/test/Transforms/InstCombine/sub.ll +++ b/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