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