[llvm] Recommit "[DAGCombiner] Transform (icmp eq/ne (and X,C0),(shift X,C1)) to use rotate or to getter constants." (2nd Try) (PR #71729)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 8 12:48:02 PST 2023
================
@@ -12456,27 +12456,132 @@ SDValue DAGCombiner::visitSETCC(SDNode *N) {
ISD::CondCode Cond = cast<CondCodeSDNode>(N->getOperand(2))->get();
EVT VT = N->getValueType(0);
+ SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
- SDValue Combined = SimplifySetCC(VT, N->getOperand(0), N->getOperand(1), Cond,
- SDLoc(N), !PreferSetCC);
-
- if (!Combined)
- return SDValue();
+ SDValue Combined = SimplifySetCC(VT, N0, N1, Cond, SDLoc(N), !PreferSetCC);
- // If we prefer to have a setcc, and we don't, we'll try our best to
- // recreate one using rebuildSetCC.
- if (PreferSetCC && Combined.getOpcode() != ISD::SETCC) {
- SDValue NewSetCC = rebuildSetCC(Combined);
+ if (Combined) {
+ // If we prefer to have a setcc, and we don't, we'll try our best to
+ // recreate one using rebuildSetCC.
+ if (PreferSetCC && Combined.getOpcode() != ISD::SETCC) {
+ SDValue NewSetCC = rebuildSetCC(Combined);
- // We don't have anything interesting to combine to.
- if (NewSetCC.getNode() == N)
- return SDValue();
+ // We don't have anything interesting to combine to.
+ if (NewSetCC.getNode() == N)
+ return SDValue();
- if (NewSetCC)
- return NewSetCC;
+ if (NewSetCC)
+ return NewSetCC;
+ }
+ return Combined;
}
- return Combined;
+ // Optimize
+ // 1) (icmp eq/ne (and X, C0), (shift X, C1))
+ // or
+ // 2) (icmp eq/ne X, (rotate X, C1))
+ // If C0 is a mask or shifted mask and the shift amt (C1) isolates the
+ // remaining bits (i.e something like `(x64 & UINT32_MAX) == (x64 >> 32)`)
+ // Then:
+ // If C1 is a power of 2, then the rotate and shift+and versions are
+ // equivilent, so we can interchange them depending on target preference.
+ // Otherwise, if we have the shift+and version we can interchange srl/shl
+ // which inturn affects the constant C0. We can use this to get better
+ // constants again determined by target preference.
+ if (Cond == ISD::SETNE || Cond == ISD::SETEQ) {
+ auto IsAndWithShift = [](SDValue A, SDValue B) {
+ return A.getOpcode() == ISD::AND &&
+ (B.getOpcode() == ISD::SRL || B.getOpcode() == ISD::SHL) &&
+ A.getOperand(0) == B.getOperand(0);
+ };
+ auto IsRotateWithOp = [](SDValue A, SDValue B) {
+ return (B.getOpcode() == ISD::ROTL || B.getOpcode() == ISD::ROTR) &&
+ B.getOperand(0) == A;
+ };
+ SDValue AndOrOp = SDValue(), ShiftOrRotate = SDValue();
+ bool IsRotate = false;
+
+ // Find either shift+and or rotate pattern.
+ if (IsAndWithShift(N0, N1)) {
+ AndOrOp = N0;
+ ShiftOrRotate = N1;
+ } else if (IsAndWithShift(N1, N0)) {
+ AndOrOp = N1;
+ ShiftOrRotate = N0;
+ } else if (IsRotateWithOp(N0, N1)) {
+ IsRotate = true;
+ AndOrOp = N0;
+ ShiftOrRotate = N1;
+ } else if (IsRotateWithOp(N1, N0)) {
+ IsRotate = true;
+ AndOrOp = N1;
+ ShiftOrRotate = N0;
+ }
+
+ if (AndOrOp && ShiftOrRotate && ShiftOrRotate.hasOneUse() &&
+ (IsRotate || AndOrOp.hasOneUse())) {
+ EVT OpVT = N0.getValueType();
+ // Get constant shift/rotate amount and possibly mask (if its shift+and
+ // variant).
+ auto GetAPIntValue = [](SDValue Op) -> std::optional<APInt> {
+ ConstantSDNode *CNode = isConstOrConstSplat(Op, /*AllowUndefs*/ false,
+ /*AllowTrunc*/ false);
+ if (CNode == nullptr)
+ return std::nullopt;
+ return CNode->getAPIntValue();
+ };
+ std::optional<APInt> AndCMask =
+ IsRotate ? std::nullopt : GetAPIntValue(AndOrOp.getOperand(1));
+ std::optional<APInt> ShiftCAmt =
+ GetAPIntValue(ShiftOrRotate.getOperand(1));
+ unsigned NumBits = OpVT.getScalarSizeInBits();
+
+ // We found constants.
+ if (ShiftCAmt && (IsRotate || AndCMask) && ShiftCAmt->ult(NumBits)) {
+ unsigned ShiftOpc = ShiftOrRotate.getOpcode();
+ // Check that the constants meet the constraints.
+ bool CanTransform = IsRotate;
+ if (!CanTransform) {
+ // Check that mask and shift compliment eachother
+ CanTransform = *ShiftCAmt == (~*AndCMask).popcount();
+ // Check that we are comparing all bits
+ CanTransform &= (*ShiftCAmt + AndCMask->popcount()) == NumBits;
+ // Check that the and mask is correct for the shift
+ CanTransform &=
+ ShiftOpc == ISD::SHL ? (~*AndCMask).isMask() : AndCMask->isMask();
+ }
----------------
goldsteinn wrote:
This is whats different from the last patch.
https://github.com/llvm/llvm-project/pull/71729
More information about the llvm-commits
mailing list