[llvm-commits] CVS: llvm/lib/Target/X86/X86ISelLowering.cpp X86ISelLowering.h

Evan Cheng evan.cheng at apple.com
Thu Apr 20 01:59:02 PDT 2006



Changes in directory llvm/lib/Target/X86:

X86ISelLowering.cpp updated: 1.177 -> 1.178
X86ISelLowering.h updated: 1.56 -> 1.57
---
Log message:

- Added support to turn "vector clear elements", e.g. pand V, <-1, -1, 0, -1>
to a vector shuffle.
- VECTOR_SHUFFLE lowering change in preparation for more efficient codegen
of vector shuffle with zero (or any splat) vector.


---
Diffs of the changes:  (+233 -78)

 X86ISelLowering.cpp |  299 ++++++++++++++++++++++++++++++++++++++--------------
 X86ISelLowering.h   |   12 +-
 2 files changed, 233 insertions(+), 78 deletions(-)


Index: llvm/lib/Target/X86/X86ISelLowering.cpp
diff -u llvm/lib/Target/X86/X86ISelLowering.cpp:1.177 llvm/lib/Target/X86/X86ISelLowering.cpp:1.178
--- llvm/lib/Target/X86/X86ISelLowering.cpp:1.177	Wed Apr 19 19:11:39 2006
+++ llvm/lib/Target/X86/X86ISelLowering.cpp	Thu Apr 20 03:58:49 2006
@@ -1501,45 +1501,51 @@
 
 /// isSHUFPMask - Return true if the specified VECTOR_SHUFFLE operand
 /// specifies a shuffle of elements that is suitable for input to SHUFP*.
-bool X86::isSHUFPMask(SDNode *N) {
-  assert(N->getOpcode() == ISD::BUILD_VECTOR);
-
-  unsigned NumElems = N->getNumOperands();
-  if (NumElems == 2) {
-    // The only cases that ought be handled by SHUFPD is
-    // Dest { 2, 1 } <=  shuffle( Dest { 1, 0 },  Src { 3, 2 }
-    // Dest { 3, 0 } <=  shuffle( Dest { 1, 0 },  Src { 3, 2 }
-    // Expect bit 0 == 1, bit1 == 2
-    SDOperand Bit0 = N->getOperand(0);
-    SDOperand Bit1 = N->getOperand(1);
-    if (isUndefOrEqual(Bit0, 0) && isUndefOrEqual(Bit1, 3))
-      return true;
-    if (isUndefOrEqual(Bit0, 1) && isUndefOrEqual(Bit1, 2))
-      return true;
-    return false;
-  }
+static bool isSHUFPMask(std::vector<SDOperand> &N) {
+  unsigned NumElems = N.size();
+  if (NumElems != 2 && NumElems != 4) return false;
+
+  unsigned Half = NumElems / 2;
+  for (unsigned i = 0; i < Half; ++i)
+    if (!isUndefOrInRange(N[i], 0, NumElems))
+      return false;
+  for (unsigned i = Half; i < NumElems; ++i)
+    if (!isUndefOrInRange(N[i], NumElems, NumElems*2))
+      return false;
 
-  if (NumElems != 4) return false;
+  return true;
+}
 
-  // Each half must refer to only one of the vector.
-  for (unsigned i = 0; i < 2; ++i) {
-    SDOperand Arg = N->getOperand(i);
-    if (Arg.getOpcode() == ISD::UNDEF) continue;
-    assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
-    unsigned Val = cast<ConstantSDNode>(Arg)->getValue();
-    if (Val >= 4) return false;
-  }
-  for (unsigned i = 2; i < 4; ++i) {
-    SDOperand Arg = N->getOperand(i);
-    if (Arg.getOpcode() == ISD::UNDEF) continue;
-    assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
-    unsigned Val = cast<ConstantSDNode>(Arg)->getValue();
-    if (Val < 4) return false;
-  }
+bool X86::isSHUFPMask(SDNode *N) {
+  assert(N->getOpcode() == ISD::BUILD_VECTOR);
+  std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
+  return ::isSHUFPMask(Ops);
+}
 
+/// isCommutedSHUFP - Returns true if the shuffle mask is except
+/// the reverse of what x86 shuffles want. x86 shuffles requires the lower
+/// half elements to come from vector 1 (which would equal the dest.) and
+/// the upper half to come from vector 2.
+static bool isCommutedSHUFP(std::vector<SDOperand> &Ops) {
+  unsigned NumElems = Ops.size();
+  if (NumElems != 2 && NumElems != 4) return false;
+
+  unsigned Half = NumElems / 2;
+  for (unsigned i = 0; i < Half; ++i)
+    if (!isUndefOrInRange(Ops[i], NumElems, NumElems*2))
+      return false;
+  for (unsigned i = Half; i < NumElems; ++i)
+    if (!isUndefOrInRange(Ops[i], 0, NumElems))
+      return false;
   return true;
 }
 
+static bool isCommutedSHUFP(SDNode *N) {
+  assert(N->getOpcode() == ISD::BUILD_VECTOR);
+  std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
+  return isCommutedSHUFP(Ops);
+}
+
 /// isMOVHLPSMask - Return true if the specified VECTOR_SHUFFLE operand
 /// specifies a shuffle of elements that is suitable for input to MOVHLPS.
 bool X86::isMOVHLPSMask(SDNode *N) {
@@ -1600,46 +1606,64 @@
 
 /// isUNPCKLMask - Return true if the specified VECTOR_SHUFFLE operand
 /// specifies a shuffle of elements that is suitable for input to UNPCKL.
-bool X86::isUNPCKLMask(SDNode *N) {
-  assert(N->getOpcode() == ISD::BUILD_VECTOR);
-
-  unsigned NumElems = N->getNumOperands();
+bool static isUNPCKLMask(std::vector<SDOperand> &N, bool V2IsSplat = false) {
+  unsigned NumElems = N.size();
   if (NumElems != 2 && NumElems != 4 && NumElems != 8 && NumElems != 16)
     return false;
 
   for (unsigned i = 0, j = 0; i != NumElems; i += 2, ++j) {
-    SDOperand BitI  = N->getOperand(i);
-    SDOperand BitI1 = N->getOperand(i+1);
+    SDOperand BitI  = N[i];
+    SDOperand BitI1 = N[i+1];
     if (!isUndefOrEqual(BitI, j))
       return false;
-    if (!isUndefOrEqual(BitI1, j + NumElems))
-      return false;
+    if (V2IsSplat) {
+      if (isUndefOrEqual(BitI1, NumElems))
+        return false;
+    } else {
+      if (!isUndefOrEqual(BitI1, j + NumElems))
+        return false;
+    }
   }
 
   return true;
 }
 
-/// isUNPCKHMask - Return true if the specified VECTOR_SHUFFLE operand
-/// specifies a shuffle of elements that is suitable for input to UNPCKH.
-bool X86::isUNPCKHMask(SDNode *N) {
+bool X86::isUNPCKLMask(SDNode *N, bool V2IsSplat) {
   assert(N->getOpcode() == ISD::BUILD_VECTOR);
+  std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
+  return ::isUNPCKLMask(Ops, V2IsSplat);
+}
 
-  unsigned NumElems = N->getNumOperands();
+/// isUNPCKHMask - Return true if the specified VECTOR_SHUFFLE operand
+/// specifies a shuffle of elements that is suitable for input to UNPCKH.
+bool static isUNPCKHMask(std::vector<SDOperand> &N, bool V2IsSplat = false) {
+  unsigned NumElems = N.size();
   if (NumElems != 2 && NumElems != 4 && NumElems != 8 && NumElems != 16)
     return false;
 
   for (unsigned i = 0, j = 0; i != NumElems; i += 2, ++j) {
-    SDOperand BitI  = N->getOperand(i);
-    SDOperand BitI1 = N->getOperand(i+1);
+    SDOperand BitI  = N[i];
+    SDOperand BitI1 = N[i+1];
     if (!isUndefOrEqual(BitI, j + NumElems/2))
       return false;
-    if (!isUndefOrEqual(BitI1, j + NumElems/2 + NumElems))
-      return false;
+    if (V2IsSplat) {
+      if (isUndefOrEqual(BitI1, NumElems))
+        return false;
+    } else {
+      if (!isUndefOrEqual(BitI1, j + NumElems/2 + NumElems))
+        return false;
+    }
   }
 
   return true;
 }
 
+bool X86::isUNPCKHMask(SDNode *N, bool V2IsSplat) {
+  assert(N->getOpcode() == ISD::BUILD_VECTOR);
+  std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
+  return ::isUNPCKHMask(Ops, V2IsSplat);
+}
+
 /// isUNPCKL_v_undef_Mask - Special case of isUNPCKLMask for canonical form
 /// of vector_shuffle v, v, <0, 4, 1, 5>, i.e. vector_shuffle v, undef,
 /// <0, 0, 1, 1>
@@ -1665,25 +1689,60 @@
 
 /// isMOVSMask - Return true if the specified VECTOR_SHUFFLE operand
 /// specifies a shuffle of elements that is suitable for input to MOVS{S|D}.
+static bool isMOVSMask(std::vector<SDOperand> &N) {
+  unsigned NumElems = N.size();
+  if (NumElems != 2 && NumElems != 4)
+    return false;
+
+  if (!isUndefOrEqual(N[0], NumElems))
+    return false;
+
+  for (unsigned i = 1; i < NumElems; ++i) {
+    SDOperand Arg = N[i];
+    if (!isUndefOrEqual(Arg, i))
+      return false;
+  }
+
+  return true;
+}
+
 bool X86::isMOVSMask(SDNode *N) {
   assert(N->getOpcode() == ISD::BUILD_VECTOR);
+  std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
+  return ::isMOVSMask(Ops);
+}
 
-  unsigned NumElems = N->getNumOperands();
+/// isCommutedMOVS - Returns true if the shuffle mask is except the reverse
+/// of what x86 movs want. X86 movs requires the lowest  element to be lowest
+/// element of vector 2 and the other elements to come from vector 1 in order.
+static bool isCommutedMOVS(std::vector<SDOperand> &Ops, bool V2IsSplat = false) {
+  unsigned NumElems = Ops.size();
   if (NumElems != 2 && NumElems != 4)
     return false;
 
-  if (!isUndefOrEqual(N->getOperand(0), NumElems))
+  if (!isUndefOrEqual(Ops[0], 0))
     return false;
 
   for (unsigned i = 1; i < NumElems; ++i) {
-    SDOperand Arg = N->getOperand(i);
-    if (!isUndefOrEqual(Arg, i))
-      return false;
+    SDOperand Arg = Ops[i];
+    if (V2IsSplat) {
+      if (!isUndefOrEqual(Arg, NumElems))
+        return false;
+    } else {
+      if (!isUndefOrEqual(Arg, i+NumElems))
+        return false;
+    }
   }
 
   return true;
 }
 
+static bool isCommutedMOVS(SDNode *N, bool V2IsSplat = false) {
+  assert(N->getOpcode() == ISD::BUILD_VECTOR);
+  std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
+  return isCommutedMOVS(Ops);
+}
+
 /// isMOVSHDUPMask - Return true if the specified VECTOR_SHUFFLE operand
 /// specifies a shuffle of elements that is suitable for input to MOVSHDUP.
 bool X86::isMOVSHDUPMask(SDNode *N) {
@@ -1958,23 +2017,57 @@
   return true;
 }
 
-/// isLowerFromV2UpperFromV1 - Returns true if the shuffle mask is except
-/// the reverse of what x86 shuffles want. x86 shuffles requires the lower
-/// half elements to come from vector 1 (which would equal the dest.) and
-/// the upper half to come from vector 2.
-static bool isLowerFromV2UpperFromV1(SDOperand Op) {
-  assert(Op.getOpcode() == ISD::BUILD_VECTOR);
+/// isSplatVector - Returns true if N is a BUILD_VECTOR node whose elements are
+/// all the same.
+static bool isSplatVector(SDNode *N) {
+  if (N->getOpcode() != ISD::BUILD_VECTOR)
+    return false;
 
-  unsigned NumElems = Op.getNumOperands();
-  for (unsigned i = 0, e = NumElems/2; i != e; ++i)
-    if (!isUndefOrInRange(Op.getOperand(i), NumElems, NumElems*2))
-      return false;
-  for (unsigned i = NumElems/2; i != NumElems; ++i)
-    if (!isUndefOrInRange(Op.getOperand(i), 0, NumElems))
+  SDOperand SplatValue = N->getOperand(0);
+  for (unsigned i = 1, e = N->getNumOperands(); i != e; ++i)
+    if (N->getOperand(i) != SplatValue)
       return false;
   return true;
 }
 
+/// NormalizeMask - V2 is a splat, modify the mask (if needed) so all elements
+/// that point to V2 points to its first element.
+static SDOperand NormalizeMask(SDOperand Mask, SelectionDAG &DAG) {
+  assert(Mask.getOpcode() == ISD::BUILD_VECTOR);
+
+  bool Changed = false;
+  std::vector<SDOperand> MaskVec;
+  unsigned NumElems = Mask.getNumOperands();
+  for (unsigned i = 0; i != NumElems; ++i) {
+    SDOperand Arg = Mask.getOperand(i);
+    if (Arg.getOpcode() != ISD::UNDEF) {
+      unsigned Val = cast<ConstantSDNode>(Arg)->getValue();
+      if (Val > NumElems) {
+        Arg = DAG.getConstant(NumElems, Arg.getValueType());
+        Changed = true;
+      }
+    }
+    MaskVec.push_back(Arg);
+  }
+
+  if (Changed)
+    Mask = DAG.getNode(ISD::BUILD_VECTOR, Mask.getValueType(), MaskVec);
+  return Mask;
+}
+
+/// getMOVSMask - Returns a vector_shuffle mask for an movs{s|d} operation
+/// of specified width.
+static SDOperand getMOVSMask(unsigned NumElems, SelectionDAG &DAG) {
+  MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(NumElems);
+  MVT::ValueType BaseVT = MVT::getVectorBaseType(MaskVT);
+
+  std::vector<SDOperand> MaskVec;
+  MaskVec.push_back(DAG.getConstant(NumElems, BaseVT));
+  for (unsigned i = 1; i != NumElems; ++i)
+    MaskVec.push_back(DAG.getConstant(i, BaseVT));
+  return DAG.getNode(ISD::BUILD_VECTOR, MaskVT, MaskVec);
+}
+
 /// getUnpacklMask - Returns a vector_shuffle mask for an unpackl operation
 /// of specified width.
 static SDOperand getUnpacklMask(unsigned NumElems, SelectionDAG &DAG) {
@@ -1988,6 +2081,20 @@
   return DAG.getNode(ISD::BUILD_VECTOR, MaskVT, MaskVec);
 }
 
+/// getUnpackhMask - Returns a vector_shuffle mask for an unpackh operation
+/// of specified width.
+static SDOperand getUnpackhMask(unsigned NumElems, SelectionDAG &DAG) {
+  MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(NumElems);
+  MVT::ValueType BaseVT = MVT::getVectorBaseType(MaskVT);
+  unsigned Half = NumElems/2;
+  std::vector<SDOperand> MaskVec;
+  for (unsigned i = 0; i != Half; ++i) {
+    MaskVec.push_back(DAG.getConstant(i + Half,            BaseVT));
+    MaskVec.push_back(DAG.getConstant(i + NumElems + Half, BaseVT));
+  }
+  return DAG.getNode(ISD::BUILD_VECTOR, MaskVT, MaskVec);
+}
+
 /// PromoteSplat - Promote a splat of v8i16 or v16i8 to v4i32.
 ///
 static SDOperand PromoteSplat(SDOperand Op, SelectionDAG &DAG) {
@@ -2817,6 +2924,7 @@
     SDOperand PermMask = Op.getOperand(2);
     MVT::ValueType VT = Op.getValueType();
     unsigned NumElems = PermMask.getNumOperands();
+    bool V2IsSplat = isSplatVector(V2.Val);
 
     if (isSplatMask(PermMask.Val)) {
       if (NumElems <= 4) return Op;
@@ -2824,10 +2932,6 @@
       return PromoteSplat(Op, DAG);
     }
 
-    if (ShouldXformToMOVHLPS(PermMask.Val) ||
-        ShouldXformToMOVLP(V1.Val, PermMask.Val))
-      return CommuteVectorShuffle(Op, DAG);
-
     if (X86::isMOVSMask(PermMask.Val) ||
         X86::isMOVSHDUPMask(PermMask.Val) ||
         X86::isMOVSLDUPMask(PermMask.Val) ||
@@ -2836,15 +2940,45 @@
         X86::isMOVLPMask(PermMask.Val))
       return Op;
 
-    if (X86::isUNPCKLMask(PermMask.Val) ||
-        X86::isUNPCKL_v_undef_Mask(PermMask.Val) ||
-        X86::isUNPCKHMask(PermMask.Val))
-      // Leave the VECTOR_SHUFFLE alone. It matches {P}UNPCKL*.
+    if (ShouldXformToMOVHLPS(PermMask.Val) ||
+        ShouldXformToMOVLP(V1.Val, PermMask.Val))
+      return CommuteVectorShuffle(Op, DAG);
+
+    if (isCommutedMOVS(PermMask.Val, V2IsSplat)) {
+      if (V2IsSplat) {
+        // V2 is a splat, so the mask may be malformed. That is, it may point
+        // to any V2 element. The instruction selectior won't like this. Get
+        // a corrected mask and commute to form a proper MOVS{S|D}.
+        SDOperand NewMask = getMOVSMask(NumElems, DAG);
+        Op = DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, NewMask);
+      }
+      return CommuteVectorShuffle(Op, DAG);
+    }
+
+    if (X86::isUNPCKL_v_undef_Mask(PermMask.Val) ||
+        X86::isUNPCKLMask(PermMask.Val) ||
+        X86::isUNPCKHMask(PermMask.Val, V2IsSplat))
       return Op;
 
+    if (V2IsSplat) {
+      // Normalize mask so all entries that point to V2 points to its first
+      // element then try to match unpck{h|l} again. If match, return a 
+      // new vector_shuffle with the corrected mask.
+      SDOperand NewMask = NormalizeMask(PermMask, DAG);
+      if (NewMask.Val != PermMask.Val) {
+        if (X86::isUNPCKLMask(PermMask.Val, true)) {
+          SDOperand NewMask = getUnpacklMask(NumElems, DAG);
+          return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, NewMask);
+        } else if (X86::isUNPCKHMask(PermMask.Val, true)) {
+          SDOperand NewMask = getUnpackhMask(NumElems, DAG);
+          return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, NewMask);
+        }
+      }
+    }
+
     // Normalize the node to match x86 shuffle ops if needed
     if (V2.getOpcode() != ISD::UNDEF)
-      if (isLowerFromV2UpperFromV1(PermMask)) {
+      if (isCommutedSHUFP(PermMask.Val)) {
         Op = CommuteVectorShuffle(Op, DAG);
         V1 = Op.getOperand(0);
         V2 = Op.getOperand(1);
@@ -3041,7 +3175,6 @@
       if (Idx == 0)
         return Op;
 
-      // TODO: if Idex == 2, we can use unpckhps
       // SHUFPS the element to the lowest double word, then movss.
       MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(4);
       SDOperand IdxNode = DAG.getConstant((Idx < 2) ? Idx : Idx+4,
@@ -3372,3 +3505,17 @@
           X86::isUNPCKL_v_undef_Mask(Mask.Val) ||
           X86::isUNPCKHMask(Mask.Val));
 }
+
+bool X86TargetLowering::isVectorClearMaskLegal(std::vector<SDOperand> &BVOps,
+                                               MVT::ValueType EVT,
+                                               SelectionDAG &DAG) const {
+  unsigned NumElts = BVOps.size();
+  // Only do shuffles on 128-bit vector types for now.
+  if (MVT::getSizeInBits(EVT) * NumElts == 64) return false;
+  if (NumElts == 2) return true;
+  if (NumElts == 4) {
+    return (isMOVSMask(BVOps) || isCommutedMOVS(BVOps, true) ||
+            isSHUFPMask(BVOps) || isCommutedSHUFP(BVOps));
+  }
+  return false;
+}


Index: llvm/lib/Target/X86/X86ISelLowering.h
diff -u llvm/lib/Target/X86/X86ISelLowering.h:1.56 llvm/lib/Target/X86/X86ISelLowering.h:1.57
--- llvm/lib/Target/X86/X86ISelLowering.h:1.56	Wed Apr 19 15:35:22 2006
+++ llvm/lib/Target/X86/X86ISelLowering.h	Thu Apr 20 03:58:49 2006
@@ -219,11 +219,11 @@
 
    /// isUNPCKLMask - Return true if the specified VECTOR_SHUFFLE operand
    /// specifies a shuffle of elements that is suitable for input to UNPCKL.
-   bool isUNPCKLMask(SDNode *N);
+   bool isUNPCKLMask(SDNode *N, bool V2IsSplat = false);
 
    /// isUNPCKHMask - Return true if the specified VECTOR_SHUFFLE operand
    /// specifies a shuffle of elements that is suitable for input to UNPCKH.
-   bool isUNPCKHMask(SDNode *N);
+   bool isUNPCKHMask(SDNode *N, bool V2IsSplat = false);
 
    /// isUNPCKL_v_undef_Mask - Special case of isUNPCKLMask for canonical form
    /// of vector_shuffle v, v, <0, 4, 1, 5>, i.e. vector_shuffle v, undef,
@@ -333,6 +333,14 @@
     /// By default, if a target supports the VECTOR_SHUFFLE node, all mask values
     /// are assumed to be legal.
     virtual bool isShuffleMaskLegal(SDOperand Mask, MVT::ValueType VT) const;
+
+    /// isVectorClearMaskLegal - Similar to isShuffleMaskLegal. This is
+    /// used by Targets can use this to indicate if there is a suitable
+    /// VECTOR_SHUFFLE that can be used to replace a VAND with a constant
+    /// pool entry.
+    virtual bool isVectorClearMaskLegal(std::vector<SDOperand> &BVOps,
+                                        MVT::ValueType EVT,
+                                        SelectionDAG &DAG) const;
   private:
     // C Calling Convention implementation.
     std::vector<SDOperand> LowerCCCArguments(Function &F, SelectionDAG &DAG);






More information about the llvm-commits mailing list