@@ -1554,7 +1554,11 @@ static bool leftDistributesOverRight(Instruction::BinaryOps LOp, bool HasNUW,
15541554 switch (ROp) {
15551555 case Intrinsic::umax:
15561556 case Intrinsic::umin:
1557- return HasNUW && LOp == Instruction::Add;
1557+ if (HasNUW && LOp == Instruction::Add)
1558+ return true ;
1559+ if (HasNUW && LOp == Instruction::Shl)
1560+ return true ;
1561+ return false ;
15581562 case Intrinsic::smax:
15591563 case Intrinsic::smin:
15601564 return HasNSW && LOp == Instruction::Add;
@@ -1592,29 +1596,37 @@ foldIntrinsicUsingDistributiveLaws(IntrinsicInst *II,
15921596 if (!leftDistributesOverRight (InnerOpcode, HasNUW, HasNSW, TopLevelOpcode))
15931597 return nullptr ;
15941598
1595- assert (II->isCommutative () && Op0->isCommutative () &&
1596- " Only inner and outer commutative op codes are supported." );
1597-
15981599 Value *A = Op0->getOperand (0 );
15991600 Value *B = Op0->getOperand (1 );
16001601 Value *C = Op1->getOperand (0 );
16011602 Value *D = Op1->getOperand (1 );
16021603
1603- // Attempts to swap variables such that A always equals C
1604- if (A != C && A != D)
1605- std::swap (A, B);
1606- if (A == C || A == D) {
1607- if (A != C)
1604+ // Attempts to swap variables such that A equals C or B equals D,
1605+ // if the inner operation is commutative.
1606+ if (Op0->isCommutative () && A != C && B != D) {
1607+ if (A == D || B == C)
16081608 std::swap (C, D);
1609+ else
1610+ return nullptr ;
1611+ }
1612+
1613+ BinaryOperator *NewBinop;
1614+ if (A == C) {
16091615 Value *NewIntrinsic = Builder.CreateBinaryIntrinsic (TopLevelOpcode, B, D);
1610- BinaryOperator *NewBinop =
1611- cast<BinaryOperator>(Builder.CreateBinOp (InnerOpcode, NewIntrinsic, A));
1612- NewBinop->setHasNoSignedWrap (HasNSW);
1613- NewBinop->setHasNoUnsignedWrap (HasNUW);
1614- return NewBinop;
1616+ NewBinop =
1617+ cast<BinaryOperator>(Builder.CreateBinOp (InnerOpcode, A, NewIntrinsic));
1618+ } else if (B == D) {
1619+ Value *NewIntrinsic = Builder.CreateBinaryIntrinsic (TopLevelOpcode, A, C);
1620+ NewBinop =
1621+ cast<BinaryOperator>(Builder.CreateBinOp (InnerOpcode, NewIntrinsic, B));
1622+ } else {
1623+ return nullptr ;
16151624 }
16161625
1617- return nullptr ;
1626+ NewBinop->setHasNoUnsignedWrap (HasNUW);
1627+ NewBinop->setHasNoSignedWrap (HasNSW);
1628+
1629+ return NewBinop;
16181630}
16191631
16201632// / CallInst simplification. This mostly only handles folding of intrinsic
@@ -1887,6 +1899,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
18871899 if (Instruction *I = foldMaxMulShift (I1, I0))
18881900 return I;
18891901 }
1902+
18901903 // If both operands of unsigned min/max are sign-extended, it is still ok
18911904 // to narrow the operation.
18921905 [[fallthrough]];
0 commit comments