[llvm-commits] [llvm] r58964 - in /llvm/trunk: docs/LangRef.html lib/Bitcode/Reader/BitcodeReader.cpp lib/CodeGen/SelectionDAG/DAGCombiner.cpp lib/CodeGen/SelectionDAG/LegalizeDAG.cpp lib/CodeGen/SelectionDAG/LegalizeTypes.h lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp lib/CodeGen/SelectionDAG/SelectionDAG.cpp lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp lib/Transforms/Scalar/InstructionCombining.cpp lib/VMCore/ConstantFold.cpp lib/VMCore/Instructions.cpp lib/VMCore/Verifier.cpp

Duncan Sands duncan.sands at math.u-psud.fr
Wed Nov 12 09:05:32 PST 2008


Hi Mon Ping, what do you think of this for splitting
vector shuffle?  I didn't bother trying to handle
non-power-of-two vector sizes since that is (a) awkward
in this setup, and (b) they are going away soon anyway
thanks to widening.

Ciao,

Duncan.

PS: I've attached the final function, since that may
be easier to read.
PPS: I didn't test it much but it seems to work!

Index: llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
===================================================================
--- llvm.orig/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp	2008-11-12 11:18:51.000000000 +0100
+++ llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp	2008-11-12 17:56:08.000000000 +0100
@@ -650,52 +650,110 @@
 
 void DAGTypeLegalizer::SplitVecRes_VECTOR_SHUFFLE(SDNode *N, SDValue &Lo,
                                                   SDValue &Hi) {
-  // Build the low part.
+  // The low and high parts of the original input give four input vectors.
+  SDValue Inputs[4];
+  GetSplitVector(N->getOperand(0), Inputs[0], Inputs[1]);
+  GetSplitVector(N->getOperand(1), Inputs[2], Inputs[3]);
+  MVT NewVT = Inputs[0].getValueType();
+  unsigned NewElts = NewVT.getVectorNumElements();
+  assert(NewVT == Inputs[1].getValueType() &&
+         "Non power-of-two vectors not supported!");
+
+  // If Lo or Hi uses elements from at most two of the four input vectors, then
+  // express it as a vector shuffle of those two inputs.  Otherwise extract the
+  // input elements by hand and construct the Lo/Hi output using a BUILD_VECTOR.
   SDValue Mask = N->getOperand(2);
-  SmallVector<SDValue, 16> Ops;
-  MVT LoVT, HiVT;
-  GetSplitDestVTs(N->getValueType(0), LoVT, HiVT);
-  MVT EltVT = LoVT.getVectorElementType();
-  unsigned LoNumElts = LoVT.getVectorNumElements();
-  unsigned NumElements = Mask.getNumOperands();
-
-  // Insert all of the elements from the input that are needed.  We use
-  // buildvector of extractelement here because the input vectors will have
-  // to be legalized, so this makes the code simpler.
-  for (unsigned i = 0; i != LoNumElts; ++i) {
-    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;
+  MVT IdxVT = Mask.getValueType().getVectorElementType();
+  MVT EltVT = NewVT.getVectorElementType();
+  SmallVector<SDValue, 16> BuildOps;
+  SmallVector<SDValue, 16> MaskOps;
+  for (unsigned High = 0; High < 2; ++High) {
+    SDValue &Output = High ? Hi : Lo;
+
+    // Build a shuffle mask for the output, discovering on the fly which
+    // input vectors to use as shuffle operands (recorded in InputUsed).
+    // At the same time, accumulate the final vector elements in BuildOps,
+    // for use if building a suitable shuffle vector proves too hard.
+    unsigned InputUsed[2] = { -1U, -1U }; // Not yet discovered.
+    unsigned FirstMaskIdx = High * NewElts;
+    bool useBuildVector = false;
+    for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
+      SDValue Arg = Mask.getOperand(FirstMaskIdx + MaskOffset);
+      if (Arg.getOpcode() == ISD::UNDEF) {
+        MaskOps.push_back(Arg);
+        BuildOps.push_back(DAG.getNode(ISD::UNDEF, EltVT));
+        continue;
       }
-      Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, EltVT, InVec,
-                                DAG.getIntPtrConstant(Idx)));
+
+      // The mask element.  This indexes into the input.
+      unsigned Idx = cast<ConstantSDNode>(Arg)->getZExtValue();
+      // The input vector this mask element indexes into.
+      unsigned Input = Idx / NewElts;
+
+      if (Input >= array_lengthof(Inputs)) {
+        // The mask element indexes off the end of the input!  This is illegal
+        // but handle it anyway.
+        MaskOps.push_back(DAG.getNode(ISD::UNDEF, IdxVT));
+        BuildOps.push_back(DAG.getNode(ISD::UNDEF, EltVT));
+        continue;
+      }
+
+      // Turn the index into an offset from the start of the input vector.
+      Idx -= Input * NewElts;
+
+      // Extract the vector element by hand, and record it for later use.
+      BuildOps.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, EltVT,
+                                     Inputs[Input],
+                                     DAG.getIntPtrConstant(Idx)));
+
+      if (useBuildVector)
+        // The following logic is only needed when creating a new shuffle, so
+        // skip it for a small speedup if we won't be building a vector shuffle.
+        continue;
+
+      // Find or create a shuffle vector operand to hold this input.
+      unsigned OpNo;
+      for (OpNo = 0; OpNo < array_lengthof(InputUsed); ++OpNo) {
+        if (InputUsed[OpNo] == Input) {
+          // This input vector is already an operand.
+          break;
+        } else if (InputUsed[OpNo] == -1U) {
+          // Create a new operand for this input vector.
+          InputUsed[OpNo] = Input;
+          break;
+        }
+      }
+
+      if (OpNo < array_lengthof(InputUsed))
+        // Add the mask index for the new shuffle vector.
+        MaskOps.push_back(DAG.getConstant(Idx + OpNo * NewElts, IdxVT));
+      else
+        // More than two input vectors used!  Give up on trying to create a
+        // shuffle vector.  Insert all elements into a BUILD_VECTOR instead.
+        useBuildVector = true;
     }
-  }
-  Lo = DAG.getNode(ISD::BUILD_VECTOR, LoVT, &Ops[0], Ops.size());
-  Ops.clear();
 
-  for (unsigned i = LoNumElts; i != NumElements; ++i) {
-    SDValue Arg = Mask.getOperand(i);
-    if (Arg.getOpcode() == ISD::UNDEF) {
-      Ops.push_back(DAG.getNode(ISD::UNDEF, EltVT));
+    if (useBuildVector) {
+      Output = DAG.getNode(ISD::BUILD_VECTOR, NewVT, &BuildOps[0],
+                           BuildOps.size());
+    } else if (InputUsed[0] == -1U) {
+      // No input vectors were used!  The result is undefined.
+      Output = DAG.getNode(ISD::UNDEF, NewVT);
     } 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)));
+      // At least one input vector was used.  Create a new shuffle vector.
+      SDValue NewMask = DAG.getNode(ISD::BUILD_VECTOR,
+                                    MVT::getVectorVT(IdxVT, MaskOps.size()),
+                                    &MaskOps[0], MaskOps.size());
+      SDValue Op0 = Inputs[InputUsed[0]];
+      // If only one input was used, use an undefined vector for the other.
+      SDValue Op1 = InputUsed[1] == -1U ?
+        DAG.getNode(ISD::UNDEF, NewVT) : Inputs[InputUsed[1]];
+      Output = DAG.getNode(ISD::VECTOR_SHUFFLE, NewVT, Op0, Op1, NewMask);
     }
+
+    BuildOps.clear();
+    MaskOps.clear();
   }
-  Hi = DAG.getNode(ISD::BUILD_VECTOR, HiVT, &Ops[0], Ops.size());
 }
 
 void DAGTypeLegalizer::SplitVecRes_VSETCC(SDNode *N, SDValue &Lo,
-------------- next part --------------
void DAGTypeLegalizer::SplitVecRes_VECTOR_SHUFFLE(SDNode *N, SDValue &Lo,
                                                  SDValue &Hi) {
  // The low and high parts of the original input give four input vectors.
  SDValue Inputs[4];
  GetSplitVector(N->getOperand(0), Inputs[0], Inputs[1]);
  GetSplitVector(N->getOperand(1), Inputs[2], Inputs[3]);
  MVT NewVT = Inputs[0].getValueType();
  unsigned NewElts = NewVT.getVectorNumElements();
  assert(NewVT == Inputs[1].getValueType() &&
         "Non power-of-two vectors not supported!");

  // If Lo or Hi uses elements from at most two of the four input vectors, then
  // express it as a vector shuffle of those two inputs.  Otherwise extract the
  // input elements by hand and construct the Lo/Hi output using a BUILD_VECTOR.
  SDValue Mask = N->getOperand(2);
  MVT IdxVT = Mask.getValueType().getVectorElementType();
  MVT EltVT = NewVT.getVectorElementType();
  SmallVector<SDValue, 16> BuildOps;
  SmallVector<SDValue, 16> MaskOps;
  for (unsigned High = 0; High < 2; ++High) {
    SDValue &Output = High ? Hi : Lo;

    // Build a shuffle mask for the output, discovering on the fly which
    // input vectors to use as shuffle operands (recorded in InputUsed).
    // At the same time, accumulate the final vector elements in BuildOps,
    // for use if building a suitable shuffle vector proves too hard.
    unsigned InputUsed[2] = { -1U, -1U }; // Not yet discovered.
    unsigned FirstMaskIdx = High * NewElts;
    bool useBuildVector = false;
    for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
      SDValue Arg = Mask.getOperand(FirstMaskIdx + MaskOffset);
      if (Arg.getOpcode() == ISD::UNDEF) {
        MaskOps.push_back(Arg);
        BuildOps.push_back(DAG.getNode(ISD::UNDEF, EltVT));
        continue;
      }

      // The mask element.  This indexes into the input.
      unsigned Idx = cast<ConstantSDNode>(Arg)->getZExtValue();
      // The input vector this mask element indexes into.
      unsigned Input = Idx / NewElts;

      if (Input >= array_lengthof(Inputs)) {
        // The mask element indexes off the end of the input!  This is illegal
        // but handle it anyway.
        MaskOps.push_back(DAG.getNode(ISD::UNDEF, IdxVT));
        BuildOps.push_back(DAG.getNode(ISD::UNDEF, EltVT));
        continue;
      }

      // Turn the index into an offset from the start of the input vector.
      Idx -= Input * NewElts;

      // Extract the vector element by hand, and record it for later use.
      BuildOps.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, EltVT,
                                     Inputs[Input],
                                     DAG.getIntPtrConstant(Idx)));

      if (useBuildVector)
        // The following logic is only needed when creating a new shuffle, so
        // skip it for a small speedup if we won't be building a vector shuffle.
        continue;

      // Find or create a shuffle vector operand to hold this input.
      unsigned OpNo;
      for (OpNo = 0; OpNo < array_lengthof(InputUsed); ++OpNo) {
        if (InputUsed[OpNo] == Input) {
          // This input vector is already an operand.
          break;
        } else if (InputUsed[OpNo] == -1U) {
          // Create a new operand for this input vector.
          InputUsed[OpNo] = Input;
          break;
        }
      }

      if (OpNo < array_lengthof(InputUsed))
        // Add the mask index for the new shuffle vector.
        MaskOps.push_back(DAG.getConstant(Idx + OpNo * NewElts, IdxVT));
      else
        // More than two input vectors used!  Give up on trying to create a
        // shuffle vector.  Insert all elements into a BUILD_VECTOR instead.
        useBuildVector = true;
    }

    if (useBuildVector) {
      Output = DAG.getNode(ISD::BUILD_VECTOR, NewVT, &BuildOps[0],
                           BuildOps.size());
    } else if (InputUsed[0] == -1U) {
      // No input vectors were used!  The result is undefined.
      Output = DAG.getNode(ISD::UNDEF, NewVT);
    } else {
      // At least one input vector was used.  Create a new shuffle vector.
      SDValue NewMask = DAG.getNode(ISD::BUILD_VECTOR,
                                    MVT::getVectorVT(IdxVT, MaskOps.size()),
                                    &MaskOps[0], MaskOps.size());
      SDValue Op0 = Inputs[InputUsed[0]];
      // If only one input was used, use an undefined vector for the other.
      SDValue Op1 = InputUsed[1] == -1U ?
        DAG.getNode(ISD::UNDEF, NewVT) : Inputs[InputUsed[1]];
      Output = DAG.getNode(ISD::VECTOR_SHUFFLE, NewVT, Op0, Op1, NewMask);
    }

    BuildOps.clear();
    MaskOps.clear();
  }
}


More information about the llvm-commits mailing list