Skip to content

Commit 2a2c35a

Browse files
authored
[InstCombine] Fold icmp spred (mul nsw X, Z), (mul nsw Y, Z) into icmp spred X, Y (#110630)
``` icmp spred (mul nsw X, Z), (mul nsw Y, Z) -> icmp spred X, Y iff Z > 0 icmp spred (mul nsw X, Z), (mul nsw Y, Z) -> icmp spred Y, X iff Z < 0 ``` Alive2: https://alive2.llvm.org/ce/z/9fXFfn
1 parent cb52e8e commit 2a2c35a

File tree

2 files changed

+172
-29
lines changed

2 files changed

+172
-29
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5273,37 +5273,46 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
52735273

52745274
{
52755275
// Try to remove shared multiplier from comparison:
5276-
// X * Z u{lt/le/gt/ge}/eq/ne Y * Z
5276+
// X * Z pred Y * Z
52775277
Value *X, *Y, *Z;
5278-
if (Pred == ICmpInst::getUnsignedPredicate(Pred) &&
5279-
((match(Op0, m_Mul(m_Value(X), m_Value(Z))) &&
5280-
match(Op1, m_c_Mul(m_Specific(Z), m_Value(Y)))) ||
5281-
(match(Op0, m_Mul(m_Value(Z), m_Value(X))) &&
5282-
match(Op1, m_c_Mul(m_Specific(Z), m_Value(Y)))))) {
5283-
bool NonZero;
5284-
if (ICmpInst::isEquality(Pred)) {
5285-
// If X != Y, fold (X *nw Z) eq/ne (Y *nw Z) -> Z eq/ne 0
5286-
if (((Op0HasNSW && Op1HasNSW) || (Op0HasNUW && Op1HasNUW)) &&
5287-
isKnownNonEqual(X, Y, DL, &AC, &I, &DT))
5288-
return new ICmpInst(Pred, Z, Constant::getNullValue(Z->getType()));
5289-
5290-
KnownBits ZKnown = computeKnownBits(Z, 0, &I);
5291-
// if Z % 2 != 0
5292-
// X * Z eq/ne Y * Z -> X eq/ne Y
5293-
if (ZKnown.countMaxTrailingZeros() == 0)
5294-
return new ICmpInst(Pred, X, Y);
5295-
NonZero = !ZKnown.One.isZero() || isKnownNonZero(Z, Q);
5296-
// if Z != 0 and nsw(X * Z) and nsw(Y * Z)
5297-
// X * Z eq/ne Y * Z -> X eq/ne Y
5298-
if (NonZero && BO0 && BO1 && Op0HasNSW && Op1HasNSW)
5278+
if ((match(Op0, m_Mul(m_Value(X), m_Value(Z))) &&
5279+
match(Op1, m_c_Mul(m_Specific(Z), m_Value(Y)))) ||
5280+
(match(Op0, m_Mul(m_Value(Z), m_Value(X))) &&
5281+
match(Op1, m_c_Mul(m_Specific(Z), m_Value(Y))))) {
5282+
if (ICmpInst::isSigned(Pred)) {
5283+
if (Op0HasNSW && Op1HasNSW) {
5284+
KnownBits ZKnown = computeKnownBits(Z, 0, &I);
5285+
if (ZKnown.isStrictlyPositive())
5286+
return new ICmpInst(Pred, X, Y);
5287+
if (ZKnown.isNegative())
5288+
return new ICmpInst(ICmpInst::getSwappedPredicate(Pred), X, Y);
5289+
}
5290+
} else {
5291+
bool NonZero;
5292+
if (ICmpInst::isEquality(Pred)) {
5293+
// If X != Y, fold (X *nw Z) eq/ne (Y *nw Z) -> Z eq/ne 0
5294+
if (((Op0HasNSW && Op1HasNSW) || (Op0HasNUW && Op1HasNUW)) &&
5295+
isKnownNonEqual(X, Y, DL, &AC, &I, &DT))
5296+
return new ICmpInst(Pred, Z, Constant::getNullValue(Z->getType()));
5297+
5298+
KnownBits ZKnown = computeKnownBits(Z, 0, &I);
5299+
// if Z % 2 != 0
5300+
// X * Z eq/ne Y * Z -> X eq/ne Y
5301+
if (ZKnown.countMaxTrailingZeros() == 0)
5302+
return new ICmpInst(Pred, X, Y);
5303+
NonZero = !ZKnown.One.isZero() || isKnownNonZero(Z, Q);
5304+
// if Z != 0 and nsw(X * Z) and nsw(Y * Z)
5305+
// X * Z eq/ne Y * Z -> X eq/ne Y
5306+
if (NonZero && BO0 && BO1 && Op0HasNSW && Op1HasNSW)
5307+
return new ICmpInst(Pred, X, Y);
5308+
} else
5309+
NonZero = isKnownNonZero(Z, Q);
5310+
5311+
// If Z != 0 and nuw(X * Z) and nuw(Y * Z)
5312+
// X * Z u{lt/le/gt/ge}/eq/ne Y * Z -> X u{lt/le/gt/ge}/eq/ne Y
5313+
if (NonZero && BO0 && BO1 && Op0HasNUW && Op1HasNUW)
52995314
return new ICmpInst(Pred, X, Y);
5300-
} else
5301-
NonZero = isKnownNonZero(Z, Q);
5302-
5303-
// If Z != 0 and nuw(X * Z) and nuw(Y * Z)
5304-
// X * Z u{lt/le/gt/ge}/eq/ne Y * Z -> X u{lt/le/gt/ge}/eq/ne Y
5305-
if (NonZero && BO0 && BO1 && Op0HasNUW && Op1HasNUW)
5306-
return new ICmpInst(Pred, X, Y);
5315+
}
53075316
}
53085317
}
53095318

llvm/test/Transforms/InstCombine/icmp-mul.ll

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,3 +1330,137 @@ entry:
13301330
%cmp = icmp ult i8 %mul1, %mul2
13311331
ret i1 %cmp
13321332
}
1333+
1334+
define i1 @icmp_mul_nsw_slt(i8 %x, i8 %y) {
1335+
; CHECK-LABEL: @icmp_mul_nsw_slt(
1336+
; CHECK-NEXT: entry:
1337+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], [[Y:%.*]]
1338+
; CHECK-NEXT: ret i1 [[CMP]]
1339+
;
1340+
entry:
1341+
%mul1 = mul nsw i8 %x, 7
1342+
%mul2 = mul nsw i8 %y, 7
1343+
%cmp = icmp slt i8 %mul1, %mul2
1344+
ret i1 %cmp
1345+
}
1346+
1347+
define i1 @icmp_mul_nsw_sle(i8 %x, i8 %y) {
1348+
; CHECK-LABEL: @icmp_mul_nsw_sle(
1349+
; CHECK-NEXT: entry:
1350+
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X:%.*]], [[Y:%.*]]
1351+
; CHECK-NEXT: ret i1 [[CMP]]
1352+
;
1353+
entry:
1354+
%mul1 = mul nsw i8 %x, 7
1355+
%mul2 = mul nsw i8 %y, 7
1356+
%cmp = icmp sle i8 %mul1, %mul2
1357+
ret i1 %cmp
1358+
}
1359+
1360+
define i1 @icmp_mul_nsw_sgt(i8 %x, i8 %y) {
1361+
; CHECK-LABEL: @icmp_mul_nsw_sgt(
1362+
; CHECK-NEXT: entry:
1363+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], [[Y:%.*]]
1364+
; CHECK-NEXT: ret i1 [[CMP]]
1365+
;
1366+
entry:
1367+
%mul1 = mul nsw i8 %x, 7
1368+
%mul2 = mul nsw i8 %y, 7
1369+
%cmp = icmp sgt i8 %mul1, %mul2
1370+
ret i1 %cmp
1371+
}
1372+
1373+
define i1 @icmp_mul_nsw_sge(i8 %x, i8 %y) {
1374+
; CHECK-LABEL: @icmp_mul_nsw_sge(
1375+
; CHECK-NEXT: entry:
1376+
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[X:%.*]], [[Y:%.*]]
1377+
; CHECK-NEXT: ret i1 [[CMP]]
1378+
;
1379+
entry:
1380+
%mul1 = mul nsw i8 %x, 7
1381+
%mul2 = mul nsw i8 %y, 7
1382+
%cmp = icmp sge i8 %mul1, %mul2
1383+
ret i1 %cmp
1384+
}
1385+
1386+
define i1 @icmp_mul_nsw_slt_neg(i8 %x, i8 %y) {
1387+
; CHECK-LABEL: @icmp_mul_nsw_slt_neg(
1388+
; CHECK-NEXT: entry:
1389+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], [[Y:%.*]]
1390+
; CHECK-NEXT: ret i1 [[CMP]]
1391+
;
1392+
entry:
1393+
%mul1 = mul nsw i8 %x, -7
1394+
%mul2 = mul nsw i8 %y, -7
1395+
%cmp = icmp slt i8 %mul1, %mul2
1396+
ret i1 %cmp
1397+
}
1398+
1399+
define i1 @icmp_mul_nsw_slt_neg_var(i8 %x, i8 %y, i8 %z) {
1400+
; CHECK-LABEL: @icmp_mul_nsw_slt_neg_var(
1401+
; CHECK-NEXT: entry:
1402+
; CHECK-NEXT: [[COND:%.*]] = icmp slt i8 [[Z:%.*]], 0
1403+
; CHECK-NEXT: call void @llvm.assume(i1 [[COND]])
1404+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], [[Y:%.*]]
1405+
; CHECK-NEXT: ret i1 [[CMP]]
1406+
;
1407+
entry:
1408+
%cond = icmp slt i8 %z, 0
1409+
call void @llvm.assume(i1 %cond)
1410+
%mul1 = mul nsw i8 %x, %z
1411+
%mul2 = mul nsw i8 %y, %z
1412+
%cmp = icmp slt i8 %mul1, %mul2
1413+
ret i1 %cmp
1414+
}
1415+
1416+
; Negative tests
1417+
1418+
define i1 @icmp_mul_nonsw_slt(i8 %x, i8 %y) {
1419+
; CHECK-LABEL: @icmp_mul_nonsw_slt(
1420+
; CHECK-NEXT: entry:
1421+
; CHECK-NEXT: [[MUL1:%.*]] = mul i8 [[X:%.*]], 7
1422+
; CHECK-NEXT: [[MUL2:%.*]] = mul nsw i8 [[Y:%.*]], 7
1423+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[MUL1]], [[MUL2]]
1424+
; CHECK-NEXT: ret i1 [[CMP]]
1425+
;
1426+
entry:
1427+
%mul1 = mul i8 %x, 7
1428+
%mul2 = mul nsw i8 %y, 7
1429+
%cmp = icmp slt i8 %mul1, %mul2
1430+
ret i1 %cmp
1431+
}
1432+
1433+
define i1 @icmp_mul_nsw_slt_unknown_sign(i8 %x, i8 %y, i8 %z) {
1434+
; CHECK-LABEL: @icmp_mul_nsw_slt_unknown_sign(
1435+
; CHECK-NEXT: entry:
1436+
; CHECK-NEXT: [[MUL1:%.*]] = mul nsw i8 [[X:%.*]], [[Z:%.*]]
1437+
; CHECK-NEXT: [[MUL2:%.*]] = mul nsw i8 [[Y:%.*]], [[Z]]
1438+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[MUL1]], [[MUL2]]
1439+
; CHECK-NEXT: ret i1 [[CMP]]
1440+
;
1441+
entry:
1442+
%mul1 = mul nsw i8 %x, %z
1443+
%mul2 = mul nsw i8 %y, %z
1444+
%cmp = icmp slt i8 %mul1, %mul2
1445+
ret i1 %cmp
1446+
}
1447+
1448+
define i1 @icmp_mul_nsw_slt_may_be_zero(i8 %x, i8 %y, i8 %z) {
1449+
; CHECK-LABEL: @icmp_mul_nsw_slt_may_be_zero(
1450+
; CHECK-NEXT: entry:
1451+
; CHECK-NEXT: [[COND:%.*]] = icmp sgt i8 [[Z:%.*]], -1
1452+
; CHECK-NEXT: call void @llvm.assume(i1 [[COND]])
1453+
; CHECK-NEXT: [[MUL1:%.*]] = mul nsw i8 [[X:%.*]], [[Z]]
1454+
; CHECK-NEXT: [[MUL2:%.*]] = mul nsw i8 [[Y:%.*]], [[Z]]
1455+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[MUL1]], [[MUL2]]
1456+
; CHECK-NEXT: ret i1 [[CMP]]
1457+
;
1458+
entry:
1459+
%cond = icmp sgt i8 %z, -1
1460+
call void @llvm.assume(i1 %cond)
1461+
1462+
%mul1 = mul nsw i8 %x, %z
1463+
%mul2 = mul nsw i8 %y, %z
1464+
%cmp = icmp slt i8 %mul1, %mul2
1465+
ret i1 %cmp
1466+
}

0 commit comments

Comments
 (0)