diff options
| author | Nemanja Ivanovic <nemanja.i.ibm@gmail.com> | 2020-06-18 21:53:50 -0500 |
|---|---|---|
| committer | Nemanja Ivanovic <nemanja.i.ibm@gmail.com> | 2020-06-18 21:54:22 -0500 |
| commit | 1fed131660b2c5d3ea7007e273a7a5da80699445 (patch) | |
| tree | 8044058fac04a316780301d0bbd1b3f72509aa87 /llvm/lib/Target | |
| parent | 8f3b2c8aa3175628128a32a6bcaecc67efd03514 (diff) | |
[PowerPC] Canonicalize shuffles to match more single-instruction masks on LE
We currently miss a number of opportunities to emit single-instruction
VMRG[LH][BHW] instructions for shuffles on little endian subtargets. Although
this in itself is not a huge performance opportunity since loading the permute
vector for a VPERM can always be pulled out of loops, producing such merge
instructions is useful to downstream optimizations.
Since VPERM is essentially opaque to all subsequent optimizations, we want to
avoid it as much as possible. Other permute instructions have semantics that can
be reasoned about much more easily in later optimizations.
This patch does the following:
- Canonicalize shuffles so that the first element comes from the first vector
(since that's what most of the mask matching functions want)
- Switch the elements that come from splat vectors so that they match the
corresponding elements from the other vector (to allow for merges)
- Adds debugging messages for when a shuffle is matched to a VPERM so that
anyone interested in improving this further can get the info for their code
Differential revision: https://reviews.llvm.org/D77448
Diffstat (limited to 'llvm/lib/Target')
| -rw-r--r-- | llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 224 | ||||
| -rw-r--r-- | llvm/lib/Target/PowerPC/PPCISelLowering.h | 10 | ||||
| -rw-r--r-- | llvm/lib/Target/PowerPC/PPCInstrVSX.td | 256 |
3 files changed, 386 insertions, 104 deletions
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index d7698a5ec962..28bd80610c84 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -125,6 +125,7 @@ cl::desc("use absolute jump tables on ppc"), cl::Hidden); STATISTIC(NumTailCalls, "Number of tail calls"); STATISTIC(NumSiblingCalls, "Number of sibling calls"); +STATISTIC(ShufflesHandledWithVPERM, "Number of shuffles lowered to a VPERM"); static bool isNByteElemShuffleMask(ShuffleVectorSDNode *, unsigned, int); @@ -1505,6 +1506,8 @@ const char *PPCTargetLowering::getTargetNodeName(unsigned Opcode) const { case PPCISD::MTVSRZ: return "PPCISD::MTVSRZ"; case PPCISD::SINT_VEC_TO_FP: return "PPCISD::SINT_VEC_TO_FP"; case PPCISD::UINT_VEC_TO_FP: return "PPCISD::UINT_VEC_TO_FP"; + case PPCISD::SCALAR_TO_VECTOR_PERMUTED: + return "PPCISD::SCALAR_TO_VECTOR_PERMUTED"; case PPCISD::ANDI_rec_1_EQ_BIT: return "PPCISD::ANDI_rec_1_EQ_BIT"; case PPCISD::ANDI_rec_1_GT_BIT: @@ -2716,7 +2719,8 @@ static bool usePartialVectorLoads(SDNode *N, const PPCSubtarget& ST) { for (SDNode::use_iterator UI = LD->use_begin(), UE = LD->use_end(); UI != UE; ++UI) if (UI.getUse().get().getResNo() == 0 && - UI->getOpcode() != ISD::SCALAR_TO_VECTOR) + UI->getOpcode() != ISD::SCALAR_TO_VECTOR && + UI->getOpcode() != PPCISD::SCALAR_TO_VECTOR_PERMUTED) return false; return true; @@ -9041,7 +9045,8 @@ static const SDValue *getNormalLoadInput(const SDValue &Op) { const SDValue *InputLoad = &Op; if (InputLoad->getOpcode() == ISD::BITCAST) InputLoad = &InputLoad->getOperand(0); - if (InputLoad->getOpcode() == ISD::SCALAR_TO_VECTOR) + if (InputLoad->getOpcode() == ISD::SCALAR_TO_VECTOR || + InputLoad->getOpcode() == PPCISD::SCALAR_TO_VECTOR_PERMUTED) InputLoad = &InputLoad->getOperand(0); if (InputLoad->getOpcode() != ISD::LOAD) return nullptr; @@ -9690,6 +9695,15 @@ SDValue PPCTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SDValue V1 = Op.getOperand(0); SDValue V2 = Op.getOperand(1); ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(Op); + + // Any nodes that were combined in the target-independent combiner prior + // to vector legalization will not be sent to the target combine. Try to + // combine it here. + if (SDValue NewShuffle = combineVectorShuffle(SVOp, DAG)) { + DAG.ReplaceAllUsesOfValueWith(Op, NewShuffle); + Op = NewShuffle; + SVOp = cast<ShuffleVectorSDNode>(Op); + } EVT VT = Op.getValueType(); bool isLittleEndian = Subtarget.isLittleEndian(); @@ -9715,6 +9729,11 @@ SDValue PPCTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, Offset = isLittleEndian ? (3 - SplatIdx) * 4 : SplatIdx * 4; else Offset = isLittleEndian ? (1 - SplatIdx) * 8 : SplatIdx * 8; + + // If we are loading a partial vector, it does not make sense to adjust + // the base pointer. This happens with (splat (s_to_v_permuted (ld))). + if (LD->getMemoryVT().getSizeInBits() == (IsFourByte ? 32 : 64)) + Offset = 0; SDValue BasePtr = LD->getBasePtr(); if (Offset != 0) BasePtr = DAG.getNode(ISD::ADD, dl, getPointerTy(DAG.getDataLayout()), @@ -9988,7 +10007,13 @@ SDValue PPCTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, MVT::i32)); } + ShufflesHandledWithVPERM++; SDValue VPermMask = DAG.getBuildVector(MVT::v16i8, dl, ResultMask); + LLVM_DEBUG(dbgs() << "Emitting a VPERM for the following shuffle:\n"); + LLVM_DEBUG(SVOp->dump()); + LLVM_DEBUG(dbgs() << "With the following permute control vector:\n"); + LLVM_DEBUG(VPermMask.dump()); + if (isLittleEndian) return DAG.getNode(PPCISD::VPERM, dl, V1.getValueType(), V2, V1, VPermMask); @@ -14114,6 +14139,199 @@ SDValue PPCTargetLowering::combineStoreFPToInt(SDNode *N, return Val; } +static bool isAlternatingShuffMask(const ArrayRef<int> &Mask, int NumElts) { + // Check that the source of the element keeps flipping + // (i.e. Mask[i] < NumElts -> Mask[i+i] >= NumElts). + bool PrevElemFromFirstVec = Mask[0] < NumElts; + for (int i = 1, e = Mask.size(); i < e; i++) { + if (PrevElemFromFirstVec && Mask[i] < NumElts) + return false; + if (!PrevElemFromFirstVec && Mask[i] >= NumElts) + return false; + PrevElemFromFirstVec = !PrevElemFromFirstVec; + } + return true; +} + +static bool isSplatBV(SDValue Op) { + if (Op.getOpcode() != ISD::BUILD_VECTOR) + return false; + SDValue FirstOp; + + // Find first non-undef input. + for (int i = 0, e = Op.getNumOperands(); i < e; i++) { + FirstOp = Op.getOperand(i); + if (!FirstOp.isUndef()) + break; + } + + // All inputs are undef or the same as the first non-undef input. + for (int i = 1, e = Op.getNumOperands(); i < e; i++) + if (Op.getOperand(i) != FirstOp && !Op.getOperand(i).isUndef()) + return false; + return true; +} + +static SDValue isScalarToVec(SDValue Op) { + if (Op.getOpcode() == ISD::SCALAR_TO_VECTOR) + return Op; + if (Op.getOpcode() != ISD::BITCAST) + return SDValue(); + Op = Op.getOperand(0); + if (Op.getOpcode() == ISD::SCALAR_TO_VECTOR) + return Op; + return SDValue(); +} + +static void fixupShuffleMaskForPermutedSToV(SmallVectorImpl<int> &ShuffV, + int LHSMaxIdx, int RHSMinIdx, + int RHSMaxIdx, int HalfVec) { + for (int i = 0, e = ShuffV.size(); i < e; i++) { + int Idx = ShuffV[i]; + if ((Idx >= 0 && Idx < LHSMaxIdx) || (Idx >= RHSMinIdx && Idx < RHSMaxIdx)) + ShuffV[i] += HalfVec; + } + return; +} + +// Replace a SCALAR_TO_VECTOR with a SCALAR_TO_VECTOR_PERMUTED except if +// the original is: +// (<n x Ty> (scalar_to_vector (Ty (extract_elt <n x Ty> %a, C)))) +// In such a case, just change the shuffle mask to extract the element +// from the permuted index. +static SDValue getSToVPermuted(SDValue OrigSToV, SelectionDAG &DAG) { + SDLoc dl(OrigSToV); + EVT VT = OrigSToV.getValueType(); + assert(OrigSToV.getOpcode() == ISD::SCALAR_TO_VECTOR && + "Expecting a SCALAR_TO_VECTOR here"); + SDValue Input = OrigSToV.getOperand(0); + + if (Input.getOpcode() == ISD::EXTRACT_VECTOR_ELT) { + ConstantSDNode *Idx = dyn_cast<ConstantSDNode>(Input.getOperand(1)); + SDValue OrigVector = Input.getOperand(0); + + // Can't handle non-const element indices or different vector types + // for the input to the extract and the output of the scalar_to_vector. + if (Idx && VT == OrigVector.getValueType()) { + SmallVector<int, 16> NewMask(VT.getVectorNumElements(), -1); + NewMask[VT.getVectorNumElements() / 2] = Idx->getZExtValue(); + return DAG.getVectorShuffle(VT, dl, OrigVector, OrigVector, NewMask); + } + } + return DAG.getNode(PPCISD::SCALAR_TO_VECTOR_PERMUTED, dl, VT, + OrigSToV.getOperand(0)); +} + +// On little endian subtargets, combine shuffles such as: +// vector_shuffle<16,1,17,3,18,5,19,7,20,9,21,11,22,13,23,15>, <zero>, %b +// into: +// vector_shuffle<16,0,17,1,18,2,19,3,20,4,21,5,22,6,23,7>, <zero>, %b +// because the latter can be matched to a single instruction merge. +// Furthermore, SCALAR_TO_VECTOR on little endian always involves a permute +// to put the value into element zero. Adjust the shuffle mask so that the +// vector can remain in permuted form (to prevent a swap prior to a shuffle). +SDValue PPCTargetLowering::combineVectorShuffle(ShuffleVectorSDNode *SVN, + SelectionDAG &DAG) const { + SDValue LHS = SVN->getOperand(0); + SDValue RHS = SVN->getOperand(1); + auto Mask = SVN->getMask(); + int NumElts = LHS.getValueType().getVectorNumElements(); + SDValue Res(SVN, 0); + SDLoc dl(SVN); + + // None of these combines are useful on big endian systems since the ISA + // already has a big endian bias. + if (!Subtarget.isLittleEndian()) + return Res; + + // If this is not a shuffle of a shuffle and the first element comes from + // the second vector, canonicalize to the commuted form. This will make it + // more likely to match one of the single instruction patterns. + if (Mask[0] >= NumElts && LHS.getOpcode() != ISD::VECTOR_SHUFFLE && + RHS.getOpcode() != ISD::VECTOR_SHUFFLE) { + std::swap(LHS, RHS); + Res = DAG.getCommutedVectorShuffle(*SVN); + Mask = cast<ShuffleVectorSDNode>(Res)->getMask(); + } + + // Adjust the shuffle mask if either input vector comes from a + // SCALAR_TO_VECTOR and keep the respective input vector in permuted + // form (to prevent the need for a swap). + SmallVector<int, 16> ShuffV(Mask.begin(), Mask.end()); + SDValue SToVLHS = isScalarToVec(LHS); + SDValue SToVRHS = isScalarToVec(RHS); + if (SToVLHS || SToVRHS) { + int NumEltsIn = SToVLHS ? SToVLHS.getValueType().getVectorNumElements() + : SToVRHS.getValueType().getVectorNumElements(); + int NumEltsOut = ShuffV.size(); + + // Initially assume that neither input is permuted. These will be adjusted + // accordingly if either input is. + int LHSMaxIdx = -1; + int RHSMinIdx = -1; + int RHSMaxIdx = -1; + int HalfVec = LHS.getValueType().getVectorNumElements() / 2; + + // Get the permuted scalar to vector nodes for the source(s) that come from + // ISD::SCALAR_TO_VECTOR. + if (SToVLHS) { + // Set up the values for the shuffle vector fixup. + LHSMaxIdx = NumEltsOut / NumEltsIn; + SToVLHS = getSToVPermuted(SToVLHS, DAG); + if (SToVLHS.getValueType() != LHS.getValueType()) + SToVLHS = DAG.getBitcast(LHS.getValueType(), SToVLHS); + LHS = SToVLHS; + } + if (SToVRHS) { + RHSMinIdx = NumEltsOut; + RHSMaxIdx = NumEltsOut / NumEltsIn + RHSMinIdx; + SToVRHS = getSToVPermuted(SToVRHS, DAG); + if (SToVRHS.getValueType() != RHS.getValueType()) + SToVRHS = DAG.getBitcast(RHS.getValueType(), SToVRHS); + RHS = SToVRHS; + } + + // Fix up the shuffle mask to reflect where the desired element actually is. + // The minimum and maximum indices that correspond to element zero for both + // the LHS and RHS are computed and will control which shuffle mask entries + // are to be changed. For example, if the RHS is permuted, any shuffle mask + // entries in the range [RHSMinIdx,RHSMaxIdx) will be incremented by + // HalfVec to refer to the corresponding element in the permuted vector. + fixupShuffleMaskForPermutedSToV(ShuffV, LHSMaxIdx, RHSMinIdx, RHSMaxIdx, + HalfVec); + Res = DAG.getVectorShuffle(SVN->getValueType(0), dl, LHS, RHS, ShuffV); + + // We may have simplified away the shuffle. We won't be able to do anything + // further with it here. + if (!isa<ShuffleVectorSDNode>(Res)) + return Res; + Mask = cast<ShuffleVectorSDNode>(Res)->getMask(); + } + + // The common case after we commuted the shuffle is that the RHS is a splat + // and we have elements coming in from the splat at indices that are not + // conducive to using a merge. + // Example: + // vector_shuffle<0,17,1,19,2,21,3,23,4,25,5,27,6,29,7,31> t1, <zero> + if (!isSplatBV(RHS)) + return Res; + + // We are looking for a mask such that all even elements are from + // one vector and all odd elements from the other. + if (!isAlternatingShuffMask(Mask, NumElts)) + return Res; + + // Adjust the mask so we are pulling in the same index from the splat + // as the index from the interesting vector in consecutive elements. + // Example: + // vector_shuffle<0,16,1,17,2,18,3,19,4,20,5,21,6,22,7,23> t1, <zero> + for (int i = 1, e = Mask.size(); i < e; i += 2) + ShuffV[i] = (ShuffV[i - 1] + NumElts); + + Res = DAG.getVectorShuffle(SVN->getValueType(0), dl, LHS, RHS, ShuffV); + return Res; +} + SDValue PPCTargetLowering::combineVReverseMemOP(ShuffleVectorSDNode *SVN, LSBaseSDNode *LSBase, DAGCombinerInfo &DCI) const { @@ -14223,7 +14441,7 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N, LSBaseSDNode* LSBase = cast<LSBaseSDNode>(N->getOperand(0)); return combineVReverseMemOP(cast<ShuffleVectorSDNode>(N), LSBase, DCI); } - break; + return combineVectorShuffle(cast<ShuffleVectorSDNode>(N), DCI.DAG); case ISD::STORE: { EVT Op1VT = N->getOperand(1).getValueType(); diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h index 77252e919553..9f7c6ab53a17 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.h +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h @@ -221,6 +221,14 @@ namespace llvm { /// As with SINT_VEC_TO_FP, used for converting illegal types. UINT_VEC_TO_FP, + /// PowerPC instructions that have SCALAR_TO_VECTOR semantics tend to + /// place the value into the least significant element of the most + /// significant doubleword in the vector. This is not element zero for + /// anything smaller than a doubleword on either endianness. This node has + /// the same semantics as SCALAR_TO_VECTOR except that the value remains in + /// the aforementioned location in the vector register. + SCALAR_TO_VECTOR_PERMUTED, + // FIXME: Remove these once the ANDI glue bug is fixed: /// i1 = ANDI_rec_1_[EQ|GT]_BIT(i32 or i64 x) - Represents the result of the /// eq or gt bit of CR0 after executing andi. x, 1. This is used to @@ -1215,6 +1223,8 @@ namespace llvm { SDValue combineSetCC(SDNode *N, DAGCombinerInfo &DCI) const; SDValue combineABS(SDNode *N, DAGCombinerInfo &DCI) const; SDValue combineVSelect(SDNode *N, DAGCombinerInfo &DCI) const; + SDValue combineVectorShuffle(ShuffleVectorSDNode *SVN, + SelectionDAG &DAG) const; SDValue combineVReverseMemOP(ShuffleVectorSDNode *SVN, LSBaseSDNode *LSBase, DAGCombinerInfo &DCI) const; diff --git a/llvm/lib/Target/PowerPC/PPCInstrVSX.td b/llvm/lib/Target/PowerPC/PPCInstrVSX.td index e7ec1808ec3b..c43b2716cb37 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrVSX.td +++ b/llvm/lib/Target/PowerPC/PPCInstrVSX.td @@ -138,6 +138,8 @@ def PPCldvsxlh : SDNode<"PPCISD::LD_VSX_LH", SDT_PPCldvsxlh, [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; def PPCldsplat : SDNode<"PPCISD::LD_SPLAT", SDT_PPCldsplat, [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; +def PPCSToV : SDNode<"PPCISD::SCALAR_TO_VECTOR_PERMUTED", + SDTypeProfile<1, 1, []>, []>; //-------------------------- Predicate definitions ---------------------------// def HasVSX : Predicate<"PPCSubTarget->hasVSX()">; @@ -288,6 +290,11 @@ class X_XS6_RA5_RB5<bits<6> opcode, bits<10> xo, string opc, } // Predicates = HasP9Vector } // AddedComplexity = 400, hasSideEffects = 0 +multiclass ScalToVecWPermute<ValueType Ty, dag In, dag NonPermOut, dag PermOut> { + def : Pat<(Ty (scalar_to_vector In)), (Ty NonPermOut)>; + def : Pat<(Ty (PPCSToV In)), (Ty PermOut)>; +} + //-------------------------- Instruction definitions -------------------------// // VSX instructions require the VSX feature, they are to be selected over // equivalent Altivec patterns (as they address a larger register set) and @@ -2710,12 +2717,14 @@ def : Pat<(v2i64 (build_vector DblToLong.A, DblToLong.A)), def : Pat<(v2i64 (build_vector DblToULong.A, DblToULong.A)), (v2i64 (XXPERMDI (COPY_TO_REGCLASS (XSCVDPUXDS $A), VSRC), (COPY_TO_REGCLASS (XSCVDPUXDS $A), VSRC), 0))>; -def : Pat<(v4i32 (scalar_to_vector FltToIntLoad.A)), - (v4i32 (XXSPLTW (COPY_TO_REGCLASS - (XSCVDPSXWSs (XFLOADf32 xoaddr:$A)), VSRC), 1))>; -def : Pat<(v4i32 (scalar_to_vector FltToUIntLoad.A)), - (v4i32 (XXSPLTW (COPY_TO_REGCLASS - (XSCVDPUXWSs (XFLOADf32 xoaddr:$A)), VSRC), 1))>; +defm : ScalToVecWPermute< + v4i32, FltToIntLoad.A, + (XXSPLTW (COPY_TO_REGCLASS (XSCVDPSXWSs (XFLOADf32 xoaddr:$A)), VSRC), 1), + (COPY_TO_REGCLASS (XSCVDPSXWSs (XFLOADf32 xoaddr:$A)), VSRC)>; +defm : ScalToVecWPermute< + v4i32, FltToUIntLoad.A, + (XXSPLTW (COPY_TO_REGCLASS (XSCVDPUXWSs (XFLOADf32 xoaddr:$A)), VSRC), 1), + (COPY_TO_REGCLASS (XSCVDPUXWSs (XFLOADf32 xoaddr:$A)), VSRC)>; def : Pat<(v4f32 (build_vector f32:$A, f32:$A, f32:$A, f32:$A)), (v4f32 (XXSPLTW (v4f32 (XSCVDPSPN $A)), 0))>; def : Pat<(v2f64 (PPCldsplat xoaddr:$A)), @@ -2730,10 +2739,12 @@ def : Pat<(v2i64 (build_vector FltToLong.A, FltToLong.A)), def : Pat<(v2i64 (build_vector FltToULong.A, FltToULong.A)), (v2i64 (XXPERMDIs (COPY_TO_REGCLASS (XSCVDPUXDSs $A), VSFRC), 0))>; -def : Pat<(v2i64 (scalar_to_vector DblToLongLoad.A)), - (v2i64 (XVCVDPSXDS (LXVDSX xoaddr:$A)))>; -def : Pat<(v2i64 (scalar_to_vector DblToULongLoad.A)), - (v2i64 (XVCVDPUXDS (LXVDSX xoaddr:$A)))>; +defm : ScalToVecWPermute< + v2i64, DblToLongLoad.A, + (XVCVDPSXDS (LXVDSX xoaddr:$A)), (XVCVDPSXDS (LXVDSX xoaddr:$A))>; +defm : ScalToVecWPermute< + v2i64, DblToULongLoad.A, + (XVCVDPUXDS (LXVDSX xoaddr:$A)), (XVCVDPUXDS (LXVDSX xoaddr:$A))>; } // HasVSX // Any big endian VSX subtarget. @@ -2831,9 +2842,10 @@ def : Pat<WToDPExtractConv.BV13U, // Any little endian VSX subtarget. let Predicates = [HasVSX, IsLittleEndian] in { -def : Pat<(v2f64 (scalar_to_vector f64:$A)), - (v2f64 (XXPERMDI (SUBREG_TO_REG (i64 1), $A, sub_64), - (SUBREG_TO_REG (i64 1), $A, sub_64), 0))>; +defm : ScalToVecWPermute<v2f64, (f64 f64:$A), + (XXPERMDI (SUBREG_TO_REG (i64 1), $A, sub_64), + (SUBREG_TO_REG (i64 1), $A, sub_64), 0), + (SUBREG_TO_REG (i64 1), $A, sub_64)>; def : Pat<(f64 (extractelt v2f64:$S, 0)), (f64 (EXTRACT_SUBREG (XXPERMDI $S, $S, 2), sub_64))>; @@ -2943,18 +2955,24 @@ def : Pat<(PPCstore_scal_int_from_vsr (STXSDX (XSCVDPUXDS f64:$src), xoaddr:$dst)>; // Load-and-splat with fp-to-int conversion (using X-Form VSX/FP loads). -def : Pat<(v4i32 (scalar_to_vector DblToIntLoad.A)), - (v4i32 (XXSPLTW (COPY_TO_REGCLASS - (XSCVDPSXWS (XFLOADf64 xoaddr:$A)), VSRC), 1))>; -def : Pat<(v4i32 (scalar_to_vector DblToUIntLoad.A)), - (v4i32 (XXSPLTW (COPY_TO_REGCLASS - (XSCVDPUXWS (XFLOADf64 xoaddr:$A)), VSRC), 1))>; -def : Pat<(v2i64 (scalar_to_vector FltToLongLoad.A)), - (v2i64 (XXPERMDIs (XSCVDPSXDS (COPY_TO_REGCLASS - (XFLOADf32 xoaddr:$A), VSFRC)), 0))>; -def : Pat<(v2i64 (scalar_to_vector FltToULongLoad.A)), - (v2i64 (XXPERMDIs (XSCVDPUXDS (COPY_TO_REGCLASS - (XFLOADf32 xoaddr:$A), VSFRC)), 0))>; +defm : ScalToVecWPermute< + v4i32, DblToIntLoad.A, + (XXSPLTW (COPY_TO_REGCLASS (XSCVDPSXWS (XFLOADf64 xoaddr:$A)), VSRC), 1), + (COPY_TO_REGCLASS (XSCVDPSXWS (XFLOADf64 xoaddr:$A)), VSRC)>; +defm : ScalToVecWPermute< + v4i32, DblToUIntLoad.A, + (XXSPLTW (COPY_TO_REGCLASS (XSCVDPUXWS (XFLOADf64 xoaddr:$A)), VSRC), 1), + (COPY_TO_REGCLASS (XSCVDPUXWS (XFLOADf64 xoaddr:$A)), VSRC)>; +defm : ScalToVecWPermute< + v2i64, FltToLongLoad.A, + (XXPERMDIs (XSCVDPSXDS (COPY_TO_REGCLASS (XFLOADf32 xoaddr:$A), VSFRC)), 0), + (SUBREG_TO_REG (i64 1), (XSCVDPSXDS (COPY_TO_REGCLASS (XFLOADf32 xoaddr:$A), + VSFRC)), sub_64)>; +defm : ScalToVecWPermute< + v2i64, FltToULongLoad.A, + (XXPERMDIs (XSCVDPUXDS (COPY_TO_REGCLASS (XFLOADf32 xoaddr:$A), VSFRC)), 0), + (SUBREG_TO_REG (i64 1), (XSCVDPUXDS (COPY_TO_REGCLASS (XFLOADf32 xoaddr:$A), + VSFRC)), sub_64)>; } // HasVSX, NoP9Vector // Any VSX subtarget that only has loads and stores that load in big endian @@ -3156,8 +3174,12 @@ def : Pat<DWToSPExtractConv.El1US1, (f64 (COPY_TO_REGCLASS $S1, VSRC)), VSFRC)))>; // v4f32 scalar <-> vector conversions (LE) -def : Pat<(v4f32 (scalar_to_vector f32:$A)), - (v4f32 (XXSLDWI (XSCVDPSPN $A), (XSCVDPSPN $A), 1))>; + // The permuted version is no better than the version that puts the value + // into the right element because XSCVDPSPN is different from all the other + // instructions used for PPCSToV. + defm : ScalToVecWPermute<v4f32, (f32 f32:$A), + (XXSLDWI (XSCVDPSPN $A), (XSCVDPSPN $A), 1), + (XXSLDWI (XSCVDPSPN $A), (XSCVDPSPN $A), 3)>; def : Pat<(f32 (vector_extract v4f32:$S, 0)), (f32 (XSCVSPDPN (XXSLDWI $S, $S, 3)))>; def : Pat<(f32 (vector_extract v4f32:$S, 1)), @@ -3189,18 +3211,25 @@ def : Pat<(f64 (PPCfcfid (f64 (PPCmtvsra (i32 (extractelt v4i32:$A, 3)))))), // LIWAX - This instruction is used for sign extending i32 -> i64. // LIWZX - This instruction will be emitted for i32, f32, and when // zero-extending i32 to i64 (zext i32 -> i64). -def : Pat<(v2i64 (scalar_to_vector (i64 (sextloadi32 xoaddr:$src)))), - (v2i64 (XXPERMDIs - (COPY_TO_REGCLASS (LIWAX xoaddr:$src), VSFRC), 2))>; -def : Pat<(v2i64 (scalar_to_vector (i64 (zextloadi32 xoaddr:$src)))), - (v2i64 (XXPERMDIs - (COPY_TO_REGCLASS (LIWZX xoaddr:$src), VSFRC), 2))>; -def : Pat<(v4i32 (scalar_to_vector (i32 (load xoaddr:$src)))), - (v4i32 (XXPERMDIs - (COPY_TO_REGCLASS (LIWZX xoaddr:$src), VSFRC), 2))>; -def : Pat<(v4f32 (scalar_to_vector (f32 (load xoaddr:$src)))), - (v4f32 (XXPERMDIs - (COPY_TO_REGCLASS (LIWZX xoaddr:$src), VSFRC), 2))>; +defm : ScalToVecWPermute< + v2i64, (i64 (sextloadi32 xoaddr:$src)), + (XXPERMDIs (COPY_TO_REGCLASS (LIWAX xoaddr:$src), VSFRC), 2), + (SUBREG_TO_REG (i64 1), (LIWAX xoaddr:$src), sub_64)>; + +defm : ScalToVecWPermute< + v2i64, (i64 (zextloadi32 xoaddr:$src)), + (XXPERMDIs (COPY_TO_REGCLASS (LIWZX xoaddr:$src), VSFRC), 2), + (SUBREG_TO_REG (i64 1), (LIWZX xoaddr:$src), sub_64)>; + +defm : ScalToVecWPermute< + v4i32, (i32 (load xoaddr:$src)), + (XXPERMDIs (COPY_TO_REGCLASS (LIWZX xoaddr:$src), VSFRC), 2), + (SUBREG_TO_REG (i64 1), (LIWZX xoaddr:$src), sub_64)>; + +defm : ScalToVecWPermute< + v4f32, (f32 (load xoaddr:$src)), + (XXPERMDIs (COPY_TO_REGCLASS (LIWZX xoaddr:$src), VSFRC), 2), + (SUBREG_TO_REG (i64 1), (LIWZX xoaddr:$src), sub_64)>; def : Pat<DWToSPExtractConv.BVU, (v4f32 (VPKUDUM (XXSLDWI (XVCVUXDSP $S2), (XVCVUXDSP $S2), 3), @@ -3336,14 +3365,17 @@ def : Pat<(i64 (vector_extract v2i64:$S, i64:$Idx)), // Little endian VSX subtarget with direct moves. let Predicates = [HasVSX, HasDirectMove, IsLittleEndian] in { // v16i8 scalar <-> vector conversions (LE) - def : Pat<(v16i8 (scalar_to_vector i32:$A)), - (v16i8 (COPY_TO_REGCLASS MovesToVSR.LE_WORD_0, VSRC))>; - def : Pat<(v8i16 (scalar_to_vector i32:$A)), - (v8i16 (COPY_TO_REGCLASS MovesToVSR.LE_WORD_0, VSRC))>; - def : Pat<(v4i32 (scalar_to_vector i32:$A)), - (v4i32 MovesToVSR.LE_WORD_0)>; - def : Pat<(v2i64 (scalar_to_vector i64:$A)), - (v2i64 MovesToVSR.LE_DWORD_0)>; + defm : ScalToVecWPermute<v16i8, (i32 i32:$A), + (COPY_TO_REGCLASS MovesToVSR.LE_WORD_0, VSRC), + (COPY_TO_REGCLASS MovesToVSR.LE_WORD_1, VSRC)>; + defm : ScalToVecWPermute<v8i16, (i32 i32:$A), + (COPY_TO_REGCLASS MovesToVSR.LE_WORD_0, VSRC), + (COPY_TO_REGCLASS MovesToVSR.LE_WORD_1, VSRC)>; + defm : ScalToVecWPermute<v4i32, (i32 i32:$A), MovesToVSR.LE_WORD_0, + (SUBREG_TO_REG (i64 1), (MTVSRWZ $A), sub_64)>; + defm : ScalToVecWPermute<v2i64, (i64 i64:$A), MovesToVSR.LE_DWORD_0, + MovesToVSR.LE_DWORD_1>; + // v2i64 scalar <-> vector conversions (LE) def : Pat<(i64 (vector_extract v2i64:$S, 0)), (i64 VectorExtractions.LE_DWORD_0)>; @@ -3641,30 +3673,41 @@ def : Pat<(int_ppc_vsx_stxvd2x v2f64:$rS, xoaddr:$dst), (STXVX $rS, xoaddr:$dst)>; // Build vectors from i8 loads -def : Pat<(v16i8 (scalar_to_vector ScalarLoads.Li8)), - (v16i8 (VSPLTBs 7, (LXSIBZX xoaddr:$src)))>; -def : Pat<(v8i16 (scalar_to_vector ScalarLoads.ZELi8)), - (v8i16 (VSPLTHs 3, (LXSIBZX xoaddr:$src)))>; -def : Pat<(v4i32 (scalar_to_vector ScalarLoads.ZELi8)), - (v4i32 (XXSPLTWs (LXSIBZX xoaddr:$src), 1))>; -def : Pat<(v2i64 (scalar_to_vector ScalarLoads.ZELi8i64)), - (v2i64 (XXPERMDIs (LXSIBZX xoaddr:$src), 0))>; -def : Pat<(v4i32 (scalar_to_vector ScalarLoads.SELi8)), - (v4i32 (XXSPLTWs (VEXTSB2Ws (LXSIBZX xoaddr:$src)), 1))>; -def : Pat<(v2i64 (scalar_to_vector ScalarLoads.SELi8i64)), - (v2i64 (XXPERMDIs (VEXTSB2Ds (LXSIBZX xoaddr:$src)), 0))>; +defm : ScalToVecWPermute<v16i8, ScalarLoads.Li8, + (VSPLTBs 7, (LXSIBZX xoaddr:$src)), + (VSPLTBs 7, (LXSIBZX xoaddr:$src))>; +defm : ScalToVecWPermute<v8i16, ScalarLoads.ZELi8, + (VSPLTHs 3, (LXSIBZX xoaddr:$src)), + (VSPLTHs 3, (LXSIBZX xoaddr:$src))>; +defm : ScalToVecWPermute<v4i32, ScalarLoads.ZELi8, + (XXSPLTWs (LXSIBZX xoaddr:$src), 1), + (XXSPLTWs (LXSIBZX xoaddr:$src), 1)>; +defm : ScalToVecWPermute<v2i64, ScalarLoads.ZELi8i64, + (XXPERMDIs (LXSIBZX xoaddr:$src), 0), + (XXPERMDIs (LXSIBZX xoaddr:$src), 0)>; +defm : ScalToVecWPermute<v4i32, ScalarLoads.SELi8, + (XXSPLTWs (VEXTSB2Ws (LXSIBZX xoaddr:$src)), 1), + (XXSPLTWs (VEXTSB2Ws (LXSIBZX xoaddr:$src)), 1)>; +defm : ScalToVecWPermute<v2i64, ScalarLoads.SELi8i64, + (XXPERMDIs (VEXTSB2Ds (LXSIBZX xoaddr:$src)), 0), + (XXPERMDIs (VEXTSB2Ds (LXSIBZX xoaddr:$src)), 0)>; // Build vectors from i16 loads -def : Pat<(v8i16 (scalar_to_vector ScalarLoads.Li16)), - (v8i16 (VSPLTHs 3, (LXSIHZX xoaddr:$src)))>; -def : Pat<(v4i32 (scalar_to_vector ScalarLoads.ZELi16)), - (v4i32 (XXSPLTWs (LXSIHZX xoaddr:$src), 1))>; -def : Pat<(v2i64 (scalar_to_vector ScalarLoads.ZELi16i64)), - (v2i64 (XXPERMDIs (LXSIHZX xoaddr:$src), 0))>; -def : Pat<(v4i32 (scalar_to_vector ScalarLoads.SELi16)), - (v4i32 (XXSPLTWs (VEXTSH2Ws (LXSIHZX xoaddr:$src)), 1))>; -def : Pat<(v2i64 (scalar_to_vector ScalarLoads.SELi16i64)), - (v2i64 (XXPERMDIs (VEXTSH2Ds (LXSIHZX xoaddr:$src)), 0))>; +defm : ScalToVecWPermute<v8i16, ScalarLoads.Li16, + (VSPLTHs 3, (LXSIHZX xoaddr:$src)), + (VSPLTHs 3, (LXSIHZX xoaddr:$src))>; +defm : ScalToVecWPermute<v4i32, ScalarLoads.ZELi16, + (XXSPLTWs (LXSIHZX xoaddr:$src), 1), + (XXSPLTWs (LXSIHZX xoaddr:$src), 1)>; +defm : ScalToVecWPermute<v2i64, ScalarLoads.ZELi16i64, + (XXPERMDIs (LXSIHZX xoaddr:$src), 0), + (XXPERMDIs (LXSIHZX xoaddr:$src), 0)>; +defm : ScalToVecWPermute<v4i32, ScalarLoads.SELi16, + (XXSPLTWs (VEXTSH2Ws (LXSIHZX xoaddr:$src)), 1), + (XXSPLTWs (VEXTSH2Ws (LXSIHZX xoaddr:$src)), 1)>; +defm : ScalToVecWPermute<v2i64, ScalarLoads.SELi16i64, + (XXPERMDIs (VEXTSH2Ds (LXSIHZX xoaddr:$src)), 0), + (XXPERMDIs (VEXTSH2Ds (LXSIHZX xoaddr:$src)), 0)>; // Load/convert and convert/store patterns for f16. def : Pat<(f64 (extloadf16 xoaddr:$src)), @@ -3806,8 +3849,7 @@ def : Pat<(f32 (PPCxsminc f32:$XA, f32:$XB)), VSSRC))>; // Endianness-neutral patterns for const splats with ISA 3.0 instructions. -def : Pat<(v4i32 (scalar_to_vector i32:$A)), - (v4i32 (MTVSRWS $A))>; +defm : ScalToVecWPermute<v4i32, (i32 i32:$A), (MTVSRWS $A), (MTVSRWS $A)>; def : Pat<(v4i32 (build_vector i32:$A, i32:$A, i32:$A, i32:$A)), (v4i32 (MTVSRWS $A))>; def : Pat<(v16i8 (build_vector immNonAllOneAnyExt8:$A, immNonAllOneAnyExt8:$A, @@ -3819,24 +3861,32 @@ def : Pat<(v16i8 (build_vector immNonAllOneAnyExt8:$A, immNonAllOneAnyExt8:$A, immNonAllOneAnyExt8:$A, immNonAllOneAnyExt8:$A, immNonAllOneAnyExt8:$A, immNonAllOneAnyExt8:$A)), (v16i8 (COPY_TO_REGCLASS (XXSPLTIB imm:$A), VSRC))>; -def : Pat<(v4i32 (scalar_to_vector FltToIntLoad.A)), - (v4i32 (XVCVSPSXWS (LXVWSX xoaddr:$A)))>; -def : Pat<(v4i32 (scalar_to_vector FltToUIntLoad.A)), - (v4i32 (XVCVSPUXWS (LXVWSX xoaddr:$A)))>; -def : Pat<(v4i32 (scalar_to_vector DblToIntLoadP9.A)), - (v4i32 (XXSPLTW (COPY_TO_REGCLASS - (XSCVDPSXWS (DFLOADf64 iaddrX4:$A)), VSRC), 1))>; -def : Pat<(v4i32 (scalar_to_vector DblToUIntLoadP9.A)), - (v4i32 (XXSPLTW (COPY_TO_REGCLASS - (XSCVDPUXWS (DFLOADf64 iaddrX4:$A)), VSRC), 1))>; -def : Pat<(v2i64 (scalar_to_vector FltToLongLoadP9.A)), - (v2i64 (XXPERMDIs (XSCVDPSXDS (COPY_TO_REGCLASS - (DFLOADf32 iaddrX4:$A), - VSFRC)), 0))>; -def : Pat<(v2i64 (scalar_to_vector FltToULongLoadP9.A)), - (v2i64 (XXPERMDIs (XSCVDPUXDS (COPY_TO_REGCLASS - (DFLOADf32 iaddrX4:$A), - VSFRC)), 0))>; +defm : ScalToVecWPermute<v4i32, FltToIntLoad.A, + (XVCVSPSXWS (LXVWSX xoaddr:$A)), + (XVCVSPSXWS (LXVWSX xoaddr:$A))>; +defm : ScalToVecWPermute<v4i32, FltToUIntLoad.A, + (XVCVSPUXWS (LXVWSX xoaddr:$A)), + (XVCVSPUXWS (LXVWSX xoaddr:$A))>; +defm : ScalToVecWPermute< + v4i32, DblToIntLoadP9.A, + (XXSPLTW (COPY_TO_REGCLASS (XSCVDPSXWS (DFLOADf64 iaddrX4:$A)), VSRC), 1), + (SUBREG_TO_REG (i64 1), (XSCVDPSXWS (DFLOADf64 iaddrX4:$A)), sub_64)>; +defm : ScalToVecWPermute< + v4i32, DblToUIntLoadP9.A, + (XXSPLTW (COPY_TO_REGCLASS (XSCVDPUXWS (DFLOADf64 iaddrX4:$A)), VSRC), 1), + (SUBREG_TO_REG (i64 1), (XSCVDPUXWS (DFLOADf64 iaddrX4:$A)), sub_64)>; +defm : ScalToVecWPermute< + v2i64, FltToLongLoadP9.A, + (XXPERMDIs (XSCVDPSXDS (COPY_TO_REGCLASS (DFLOADf32 iaddrX4:$A), VSFRC)), 0), + (SUBREG_TO_REG + (i64 1), + (XSCVDPSXDS (COPY_TO_REGCLASS (DFLOADf32 iaddrX4:$A), VSFRC)), sub_64)>; +defm : ScalToVecWPermute< + v2i64, FltToULongLoadP9.A, + (XXPERMDIs (XSCVDPUXDS (COPY_TO_REGCLASS (DFLOADf32 iaddrX4:$A), VSFRC)), 0), + (SUBREG_TO_REG + (i64 1), + (XSCVDPUXDS (COPY_TO_REGCLASS (DFLOADf32 iaddrX4:$A), VSFRC)), sub_64)>; def : Pat<(v4f32 (PPCldsplat xoaddr:$A)), (v4f32 (LXVWSX xoaddr:$A))>; def : Pat<(v4i32 (PPCldsplat xoaddr:$A)), @@ -4116,19 +4166,23 @@ def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 6)), xoaddr:$dst), def : Pat<(truncstorei16 (i32 (vector_extract v8i16:$S, 7)), xoaddr:$dst), (STXSIHXv (COPY_TO_REGCLASS (v16i8 (VSLDOI $S, $S, 10)), VSRC), xoaddr:$dst)>; -def : Pat<(v2i64 (scalar_to_vector (i64 (load iaddrX4:$src)))), - (v2i64 (XXPERMDIs - (COPY_TO_REGCLASS (DFLOADf64 iaddrX4:$src), VSFRC), 2))>; -def : Pat<(v2i64 (scalar_to_vector (i64 (load xaddrX4:$src)))), - (v2i64 (XXPERMDIs - (COPY_TO_REGCLASS (XFLOADf64 xaddrX4:$src), VSFRC), 2))>; +defm : ScalToVecWPermute< + v2i64, (i64 (load iaddrX4:$src)), + (XXPERMDIs (COPY_TO_REGCLASS (DFLOADf64 iaddrX4:$src), VSFRC), 2), + (SUBREG_TO_REG (i64 1), (DFLOADf64 iaddrX4:$src), sub_64)>; +defm : ScalToVecWPermute< + v2i64, (i64 (load xaddrX4:$src)), + (XXPERMDIs (COPY_TO_REGCLASS (XFLOADf64 xaddrX4:$src), VSFRC), 2), + (SUBREG_TO_REG (i64 1), (XFLOADf64 xaddrX4:$src), sub_64)>; +defm : ScalToVecWPermute< + v2f64, (f64 (load iaddrX4:$src)), + (XXPERMDIs (COPY_TO_REGCLASS (DFLOADf64 iaddrX4:$src), VSFRC), 2), + (SUBREG_TO_REG (i64 1), (DFLOADf64 iaddrX4:$src), sub_64)>; +defm : ScalToVecWPermute< + v2f64, (f64 (load xaddrX4:$src)), + (XXPERMDIs (COPY_TO_REGCLASS (XFLOADf64 xaddrX4:$src), VSFRC), 2), + (SUBREG_TO_REG (i64 1), (XFLOADf64 xaddrX4:$src), sub_64)>; -def : Pat<(v2f64 (scalar_to_vector (f64 (load iaddrX4:$src)))), - (v2f64 (XXPERMDIs - (COPY_TO_REGCLASS (DFLOADf64 iaddrX4:$src), VSFRC), 2))>; -def : Pat<(v2f64 (scalar_to_vector (f64 (load xaddrX4:$src)))), - (v2f64 (XXPERMDIs - (COPY_TO_REGCLASS (XFLOADf64 xaddrX4:$src), VSFRC), 2))>; def : Pat<(store (i64 (extractelt v2i64:$A, 0)), xaddrX4:$src), (XFSTOREf64 (EXTRACT_SUBREG (XXPERMDI $A, $A, 2), sub_64), xaddrX4:$src)>; |
