diff options
| author | Simon Pilgrim <llvm-dev@redking.me.uk> | 2025-06-01 15:05:44 +0100 |
|---|---|---|
| committer | Simon Pilgrim <llvm-dev@redking.me.uk> | 2025-06-01 15:05:44 +0100 |
| commit | 71079fcb8e2f3f25bf06740d4bbc498ee075459c (patch) | |
| tree | 8727eb9d53302c90619fcd97c5a8ff403c9c673e | |
| parent | 33bbce5e34fcc0bf85f327258e7da356ab8b8978 (diff) | |
[X86] Move IsElementEquivalent above shuffle comparison helpers. NFC.
No change - but makes it easier for the shuffle helpers to call IsElementEquivalent.
| -rw-r--r-- | llvm/lib/Target/X86/X86ISelLowering.cpp | 174 |
1 files changed, 87 insertions, 87 deletions
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index c5d92d5034e8..b1a3e3c006bb 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -9793,6 +9793,93 @@ static SDValue LowerCONCAT_VECTORS(SDValue Op, // patterns. //===----------------------------------------------------------------------===// +/// Checks whether the vector elements referenced by two shuffle masks are +/// equivalent. +static bool IsElementEquivalent(int MaskSize, SDValue Op, SDValue ExpectedOp, + int Idx, int ExpectedIdx) { + assert(0 <= Idx && Idx < MaskSize && 0 <= ExpectedIdx && + ExpectedIdx < MaskSize && "Out of range element index"); + if (!Op || !ExpectedOp || Op.getOpcode() != ExpectedOp.getOpcode()) + return false; + + EVT VT = Op.getValueType(); + switch (Op.getOpcode()) { + case ISD::BUILD_VECTOR: + // If the values are build vectors, we can look through them to find + // equivalent inputs that make the shuffles equivalent. + // TODO: Handle MaskSize != Op.getNumOperands()? + if (MaskSize == (int)Op.getNumOperands() && + MaskSize == (int)ExpectedOp.getNumOperands()) + return Op.getOperand(Idx) == ExpectedOp.getOperand(ExpectedIdx); + break; + case ISD::BITCAST: { + SDValue Src = peekThroughBitcasts(Op); + EVT SrcVT = Src.getValueType(); + if (Op == ExpectedOp && SrcVT.isVector() && + (int)VT.getVectorNumElements() == MaskSize) { + if ((SrcVT.getScalarSizeInBits() % VT.getScalarSizeInBits()) == 0) { + unsigned Scale = SrcVT.getScalarSizeInBits() / VT.getScalarSizeInBits(); + return (Idx % Scale) == (ExpectedIdx % Scale) && + IsElementEquivalent(SrcVT.getVectorNumElements(), Src, Src, + Idx / Scale, ExpectedIdx / Scale); + } + if ((VT.getScalarSizeInBits() % SrcVT.getScalarSizeInBits()) == 0) { + unsigned Scale = VT.getScalarSizeInBits() / SrcVT.getScalarSizeInBits(); + for (unsigned I = 0; I != Scale; ++I) + if (!IsElementEquivalent(SrcVT.getVectorNumElements(), Src, Src, + (Idx * Scale) + I, + (ExpectedIdx * Scale) + I)) + return false; + return true; + } + } + break; + } + case ISD::VECTOR_SHUFFLE: { + auto *SVN = cast<ShuffleVectorSDNode>(Op); + return Op == ExpectedOp && (int)VT.getVectorNumElements() == MaskSize && + SVN->getMaskElt(Idx) == SVN->getMaskElt(ExpectedIdx); + } + case X86ISD::VBROADCAST: + case X86ISD::VBROADCAST_LOAD: + // TODO: Handle MaskSize != VT.getVectorNumElements()? + return (Op == ExpectedOp && (int)VT.getVectorNumElements() == MaskSize); + case X86ISD::SUBV_BROADCAST_LOAD: + // TODO: Handle MaskSize != VT.getVectorNumElements()? + if (Op == ExpectedOp && (int)VT.getVectorNumElements() == MaskSize) { + auto *MemOp = cast<MemSDNode>(Op); + unsigned NumMemElts = MemOp->getMemoryVT().getVectorNumElements(); + return (Idx % NumMemElts) == (ExpectedIdx % NumMemElts); + } + break; + case X86ISD::HADD: + case X86ISD::HSUB: + case X86ISD::FHADD: + case X86ISD::FHSUB: + case X86ISD::PACKSS: + case X86ISD::PACKUS: + // HOP(X,X) can refer to the elt from the lower/upper half of a lane. + // TODO: Handle MaskSize != NumElts? + // TODO: Handle HOP(X,Y) vs HOP(Y,X) equivalence cases. + if (Op == ExpectedOp && Op.getOperand(0) == Op.getOperand(1)) { + int NumElts = VT.getVectorNumElements(); + if (MaskSize == NumElts) { + int NumLanes = VT.getSizeInBits() / 128; + int NumEltsPerLane = NumElts / NumLanes; + int NumHalfEltsPerLane = NumEltsPerLane / 2; + bool SameLane = + (Idx / NumEltsPerLane) == (ExpectedIdx / NumEltsPerLane); + bool SameElt = + (Idx % NumHalfEltsPerLane) == (ExpectedIdx % NumHalfEltsPerLane); + return SameLane && SameElt; + } + } + break; + } + + return false; +} + /// Tiny helper function to identify a no-op mask. /// /// This is a somewhat boring predicate function. It checks whether the mask @@ -9968,93 +10055,6 @@ static bool isRepeatedTargetShuffleMask(unsigned LaneSizeInBits, MVT VT, Mask, RepeatedMask); } -/// Checks whether the vector elements referenced by two shuffle masks are -/// equivalent. -static bool IsElementEquivalent(int MaskSize, SDValue Op, SDValue ExpectedOp, - int Idx, int ExpectedIdx) { - assert(0 <= Idx && Idx < MaskSize && 0 <= ExpectedIdx && - ExpectedIdx < MaskSize && "Out of range element index"); - if (!Op || !ExpectedOp || Op.getOpcode() != ExpectedOp.getOpcode()) - return false; - - EVT VT = Op.getValueType(); - switch (Op.getOpcode()) { - case ISD::BUILD_VECTOR: - // If the values are build vectors, we can look through them to find - // equivalent inputs that make the shuffles equivalent. - // TODO: Handle MaskSize != Op.getNumOperands()? - if (MaskSize == (int)Op.getNumOperands() && - MaskSize == (int)ExpectedOp.getNumOperands()) - return Op.getOperand(Idx) == ExpectedOp.getOperand(ExpectedIdx); - break; - case ISD::BITCAST: { - SDValue Src = peekThroughBitcasts(Op); - EVT SrcVT = Src.getValueType(); - if (Op == ExpectedOp && SrcVT.isVector() && - (int)VT.getVectorNumElements() == MaskSize) { - if ((SrcVT.getScalarSizeInBits() % VT.getScalarSizeInBits()) == 0) { - unsigned Scale = SrcVT.getScalarSizeInBits() / VT.getScalarSizeInBits(); - return (Idx % Scale) == (ExpectedIdx % Scale) && - IsElementEquivalent(SrcVT.getVectorNumElements(), Src, Src, - Idx / Scale, ExpectedIdx / Scale); - } - if ((VT.getScalarSizeInBits() % SrcVT.getScalarSizeInBits()) == 0) { - unsigned Scale = VT.getScalarSizeInBits() / SrcVT.getScalarSizeInBits(); - for (unsigned I = 0; I != Scale; ++I) - if (!IsElementEquivalent(SrcVT.getVectorNumElements(), Src, Src, - (Idx * Scale) + I, - (ExpectedIdx * Scale) + I)) - return false; - return true; - } - } - break; - } - case ISD::VECTOR_SHUFFLE: { - auto *SVN = cast<ShuffleVectorSDNode>(Op); - return Op == ExpectedOp && (int)VT.getVectorNumElements() == MaskSize && - SVN->getMaskElt(Idx) == SVN->getMaskElt(ExpectedIdx); - } - case X86ISD::VBROADCAST: - case X86ISD::VBROADCAST_LOAD: - // TODO: Handle MaskSize != VT.getVectorNumElements()? - return (Op == ExpectedOp && (int)VT.getVectorNumElements() == MaskSize); - case X86ISD::SUBV_BROADCAST_LOAD: - // TODO: Handle MaskSize != VT.getVectorNumElements()? - if (Op == ExpectedOp && (int)VT.getVectorNumElements() == MaskSize) { - auto *MemOp = cast<MemSDNode>(Op); - unsigned NumMemElts = MemOp->getMemoryVT().getVectorNumElements(); - return (Idx % NumMemElts) == (ExpectedIdx % NumMemElts); - } - break; - case X86ISD::HADD: - case X86ISD::HSUB: - case X86ISD::FHADD: - case X86ISD::FHSUB: - case X86ISD::PACKSS: - case X86ISD::PACKUS: - // HOP(X,X) can refer to the elt from the lower/upper half of a lane. - // TODO: Handle MaskSize != NumElts? - // TODO: Handle HOP(X,Y) vs HOP(Y,X) equivalence cases. - if (Op == ExpectedOp && Op.getOperand(0) == Op.getOperand(1)) { - int NumElts = VT.getVectorNumElements(); - if (MaskSize == NumElts) { - int NumLanes = VT.getSizeInBits() / 128; - int NumEltsPerLane = NumElts / NumLanes; - int NumHalfEltsPerLane = NumEltsPerLane / 2; - bool SameLane = - (Idx / NumEltsPerLane) == (ExpectedIdx / NumEltsPerLane); - bool SameElt = - (Idx % NumHalfEltsPerLane) == (ExpectedIdx % NumHalfEltsPerLane); - return SameLane && SameElt; - } - } - break; - } - - return false; -} - /// Checks whether a shuffle mask is equivalent to an explicit list of /// arguments. /// |
