ARM: Remove duplicated instructions; add vcvt, vmla, vmls disassembler.

Remove kThumb2VcvtID in the assembler which was duplicated.
Add vcvt, vmla, vmls in the disassembler.

Change-Id: I14cc39375c922c9917274d8dcfcb515e888fdf26
diff --git a/compiler/dex/quick/arm/arm_lir.h b/compiler/dex/quick/arm/arm_lir.h
index 9f52f20..c218621 100644
--- a/compiler/dex/quick/arm/arm_lir.h
+++ b/compiler/dex/quick/arm/arm_lir.h
@@ -333,8 +333,7 @@
   kThumb2Vdivs,      // vdiv vd, vn, vm [111011101000] rn[19..16] rd[15-12] [10100000] rm[3..0].
   kThumb2Vdivd,      // vdiv vd, vn, vm [111011101000] rn[19..16] rd[15-12] [10110000] rm[3..0].
   kThumb2VmlaF64,    // vmla.F64 vd, vn, vm [111011100000] vn[19..16] vd[15..12] [10110000] vm[3..0].
-  kThumb2VcvtIF,     // vcvt.F32 vd, vm [1110111010111000] vd[15..12] [10101100] vm[3..0].
-  kThumb2VcvtID,     // vcvt.F64 vd, vm [1110111010111000] vd[15..12] [10111100] vm[3..0].
+  kThumb2VcvtIF,     // vcvt.F32.S32 vd, vm [1110111010111000] vd[15..12] [10101100] vm[3..0].
   kThumb2VcvtFI,     // vcvt.S32.F32 vd, vm [1110111010111101] vd[15..12] [10101100] vm[3..0].
   kThumb2VcvtDI,     // vcvt.S32.F32 vd, vm [1110111010111101] vd[15..12] [10111100] vm[3..0].
   kThumb2VcvtFd,     // vcvt.F64.F32 vd, vm [1110111010110111] vd[15..12] [10101100] vm[3..0].
diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc
index 2a9b5a5..caf84d9 100644
--- a/compiler/dex/quick/arm/assemble_arm.cc
+++ b/compiler/dex/quick/arm/assemble_arm.cc
@@ -464,11 +464,7 @@
     ENCODING_MAP(kThumb2VcvtIF,       0xeeb80ac0,
                  kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
-                 "vcvt.f32", "!0s, !1s", 4, kFixupNone),
-    ENCODING_MAP(kThumb2VcvtID,       0xeeb80bc0,
-                 kFmtDfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
-                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
-                 "vcvt.f64", "!0S, !1s", 4, kFixupNone),
+                 "vcvt.f32.s32", "!0s, !1s", 4, kFixupNone),
     ENCODING_MAP(kThumb2VcvtFI,       0xeebd0ac0,
                  kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
diff --git a/compiler/dex/quick/arm/fp_arm.cc b/compiler/dex/quick/arm/fp_arm.cc
index dd0a429..89652ef 100644
--- a/compiler/dex/quick/arm/fp_arm.cc
+++ b/compiler/dex/quick/arm/fp_arm.cc
@@ -136,7 +136,7 @@
       op = kThumb2VcvtFd;
       break;
     case Instruction::INT_TO_DOUBLE:
-      op = kThumb2VcvtID;
+      op = kThumb2VcvtF64S32;
       break;
     case Instruction::DOUBLE_TO_INT:
       op = kThumb2VcvtDI;
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index 3e6e33f..c35edbb 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -202,6 +202,13 @@
     uint32_t N = (instr >> extra_at_bit) & 1;
     r = (size != 0 ? ((N << 4) | Vn) : ((Vn << 1) | N));
   }
+  explicit FpRegister(uint32_t instr, uint16_t at_bit, uint16_t extra_at_bit,
+                      uint32_t forced_size) {
+    size = forced_size;
+    uint32_t Vn = (instr >> at_bit) & 0xF;
+    uint32_t N = (instr >> extra_at_bit) & 1;
+    r = (size != 0 ? ((N << 4) | Vn) : ((Vn << 1) | N));
+  }
   FpRegister(const FpRegister& other, uint32_t offset)
       : size(other.size), r(other.r + offset) {}
 
@@ -752,6 +759,85 @@
             }
           } else if ((op3 >> 4) == 2 && op4 == 0) {     // 10xxxx, op = 0
             // fp data processing
+            if ((op3 & 0xB) == 0) {  // 100x00
+              // VMLA, VMLS
+              // |1111|1100|0|0|00|0000|1111|110|0|0|0 |0|0|0000|
+              // |5  2|1  8|7|6|54|3  0|5  2|1 9|8|7|6 |5|4|3  0|
+              // |----|----|-|-|--|----|----|---|-|-|- |-|-|----|
+              // |3322|2222|2|2|22|1111|1111|110|0|0|0 |0|0|0000|
+              // |1  8|7  4|3|2|10|9  6|5  2|1 9|8|7|6 |5|4|3  0|
+              // |----|----|-|-|--|----|----|---|-|-|- |-|-|----|
+              // |1110|1110|0|D|00| Vn | Vd |101|S|N|op|M|0| Vm |
+              uint32_t op = (instr >> 6) & 1;
+              FpRegister d(instr, 12, 22);
+              FpRegister n(instr, 16, 7);
+              FpRegister m(instr, 0, 5);
+              opcode << (op == 0 ? "vmla" : "vmls");
+              args << d << ", " << n << ", " << m;
+            } else if ((op3 & 0xB) == 0xB) {  // 101x11
+              uint32_t Q = (instr >> 6) & 1;
+              if (Q == 1) {
+                // VCVT (floating-point conversion)
+                // |1111|1100|0|0|00|0000|1111|110|0|0 |0|0|0|0000|
+                // |5  2|1  8|7|6|54|3  0|5  2|1 9|8|7 |6|5|4|3  0|
+                // |----|----|-|-|--|----|----|---|-|- |-|-|-|----|
+                // |3322|2222|2|2|22|1111|1111|110|0|0 |0|0|0|0000|
+                // |1  8|7  4|3|2|10|9  6|5  2|1 9|8|7 |6|5|4|3  0|
+                // |----|----|-|-|--|----|----|---|-|- |-|-|-|----|
+                // |1110|1110|1|D|11|op5 | Vd |101|S|op|1|M|0| Vm |
+                uint32_t op5 = (instr >> 16) & 0xF;
+                uint32_t S = (instr >> 8) & 1;
+                uint32_t op = (instr >> 7) & 1;
+                // Register types in these instructions relies on the combination of op5 and S.
+                FpRegister Dd(instr, 12, 22, 1);
+                FpRegister Sd(instr, 12, 22, 0);
+                FpRegister Dm(instr, 0, 5, 1);
+                FpRegister Sm(instr, 0, 5, 0);
+                if (op5 == 0xD) {
+                  if (S == 1) {
+                    // vcvt{r}.s32.f64
+                    opcode << "vcvt" << (op == 0 ? "r" : "") << ".s32.f64";
+                    args << Sd << ", " << Dm;
+                  } else {
+                    // vcvt{r}.s32.f32
+                    opcode << "vcvt" << (op == 0 ? "r" : "") << ".s32.f32";
+                    args << Sd << ", " << Sm;
+                  }
+                } else if (op5 == 0xC) {
+                  if (S == 1) {
+                    // vcvt{r}.u32.f64
+                    opcode << "vcvt" << (op == 0 ? "r" : "") << ".u32.f64";
+                    args << Sd << ", " << Dm;
+                  } else {
+                    // vcvt{r}.u32.f32
+                    opcode << "vcvt" << (op == 0 ? "r" : "") << ".u32.f32";
+                    args << Sd << ", " << Sm;
+                  }
+                } else if (op5 == 0x8) {
+                  if (S == 1) {
+                    // vcvt.f64.<Tm>
+                    opcode << "vcvt.f64." << (op == 0 ? "u" : "s") << "32";
+                    args << Dd << ", " << Sm;
+                  } else {
+                    // vcvt.f32.<Tm>
+                    opcode << "vcvt.f32." << (op == 0 ? "u" : "s") << "32";
+                    args << Sd << ", " << Sm;
+                  }
+                } else if (op5 == 0x7) {
+                  if (op == 1) {
+                    if (S == 1) {
+                      // vcvt.f64.f32
+                      opcode << "vcvt.f64.f32";
+                      args << Dd << ", " << Sm;
+                    } else {
+                      // vcvt.f32.f64
+                      opcode << "vcvt.f32.f64";
+                      args << Sd << ", " << Dm;
+                    }
+                  }
+                }
+              }
+            }
           } else if ((op3 >> 4) == 2 && op4 == 1) {     // 10xxxx, op = 1
             if (coproc == 10 && (op3 & 0xE) == 0) {
               // VMOV (between ARM core register and single-precision register)