Skip to content

Commit 1c49419

Browse files
authored
[InstCombine] simplify (X * C0) / (X * C1) into C0 / C1. (#73204)
fix #72114 proof: https://alive2.llvm.org/ce/z/xqprFm
1 parent d7ee99a commit 1c49419

File tree

2 files changed

+166
-13
lines changed

2 files changed

+166
-13
lines changed

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,38 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
12051205
}
12061206
}
12071207

1208+
// (X * Y) / (X * Z) --> Y / Z (and commuted variants)
1209+
if (match(Op0, m_Mul(m_Value(X), m_Value(Y)))) {
1210+
auto OB0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
1211+
auto OB0HasNUW = cast<OverflowingBinaryOperator>(Op0)->hasNoUnsignedWrap();
1212+
1213+
auto CreateDivOrNull = [&](Value *A, Value *B) -> Instruction * {
1214+
auto OB1HasNSW = cast<OverflowingBinaryOperator>(Op1)->hasNoSignedWrap();
1215+
auto OB1HasNUW =
1216+
cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
1217+
const APInt *C1, *C2;
1218+
if (IsSigned && OB0HasNSW) {
1219+
if (OB1HasNSW && match(B, m_APInt(C1)) && !C1->isAllOnes())
1220+
return BinaryOperator::CreateSDiv(A, B);
1221+
}
1222+
if (!IsSigned && OB0HasNUW) {
1223+
if (OB1HasNUW)
1224+
return BinaryOperator::CreateUDiv(A, B);
1225+
if (match(A, m_APInt(C1)) && match(B, m_APInt(C2)) && C2->ule(*C1))
1226+
return BinaryOperator::CreateUDiv(A, B);
1227+
}
1228+
return nullptr;
1229+
};
1230+
1231+
if (match(Op1, m_c_Mul(m_Specific(X), m_Value(Z)))) {
1232+
if (auto *Val = CreateDivOrNull(Y, Z))
1233+
return Val;
1234+
}
1235+
if (match(Op1, m_c_Mul(m_Specific(Y), m_Value(Z)))) {
1236+
if (auto *Val = CreateDivOrNull(X, Z))
1237+
return Val;
1238+
}
1239+
}
12081240
return nullptr;
12091241
}
12101242

@@ -1375,20 +1407,7 @@ Instruction *InstCombinerImpl::visitUDiv(BinaryOperator &I) {
13751407
if (Instruction *NarrowDiv = narrowUDivURem(I, *this))
13761408
return NarrowDiv;
13771409

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

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

llvm/test/Transforms/InstCombine/div.ll

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,140 @@ 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 @udiv_mul_nuw_mul_negative(i4 %a) {
1531+
; CHECK-LABEL: @udiv_mul_nuw_mul_negative(
1532+
; CHECK-NEXT: [[ADD4:%.*]] = mul i4 [[A:%.*]], -3
1533+
; CHECK-NEXT: [[ADD5:%.*]] = shl nuw i4 [[A]], 2
1534+
; CHECK-NEXT: [[DIV:%.*]] = udiv i4 [[ADD5]], [[ADD4]]
1535+
; CHECK-NEXT: ret i4 [[DIV]]
1536+
;
1537+
%add4 = mul i4 %a, 13
1538+
%add5 = mul nuw i4 %a, 4
1539+
%div = udiv i4 %add5, %add4
1540+
ret i4 %div
1541+
}
1542+
1543+
define i4 @sdiv_mul_nsw_mul_nsw_allones(i4 %a) {
1544+
; CHECK-LABEL: @sdiv_mul_nsw_mul_nsw_allones(
1545+
; CHECK-NEXT: [[ADD4:%.*]] = sub nsw i4 0, [[A:%.*]]
1546+
; CHECK-NEXT: [[ADD5:%.*]] = shl i4 [[A]], 3
1547+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
1548+
; CHECK-NEXT: ret i4 [[DIV]]
1549+
;
1550+
%add4 = mul nsw i4 %a, -1
1551+
%add5 = mul nsw i4 %a, -8
1552+
%div = sdiv i4 %add5, %add4
1553+
ret i4 %div
1554+
}
1555+
1556+
define i4 @sdiv_mul_nsw_mul_signmask(i4 %a, i4 %c2) {
1557+
; CHECK-LABEL: @sdiv_mul_nsw_mul_signmask(
1558+
; CHECK-NEXT: [[ADD4:%.*]] = shl i4 [[A:%.*]], 3
1559+
; CHECK-NEXT: [[ADD5:%.*]] = mul nsw i4 [[A]], [[C2:%.*]]
1560+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
1561+
; CHECK-NEXT: ret i4 [[DIV]]
1562+
;
1563+
%add4 = mul nsw i4 %a, -8
1564+
%add5 = mul nsw i4 %a, %c2
1565+
%div = sdiv i4 %add5, %add4
1566+
ret i4 %div
1567+
}
1568+
14351569
define i32 @sdiv_sub1(i32 %arg) {
14361570
; CHECK-LABEL: @sdiv_sub1(
14371571
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG:%.*]], -2147483648

0 commit comments

Comments
 (0)