ARM: Use stm/ldm for live registers save/restore in SlowPathCode.

In case when there is more than 4 register to save/restore in the
SlowPathCode stm/ldm can save some code size.

Test: m test-art-target; m test-art-host

Change-Id: I2d5b44bab58b67207105302cd7d8ee3300b9040a
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index aefbf26..ee5811c 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -763,6 +763,9 @@
   virtual void PushList(RegList regs, Condition cond = AL) = 0;
   virtual void PopList(RegList regs, Condition cond = AL) = 0;
 
+  virtual void StoreList(RegList regs, size_t stack_offset) = 0;
+  virtual void LoadList(RegList regs, size_t stack_offset) = 0;
+
   virtual void Mov(Register rd, Register rm, Condition cond = AL) = 0;
 
   // Convenience shift instructions. Use mov instruction with shifter operand
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index f5ccf40..2269ba2 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -3372,6 +3372,30 @@
   ldm(IA_W, SP, regs, cond);
 }
 
+void Thumb2Assembler::StoreList(RegList regs, size_t stack_offset) {
+  DCHECK_NE(regs, 0u);
+  DCHECK_EQ(regs & (1u << IP), 0u);
+  if (IsPowerOfTwo(regs)) {
+    Register reg = static_cast<Register>(CTZ(static_cast<uint32_t>(regs)));
+    str(reg, Address(SP, stack_offset));
+  } else {
+    add(IP, SP, ShifterOperand(stack_offset));
+    stm(IA, IP, regs);
+  }
+}
+
+void Thumb2Assembler::LoadList(RegList regs, size_t stack_offset) {
+  DCHECK_NE(regs, 0u);
+  DCHECK_EQ(regs & (1u << IP), 0u);
+  if (IsPowerOfTwo(regs)) {
+    Register reg = static_cast<Register>(CTZ(static_cast<uint32_t>(regs)));
+    ldr(reg, Address(SP, stack_offset));
+  } else {
+    Register lowest_reg = static_cast<Register>(CTZ(static_cast<uint32_t>(regs)));
+    add(lowest_reg, SP, ShifterOperand(stack_offset));
+    ldm(IA, lowest_reg, regs);
+  }
+}
 
 void Thumb2Assembler::Mov(Register rd, Register rm, Condition cond) {
   if (cond != AL || rd != rm) {
diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h
index 917c947..1c495aa 100644
--- a/compiler/utils/arm/assembler_thumb2.h
+++ b/compiler/utils/arm/assembler_thumb2.h
@@ -293,6 +293,8 @@
 
   void PushList(RegList regs, Condition cond = AL) OVERRIDE;
   void PopList(RegList regs, Condition cond = AL) OVERRIDE;
+  void StoreList(RegList regs, size_t stack_offset) OVERRIDE;
+  void LoadList(RegList regs, size_t stack_offset) OVERRIDE;
 
   void Mov(Register rd, Register rm, Condition cond = AL) OVERRIDE;