Fix Thumb2 assembler to emit 16-bit add/sub SP, #imm.

Also allow 16-bit add rN, SP, #imm.

Change-Id: I50100ad0b0e19a1c855a2319615e86d7a2b66a69
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index 479186c..e262134 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -698,48 +698,37 @@
     return true;
   }
 
-  bool can_contain_high_register = (opcode == MOV)
-      || ((opcode == ADD || opcode == SUB) && (rn == rd));
-
-  if (IsHighRegister(rd) || IsHighRegister(rn)) {
-    if (can_contain_high_register) {
-      // There are high register instructions available for this opcode.
-      // However, there is no RRX available.
-      if (so.IsShift() && so.GetShift() == RRX) {
-        return true;
+  // Check special case for SP relative ADD and SUB immediate.
+  if ((opcode == ADD || opcode == SUB) && rn == SP && so.IsImmediate()) {
+    // If the immediate is in range, use 16 bit.
+    if (rd == SP) {
+      if (so.GetImmediate() < (1 << 9)) {    // 9 bit immediate.
+        return false;
       }
-
-      // Check special case for SP relative ADD and SUB immediate.
-      if ((opcode == ADD || opcode == SUB) && so.IsImmediate()) {
-        // If rn is SP and rd is a high register we need to use a 32 bit encoding.
-         if (rn == SP && rd != SP && IsHighRegister(rd)) {
-           return true;
-         }
-
-         uint32_t imm = so.GetImmediate();
-         // If the immediates are out of range use 32 bit.
-         if (rd == SP && rn == SP) {
-           if (imm > (1 << 9)) {    // 9 bit immediate.
-             return true;
-           }
-         } else if (opcode == ADD && rd != SP && rn == SP) {   // 10 bit immediate.
-           if (imm > (1 << 10)) {
-             return true;
-           }
-         } else if (opcode == SUB && rd != SP && rn == SP) {
-           // SUB rd, SP, #imm is always 32 bit.
-           return true;
-         }
+    } else if (!IsHighRegister(rd) && opcode == ADD) {
+      if (so.GetImmediate() < (1 << 10)) {    // 10 bit immediate.
+        return false;
       }
     }
+  }
 
-    // The ADD,SUB and MOV instructions that work with high registers don't have
-    // immediate variants.
-    if (so.IsImmediate()) {
+  bool can_contain_high_register = (opcode == MOV)
+      || ((opcode == ADD) && (rn == rd));
+
+  if (IsHighRegister(rd) || IsHighRegister(rn)) {
+    if (!can_contain_high_register) {
       return true;
     }
 
-    if (!can_contain_high_register) {
+    // There are high register instructions available for this opcode.
+    // However, there is no actual shift available, neither for ADD nor for MOV (ASR/LSR/LSL/ROR).
+    if (so.IsShift() && (so.GetShift() == RRX || so.GetImmediate() != 0u)) {
+      return true;
+    }
+
+    // The ADD and MOV instructions that work with high registers don't have 16-bit
+    // immediate variants.
+    if (so.IsImmediate()) {
       return true;
     }
   }
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc
index 3f2641c..3d03234 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -102,11 +102,11 @@
   "   4:	11a3      	asrs	r3, r4, #6\n",
   "   6:	ea4f 13f4 	mov.w	r3, r4, ror #7\n",
   "   a:	41e3      	rors	r3, r4\n",
-  "   c:	0128      	lsls	r0, r5, #4\n",
-  "   e:	0968      	lsrs	r0, r5, #5\n",
-  "  10:	11a8      	asrs	r0, r5, #6\n",
-  "  12:	ea4f 18f4 	mov.w	r8, r4, ror #7\n",
-  "  16:	ea4f 0834 	mov.w	r8, r4, rrx\n",
+  "   c:	ea4f 1804 	mov.w	r8, r4, lsl #4\n",
+  "  10:	ea4f 1854 	mov.w	r8, r4, lsr #5\n",
+  "  14:	ea4f 18a4 	mov.w	r8, r4, asr #6\n",
+  "  18:	ea4f 18f4 	mov.w	r8, r4, ror #7\n",
+  "  1c:	ea4f 0834 	mov.w	r8, r4, rrx\n",
   nullptr
 };
 const char* BasicLoadResults[] = {
@@ -340,15 +340,15 @@
   nullptr
 };
 const char* SpecialAddSubResults[] = {
-  "   0:	f20d 0250 	addw	r2, sp, #80	; 0x50\n",
-  "   4:	f20d 0d50 	addw	sp, sp, #80	; 0x50\n",
-  "   8:	f20d 0850 	addw	r8, sp, #80	; 0x50\n",
-  "   c:	f60d 7200 	addw	r2, sp, #3840	; 0xf00\n",
-  "  10:	f60d 7d00 	addw	sp, sp, #3840	; 0xf00\n",
-  "  14:	f2ad 0d50 	subw	sp, sp, #80	; 0x50\n",
-  "  18:	f2ad 0050 	subw	r0, sp, #80	; 0x50\n",
-  "  1c:	f2ad 0850 	subw	r8, sp, #80	; 0x50\n",
-  "  20:	f6ad 7d00 	subw	sp, sp, #3840	; 0xf00\n",
+  "   0:	aa14      	add	r2, sp, #80	; 0x50\n",
+  "   2:	b014      	add	sp, #80		; 0x50\n",
+  "   4:	f20d 0850 	addw	r8, sp, #80	; 0x50\n",
+  "   8:	f60d 7200 	addw	r2, sp, #3840	; 0xf00\n",
+  "   c:	f60d 7d00 	addw	sp, sp, #3840	; 0xf00\n",
+  "  10:	b094      	sub	sp, #80		; 0x50\n",
+  "  12:	f2ad 0050 	subw	r0, sp, #80	; 0x50\n",
+  "  16:	f2ad 0850 	subw	r8, sp, #80	; 0x50\n",
+  "  1a:	f6ad 7d00 	subw	sp, sp, #3840	; 0xf00\n",
   nullptr
 };
 const char* StoreToOffsetResults[] = {