@@ -1505,6 +1505,87 @@ foldMinimumOverTrailingOrLeadingZeroCount(Value *I0, Value *I1,
1505
1505
ConstantInt::getTrue (ZeroUndef->getType ()));
1506
1506
}
1507
1507
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
+
1508
1589
// / CallInst simplification. This mostly only handles folding of intrinsic
1509
1590
// / instructions. For normal calls, it allows visitCallBase to do the heavy
1510
1591
// / lifting.
@@ -1929,6 +2010,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
1929
2010
}
1930
2011
}
1931
2012
2013
+ if (Value *V = foldIntrinsicUsingDistributiveLaws (II, Builder))
2014
+ return replaceInstUsesWith (*II, V);
2015
+
1932
2016
break ;
1933
2017
}
1934
2018
case Intrinsic::bitreverse: {
0 commit comments