Thumb2 pre/post indexed loads.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@74696 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp
index da327e4..4b73ba2 100644
--- a/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -102,6 +102,8 @@
                              SDValue &OffImm);
   bool SelectT2AddrModeImm8(SDValue Op, SDValue N, SDValue &Base,
                             SDValue &OffImm);
+  bool SelectT2AddrModeImm8Offset(SDValue Op, SDValue N,
+                                 SDValue &OffImm);
   bool SelectT2AddrModeImm8s4(SDValue Op, SDValue N, SDValue &Base,
                               SDValue &OffImm);
   bool SelectT2AddrModeSoReg(SDValue Op, SDValue N, SDValue &Base,
@@ -111,7 +113,11 @@
 #include "ARMGenDAGISel.inc"
 
 private:
+  /// SelectARMIndexedLoad - Indexed (pre/post inc/dec) load matching code for
+  /// ARM.
   SDNode *SelectARMIndexedLoad(SDValue Op);
+  SDNode *SelectT2IndexedLoad(SDValue Op);
+
 
   /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
   /// inline asm expressions.
@@ -628,6 +634,25 @@
   return false;
 }
 
+bool ARMDAGToDAGISel::SelectT2AddrModeImm8Offset(SDValue Op, SDValue N,
+                                                 SDValue &OffImm){
+  unsigned Opcode = Op.getOpcode();
+  ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
+    ? cast<LoadSDNode>(Op)->getAddressingMode()
+    : cast<StoreSDNode>(Op)->getAddressingMode();
+  if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N)) {
+    int RHSC = (int)RHS->getZExtValue();
+    if (RHSC >= 0 && RHSC < 0x100) { // 8 bits.
+      OffImm = (AM == ISD::PRE_INC)
+        ? CurDAG->getTargetConstant(RHSC, MVT::i32)
+        : CurDAG->getTargetConstant(-RHSC, MVT::i32);
+      return true;
+    }
+  }
+
+  return false;
+}
+
 bool ARMDAGToDAGISel::SelectT2AddrModeImm8s4(SDValue Op, SDValue N,
                                              SDValue &Base, SDValue &OffImm) {
   if (N.getOpcode() == ISD::ADD) {
@@ -762,6 +787,46 @@
   return NULL;
 }
 
+SDNode *ARMDAGToDAGISel::SelectT2IndexedLoad(SDValue Op) {
+  LoadSDNode *LD = cast<LoadSDNode>(Op);
+  ISD::MemIndexedMode AM = LD->getAddressingMode();
+  if (AM == ISD::UNINDEXED)
+    return NULL;
+
+  MVT LoadedVT = LD->getMemoryVT();
+  SDValue Offset;
+  bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC);
+  unsigned Opcode = 0;
+  bool Match = false;
+  if (SelectT2AddrModeImm8Offset(Op, LD->getOffset(), Offset)) {
+    switch (LoadedVT.getSimpleVT()) {
+    case MVT::i32:
+      Opcode = isPre ? ARM::t2LDR_PRE : ARM::t2LDR_POST;
+      break;
+    case MVT::i16:
+      Opcode = isPre ? ARM::t2LDRH_PRE : ARM::t2LDRH_POST;
+      break;
+    case MVT::i8:
+      Opcode = isPre ? ARM::t2LDRB_PRE : ARM::t2LDRB_POST;
+      break;
+    default:
+      return NULL;
+    }
+    Match = true;
+  }
+
+  if (Match) {
+    SDValue Chain = LD->getChain();
+    SDValue Base = LD->getBasePtr();
+    SDValue Ops[]= { Base, Offset, getAL(CurDAG),
+                     CurDAG->getRegister(0, MVT::i32), Chain };
+    return CurDAG->getTargetNode(Opcode, Op.getDebugLoc(), MVT::i32, MVT::i32,
+                                 MVT::Other, Ops, 5);
+  }
+
+  return NULL;
+}
+
 
 SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
   SDNode *N = Op.getNode();
@@ -892,7 +957,11 @@
     return CurDAG->getTargetNode(ARM::SMULL, dl, MVT::i32, MVT::i32, Ops, 5);
   }
   case ISD::LOAD: {
-    SDNode *ResNode = SelectARMIndexedLoad(Op);
+    SDNode *ResNode = 0;
+    if (Subtarget->isThumb2())
+      ResNode = SelectT2IndexedLoad(Op);
+    else
+      ResNode = SelectARMIndexedLoad(Op);
     if (ResNode)
       return ResNode;
     // Other cases are autogenerated.