Add support for generating code for vst{234}lane intrinsics.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@80707 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp
index 87c0d11..86407f7 100644
--- a/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -1484,6 +1484,61 @@
                               N->getOperand(5), N->getOperand(6), Chain };
       return CurDAG->getTargetNode(Opc, dl, MVT::Other, Ops, 8);
     }
+
+    case Intrinsic::arm_neon_vst2lane: {
+      SDValue MemAddr, MemUpdate, MemOpc;
+      if (!SelectAddrMode6(Op, N->getOperand(2), MemAddr, MemUpdate, MemOpc))
+        return NULL;
+      switch (N->getOperand(3).getValueType().getSimpleVT().SimpleTy) {
+      default: llvm_unreachable("unhandled vst2lane type");
+      case MVT::v8i8:  Opc = ARM::VST2LNd8; break;
+      case MVT::v4i16: Opc = ARM::VST2LNd16; break;
+      case MVT::v2f32:
+      case MVT::v2i32: Opc = ARM::VST2LNd32; break;
+      }
+      SDValue Chain = N->getOperand(0);
+      const SDValue Ops[] = { MemAddr, MemUpdate, MemOpc,
+                              N->getOperand(3), N->getOperand(4),
+                              N->getOperand(5), Chain };
+      return CurDAG->getTargetNode(Opc, dl, MVT::Other, Ops, 7);
+    }
+
+    case Intrinsic::arm_neon_vst3lane: {
+      SDValue MemAddr, MemUpdate, MemOpc;
+      if (!SelectAddrMode6(Op, N->getOperand(2), MemAddr, MemUpdate, MemOpc))
+        return NULL;
+      switch (N->getOperand(3).getValueType().getSimpleVT().SimpleTy) {
+      default: llvm_unreachable("unhandled vst3lane type");
+      case MVT::v8i8:  Opc = ARM::VST3LNd8; break;
+      case MVT::v4i16: Opc = ARM::VST3LNd16; break;
+      case MVT::v2f32:
+      case MVT::v2i32: Opc = ARM::VST3LNd32; break;
+      }
+      SDValue Chain = N->getOperand(0);
+      const SDValue Ops[] = { MemAddr, MemUpdate, MemOpc,
+                              N->getOperand(3), N->getOperand(4),
+                              N->getOperand(5), N->getOperand(6), Chain };
+      return CurDAG->getTargetNode(Opc, dl, MVT::Other, Ops, 8);
+    }
+
+    case Intrinsic::arm_neon_vst4lane: {
+      SDValue MemAddr, MemUpdate, MemOpc;
+      if (!SelectAddrMode6(Op, N->getOperand(2), MemAddr, MemUpdate, MemOpc))
+        return NULL;
+      switch (N->getOperand(3).getValueType().getSimpleVT().SimpleTy) {
+      default: llvm_unreachable("unhandled vst4lane type");
+      case MVT::v8i8:  Opc = ARM::VST4LNd8; break;
+      case MVT::v4i16: Opc = ARM::VST4LNd16; break;
+      case MVT::v2f32:
+      case MVT::v2i32: Opc = ARM::VST4LNd32; break;
+      }
+      SDValue Chain = N->getOperand(0);
+      const SDValue Ops[] = { MemAddr, MemUpdate, MemOpc,
+                              N->getOperand(3), N->getOperand(4),
+                              N->getOperand(5), N->getOperand(6),
+                              N->getOperand(7), Chain };
+      return CurDAG->getTargetNode(Opc, dl, MVT::Other, Ops, 9);
+    }
     }
   }
   }
diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp
index 0e1606f..8d79e5b 100644
--- a/lib/Target/ARM/ARMISelLowering.cpp
+++ b/lib/Target/ARM/ARMISelLowering.cpp
@@ -1370,6 +1370,26 @@
   return DAG.UpdateNodeOperands(Op, &Ops[0], Ops.size());
 }
 
+static SDValue LowerNeonVSTLaneIntrinsic(SDValue Op, SelectionDAG &DAG,
+                                         unsigned NumVecs) {
+  SDNode *Node = Op.getNode();
+  EVT VT = Node->getOperand(3).getValueType();
+
+  if (!VT.is64BitVector())
+    return SDValue(); // unimplemented
+
+  // Change the lane number operand to be a TargetConstant; otherwise it
+  // will be legalized into a register.
+  ConstantSDNode *Lane = dyn_cast<ConstantSDNode>(Node->getOperand(NumVecs+3));
+  if (!Lane) {
+    assert(false && "vst lane number must be a constant");
+    return SDValue();
+  }
+  SmallVector<SDValue, 8> Ops(Node->op_begin(), Node->op_end());
+  Ops[NumVecs+3] = DAG.getTargetConstant(Lane->getZExtValue(), MVT::i32);
+  return DAG.UpdateNodeOperands(Op, &Ops[0], Ops.size());
+}
+
 SDValue
 ARMTargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) {
   unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
@@ -1388,6 +1408,12 @@
     return LowerNeonVSTIntrinsic(Op, DAG, 3);
   case Intrinsic::arm_neon_vst4:
     return LowerNeonVSTIntrinsic(Op, DAG, 4);
+  case Intrinsic::arm_neon_vst2lane:
+    return LowerNeonVSTLaneIntrinsic(Op, DAG, 2);
+  case Intrinsic::arm_neon_vst3lane:
+    return LowerNeonVSTLaneIntrinsic(Op, DAG, 3);
+  case Intrinsic::arm_neon_vst4lane:
+    return LowerNeonVSTLaneIntrinsic(Op, DAG, 4);
   default: return SDValue();    // Don't custom lower most intrinsics.
   }
 }
diff --git a/lib/Target/ARM/ARMInstrNEON.td b/lib/Target/ARM/ARMInstrNEON.td
index 6fbcf6c..0c2f655 100644
--- a/lib/Target/ARM/ARMInstrNEON.td
+++ b/lib/Target/ARM/ARMInstrNEON.td
@@ -300,6 +300,40 @@
 def  VST4d8   : VST4D<"vst4.8">;
 def  VST4d16  : VST4D<"vst4.16">;
 def  VST4d32  : VST4D<"vst4.32">;
+
+//   VST2LN   : Vector Store (single 2-element structure from one lane)
+class VST2LND<string OpcodeStr>
+  : NLdSt<(outs), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, nohash_imm:$lane),
+          NoItinerary,
+          !strconcat(OpcodeStr, "\t\\{$src1[$lane],$src2[$lane]\\}, $addr"),
+          "", []>;
+
+def VST2LNd8  : VST2LND<"vst2.8">;
+def VST2LNd16 : VST2LND<"vst2.16">;
+def VST2LNd32 : VST2LND<"vst2.32">;
+
+//   VST3LN   : Vector Store (single 3-element structure from one lane)
+class VST3LND<string OpcodeStr>
+  : NLdSt<(outs), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3,
+          nohash_imm:$lane), NoItinerary,
+          !strconcat(OpcodeStr,
+          "\t\\{$src1[$lane],$src2[$lane],$src3[$lane]\\}, $addr"), "", []>;
+
+def VST3LNd8  : VST3LND<"vst3.8">;
+def VST3LNd16 : VST3LND<"vst3.16">;
+def VST3LNd32 : VST3LND<"vst3.32">;
+
+//   VST4LN   : Vector Store (single 4-element structure from one lane)
+class VST4LND<string OpcodeStr>
+  : NLdSt<(outs), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3,
+          DPR:$src4, nohash_imm:$lane), NoItinerary,
+          !strconcat(OpcodeStr,
+          "\t\\{$src1[$lane],$src2[$lane],$src3[$lane],$src4[$lane]\\}, $addr"),
+          "", []>;
+
+def VST4LNd8  : VST4LND<"vst4.8">;
+def VST4LNd16 : VST4LND<"vst4.16">;
+def VST4LNd32 : VST4LND<"vst4.32">;
 }
 
 
diff --git a/lib/Target/ARM/NEONPreAllocPass.cpp b/lib/Target/ARM/NEONPreAllocPass.cpp
index 6938013..985cc86 100644
--- a/lib/Target/ARM/NEONPreAllocPass.cpp
+++ b/lib/Target/ARM/NEONPreAllocPass.cpp
@@ -75,6 +75,9 @@
   case ARM::VST2d8:
   case ARM::VST2d16:
   case ARM::VST2d32:
+  case ARM::VST2LNd8:
+  case ARM::VST2LNd16:
+  case ARM::VST2LNd32:
     FirstOpnd = 3;
     NumRegs = 2;
     return true;
@@ -82,6 +85,9 @@
   case ARM::VST3d8:
   case ARM::VST3d16:
   case ARM::VST3d32:
+  case ARM::VST3LNd8:
+  case ARM::VST3LNd16:
+  case ARM::VST3LNd32:
     FirstOpnd = 3;
     NumRegs = 3;
     return true;
@@ -89,6 +95,9 @@
   case ARM::VST4d8:
   case ARM::VST4d16:
   case ARM::VST4d32:
+  case ARM::VST4LNd8:
+  case ARM::VST4LNd16:
+  case ARM::VST4LNd32:
     FirstOpnd = 3;
     NumRegs = 4;
     return true;