[InstCombine] propagate "exact" through folds of div

These folds were added recently with:
6b869be810
8da2fa856f
...but they didn't account for the "exact" attribute,
and that can be safely propagated:
https://alive2.llvm.org/ce/z/F_WhnR
https://alive2.llvm.org/ce/z/ft9Cgr
This commit is contained in:
Sanjay Patel 2022-10-12 09:05:34 -04:00
parent 2639caf560
commit fe97f95036
2 changed files with 25 additions and 19 deletions

View File

@ -827,28 +827,34 @@ static Instruction *foldIDivShl(BinaryOperator &I,
Type *Ty = I.getType();
// With appropriate no-wrap constraints, remove a common factor in the
// dividend and divisor that is disguised as a left-shift.
// dividend and divisor that is disguised as a left-shifted value.
Value *X, *Y, *Z;
if (match(Op1, m_Shl(m_Value(X), m_Value(Z))) &&
match(Op0, m_c_Mul(m_Specific(X), m_Value(Y)))) {
// Both operands must have the matching no-wrap for this kind of division.
auto *Mul = cast<OverflowingBinaryOperator>(Op0);
auto *Shl = cast<OverflowingBinaryOperator>(Op1);
bool HasNUW = Mul->hasNoUnsignedWrap() && Shl->hasNoUnsignedWrap();
bool HasNSW = Mul->hasNoSignedWrap() && Shl->hasNoSignedWrap();
if (!match(Op1, m_Shl(m_Value(X), m_Value(Z))) ||
!match(Op0, m_c_Mul(m_Specific(X), m_Value(Y))))
return nullptr;
// (X * Y) u/ (X << Z) --> Y u>> Z
if (!IsSigned && HasNUW)
return BinaryOperator::CreateLShr(Y, Z);
// Both operands must have the matching no-wrap for this kind of division.
Instruction *Ret = nullptr;
auto *Mul = cast<OverflowingBinaryOperator>(Op0);
auto *Shl = cast<OverflowingBinaryOperator>(Op1);
bool HasNUW = Mul->hasNoUnsignedWrap() && Shl->hasNoUnsignedWrap();
bool HasNSW = Mul->hasNoSignedWrap() && Shl->hasNoSignedWrap();
// (X * Y) s/ (X << Z) --> Y s/ (1 << Z)
if (IsSigned && HasNSW && (Op0->hasOneUse() || Op1->hasOneUse())) {
Value *Shl = Builder.CreateShl(ConstantInt::get(Ty, 1), Z);
return BinaryOperator::CreateSDiv(Y, Shl);
}
// (X * Y) u/ (X << Z) --> Y u>> Z
if (!IsSigned && HasNUW)
Ret = BinaryOperator::CreateLShr(Y, Z);
// (X * Y) s/ (X << Z) --> Y s/ (1 << Z)
if (IsSigned && HasNSW && (Op0->hasOneUse() || Op1->hasOneUse())) {
Value *Shl = Builder.CreateShl(ConstantInt::get(Ty, 1), Z);
Ret = BinaryOperator::CreateSDiv(Y, Shl);
}
return nullptr;
if (!Ret)
return nullptr;
Ret->setIsExact(I.isExact());
return Ret;
}
/// This function implements the transforms common to both integer division

View File

@ -314,7 +314,7 @@ define i5 @sdiv_mul_shl_nsw(i5 %x, i5 %y, i5 %z) {
define i5 @sdiv_mul_shl_nsw_exact_commute1(i5 %x, i5 %y, i5 %z) {
; CHECK-LABEL: @sdiv_mul_shl_nsw_exact_commute1(
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i5 1, [[Z:%.*]]
; CHECK-NEXT: [[D:%.*]] = sdiv i5 [[Y:%.*]], [[TMP1]]
; CHECK-NEXT: [[D:%.*]] = sdiv exact i5 [[Y:%.*]], [[TMP1]]
; CHECK-NEXT: ret i5 [[D]]
;
%m1 = mul nsw i5 %y, %x
@ -453,7 +453,7 @@ define i5 @udiv_mul_shl_nuw(i5 %x, i5 %y, i5 %z) {
define i5 @udiv_mul_shl_nuw_exact_commute1(i5 %x, i5 %y, i5 %z) {
; CHECK-LABEL: @udiv_mul_shl_nuw_exact_commute1(
; CHECK-NEXT: [[D:%.*]] = lshr i5 [[Y:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[D:%.*]] = lshr exact i5 [[Y:%.*]], [[Z:%.*]]
; CHECK-NEXT: ret i5 [[D]]
;
%m1 = mul nuw i5 %y, %x