Add support for Neon VEXT (vector extract) shuffles.
This is derived from a patch by Anton Korzh.  I modified it to recognize
the VEXT shuffles during legalization and lower them to a target-specific
DAG node.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79428 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp
index 99135b2..859511b 100644
--- a/lib/Target/ARM/ARMISelLowering.cpp
+++ b/lib/Target/ARM/ARMISelLowering.cpp
@@ -487,6 +487,7 @@
   case ARMISD::VST2D:         return "ARMISD::VST2D";
   case ARMISD::VST3D:         return "ARMISD::VST3D";
   case ARMISD::VST4D:         return "ARMISD::VST4D";
+  case ARMISD::VEXT:          return "ARMISD::VEXT";
   case ARMISD::VREV64:        return "ARMISD::VREV64";
   case ARMISD::VREV32:        return "ARMISD::VREV32";
   case ARMISD::VREV16:        return "ARMISD::VREV16";
@@ -2343,6 +2344,41 @@
                      SplatBitSize, DAG);
 }
 
+static bool isVEXTMask(ShuffleVectorSDNode *N, bool &ReverseVEXT,
+                       unsigned &Imm) {
+  EVT VT = N->getValueType(0);
+  unsigned NumElts = VT.getVectorNumElements();
+  ReverseVEXT = false;
+  Imm = N->getMaskElt(0);
+
+  // If this is a VEXT shuffle, the immediate value is the index of the first
+  // element.  The other shuffle indices must be the successive elements after
+  // the first one.
+  unsigned ExpectedElt = Imm;
+  for (unsigned i = 1; i < NumElts; ++i) {
+
+    // Increment the expected index.  If it wraps around, it may still be
+    // a VEXT but the source vectors must be swapped.
+    ExpectedElt += 1;
+    if (ExpectedElt == NumElts * 2) {
+      ExpectedElt = 0;
+      ReverseVEXT = true;
+    }
+
+    if (ExpectedElt != static_cast<unsigned>(N->getMaskElt(i)))
+      return false;
+  }
+
+  // Adjust the index value if the source operands will be swapped.
+  if (ReverseVEXT)
+    Imm -= NumElts;
+
+  // VEXT only handles 8-bit elements so scale the index for larger elements.
+  Imm *= VT.getVectorElementType().getSizeInBits() / 8;
+
+  return true;
+}
+
 /// isVREVMask - Check if a vector shuffle corresponds to a VREV
 /// instruction with the specified blocksize.  (The order of the elements
 /// within each block of the vector is reversed.)
@@ -2458,8 +2494,20 @@
       return DAG.getNode(ARMISD::VDUP, dl, VT, Op0.getOperand(0));
     }
     return DAG.getNode(ARMISD::VDUPLANE, dl, VT, SVN->getOperand(0),
-		       DAG.getConstant(Lane, MVT::i32));
+                       DAG.getConstant(Lane, MVT::i32));
   }
+
+  bool ReverseVEXT;
+  unsigned Imm;
+  if (isVEXTMask(SVN, ReverseVEXT, Imm)) {
+    SDValue Op0 = SVN->getOperand(0);
+    SDValue Op1 = SVN->getOperand(1);
+    if (ReverseVEXT)
+      std::swap(Op0, Op1);
+    return DAG.getNode(ARMISD::VEXT, dl, VT, Op0, Op1,
+                       DAG.getConstant(Imm, MVT::i32));
+  }
+
   if (isVREVMask(SVN, 64))
     return DAG.getNode(ARMISD::VREV64, dl, VT, SVN->getOperand(0));
   if (isVREVMask(SVN, 32))