[llvm-commits] PATCH: Teach the x86 backend to fold mask & shift patterns into an addressing mode computation

Duncan Sands baldrick at free.fr
Sun Jan 8 06:01:04 PST 2012


Hi Chandler,

> --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
> +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
> @@ -4237,6 +4237,17 @@ SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) {
>        return SDValue(N, 0);   // Return N so it doesn't get rechecked!
>      }
>
> +    // fold (zext (truncate (zextload x))) -> (zext (zextload x))
> +    if (LoadSDNode *Load = dyn_cast<LoadSDNode>(N0.getOperand(0).getNode())) {
> +      EVT TruncVT = N0.getValueType(), MemVT = Load->getMemoryVT();
> +      // This is safe as long as the truncate doesn't truncate any of the bits
> +      // loaded from memory and we zero extended the rest of the bits.
> +      if (ISD::isZEXTLoad(Load) && TruncVT.bitsGE(MemVT) && 0) {
> +        return DAG.getNode(ISD::ZERO_EXTEND, N->getDebugLoc(), VT,
> +                           N0.getOperand(0));
> +      }
> +    }

this is a special case of a much more general transform: zext(trunc(x)) ->
zext(x) if the bits dropped by the trunc are known zero [in full generality
the result of the transform might be x if the zext is just restoring the
bits truncated, or trunc(x) (to a different size) if the zext does not
restore all of the truncated bits].  How about implementing the general
transform instead?

> --- a/lib/Target/X86/X86ISelDAGToDAG.cpp
> +++ b/lib/Target/X86/X86ISelDAGToDAG.cpp
> @@ -814,6 +814,106 @@ bool X86DAGToDAGISel::MatchAddressRecursively(SDValue N, X86ISelAddressMode &AM,
>      break;
>      }
>
> +  case ISD::SRL: {
> +    // Try some heroics to detect shifts of masked values where the mask can be
> +    // replaced by extending the shift and undoing that in the addressing mode
> +    // scale. Patterns such as (shl (srl x, c1), c2) are canonicalized into
> +    // (and (srl x, SHIFT), MASK) by DAGCombines that don't know the shl can be
> +    // done in the addressing mode.

How about an explicit example of what you want to achieve?

> +
> +    // Scale must not be used already.
> +    if (AM.IndexReg.getNode() != 0 || AM.Scale != 1) break;
> +
> +    if (N.getNumOperands() != 2) break;

Can this check actually ever fire?  Also, might this be loading a vector value?

> +    ConstantSDNode *ShiftAmtNode = dyn_cast<ConstantSDNode>(N.getOperand(1));
> +    if (!ShiftAmtNode) break;
> +    SDValue And = N.getOperand(0);
> +    if (And.getOpcode() != ISD::AND || And.getNumOperands() != 2) break;

Can an "and" really have more than two operands?

> +    ConstantSDNode *MaskNode = dyn_cast<ConstantSDNode>(And.getOperand(1));
> +    if (!MaskNode) break;
> +    SDValue X = And.getOperand(0);
> +
> +    // We only handle up to 64-bit values here for simplicity.
> +    if (X.getValueSizeInBits() > 64) break;
> +
> +    // The number of bits that would have to be shifted left is the number of
> +    // zero bits in the mask *after* it is shifted right.

Are you sure about that?  shl(shr x, N),M should result in M bits being masked.
Thus I would have expected AMShiftAmt below to be MaskTZ (assuming AMShiftAmt
is the amount the zapped shl would have shifted by, which is what your comment
suggested to me; how about more explicit variable names or comments).

> +    uint64_t Mask = MaskNode->getZExtValue();
> +    unsigned ShiftAmt = ShiftAmtNode->getZExtValue();
> +    unsigned MaskLZ = CountLeadingZeros_64(Mask);
> +    unsigned MaskTZ = CountTrailingZeros_64(Mask);
> +    int AMShiftAmt = MaskTZ - ShiftAmt;
> +
> +    // There is nothing we can do here unless the mask is removing some bits.
> +    // Also, the addressing mode can only represent shifts of 1, 2, or 3 bits.
> +    if (AMShiftAmt <= 0 || AMShiftAmt > 3) break;
> +
> +    // We also need to ensure that mask is a continuous run of bits.
> +    if (CountTrailingOnes_64(Mask >> MaskTZ) + MaskTZ + MaskLZ != 64) break;

Is this the best way to check this?

> +
> +    // Scale the leading zero count down based on the actual size of the value.
> +    MaskLZ -= 64 - X.getValueSizeInBits();

I got bored at this point and stopped thinking about this.

Ciao, Duncan.



More information about the llvm-commits mailing list