Skip to content

Commit 619f872

Browse files
committed
[InstCombine] Simplify (X * C0) / (X * C1) into C0 / C1.
proof: https://alive2.llvm.org/ce/z/IIEKgf
1 parent 0d77978 commit 619f872

File tree

2 files changed

+162
-13
lines changed

2 files changed

+162
-13
lines changed

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,47 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
12071207
}
12081208
}
12091209

1210+
// (X * Y) / (X * Z) --> Y / Z (and commuted variants)
1211+
if (match(Op0, m_Mul(m_Value(X), m_Value(Y)))) {
1212+
auto OB0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
1213+
auto OB0HasNUW = cast<OverflowingBinaryOperator>(Op0)->hasNoUnsignedWrap();
1214+
1215+
auto CreateDivOrNull = [&](Value *A, Value *B, Value *C) -> Instruction * {
1216+
auto OB1HasNSW = cast<OverflowingBinaryOperator>(Op1)->hasNoSignedWrap();
1217+
auto OB1HasNUW =
1218+
cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
1219+
const APInt *C1, *C2;
1220+
if (IsSigned && OB0HasNSW) {
1221+
if (OB1HasNSW && match(B, m_APInt(C1)) && !C1->isAllOnes())
1222+
return BinaryOperator::CreateSDiv(A, B);
1223+
if (match(A, m_APInt(C1)) && match(B, m_APInt(C2)))
1224+
if (auto *V = simplifyMulInst(C, B, OB1HasNSW, OB1HasNUW,
1225+
SQ.getWithInstruction(&I))) {
1226+
const APInt *AV;
1227+
APInt Q, R;
1228+
APInt::sdivrem(*C1, *C2, Q, R);
1229+
if (match(V, m_APInt(AV)) && !AV->isSignMask() && R.isZero())
1230+
return replaceInstUsesWith(I, ConstantInt::get(A->getType(), Q));
1231+
}
1232+
}
1233+
if (!IsSigned && OB0HasNUW) {
1234+
if (OB1HasNUW)
1235+
return BinaryOperator::CreateUDiv(A, B);
1236+
if (match(A, m_APInt(C1)) && match(B, m_APInt(C2)) && C2->ule(*C1))
1237+
return BinaryOperator::CreateUDiv(A, B);
1238+
}
1239+
return nullptr;
1240+
};
1241+
1242+
if (match(Op1, m_c_Mul(m_Specific(X), m_Value(Z)))) {
1243+
if (auto *Val = CreateDivOrNull(Y, Z, X))
1244+
return Val;
1245+
}
1246+
if (match(Op1, m_c_Mul(m_Specific(Y), m_Value(Z)))) {
1247+
if (auto *Val = CreateDivOrNull(X, Z, Y))
1248+
return Val;
1249+
}
1250+
}
12101251
return nullptr;
12111252
}
12121253

@@ -1377,20 +1418,7 @@ Instruction *InstCombinerImpl::visitUDiv(BinaryOperator &I) {
13771418
if (Instruction *NarrowDiv = narrowUDivURem(I, *this))
13781419
return NarrowDiv;
13791420

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

13951423
// Look through a right-shift to find the common factor:
13961424
// ((Op1 *nuw A) >> B) / Op1 --> A >> B

llvm/test/Transforms/InstCombine/div.ll

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,127 @@ define <2 x i8> @sdiv_sdiv_mul_nsw(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
14321432
ret <2 x i8> %r
14331433
}
14341434

1435+
; (X * C0) / (X * C1) --> C0 / C1
1436+
define i8 @sdiv_mul_nsw_mul_nsw(i8 %x,i8 %y,i8 %z) {
1437+
; CHECK-LABEL: @sdiv_mul_nsw_mul_nsw(
1438+
; CHECK-NEXT: [[ADD4:%.*]] = mul nsw i8 [[X:%.*]], [[Z:%.*]]
1439+
; CHECK-NEXT: [[ADD5:%.*]] = mul nsw i8 [[X]], [[Y:%.*]]
1440+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
1441+
; CHECK-NEXT: ret i8 [[DIV]]
1442+
;
1443+
%add4 = mul nsw i8 %x, %z
1444+
%add5 = mul nsw i8 %x, %y
1445+
%div = sdiv i8 %add5, %add4
1446+
ret i8 %div
1447+
}
1448+
1449+
define i8 @udiv_mul_nuw_mul_nuw(i8 %x,i8 %y,i8 %z) {
1450+
; CHECK-LABEL: @udiv_mul_nuw_mul_nuw(
1451+
; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[Y:%.*]], [[Z:%.*]]
1452+
; CHECK-NEXT: ret i8 [[DIV]]
1453+
;
1454+
%add4 = mul nuw i8 %x, %z
1455+
%add5 = mul nuw i8 %x, %y
1456+
%div = udiv i8 %add5, %add4
1457+
ret i8 %div
1458+
}
1459+
1460+
define i8 @sdiv_mul_nsw_constant_mul_nsw_constant(i8 %x) {
1461+
; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_nsw_constant(
1462+
; CHECK-NEXT: ret i8 2
1463+
;
1464+
%add4 = mul nsw i8 %x, 5
1465+
%add5 = mul nsw i8 %x, 10
1466+
%div = sdiv i8 %add5, %add4
1467+
ret i8 %div
1468+
}
1469+
1470+
define i4 @sdiv_mul_nsw_constant_mul_constant(i4 %a) {
1471+
; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant(
1472+
; CHECK-NEXT: [[ADD4:%.*]] = mul i4 [[A:%.*]], 3
1473+
; CHECK-NEXT: [[ADD5:%.*]] = mul nsw i4 [[A]], 6
1474+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
1475+
; CHECK-NEXT: ret i4 [[DIV]]
1476+
;
1477+
%add4 = mul i4 %a, 3
1478+
%add5 = mul nsw i4 %a, 6
1479+
%div = sdiv i4 %add5, %add4
1480+
ret i4 %div
1481+
}
1482+
define i4 @sdiv_mul_nsw_constant_mul_constant2(i4 %a) {
1483+
; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant2(
1484+
; CHECK-NEXT: [[ADD4:%.*]] = sub i4 0, [[A:%.*]]
1485+
; CHECK-NEXT: [[ADD5:%.*]] = shl i4 [[A]], 3
1486+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
1487+
; CHECK-NEXT: ret i4 [[DIV]]
1488+
;
1489+
%add4 = mul i4 %a, 15
1490+
%add5 = mul nsw i4 %a, 8
1491+
%div = sdiv i4 %add5, %add4
1492+
ret i4 %div
1493+
}
1494+
1495+
define i4 @sdiv_mul_nsw_constant_mul_constant3(i4 %a) {
1496+
; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant3(
1497+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i4 [[A:%.*]], -8
1498+
; CHECK-NEXT: [[DIV:%.*]] = select i1 [[TMP1]], i4 1, i4 -1
1499+
; CHECK-NEXT: ret i4 [[DIV]]
1500+
;
1501+
%add4 = mul i4 %a, 15
1502+
%add5 = mul nsw i4 %a, 1
1503+
%div = sdiv i4 %add5, %add4
1504+
ret i4 %div
1505+
}
1506+
1507+
define i4 @sdiv_mul_nsw_mul(i4 %a) {
1508+
; CHECK-LABEL: @sdiv_mul_nsw_mul(
1509+
; CHECK-NEXT: [[ADD4:%.*]] = sub i4 0, [[A:%.*]]
1510+
; CHECK-NEXT: [[ADD5:%.*]] = shl i4 [[A]], 3
1511+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
1512+
; CHECK-NEXT: ret i4 [[DIV]]
1513+
;
1514+
%add4 = mul i4 %a, -1
1515+
%add5 = mul nsw i4 %a, -8
1516+
%div = sdiv i4 %add5, %add4
1517+
ret i4 %div
1518+
}
1519+
1520+
define i4 @udiv_mul_nuw_constant_mul_constant(i4 %a) {
1521+
; CHECK-LABEL: @udiv_mul_nuw_constant_mul_constant(
1522+
; CHECK-NEXT: ret i4 2
1523+
;
1524+
%add4 = mul i4 %a, 3
1525+
%add5 = mul nuw i4 %a, 6
1526+
%div = udiv i4 %add5, %add4
1527+
ret i4 %div
1528+
}
1529+
1530+
define i4 @sdiv_mul_nsw_mul_nsw_allones(i4 %a) {
1531+
; CHECK-LABEL: @sdiv_mul_nsw_mul_nsw_allones(
1532+
; CHECK-NEXT: [[ADD4:%.*]] = sub nsw i4 0, [[A:%.*]]
1533+
; CHECK-NEXT: [[ADD5:%.*]] = shl i4 [[A]], 3
1534+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
1535+
; CHECK-NEXT: ret i4 [[DIV]]
1536+
;
1537+
%add4 = mul nsw i4 %a, -1
1538+
%add5 = mul nsw i4 %a, -8
1539+
%div = sdiv i4 %add5, %add4
1540+
ret i4 %div
1541+
}
1542+
1543+
define i4 @sdiv_mul_nsw_mul_signmask(i4 %a, i4 %c2) {
1544+
; CHECK-LABEL: @sdiv_mul_nsw_mul_signmask(
1545+
; CHECK-NEXT: [[ADD4:%.*]] = shl i4 [[A:%.*]], 3
1546+
; CHECK-NEXT: [[ADD5:%.*]] = mul nsw i4 [[A]], [[C2:%.*]]
1547+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
1548+
; CHECK-NEXT: ret i4 [[DIV]]
1549+
;
1550+
%add4 = mul nsw i4 %a, -8
1551+
%add5 = mul nsw i4 %a, %c2
1552+
%div = sdiv i4 %add5, %add4
1553+
ret i4 %div
1554+
}
1555+
14351556
define i32 @sdiv_sub1(i32 %arg) {
14361557
; CHECK-LABEL: @sdiv_sub1(
14371558
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG:%.*]], -2147483648

0 commit comments

Comments
 (0)