Skip to content

Commit 656f78f

Browse files
committed
Adding missed optimisation
1 parent f7b4cd2 commit 656f78f

File tree

3 files changed

+151
-96
lines changed

3 files changed

+151
-96
lines changed

llvm/include/llvm/IR/Operator.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ class OverflowingBinaryOperator : public Operator {
123123
return NoWrapKind;
124124
}
125125

126+
/// Return true if the instruction is commutative
127+
bool isCommutative() const { return Instruction::isCommutative(getOpcode()); }
128+
126129
static bool classof(const Instruction *I) {
127130
return I->getOpcode() == Instruction::Add ||
128131
I->getOpcode() == Instruction::Sub ||

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,87 @@ foldMinimumOverTrailingOrLeadingZeroCount(Value *I0, Value *I1,
15051505
ConstantInt::getTrue(ZeroUndef->getType()));
15061506
}
15071507

1508+
/// Return whether "X LOp (Y ROp Z)" is always equal to
1509+
/// "(X LOp Y) ROp (X LOp Z)".
1510+
static bool foldIntrinsicUsingDistributiveLaws(Instruction::BinaryOps LOp,
1511+
bool hasNUW, bool hasNSW,
1512+
Intrinsic::ID ROp) {
1513+
switch (ROp) {
1514+
case Intrinsic::umax:
1515+
return hasNUW && LOp == Instruction::Add;
1516+
case Intrinsic::umin:
1517+
return hasNUW && LOp == Instruction::Add;
1518+
case Intrinsic::smax:
1519+
return hasNSW && LOp == Instruction::Add;
1520+
case Intrinsic::smin:
1521+
return hasNSW && LOp == Instruction::Add;
1522+
default:
1523+
return false;
1524+
}
1525+
}
1526+
1527+
// Attempts to factorise a common term
1528+
// in an instruction that has the form "(A op' B) op (C op' D)
1529+
// where op is an intrinsic and op' is a binop
1530+
static Value *
1531+
foldIntrinsicUsingDistributiveLaws(IntrinsicInst *II,
1532+
InstCombiner::BuilderTy &Builder) {
1533+
Value *LHS = II->getOperand(0), *RHS = II->getOperand(1);
1534+
Intrinsic::ID TopLevelOpcode = II->getIntrinsicID();
1535+
1536+
OverflowingBinaryOperator *Op0 = dyn_cast<OverflowingBinaryOperator>(LHS);
1537+
OverflowingBinaryOperator *Op1 = dyn_cast<OverflowingBinaryOperator>(RHS);
1538+
1539+
if (!Op0 || !Op1)
1540+
return nullptr;
1541+
1542+
if (Op0->getOpcode() != Op1->getOpcode())
1543+
return nullptr;
1544+
1545+
if (!Op0->hasOneUse() || !Op1->hasOneUse())
1546+
return nullptr;
1547+
1548+
Instruction::BinaryOps InnerOpcode =
1549+
static_cast<Instruction::BinaryOps>(Op0->getOpcode());
1550+
bool HasNUW = Op0->hasNoUnsignedWrap() && Op1->hasNoUnsignedWrap();
1551+
bool HasNSW = Op0->hasNoSignedWrap() && Op1->hasNoSignedWrap();
1552+
1553+
if (!InnerOpcode)
1554+
return nullptr;
1555+
1556+
if (!foldIntrinsicUsingDistributiveLaws(InnerOpcode, HasNUW, HasNSW,
1557+
TopLevelOpcode))
1558+
return nullptr;
1559+
1560+
assert(II->isCommutative() && Op0->isCommutative() &&
1561+
"Only inner and outer commutative op codes are supported.");
1562+
1563+
Value *A = Op0->getOperand(0);
1564+
Value *B = Op0->getOperand(1);
1565+
Value *C = Op1->getOperand(0);
1566+
Value *D = Op1->getOperand(1);
1567+
1568+
// Attempts to swap variables such that A always equals C
1569+
if (A == C || A == D || B == D || B == C) {
1570+
if (A != C) {
1571+
std::swap(C, D);
1572+
}
1573+
1574+
if (B == D || B == C)
1575+
std::swap(A, B);
1576+
1577+
Value *NewIntrinsic = Builder.CreateBinaryIntrinsic(TopLevelOpcode, B, D);
1578+
BinaryOperator *NewBinop =
1579+
cast<BinaryOperator>(Builder.CreateBinOp(InnerOpcode, NewIntrinsic, A));
1580+
NewBinop->setHasNoSignedWrap(HasNSW);
1581+
NewBinop->setHasNoUnsignedWrap(HasNUW);
1582+
return NewBinop;
1583+
}
1584+
1585+
return nullptr;
1586+
}
1587+
1588+
15081589
/// CallInst simplification. This mostly only handles folding of intrinsic
15091590
/// instructions. For normal calls, it allows visitCallBase to do the heavy
15101591
/// lifting.
@@ -1929,6 +2010,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
19292010
}
19302011
}
19312012

2013+
if (Value *V = foldIntrinsicUsingDistributiveLaws(II, Builder))
2014+
return replaceInstUsesWith(*II, V);
2015+
19322016
break;
19332017
}
19342018
case Intrinsic::bitreverse: {

0 commit comments

Comments
 (0)