@@ -12466,27 +12466,132 @@ SDValue DAGCombiner::visitSETCC(SDNode *N) {
12466
12466
12467
12467
ISD::CondCode Cond = cast<CondCodeSDNode>(N->getOperand(2))->get();
12468
12468
EVT VT = N->getValueType(0);
12469
+ SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
12469
12470
12470
- SDValue Combined = SimplifySetCC(VT, N->getOperand(0), N->getOperand(1), Cond,
12471
- SDLoc(N), !PreferSetCC);
12472
-
12473
- if (!Combined)
12474
- return SDValue();
12471
+ SDValue Combined = SimplifySetCC(VT, N0, N1, Cond, SDLoc(N), !PreferSetCC);
12475
12472
12476
- // If we prefer to have a setcc, and we don't, we'll try our best to
12477
- // recreate one using rebuildSetCC.
12478
- if (PreferSetCC && Combined.getOpcode() != ISD::SETCC) {
12479
- SDValue NewSetCC = rebuildSetCC(Combined);
12473
+ if (Combined) {
12474
+ // If we prefer to have a setcc, and we don't, we'll try our best to
12475
+ // recreate one using rebuildSetCC.
12476
+ if (PreferSetCC && Combined.getOpcode() != ISD::SETCC) {
12477
+ SDValue NewSetCC = rebuildSetCC(Combined);
12480
12478
12481
- // We don't have anything interesting to combine to.
12482
- if (NewSetCC.getNode() == N)
12483
- return SDValue();
12479
+ // We don't have anything interesting to combine to.
12480
+ if (NewSetCC.getNode() == N)
12481
+ return SDValue();
12484
12482
12485
- if (NewSetCC)
12486
- return NewSetCC;
12483
+ if (NewSetCC)
12484
+ return NewSetCC;
12485
+ }
12486
+ return Combined;
12487
12487
}
12488
12488
12489
- return Combined;
12489
+ // Optimize
12490
+ // 1) (icmp eq/ne (and X, C0), (shift X, C1))
12491
+ // or
12492
+ // 2) (icmp eq/ne X, (rotate X, C1))
12493
+ // If C0 is a mask or shifted mask and the shift amt (C1) isolates the
12494
+ // remaining bits (i.e something like `(x64 & UINT32_MAX) == (x64 >> 32)`)
12495
+ // Then:
12496
+ // If C1 is a power of 2, then the rotate and shift+and versions are
12497
+ // equivilent, so we can interchange them depending on target preference.
12498
+ // Otherwise, if we have the shift+and version we can interchange srl/shl
12499
+ // which inturn affects the constant C0. We can use this to get better
12500
+ // constants again determined by target preference.
12501
+ if (Cond == ISD::SETNE || Cond == ISD::SETEQ) {
12502
+ auto IsAndWithShift = [](SDValue A, SDValue B) {
12503
+ return A.getOpcode() == ISD::AND &&
12504
+ (B.getOpcode() == ISD::SRL || B.getOpcode() == ISD::SHL) &&
12505
+ A.getOperand(0) == B.getOperand(0);
12506
+ };
12507
+ auto IsRotateWithOp = [](SDValue A, SDValue B) {
12508
+ return (B.getOpcode() == ISD::ROTL || B.getOpcode() == ISD::ROTR) &&
12509
+ B.getOperand(0) == A;
12510
+ };
12511
+ SDValue AndOrOp = SDValue(), ShiftOrRotate = SDValue();
12512
+ bool IsRotate = false;
12513
+
12514
+ // Find either shift+and or rotate pattern.
12515
+ if (IsAndWithShift(N0, N1)) {
12516
+ AndOrOp = N0;
12517
+ ShiftOrRotate = N1;
12518
+ } else if (IsAndWithShift(N1, N0)) {
12519
+ AndOrOp = N1;
12520
+ ShiftOrRotate = N0;
12521
+ } else if (IsRotateWithOp(N0, N1)) {
12522
+ IsRotate = true;
12523
+ AndOrOp = N0;
12524
+ ShiftOrRotate = N1;
12525
+ } else if (IsRotateWithOp(N1, N0)) {
12526
+ IsRotate = true;
12527
+ AndOrOp = N1;
12528
+ ShiftOrRotate = N0;
12529
+ }
12530
+
12531
+ if (AndOrOp && ShiftOrRotate && ShiftOrRotate.hasOneUse() &&
12532
+ (IsRotate || AndOrOp.hasOneUse())) {
12533
+ EVT OpVT = N0.getValueType();
12534
+ // Get constant shift/rotate amount and possibly mask (if its shift+and
12535
+ // variant).
12536
+ auto GetAPIntValue = [](SDValue Op) -> std::optional<APInt> {
12537
+ ConstantSDNode *CNode = isConstOrConstSplat(Op, /*AllowUndefs*/ false,
12538
+ /*AllowTrunc*/ false);
12539
+ if (CNode == nullptr)
12540
+ return std::nullopt;
12541
+ return CNode->getAPIntValue();
12542
+ };
12543
+ std::optional<APInt> AndCMask =
12544
+ IsRotate ? std::nullopt : GetAPIntValue(AndOrOp.getOperand(1));
12545
+ std::optional<APInt> ShiftCAmt =
12546
+ GetAPIntValue(ShiftOrRotate.getOperand(1));
12547
+ unsigned NumBits = OpVT.getScalarSizeInBits();
12548
+
12549
+ // We found constants.
12550
+ if (ShiftCAmt && (IsRotate || AndCMask) && ShiftCAmt->ult(NumBits)) {
12551
+ unsigned ShiftOpc = ShiftOrRotate.getOpcode();
12552
+ // Check that the constants meet the constraints.
12553
+ bool CanTransform = IsRotate;
12554
+ if (!CanTransform) {
12555
+ // Check that mask and shift compliment eachother
12556
+ CanTransform = *ShiftCAmt == (~*AndCMask).popcount();
12557
+ // Check that we are comparing all bits
12558
+ CanTransform &= (*ShiftCAmt + AndCMask->popcount()) == NumBits;
12559
+ // Check that the and mask is correct for the shift
12560
+ CanTransform &=
12561
+ ShiftOpc == ISD::SHL ? (~*AndCMask).isMask() : AndCMask->isMask();
12562
+ }
12563
+
12564
+ // See if target prefers another shift/rotate opcode.
12565
+ unsigned NewShiftOpc = TLI.preferedOpcodeForCmpEqPiecesOfOperand(
12566
+ OpVT, ShiftOpc, ShiftCAmt->isPowerOf2(), *ShiftCAmt, AndCMask);
12567
+ // Transform is valid and we have a new preference.
12568
+ if (CanTransform && NewShiftOpc != ShiftOpc) {
12569
+ SDLoc DL(N);
12570
+ SDValue NewShiftOrRotate =
12571
+ DAG.getNode(NewShiftOpc, DL, OpVT, ShiftOrRotate.getOperand(0),
12572
+ ShiftOrRotate.getOperand(1));
12573
+ SDValue NewAndOrOp = SDValue();
12574
+
12575
+ if (NewShiftOpc == ISD::SHL || NewShiftOpc == ISD::SRL) {
12576
+ APInt NewMask =
12577
+ NewShiftOpc == ISD::SHL
12578
+ ? APInt::getHighBitsSet(NumBits,
12579
+ NumBits - ShiftCAmt->getZExtValue())
12580
+ : APInt::getLowBitsSet(NumBits,
12581
+ NumBits - ShiftCAmt->getZExtValue());
12582
+ NewAndOrOp =
12583
+ DAG.getNode(ISD::AND, DL, OpVT, ShiftOrRotate.getOperand(0),
12584
+ DAG.getConstant(NewMask, DL, OpVT));
12585
+ } else {
12586
+ NewAndOrOp = ShiftOrRotate.getOperand(0);
12587
+ }
12588
+
12589
+ return DAG.getSetCC(DL, VT, NewAndOrOp, NewShiftOrRotate, Cond);
12590
+ }
12591
+ }
12592
+ }
12593
+ }
12594
+ return SDValue();
12490
12595
}
12491
12596
12492
12597
SDValue DAGCombiner::visitSETCCCARRY(SDNode *N) {
0 commit comments