@@ -1505,6 +1505,80 @@ 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 (!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
+
1508
1582
// / CallInst simplification. This mostly only handles folding of intrinsic
1509
1583
// / instructions. For normal calls, it allows visitCallBase to do the heavy
1510
1584
// / lifting.
@@ -1929,6 +2003,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
1929
2003
}
1930
2004
}
1931
2005
2006
+ if (Value *V = foldIntrinsicUsingDistributiveLaws (II, Builder))
2007
+ return replaceInstUsesWith (*II, V);
2008
+
1932
2009
break ;
1933
2010
}
1934
2011
case Intrinsic::bitreverse: {
0 commit comments