aboutsummaryrefslogtreecommitdiffstats
path: root/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp')
-rw-r--r--lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp172
1 files changed, 169 insertions, 3 deletions
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp
index 3e19b71..032e8bf 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) {