diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 118 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64ISelLowering.h | 6 |
2 files changed, 95 insertions, 29 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 27277c47f39..327547c27cc 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -4153,22 +4153,76 @@ AArch64TargetLowering::isFMAFasterThanFMulAndFAdd(EVT VT) const { return false; } +// Check whether a shuffle_vector could be presented as concat_vector. +bool AArch64TargetLowering::isConcatVector(SDValue Op, SelectionDAG &DAG, + SDValue V0, SDValue V1, + const int *Mask, + SDValue &Res) const { + SDLoc DL(Op); + EVT VT = Op.getValueType(); + if (VT.getSizeInBits() != 128) + return false; + if (VT.getVectorElementType() != V0.getValueType().getVectorElementType() || + VT.getVectorElementType() != V1.getValueType().getVectorElementType()) + return false; + + unsigned NumElts = VT.getVectorNumElements(); + bool isContactVector = true; + bool splitV0 = false; + if (V0.getValueType().getSizeInBits() == 128) + splitV0 = true; + + for (int I = 0, E = NumElts / 2; I != E; I++) { + if (Mask[I] != I) { + isContactVector = false; + break; + } + } + + if (isContactVector) { + int offset = NumElts / 2; + for (int I = NumElts / 2, E = NumElts; I != E; I++) { + if (Mask[I] != I + splitV0 * offset) { + isContactVector = false; + break; + } + } + } + + if (isContactVector) { + EVT CastVT = EVT::getVectorVT(*DAG.getContext(), VT.getVectorElementType(), + NumElts / 2); + if (splitV0) { + V0 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, CastVT, V0, + DAG.getConstant(0, MVT::i64)); + } + if (V1.getValueType().getSizeInBits() == 128) { + V1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, CastVT, V1, + DAG.getConstant(0, MVT::i64)); + } + Res = DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, V0, V1); + return true; + } + return false; +} -// Check whether a Build Vector could be presented as Shuffle Vector. If yes, -// try to call LowerVECTOR_SHUFFLE to lower it. +// Check whether a Build Vector could be presented as Shuffle Vector. +// This Shuffle Vector maybe not legalized, so the length of its operand and +// the length of result may not equal. bool AArch64TargetLowering::isKnownShuffleVector(SDValue Op, SelectionDAG &DAG, - SDValue &Res) const { + SDValue &V0, SDValue &V1, + int *Mask) const { SDLoc DL(Op); EVT VT = Op.getValueType(); unsigned NumElts = VT.getVectorNumElements(); unsigned V0NumElts = 0; - int Mask[16]; - SDValue V0, V1; // Check if all elements are extracted from less than 3 vectors. for (unsigned i = 0; i < NumElts; ++i) { SDValue Elt = Op.getOperand(i); - if (Elt.getOpcode() != ISD::EXTRACT_VECTOR_ELT) + if (Elt.getOpcode() != ISD::EXTRACT_VECTOR_ELT || + Elt.getOperand(0).getValueType().getVectorElementType() != + VT.getVectorElementType()) return false; if (V0.getNode() == 0) { @@ -4189,25 +4243,7 @@ bool AArch64TargetLowering::isKnownShuffleVector(SDValue Op, SelectionDAG &DAG, return false; } } - - if (!V1.getNode() && V0NumElts == NumElts * 2) { - V1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, VT, V0, - DAG.getConstant(NumElts, MVT::i64)); - V0 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, VT, V0, - DAG.getConstant(0, MVT::i64)); - V0NumElts = V0.getValueType().getVectorNumElements(); - } - - if (V1.getNode() && NumElts == V0NumElts && - V0NumElts == V1.getValueType().getVectorNumElements()) { - SDValue Shuffle = DAG.getVectorShuffle(VT, DL, V0, V1, Mask); - if(Shuffle.getOpcode() != ISD::VECTOR_SHUFFLE) - Res = Shuffle; - else - Res = LowerVECTOR_SHUFFLE(Shuffle, DAG); - return true; - } else - return false; + return true; } // If this is a case we can't handle, return null and let the default @@ -4413,9 +4449,31 @@ AArch64TargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, return SDValue(); // Try to lower this in lowering ShuffleVector way. - SDValue Shuf; - if (isKnownShuffleVector(Op, DAG, Shuf)) - return Shuf; + SDValue V0, V1; + int Mask[16]; + if (isKnownShuffleVector(Op, DAG, V0, V1, Mask)) { + unsigned V0NumElts = V0.getValueType().getVectorNumElements(); + if (!V1.getNode() && V0NumElts == NumElts * 2) { + V1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, VT, V0, + DAG.getConstant(NumElts, MVT::i64)); + V0 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, VT, V0, + DAG.getConstant(0, MVT::i64)); + V0NumElts = V0.getValueType().getVectorNumElements(); + } + + if (V1.getNode() && NumElts == V0NumElts && + V0NumElts == V1.getValueType().getVectorNumElements()) { + SDValue Shuffle = DAG.getVectorShuffle(VT, DL, V0, V1, Mask); + if (Shuffle.getOpcode() != ISD::VECTOR_SHUFFLE) + return Shuffle; + else + return LowerVECTOR_SHUFFLE(Shuffle, DAG); + } else { + SDValue Res; + if (isConcatVector(Op, DAG, V0, V1, Mask, Res)) + return Res; + } + } // If all else fails, just use a sequence of INSERT_VECTOR_ELT when we // know the default expansion would otherwise fall back on something even @@ -4601,6 +4659,10 @@ AArch64TargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, return DAG.getNode(ISDNo, dl, VT, V1, V2); } + SDValue Res; + if (isConcatVector(Op, DAG, V1, V2, &ShuffleMask[0], Res)) + return Res; + // If the element of shuffle mask are all the same constant, we can // transform it into either NEON_VDUP or NEON_VDUPLANE if (ShuffleVectorSDNode::isSplatMask(&ShuffleMask[0], VT)) { diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h index 3879663e570..149de557d08 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -232,7 +232,11 @@ public: SDLoc dl, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const; - bool isKnownShuffleVector(SDValue Op, SelectionDAG &DAG, SDValue &Res) const; + bool isConcatVector(SDValue Op, SelectionDAG &DAG, SDValue V0, SDValue V1, + const int *Mask, SDValue &Res) const; + + bool isKnownShuffleVector(SDValue Op, SelectionDAG &DAG, SDValue &V0, + SDValue &V1, int *Mask) const; SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, const AArch64Subtarget *ST) const; |