diff options
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 8 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 28 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/LegalizeTypes.h | 1 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp | 54 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp | 172 |
6 files changed, 244 insertions, 22 deletions
diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index f8d92cba79..0b6809b56f 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -4997,6 +4997,12 @@ SDValue DAGCombiner::visitVECTOR_SHUFFLE(SDNode *N) { SDValue ShufMask = N->getOperand(2); unsigned NumElts = ShufMask.getNumOperands(); + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + + assert(N0.getValueType().getVectorNumElements() == NumElts && + "Vector shuffle must be normalized in DAG"); + // If the shuffle mask is an identity operation on the LHS, return the LHS. bool isIdentity = true; for (unsigned i = 0; i != NumElts; ++i) { @@ -5043,8 +5049,6 @@ SDValue DAGCombiner::visitVECTOR_SHUFFLE(SDNode *N) { } } - SDValue N0 = N->getOperand(0); - SDValue N1 = N->getOperand(1); // Normalize unary shuffle so the RHS is undef. if (isUnary && VecNum == 1) std::swap(N0, N1); diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index 84c6fb82f7..5ac7a8043c 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -3099,7 +3099,7 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { } Result = DAG.UpdateNodeOperands(Result, Tmp1, Tmp2); - + switch (TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0))) { default: assert(0 && "BinOp legalize operation not supported"); case TargetLowering::Legal: break; @@ -7210,16 +7210,34 @@ void SelectionDAGLegalize::SplitVectorOp(SDValue Op, SDValue &Lo, Lo = Node->getOperand(0); Hi = Node->getOperand(1); } else { - SmallVector<SDValue, 8> LoOps(Node->op_begin(), - Node->op_begin()+NewNumSubvectors); + SmallVector<SDValue, 8> LoOps(Node->op_begin(), + Node->op_begin()+NewNumSubvectors); Lo = DAG.getNode(ISD::CONCAT_VECTORS, NewVT_Lo, &LoOps[0], LoOps.size()); - SmallVector<SDValue, 8> HiOps(Node->op_begin()+NewNumSubvectors, + SmallVector<SDValue, 8> HiOps(Node->op_begin()+NewNumSubvectors, Node->op_end()); Hi = DAG.getNode(ISD::CONCAT_VECTORS, NewVT_Hi, &HiOps[0], HiOps.size()); } break; } + case ISD::EXTRACT_SUBVECTOR: { + SDValue Vec = Op.getOperand(0); + SDValue Idx = Op.getOperand(1); + MVT IdxVT = Idx.getValueType(); + + Lo = DAG.getNode(ISD::EXTRACT_SUBVECTOR, NewVT_Lo, Vec, Idx); + ConstantSDNode *CIdx = dyn_cast<ConstantSDNode>(Idx); + if (CIdx) { + Hi = DAG.getNode(ISD::EXTRACT_SUBVECTOR, NewVT_Hi, Vec, + DAG.getConstant(CIdx->getZExtValue() + NewNumElts_Lo, + IdxVT)); + } else { + Idx = DAG.getNode(ISD::ADD, IdxVT, Idx, + DAG.getConstant(NewNumElts_Lo, IdxVT)); + Hi = DAG.getNode(ISD::EXTRACT_SUBVECTOR, NewVT_Hi, Vec, Idx); + } + break; + } case ISD::SELECT: { SDValue Cond = Node->getOperand(0); @@ -7517,7 +7535,7 @@ SDValue SelectionDAGLegalize::ScalarizeVectorOp(SDValue Op) { } case ISD::EXTRACT_SUBVECTOR: Result = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, NewVT, Node->getOperand(0), - Node->getOperand(1)); + Node->getOperand(1)); break; case ISD::BIT_CONVERT: { SDValue Op0 = Op.getOperand(0); diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/lib/CodeGen/SelectionDAG/LegalizeTypes.h index 1d1ed34944..cb89effc59 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -476,6 +476,7 @@ private: void SplitVecRes_BUILD_PAIR(SDNode *N, SDValue &Lo, SDValue &Hi); void SplitVecRes_BUILD_VECTOR(SDNode *N, SDValue &Lo, SDValue &Hi); void SplitVecRes_CONCAT_VECTORS(SDNode *N, SDValue &Lo, SDValue &Hi); + void SplitVecRes_EXTRACT_SUBVECTOR(SDNode *N, SDValue &Lo, SDValue &Hi); void SplitVecRes_FPOWI(SDNode *N, SDValue &Lo, SDValue &Hi); void SplitVecRes_INSERT_VECTOR_ELT(SDNode *N, SDValue &Lo, SDValue &Hi); void SplitVecRes_LOAD(LoadSDNode *N, SDValue &Lo, SDValue &Hi); diff --git a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp index 2378798267..c155990506 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -336,10 +336,11 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) { case ISD::SELECT_CC: SplitRes_SELECT_CC(N, Lo, Hi); break; case ISD::UNDEF: SplitRes_UNDEF(N, Lo, Hi); break; - case ISD::BIT_CONVERT: SplitVecRes_BIT_CONVERT(N, Lo, Hi); break; - case ISD::BUILD_VECTOR: SplitVecRes_BUILD_VECTOR(N, Lo, Hi); break; - case ISD::CONCAT_VECTORS: SplitVecRes_CONCAT_VECTORS(N, Lo, Hi); break; - case ISD::FPOWI: SplitVecRes_FPOWI(N, Lo, Hi); break; + case ISD::BIT_CONVERT: SplitVecRes_BIT_CONVERT(N, Lo, Hi); break; + case ISD::BUILD_VECTOR: SplitVecRes_BUILD_VECTOR(N, Lo, Hi); break; + case ISD::CONCAT_VECTORS: SplitVecRes_CONCAT_VECTORS(N, Lo, Hi); break; + case ISD::EXTRACT_SUBVECTOR: SplitVecRes_EXTRACT_SUBVECTOR(N, Lo, Hi); break; + case ISD::FPOWI: SplitVecRes_FPOWI(N, Lo, Hi); break; case ISD::INSERT_VECTOR_ELT: SplitVecRes_INSERT_VECTOR_ELT(N, Lo, Hi); break; case ISD::LOAD: SplitVecRes_LOAD(cast<LoadSDNode>(N), Lo, Hi);break; case ISD::VECTOR_SHUFFLE: SplitVecRes_VECTOR_SHUFFLE(N, Lo, Hi); break; @@ -486,6 +487,32 @@ void DAGTypeLegalizer::SplitVecRes_CONCAT_VECTORS(SDNode *N, SDValue &Lo, Hi = DAG.getNode(ISD::CONCAT_VECTORS, HiVT, &HiOps[0], HiOps.size()); } +void DAGTypeLegalizer::SplitVecRes_EXTRACT_SUBVECTOR(SDNode *N, SDValue &Lo, + SDValue &Hi) { + MVT LoVT, HiVT; + GetSplitDestVTs(N->getValueType(0), LoVT, HiVT); + unsigned LoNumElts = LoVT.getVectorNumElements(); + + SDValue Vec = N->getOperand(0); + SDValue Idx = N->getOperand(1); + MVT IdxVT = Idx.getValueType(); + Lo = DAG.getNode(ISD::EXTRACT_SUBVECTOR, LoVT, Vec, Idx); + + ConstantSDNode *CIdx = dyn_cast<ConstantSDNode>(Idx); + if (CIdx) { + unsigned IdxVal = CIdx->getZExtValue(); + assert (IdxVal % LoVT.getVectorNumElements() == 0 && + (IdxVal+LoNumElts) % HiVT.getVectorNumElements()==0 && + "Index must be a multiple of the result type"); + Hi = DAG.getNode(ISD::EXTRACT_SUBVECTOR, HiVT, Vec, + DAG.getConstant(IdxVal + LoNumElts, IdxVT)); + } else { + assert(LoVT == HiVT && "Low and High value type should be the same"); + Idx = DAG.getNode(ISD::ADD, IdxVT, Idx, DAG.getConstant(LoNumElts, IdxVT)); + Hi = DAG.getNode(ISD::EXTRACT_SUBVECTOR, HiVT, Vec, Idx); + } +} + void DAGTypeLegalizer::SplitVecRes_FPOWI(SDNode *N, SDValue &Lo, SDValue &Hi) { GetSplitVector(N->getOperand(0), Lo, Hi); @@ -631,14 +658,19 @@ void DAGTypeLegalizer::SplitVecRes_VECTOR_SHUFFLE(SDNode *N, SDValue &Lo, Ops.clear(); for (unsigned i = LoNumElts; i != NumElements; ++i) { - unsigned Idx = cast<ConstantSDNode>(Mask.getOperand(i))->getZExtValue(); - SDValue InVec = N->getOperand(0); - if (Idx >= NumElements) { - InVec = N->getOperand(1); - Idx -= NumElements; + SDValue Arg = Mask.getOperand(i); + if (Arg.getOpcode() == ISD::UNDEF) { + Ops.push_back(DAG.getNode(ISD::UNDEF, EltVT)); + } else { + unsigned Idx = cast<ConstantSDNode>(Mask.getOperand(i))->getZExtValue(); + SDValue InVec = N->getOperand(0); + if (Idx >= NumElements) { + InVec = N->getOperand(1); + Idx -= NumElements; + } + Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, EltVT, InVec, + DAG.getIntPtrConstant(Idx))); } - Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, EltVT, InVec, - DAG.getIntPtrConstant(Idx))); } Hi = DAG.getNode(ISD::BUILD_VECTOR, HiVT, &Ops[0], Ops.size()); } diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 3601b6e0e0..fb8630f4cf 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -2697,7 +2697,8 @@ SDValue SelectionDAG::getNode(unsigned Opcode, MVT VT, } break; case ISD::VECTOR_SHUFFLE: - assert(VT == N1.getValueType() && VT == N2.getValueType() && + assert(N1.getValueType() == N2.getValueType() && + N1.getValueType().isVector() && VT.isVector() && N3.getValueType().isVector() && N3.getOpcode() == ISD::BUILD_VECTOR && VT.getVectorNumElements() == N3.getNumOperands() && diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp index 3e19b71b3b..032e8bff3d 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp @@ -2288,14 +2288,180 @@ void SelectionDAGLowering::visitExtractElement(User &I) { TLI.getValueType(I.getType()), InVec, InIdx)); } + +// Utility for visitShuffleVector - Returns true if the mask is mask starting +// from SIndx and increasing to the element length (undefs are allowed). +static bool SequentialMask(SDValue Mask, unsigned SIndx) { + unsigned NumElems = Mask.getNumOperands(); + for (unsigned i = 0; i != NumElems; ++i) { + if (Mask.getOperand(i).getOpcode() != ISD::UNDEF) { + unsigned Idx = cast<ConstantSDNode>(Mask.getOperand(i))->getZExtValue(); + if (Idx != i + SIndx) + return false; + } + } + return true; +} + void SelectionDAGLowering::visitShuffleVector(User &I) { SDValue V1 = getValue(I.getOperand(0)); SDValue V2 = getValue(I.getOperand(1)); SDValue Mask = getValue(I.getOperand(2)); - setValue(&I, DAG.getNode(ISD::VECTOR_SHUFFLE, - TLI.getValueType(I.getType()), - V1, V2, Mask)); + MVT VT = TLI.getValueType(I.getType()); + MVT VT1 = V1.getValueType(); + unsigned MaskNumElts = Mask.getNumOperands(); + unsigned Src1NumElts = VT1.getVectorNumElements(); + + if (Src1NumElts == MaskNumElts) { + setValue(&I, DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, Mask)); + return; + } + + // Normalize the shuffle vector since mask and vector length don't match. + if (Src1NumElts < MaskNumElts && MaskNumElts % Src1NumElts == 0) { + // We can concat vectors to make the mask and input vector match. + if (Src1NumElts*2 == MaskNumElts && SequentialMask(Mask, 0)) { + // The shuffle is concatenating two vectors. + setValue(&I, DAG.getNode(ISD::CONCAT_VECTORS, VT, V1, V2)); + return; + } + + // Pad both vectors with undefs to the same size as the mask. + unsigned NumConcat = MaskNumElts / Src1NumElts; + std::vector<SDValue> UnOps(Src1NumElts, + DAG.getNode(ISD::UNDEF, + VT1.getVectorElementType())); + SDValue UndefVal = DAG.getNode(ISD::BUILD_VECTOR, VT1, + &UnOps[0], UnOps.size()); + + SmallVector<SDValue, 8> MOps1, MOps2; + MOps1.push_back(V1); + MOps2.push_back(V2); + for (unsigned i = 1; i != NumConcat; ++i) { + MOps1.push_back(UndefVal); + MOps2.push_back(UndefVal); + } + V1 = DAG.getNode(ISD::CONCAT_VECTORS, VT, &MOps1[0], MOps1.size()); + V2 = DAG.getNode(ISD::CONCAT_VECTORS, VT, &MOps2[0], MOps2.size()); + + // Readjust mask for new input vector length. + SmallVector<SDValue, 8> MappedOps; + for (unsigned i = 0; i != MaskNumElts; ++i) { + if (Mask.getOperand(i).getOpcode() == ISD::UNDEF) { + MappedOps.push_back(Mask.getOperand(i)); + } else { + unsigned Idx = cast<ConstantSDNode>(Mask.getOperand(i))->getZExtValue(); + if (Idx < Src1NumElts) { + MappedOps.push_back(DAG.getConstant(Idx, + Mask.getOperand(i).getValueType())); + } else { + MappedOps.push_back(DAG.getConstant(Idx + MaskNumElts - Src1NumElts, + Mask.getOperand(i).getValueType())); + } + } + } + Mask = DAG.getNode(ISD::BUILD_VECTOR, Mask.getValueType(), + &MappedOps[0], MappedOps.size()); + + setValue(&I, DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, Mask)); + return; + } + + if (Src1NumElts > MaskNumElts) { + // Resulting vector is shorter than the incoming vector. + if (Src1NumElts == MaskNumElts && SequentialMask(Mask,0)) { + // Shuffle extracts 1st vector. + setValue(&I, V1); + return; + } + + if (Src1NumElts == MaskNumElts && SequentialMask(Mask,MaskNumElts)) { + // Shuffle extracts 2nd vector. + setValue(&I, V2); + return; + } + + // Analyze the access pattern of the vector to see if we can extract each + // subvector and then do the shuffle. The analysis is done by calculating + // the range of elements the mask access on both vectors. If it is useful, + // we could do better by considering separate what elements are accessed + // in each vector (i.e., have min/max for each vector). + int MinRange = Src1NumElts+1; + int MaxRange = -1; + for (unsigned i = 0; i != MaskNumElts; ++i) { + SDValue Arg = Mask.getOperand(i); + if (Arg.getOpcode() != ISD::UNDEF) { + assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!"); + int Idx = cast<ConstantSDNode>(Mask.getOperand(i))->getZExtValue(); + if (Idx > (int) Src1NumElts) + Idx -= Src1NumElts; + if (Idx > MaxRange) + MaxRange = Idx; + if (Idx < MinRange) + MinRange = Idx; + } + } + // Adjust MinRange to start at an even boundary since this give us + // better quality splits later. + if ((unsigned) MinRange < Src1NumElts && MinRange%2 != 0) + MinRange = MinRange - 1; + if (MaxRange - MinRange < (int) MaskNumElts) { + // Extract subvector because the range is less than the new vector length + unsigned StartIdx = (MinRange/MaskNumElts)*MaskNumElts; + if (MaxRange - StartIdx < MaskNumElts) { + V1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, VT, V1, + DAG.getIntPtrConstant(MinRange)); + V2 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, VT, V2, + DAG.getIntPtrConstant(MinRange)); + // Readjust mask for new input vector length. + SmallVector<SDValue, 8> MappedOps; + for (unsigned i = 0; i != MaskNumElts; ++i) { + if (Mask.getOperand(i).getOpcode() == ISD::UNDEF) { + MappedOps.push_back(Mask.getOperand(i)); + } else { + unsigned Idx = + cast<ConstantSDNode>(Mask.getOperand(i))->getZExtValue(); + if (Idx < Src1NumElts) { + MappedOps.push_back(DAG.getConstant(Idx - StartIdx, + Mask.getOperand(i).getValueType())); + } else { + Idx = Idx - Src1NumElts - StartIdx + MaskNumElts; + MappedOps.push_back(DAG.getConstant(Idx, + Mask.getOperand(i).getValueType())); + } + } + } + Mask = DAG.getNode(ISD::BUILD_VECTOR, Mask.getValueType(), + &MappedOps[0], MappedOps.size()); + + setValue(&I, DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, Mask)); + return; + } + } + } + + // We can't use either concat vectors or extract subvectors so we fall back + // to insert and extracts. + MVT EltVT = VT.getVectorElementType(); + MVT PtrVT = TLI.getPointerTy(); + SmallVector<SDValue,8> Ops; + for (unsigned i = 0; i != MaskNumElts; ++i) { + SDValue Arg = Mask.getOperand(i); + if (Arg.getOpcode() == ISD::UNDEF) { + Ops.push_back(DAG.getNode(ISD::UNDEF, EltVT)); + } else { + assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!"); + unsigned Idx = cast<ConstantSDNode>(Arg)->getZExtValue(); + if (Idx < Src1NumElts) + Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, EltVT, V1, + DAG.getConstant(Idx, PtrVT))); + else + Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, EltVT, V2, + DAG.getConstant(Idx - Src1NumElts, PtrVT))); + } + } + setValue(&I, DAG.getNode(ISD::BUILD_VECTOR, VT, &Ops[0], Ops.size())); } void SelectionDAGLowering::visitInsertValue(InsertValueInst &I) { |