Skip to content

Commit ced8dba

Browse files
committed
Adding missed optimisation
1 parent 80a316f commit ced8dba

File tree

3 files changed

+140
-96
lines changed

3 files changed

+140
-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: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,76 @@ foldMinimumOverTrailingOrLeadingZeroCount(Value *I0, Value *I1,
15031503
ConstantInt::getTrue(ZeroUndef->getType()));
15041504
}
15051505

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

2000+
if (Value *V = foldIntrinsicUsingDistributiveLaws(II, Builder))
2001+
return replaceInstUsesWith(*II, V);
2002+
19302003
break;
19312004
}
19322005
case Intrinsic::bitreverse: {

0 commit comments

Comments
 (0)