Skip to content

[InstCombine] simplify (X * C0) / (X * C1) into C0 / C1. #73204

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 32 additions & 13 deletions llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1207,6 +1207,38 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
}
}

// (X * Y) / (X * Z) --> Y / Z (and commuted variants)
if (match(Op0, m_Mul(m_Value(X), m_Value(Y)))) {
auto OB0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
auto OB0HasNUW = cast<OverflowingBinaryOperator>(Op0)->hasNoUnsignedWrap();

auto CreateDivOrNull = [&](Value *A, Value *B) -> Instruction * {
auto OB1HasNSW = cast<OverflowingBinaryOperator>(Op1)->hasNoSignedWrap();
auto OB1HasNUW =
cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
const APInt *C1, *C2;
if (IsSigned && OB0HasNSW) {
if (OB1HasNSW && match(B, m_APInt(C1)) && !C1->isAllOnes())
return BinaryOperator::CreateSDiv(A, B);
}
if (!IsSigned && OB0HasNUW) {
if (OB1HasNUW)
return BinaryOperator::CreateUDiv(A, B);
if (match(A, m_APInt(C1)) && match(B, m_APInt(C2)) && C2->ule(*C1))
return BinaryOperator::CreateUDiv(A, B);
}
return nullptr;
};

if (match(Op1, m_c_Mul(m_Specific(X), m_Value(Z)))) {
if (auto *Val = CreateDivOrNull(Y, Z))
return Val;
}
if (match(Op1, m_c_Mul(m_Specific(Y), m_Value(Z)))) {
if (auto *Val = CreateDivOrNull(X, Z))
return Val;
}
}
return nullptr;
}

Expand Down Expand Up @@ -1377,20 +1409,7 @@ Instruction *InstCombinerImpl::visitUDiv(BinaryOperator &I) {
if (Instruction *NarrowDiv = narrowUDivURem(I, *this))
return NarrowDiv;

// If the udiv operands are non-overflowing multiplies with a common operand,
// then eliminate the common factor:
// (A * B) / (A * X) --> B / X (and commuted variants)
// TODO: The code would be reduced if we had m_c_NUWMul pattern matching.
// TODO: If -reassociation handled this generally, we could remove this.
Value *A, *B;
if (match(Op0, m_NUWMul(m_Value(A), m_Value(B)))) {
if (match(Op1, m_NUWMul(m_Specific(A), m_Value(X))) ||
match(Op1, m_NUWMul(m_Value(X), m_Specific(A))))
return BinaryOperator::CreateUDiv(B, X);
if (match(Op1, m_NUWMul(m_Specific(B), m_Value(X))) ||
match(Op1, m_NUWMul(m_Value(X), m_Specific(B))))
return BinaryOperator::CreateUDiv(A, X);
}

// Look through a right-shift to find the common factor:
// ((Op1 *nuw A) >> B) / Op1 --> A >> B
Expand Down
134 changes: 134 additions & 0 deletions llvm/test/Transforms/InstCombine/div.ll
Original file line number Diff line number Diff line change
Expand Up @@ -1432,6 +1432,140 @@ define <2 x i8> @sdiv_sdiv_mul_nsw(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
ret <2 x i8> %r
}

; (X * C0) / (X * C1) --> C0 / C1
define i8 @sdiv_mul_nsw_mul_nsw(i8 %x,i8 %y,i8 %z) {
; CHECK-LABEL: @sdiv_mul_nsw_mul_nsw(
; CHECK-NEXT: [[ADD4:%.*]] = mul nsw i8 [[X:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[ADD5:%.*]] = mul nsw i8 [[X]], [[Y:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
; CHECK-NEXT: ret i8 [[DIV]]
;
%add4 = mul nsw i8 %x, %z
%add5 = mul nsw i8 %x, %y
%div = sdiv i8 %add5, %add4
ret i8 %div
}

define i8 @udiv_mul_nuw_mul_nuw(i8 %x,i8 %y,i8 %z) {
; CHECK-LABEL: @udiv_mul_nuw_mul_nuw(
; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[Y:%.*]], [[Z:%.*]]
; CHECK-NEXT: ret i8 [[DIV]]
;
%add4 = mul nuw i8 %x, %z
%add5 = mul nuw i8 %x, %y
%div = udiv i8 %add5, %add4
ret i8 %div
}

define i8 @sdiv_mul_nsw_constant_mul_nsw_constant(i8 %x) {
; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_nsw_constant(
; CHECK-NEXT: ret i8 2
;
%add4 = mul nsw i8 %x, 5
%add5 = mul nsw i8 %x, 10
%div = sdiv i8 %add5, %add4
ret i8 %div
}

define i4 @sdiv_mul_nsw_constant_mul_constant(i4 %a) {
; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant(
; CHECK-NEXT: [[ADD4:%.*]] = mul i4 [[A:%.*]], 3
; CHECK-NEXT: [[ADD5:%.*]] = mul nsw i4 [[A]], 6
; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
; CHECK-NEXT: ret i4 [[DIV]]
;
%add4 = mul i4 %a, 3
%add5 = mul nsw i4 %a, 6
%div = sdiv i4 %add5, %add4
ret i4 %div
}
define i4 @sdiv_mul_nsw_constant_mul_constant2(i4 %a) {
; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant2(
; CHECK-NEXT: [[ADD4:%.*]] = sub i4 0, [[A:%.*]]
; CHECK-NEXT: [[ADD5:%.*]] = shl i4 [[A]], 3
; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
; CHECK-NEXT: ret i4 [[DIV]]
;
%add4 = mul i4 %a, 15
%add5 = mul nsw i4 %a, 8
%div = sdiv i4 %add5, %add4
ret i4 %div
}

define i4 @sdiv_mul_nsw_constant_mul_constant3(i4 %a) {
; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant3(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i4 [[A:%.*]], -8
; CHECK-NEXT: [[DIV:%.*]] = select i1 [[TMP1]], i4 1, i4 -1
; CHECK-NEXT: ret i4 [[DIV]]
;
%add4 = mul i4 %a, 15
%add5 = mul nsw i4 %a, 1
%div = sdiv i4 %add5, %add4
ret i4 %div
}

define i4 @sdiv_mul_nsw_mul(i4 %a) {
; CHECK-LABEL: @sdiv_mul_nsw_mul(
; CHECK-NEXT: [[ADD4:%.*]] = sub i4 0, [[A:%.*]]
; CHECK-NEXT: [[ADD5:%.*]] = shl i4 [[A]], 3
; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
; CHECK-NEXT: ret i4 [[DIV]]
;
%add4 = mul i4 %a, -1
%add5 = mul nsw i4 %a, -8
%div = sdiv i4 %add5, %add4
ret i4 %div
}

define i4 @udiv_mul_nuw_constant_mul_constant(i4 %a) {
; CHECK-LABEL: @udiv_mul_nuw_constant_mul_constant(
; CHECK-NEXT: ret i4 2
;
%add4 = mul i4 %a, 3
%add5 = mul nuw i4 %a, 6
%div = udiv i4 %add5, %add4
ret i4 %div
}

define i4 @udiv_mul_nuw_mul_negative(i4 %a) {
; CHECK-LABEL: @udiv_mul_nuw_mul_negative(
; CHECK-NEXT: [[ADD4:%.*]] = mul i4 [[A:%.*]], -3
; CHECK-NEXT: [[ADD5:%.*]] = shl nuw i4 [[A]], 2
; CHECK-NEXT: [[DIV:%.*]] = udiv i4 [[ADD5]], [[ADD4]]
; CHECK-NEXT: ret i4 [[DIV]]
;
%add4 = mul i4 %a, 13
%add5 = mul nuw i4 %a, 4
%div = udiv i4 %add5, %add4
ret i4 %div
}

define i4 @sdiv_mul_nsw_mul_nsw_allones(i4 %a) {
; CHECK-LABEL: @sdiv_mul_nsw_mul_nsw_allones(
; CHECK-NEXT: [[ADD4:%.*]] = sub nsw i4 0, [[A:%.*]]
; CHECK-NEXT: [[ADD5:%.*]] = shl i4 [[A]], 3
; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
; CHECK-NEXT: ret i4 [[DIV]]
;
%add4 = mul nsw i4 %a, -1
%add5 = mul nsw i4 %a, -8
%div = sdiv i4 %add5, %add4
ret i4 %div
}

define i4 @sdiv_mul_nsw_mul_signmask(i4 %a, i4 %c2) {
; CHECK-LABEL: @sdiv_mul_nsw_mul_signmask(
; CHECK-NEXT: [[ADD4:%.*]] = shl i4 [[A:%.*]], 3
; CHECK-NEXT: [[ADD5:%.*]] = mul nsw i4 [[A]], [[C2:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
; CHECK-NEXT: ret i4 [[DIV]]
;
%add4 = mul nsw i4 %a, -8
%add5 = mul nsw i4 %a, %c2
%div = sdiv i4 %add5, %add4
ret i4 %div
}

define i32 @sdiv_sub1(i32 %arg) {
; CHECK-LABEL: @sdiv_sub1(
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG:%.*]], -2147483648
Expand Down