@@ -1503,6 +1503,76 @@ foldMinimumOverTrailingOrLeadingZeroCount(Value *I0, Value *I1,
1503
1503
ConstantInt::getTrue (ZeroUndef->getType ()));
1504
1504
}
1505
1505
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
+
1506
1576
// / CallInst simplification. This mostly only handles folding of intrinsic
1507
1577
// / instructions. For normal calls, it allows visitCallBase to do the heavy
1508
1578
// / lifting.
@@ -1927,6 +1997,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
1927
1997
}
1928
1998
}
1929
1999
2000
+ if (Value *V = foldIntrinsicUsingDistributiveLaws (II, Builder))
2001
+ return replaceInstUsesWith (*II, V);
2002
+
1930
2003
break ;
1931
2004
}
1932
2005
case Intrinsic::bitreverse: {
0 commit comments