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