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