@@ -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