@@ -12443,27 +12443,127 @@ SDValue DAGCombiner::visitSETCC(SDNode *N) {
1244312443
1244412444 ISD::CondCode Cond = cast<CondCodeSDNode>(N->getOperand(2))->get();
1244512445 EVT VT = N->getValueType(0);
12446+ SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
1244612447
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);
1245212449
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);
1245712455
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();
1246112459
12462- if (NewSetCC)
12463- return NewSetCC;
12460+ if (NewSetCC)
12461+ return NewSetCC;
12462+ }
12463+ return Combined;
1246412464 }
1246512465
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();
1246712567}
1246812568
1246912569SDValue DAGCombiner::visitSETCCCARRY(SDNode *N) {
0 commit comments