// 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.
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
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:%.*]]
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:%.*]]
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:%.*]]
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