Skip to content

Commit b1543ac

Browse files
committed
Adding missed optimisation
1 parent 38bb1bc commit b1543ac

File tree

3 files changed

+144
-96
lines changed

3 files changed

+144
-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: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,80 @@ 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 (!foldIntrinsicUsingDistributiveLaws(InnerOpcode, HasNUW, HasNSW,
1554+
TopLevelOpcode))
1555+
return nullptr;
1556+
1557+
assert(II->isCommutative() && Op0->isCommutative() &&
1558+
"Only inner and outer commutative op codes are supported.");
1559+
1560+
Value *A = Op0->getOperand(0);
1561+
Value *B = Op0->getOperand(1);
1562+
Value *C = Op1->getOperand(0);
1563+
Value *D = Op1->getOperand(1);
1564+
1565+
// Attempts to swap variables such that A always equals C
1566+
if (A != C && A != D)
1567+
std::swap(A, B);
1568+
if (A == C || A == D) {
1569+
if (A != C)
1570+
std::swap(C, D);
1571+
Value *NewIntrinsic = Builder.CreateBinaryIntrinsic(TopLevelOpcode, B, D);
1572+
BinaryOperator *NewBinop =
1573+
cast<BinaryOperator>(Builder.CreateBinOp(InnerOpcode, NewIntrinsic, A));
1574+
NewBinop->setHasNoSignedWrap(HasNSW);
1575+
NewBinop->setHasNoUnsignedWrap(HasNUW);
1576+
return NewBinop;
1577+
}
1578+
1579+
return nullptr;
1580+
}
1581+
15081582
/// CallInst simplification. This mostly only handles folding of intrinsic
15091583
/// instructions. For normal calls, it allows visitCallBase to do the heavy
15101584
/// lifting.
@@ -1929,6 +2003,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
19292003
}
19302004
}
19312005

2006+
if (Value *V = foldIntrinsicUsingDistributiveLaws(II, Builder))
2007+
return replaceInstUsesWith(*II, V);
2008+
19322009
break;
19332010
}
19342011
case Intrinsic::bitreverse: {

0 commit comments

Comments
 (0)