Add VADD instruction to the ARM integrated assembler.

BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/1540653003 .
diff --git a/src/DartARM32/assembler_arm.cc b/src/DartARM32/assembler_arm.cc
index 76906ee..8432a01 100644
--- a/src/DartARM32/assembler_arm.cc
+++ b/src/DartARM32/assembler_arm.cc
@@ -880,7 +880,8 @@
   EmitMultiVDMemOp(cond, am, false, base, first, count);
 }
 
-
+#if 0
+// Moved to ARM32::AssemblerARM32::emitVFPsss
 void Assembler::EmitVFPsss(Condition cond, int32_t opcode,
                            SRegister sd, SRegister sn, SRegister sm) {
   ASSERT(TargetCPUFeatures::vfp_supported());
@@ -899,7 +900,7 @@
   Emit(encoding);
 }
 
-
+// Moved to ARM32::AssemblerARM32::emitVFPddd
 void Assembler::EmitVFPddd(Condition cond, int32_t opcode,
                            DRegister dd, DRegister dn, DRegister dm) {
   ASSERT(TargetCPUFeatures::vfp_supported());
@@ -917,7 +918,7 @@
                      (static_cast<int32_t>(dm) & 0xf);
   Emit(encoding);
 }
-
+#endif
 
 void Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) {
   EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm);
@@ -964,18 +965,19 @@
   return false;
 }
 
-
+#if 0
+// Moved to Arm32::AssemblerARM32::vadds()
 void Assembler::vadds(SRegister sd, SRegister sn, SRegister sm,
                       Condition cond) {
   EmitVFPsss(cond, B21 | B20, sd, sn, sm);
 }
 
-
+// Moved to Arm32::AssemblerARM32::vaddd()
 void Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm,
                       Condition cond) {
   EmitVFPddd(cond, B21 | B20, dd, dn, dm);
 }
-
+#endif
 
 void Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm,
                       Condition cond) {
diff --git a/src/DartARM32/assembler_arm.h b/src/DartARM32/assembler_arm.h
index 6ef799e..0e2d2d4 100644
--- a/src/DartARM32/assembler_arm.h
+++ b/src/DartARM32/assembler_arm.h
@@ -647,8 +647,12 @@
   void vstmd(BlockAddressMode am, Register base,
              DRegister first, intptr_t count, Condition cond = AL);
 
+#if 0
+  // Moved to Arm32::AssemblerARM32::vadds()
   void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
+  // Moved to Arm32::AssemblerARM32::vaddd()
   void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
+#endif
   void vaddqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
   void vaddqs(QRegister qd, QRegister qn, QRegister qm);
   void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
@@ -1228,7 +1232,7 @@
                  Register rm,
                  Register rs);
 
-  // Moved to ARM32::AssemblerAR32::emitDivOp();
+  // Moved to ARM32::AssemblerARM32::emitDivOp();
   void EmitDivOp(Condition cond,
                  int32_t opcode,
                  Register rd,
@@ -1250,17 +1254,21 @@
                         DRegister start,
                         int32_t count);
 
+#if 0
+  // Moved to ARM32::AssemblerARM32::emitVFPsss
   void EmitVFPsss(Condition cond,
                   int32_t opcode,
                   SRegister sd,
                   SRegister sn,
                   SRegister sm);
 
+  // Moved to ARM32::AssemblerARM32::emitVFPddd
   void EmitVFPddd(Condition cond,
                   int32_t opcode,
                   DRegister dd,
                   DRegister dn,
                   DRegister dm);
+#endif
 
   void EmitVFPsd(Condition cond,
                  int32_t opcode,
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
index 8448612..396f8f8 100644
--- a/src/IceAssemblerARM32.cpp
+++ b/src/IceAssemblerARM32.cpp
@@ -140,14 +140,6 @@
   return static_cast<RegARM32::GPRRegister>(R);
 }
 
-bool isGPRRegisterDefined(IValueT R) {
-  return R != encodeGPRRegister(RegARM32::Encoded_Not_GPR);
-}
-
-bool isConditionDefined(CondARM32::Cond Cond) {
-  return Cond != CondARM32::kNone;
-}
-
 IValueT encodeCondition(CondARM32::Cond Cond) {
   return static_cast<IValueT>(Cond);
 }
@@ -197,17 +189,28 @@
 };
 
 IValueT getEncodedGPRegNum(const Variable *Var) {
+  assert(Var->hasReg());
   int32_t Reg = Var->getRegNum();
   return llvm::isa<Variable64On32>(Var) ? RegARM32::getI64PairFirstGPRNum(Reg)
-                                        : RegARM32::getEncodedGPR(Reg);
+                                        : RegARM32::getEncodedGPReg(Reg);
 }
 
 IValueT getEncodedSRegNum(const Variable *Var) {
-  assert(Var->hasReg());
-  assert(RegARM32::isEncodedSReg(Var->getRegNum()));
   return RegARM32::getEncodedSReg(Var->getRegNum());
 }
 
+IValueT getEncodedDRegNum(const Variable *Var) {
+  return RegARM32::getEncodedDReg(Var->getRegNum());
+}
+
+IValueT getYInRegXXXXY(IValueT RegXXXXY) { return RegXXXXY & 0x1; }
+
+IValueT getXXXXInRegXXXXY(IValueT RegXXXXY) { return RegXXXXY >> 1; }
+
+IValueT getYInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX >> 4; }
+
+IValueT getXXXXInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX & 0x0f; }
+
 // The way an operand is encoded into a sequence of bits in functions
 // encodeOperand and encodeAddress below.
 enum EncodedOperand {
@@ -278,11 +281,25 @@
          (Rm << kRmShift);
 }
 
-EncodedOperand encodeOperand(const Operand *Opnd, IValueT &Value) {
+// Defines the set of registers expected in an operand.
+enum RegSetWanted { WantGPRegs, WantSRegs, WantDRegs };
+
+EncodedOperand encodeOperand(const Operand *Opnd, IValueT &Value,
+                             RegSetWanted WantedRegSet) {
   Value = 0; // Make sure initialized.
   if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
     if (Var->hasReg()) {
-      Value = getEncodedGPRegNum(Var);
+      switch (WantedRegSet) {
+      case WantGPRegs:
+        Value = getEncodedGPRegNum(Var);
+        break;
+      case WantSRegs:
+        Value = getEncodedSRegNum(Var);
+        break;
+      case WantDRegs:
+        Value = getEncodedDRegNum(Var);
+        break;
+      }
       return EncodedAsRegister;
     }
     return CantEncode;
@@ -302,11 +319,11 @@
   if (const auto *FlexReg = llvm::dyn_cast<OperandARM32FlexReg>(Opnd)) {
     Operand *Amt = FlexReg->getShiftAmt();
     IValueT Rm;
-    if (encodeOperand(FlexReg->getReg(), Rm) != EncodedAsRegister)
+    if (encodeOperand(FlexReg->getReg(), Rm, WantGPRegs) != EncodedAsRegister)
       return CantEncode;
     if (const auto *Var = llvm::dyn_cast<Variable>(Amt)) {
       IValueT Rs;
-      if (encodeOperand(Var, Rs) != EncodedAsRegister)
+      if (encodeOperand(Var, Rs, WantGPRegs) != EncodedAsRegister)
         return CantEncode;
       Value = encodeShiftRotateReg(Rm, FlexReg->getShiftOp(), Rs);
       return EncodedAsRegShiftReg;
@@ -421,27 +438,28 @@
          Utils::IsInt(kBranchOffsetBits, Offset >> 2);
 }
 
-IValueT encodeRegister(const Operand *OpReg, const char *RegName,
-                       const char *InstName) {
+IValueT encodeRegister(const Operand *OpReg, RegSetWanted WantedRegSet,
+                       const char *RegName, const char *InstName) {
   IValueT Reg = 0;
-  if (encodeOperand(OpReg, Reg) != EncodedAsRegister)
+  if (encodeOperand(OpReg, Reg, WantedRegSet) != EncodedAsRegister)
     llvm::report_fatal_error(std::string(InstName) + ": Can't find register " +
                              RegName);
   return Reg;
 }
 
-void verifyRegDefined(IValueT Reg, const char *RegName, const char *InstName) {
-  if (BuildDefs::minimal())
-    return;
-  if (!isGPRRegisterDefined(Reg))
-    llvm::report_fatal_error(std::string(InstName) + ": Can't find " + RegName);
+IValueT encodeGPRegister(const Operand *OpReg, const char *RegName,
+                         const char *InstName) {
+  return encodeRegister(OpReg, WantGPRegs, RegName, InstName);
 }
 
-void verifyCondDefined(CondARM32::Cond Cond, const char *InstName) {
-  if (BuildDefs::minimal())
-    return;
-  if (!isConditionDefined(Cond))
-    llvm::report_fatal_error(std::string(InstName) + ": Condition not defined");
+IValueT encodeSRegister(const Operand *OpReg, const char *RegName,
+                        const char *InstName) {
+  return encodeRegister(OpReg, WantSRegs, RegName, InstName);
+}
+
+IValueT encodeDRegister(const Operand *OpReg, const char *RegName,
+                        const char *InstName) {
+  return encodeRegister(OpReg, WantDRegs, RegName, InstName);
 }
 
 void verifyPOrNotW(IValueT Address, const char *InstName) {
@@ -631,8 +649,8 @@
     verifyRegNotPcWhenSetFlags(Rd, SetFlags, InstName);
     break;
   }
-  verifyRegDefined(Rd, "Rd", InstName);
-  verifyCondDefined(Cond, InstName);
+  assert(Rd < RegARM32::getNumGPRegs());
+  assert(CondARM32::isDefined(Cond));
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) |
                            (InstType << kTypeShift) | (Opcode << kOpcodeShift) |
@@ -645,8 +663,8 @@
                                 const Operand *OpRd, const Operand *OpRn,
                                 const Operand *OpSrc1, bool SetFlags,
                                 EmitChecks RuleChecks, const char *InstName) {
-  IValueT Rd = encodeRegister(OpRd, "Rd", InstName);
-  IValueT Rn = encodeRegister(OpRn, "Rn", InstName);
+  IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
+  IValueT Rn = encodeGPRegister(OpRn, "Rn", InstName);
   emitType01(Cond, Opcode, Rd, Rn, OpSrc1, SetFlags, RuleChecks, InstName);
 }
 
@@ -656,7 +674,7 @@
                                 const char *InstName) {
   IValueT Src1Value;
   // TODO(kschimpf) Other possible decodings of data operations.
-  switch (encodeOperand(OpSrc1, Src1Value)) {
+  switch (encodeOperand(OpSrc1, Src1Value, WantGPRegs)) {
   default:
     llvm::report_fatal_error(std::string(InstName) +
                              ": Can't encode instruction");
@@ -714,11 +732,11 @@
 }
 
 void AssemblerARM32::emitType05(CondARM32::Cond Cond, IOffsetT Offset,
-                                bool Link, const char *InstName) {
+                                bool Link) {
   // cccc101liiiiiiiiiiiiiiiiiiiiiiii where cccc=Cond, l=Link, and
   // iiiiiiiiiiiiiiiiiiiiiiii=
   // EncodedBranchOffset(cccc101l000000000000000000000000, Offset);
-  verifyCondDefined(Cond, InstName);
+  assert(CondARM32::isDefined(Cond));
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   IValueT Encoding = static_cast<int32_t>(Cond) << kConditionShift |
                      5 << kTypeShift | (Link ? 1 : 0) << kLinkShift;
@@ -728,15 +746,14 @@
 
 void AssemblerARM32::emitBranch(Label *L, CondARM32::Cond Cond, bool Link) {
   // TODO(kschimpf): Handle far jumps.
-  constexpr const char *BranchName = "b";
   if (L->isBound()) {
     const int32_t Dest = L->getPosition() - Buffer.size();
-    emitType05(Cond, Dest, Link, BranchName);
+    emitType05(Cond, Dest, Link);
     return;
   }
   const IOffsetT Position = Buffer.size();
   // Use the offset field of the branch instruction for linking the sites.
-  emitType05(Cond, L->getEncodedPosition(), Link, BranchName);
+  emitType05(Cond, L->getEncodedPosition(), Link);
   L->linkTo(*this, Position);
 }
 
@@ -758,15 +775,15 @@
   // defining RotatedImm8.
   constexpr bool SetFlags = true;
   constexpr IValueT Rd = RegARM32::Encoded_Reg_r0;
-  IValueT Rn = encodeRegister(OpRn, "Rn", InstName);
+  IValueT Rn = encodeGPRegister(OpRn, "Rn", InstName);
   emitType01(Cond, Opcode, Rd, Rn, OpSrc1, SetFlags, NoChecks, InstName);
 }
 
 void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, IValueT InstType,
                                bool IsLoad, bool IsByte, IValueT Rt,
-                               IValueT Address, const char *InstName) {
-  verifyRegDefined(Rt, "Rt", InstName);
-  verifyCondDefined(Cond, InstName);
+                               IValueT Address) {
+  assert(Rt < RegARM32::getNumGPRegs());
+  assert(CondARM32::isDefined(Cond));
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) |
                            (InstType << kTypeShift) | (IsLoad ? L : 0) |
@@ -802,8 +819,7 @@
       llvm::report_fatal_error(std::string(InstName) +
                                ": Use push/pop instead");
 
-    emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address,
-              InstName);
+    emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address);
     return;
   }
   case EncodedAsShiftRotateImm5: {
@@ -826,8 +842,7 @@
       verifyRegNotPc(Rn, "Rn", InstName);
       verifyRegsNotEq(Rn, "Rn", Rt, "Rt", InstName);
     }
-    emitMemOp(Cond, kInstTypeRegisterShift, IsLoad, IsByte, Rt, Address,
-              InstName);
+    emitMemOp(Cond, kInstTypeRegisterShift, IsLoad, IsByte, Rt, Address);
     return;
   }
   }
@@ -851,8 +866,8 @@
     // cccc000pu0wxnnnnttttiiiiyyyyjjjj where cccc=Cond, nnnn=Rn, tttt=Rt,
     // iiiijjjj=Imm8, pu0w<<21 is a BlockAddr, x000000000000yyyy0000=Opcode,
     // and pu0w0nnnn0000iiii0000jjjj=Address.
-    verifyRegDefined(Rt, "Rt", InstName);
-    verifyCondDefined(Cond, InstName);
+    assert(Rt < RegARM32::getNumGPRegs());
+    assert(CondARM32::isDefined(Cond));
     verifyPOrNotW(Address, InstName);
     verifyRegNotPc(Rt, "Rt", InstName);
     if (isBitSet(W, Address))
@@ -871,8 +886,8 @@
     // cccc000pu0wxnnnntttt00001011mmmm where cccc=Cond, tttt=Rt, nnnn=Rn,
     // mmmm=Rm, pu0w<<21 is a BlockAddr, x000000000000yyyy0000=Opcode, and
     // pu0w0nnnn000000000000mmmm=Address.
-    verifyRegDefined(Rt, "Rt", InstName);
-    verifyCondDefined(Cond, InstName);
+    assert(Rt < RegARM32::getNumGPRegs());
+    assert(CondARM32::isDefined(Cond));
     verifyPOrNotW(Address, InstName);
     verifyRegNotPc(Rt, "Rt", InstName);
     verifyAddrRegNotPc(kRmShift, Address, "Rm", InstName);
@@ -895,11 +910,11 @@
 }
 
 void AssemblerARM32::emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
-                               IValueT Rn, IValueT Rm, const char *InstName) {
-  verifyRegDefined(Rd, "Rd", InstName);
-  verifyRegDefined(Rn, "Rn", InstName);
-  verifyRegDefined(Rm, "Rm", InstName);
-  verifyCondDefined(Cond, InstName);
+                               IValueT Rn, IValueT Rm) {
+  assert(Rd < RegARM32::getNumGPRegs());
+  assert(Rn < RegARM32::getNumGPRegs());
+  assert(Rm < RegARM32::getNumGPRegs());
+  assert(CondARM32::isDefined(Cond));
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   const IValueT Encoding = Opcode | (encodeCondition(Cond) << kConditionShift) |
                            (Rn << kDivRnShift) | (Rd << kDivRdShift) | B26 |
@@ -910,12 +925,12 @@
 
 void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
                                IValueT Rn, IValueT Rm, IValueT Rs,
-                               bool SetFlags, const char *InstName) {
-  verifyRegDefined(Rd, "Rd", InstName);
-  verifyRegDefined(Rn, "Rn", InstName);
-  verifyRegDefined(Rm, "Rm", InstName);
-  verifyRegDefined(Rs, "Rs", InstName);
-  verifyCondDefined(Cond, InstName);
+                               bool SetFlags) {
+  assert(Rd < RegARM32::getNumGPRegs());
+  assert(Rn < RegARM32::getNumGPRegs());
+  assert(Rm < RegARM32::getNumGPRegs());
+  assert(Rs < RegARM32::getNumGPRegs());
+  assert(CondARM32::isDefined(Cond));
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   IValueT Encoding = Opcode | (encodeCondition(Cond) << kConditionShift) |
                      (encodeBool(SetFlags) << kSShift) | (Rn << kRnShift) |
@@ -926,14 +941,10 @@
 
 void AssemblerARM32::emitMultiMemOp(CondARM32::Cond Cond,
                                     BlockAddressMode AddressMode, bool IsLoad,
-                                    IValueT BaseReg, IValueT Registers,
-                                    const char *InstName) {
-  constexpr IValueT NumGPRegisters = 16;
-  verifyCondDefined(Cond, InstName);
-  verifyRegDefined(BaseReg, "base", InstName);
-  if (Registers >= (1 << NumGPRegisters))
-    llvm::report_fatal_error(std::string(InstName) +
-                             ": Register set too large");
+                                    IValueT BaseReg, IValueT Registers) {
+  assert(CondARM32::isDefined(Cond));
+  assert(BaseReg < RegARM32::getNumGPRegs());
+  assert(Registers < (1 << RegARM32::getNumGPRegs()));
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | B27 |
                      AddressMode | (IsLoad ? L : 0) | (BaseReg << kRnShift) |
@@ -944,8 +955,8 @@
 void AssemblerARM32::emitSignExtend(CondARM32::Cond Cond, IValueT Opcode,
                                     const Operand *OpRd, const Operand *OpSrc0,
                                     const char *InstName) {
-  IValueT Rd = encodeRegister(OpRd, "Rd", InstName);
-  IValueT Rm = encodeRegister(OpSrc0, "Rm", InstName);
+  IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
+  IValueT Rm = encodeGPRegister(OpSrc0, "Rm", InstName);
   // Note: For the moment, we assume no rotation is specified.
   RotationValue Rotation = kRotateNone;
   constexpr IValueT Rn = RegARM32::Encoded_Reg_pc;
@@ -976,7 +987,7 @@
   }
   }
 
-  verifyCondDefined(Cond, InstName);
+  assert(CondARM32::isDefined(Cond));
   IValueT Rot = encodeRotation(Rotation);
   if (!Utils::IsUint(2, Rot))
     llvm::report_fatal_error(std::string(InstName) +
@@ -988,6 +999,38 @@
   emitInst(Encoding);
 }
 
+void AssemblerARM32::emitVFPddd(CondARM32::Cond Cond, IValueT Opcode,
+                                IValueT Dd, IValueT Dn, IValueT Dm) {
+  assert(Dd < RegARM32::getNumDRegs());
+  assert(Dn < RegARM32::getNumDRegs());
+  assert(Dm < RegARM32::getNumDRegs());
+  assert(CondARM32::isDefined(Cond));
+  AssemblerBuffer::EnsureCapacity ensured(&Buffer);
+  constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9 | B8;
+  const IValueT Encoding =
+      Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) |
+      (getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dn) << 16) |
+      (getXXXXInRegYXXXX(Dn) << 12) | (getYInRegYXXXX(Dn) << 7) |
+      (getYInRegYXXXX(Dm) << 5) | getXXXXInRegYXXXX(Dm);
+  emitInst(Encoding);
+}
+
+void AssemblerARM32::emitVFPsss(CondARM32::Cond Cond, IValueT Opcode,
+                                IValueT Sd, IValueT Sn, IValueT Sm) {
+  assert(Sd < RegARM32::getNumSRegs());
+  assert(Sn < RegARM32::getNumSRegs());
+  assert(Sm < RegARM32::getNumSRegs());
+  assert(CondARM32::isDefined(Cond));
+  AssemblerBuffer::EnsureCapacity ensured(&Buffer);
+  constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9;
+  const IValueT Encoding =
+      Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) |
+      (getYInRegXXXXY(Sd) << 22) | (getXXXXInRegXXXXY(Sn) << 16) |
+      (getXXXXInRegXXXXY(Sd) << 12) | (getYInRegXXXXY(Sn) << 7) |
+      (getYInRegXXXXY(Sm) << 5) | getXXXXInRegXXXXY(Sm);
+  emitInst(Encoding);
+}
+
 void AssemblerARM32::adc(const Operand *OpRd, const Operand *OpRn,
                          const Operand *OpSrc1, bool SetFlags,
                          CondARM32::Cond Cond) {
@@ -1094,11 +1137,10 @@
   // cccc1011iiiiiiiiiiiiiiiiiiiiiiii where cccc=Cond (not currently allowed)
   // and iiiiiiiiiiiiiiiiiiiiiiii is the (encoded) Target to branch to.
   emitFixup(createBlFixup(Target));
-  constexpr const char *BlName = "bl";
   constexpr CondARM32::Cond Cond = CondARM32::AL;
   constexpr IValueT Immed = 0;
   constexpr bool Link = true;
-  emitType05(Cond, Immed, Link, BlName);
+  emitType05(Cond, Immed, Link);
 }
 
 void AssemblerARM32::blx(const Operand *Target) {
@@ -1108,7 +1150,7 @@
   // cccc000100101111111111110011mmmm where cccc=Cond (not currently allowed)
   // and mmmm=Rm.
   constexpr const char *BlxName = "Blx";
-  IValueT Rm = encodeRegister(Target, "Rm", BlxName);
+  IValueT Rm = encodeGPRegister(Target, "Rm", BlxName);
   verifyRegNotPc(Rm, "Rm", BlxName);
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   constexpr CondARM32::Cond Cond = CondARM32::AL;
@@ -1122,9 +1164,7 @@
   //   bx<c> <Rm>
   //
   // cccc000100101111111111110001mmmm where mmmm=rm and cccc=Cond.
-  constexpr const char *BxName = "bx";
-  verifyCondDefined(Cond, BxName);
-  verifyRegDefined(Rm, "Rm", BxName);
+  assert(CondARM32::isDefined(Cond));
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | B24 |
                            B21 | (0xfff << 8) | B4 |
@@ -1141,13 +1181,13 @@
   constexpr const char *ClzName = "clz";
   constexpr const char *RdName = "Rd";
   constexpr const char *RmName = "Rm";
-  IValueT Rd = encodeRegister(OpRd, RdName, ClzName);
-  verifyRegDefined(Rd, RdName, ClzName);
+  IValueT Rd = encodeGPRegister(OpRd, RdName, ClzName);
+  assert(Rd < RegARM32::getNumGPRegs());
   verifyRegNotPc(Rd, RdName, ClzName);
-  IValueT Rm = encodeRegister(OpSrc, RmName, ClzName);
-  verifyRegDefined(Rm, RmName, ClzName);
+  IValueT Rm = encodeGPRegister(OpSrc, RmName, ClzName);
+  assert(Rm < RegARM32::getNumGPRegs());
   verifyRegNotPc(Rm, RmName, ClzName);
-  verifyCondDefined(Cond, ClzName);
+  assert(CondARM32::isDefined(Cond));
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   constexpr IValueT PredefinedBits =
       B24 | B22 | B21 | (0xF << 16) | (0xf << 8) | B4;
@@ -1230,7 +1270,7 @@
                          CondARM32::Cond Cond, const TargetInfo &TInfo) {
   constexpr const char *LdrName = "ldr";
   constexpr bool IsLoad = true;
-  IValueT Rt = encodeRegister(OpRt, "Rt", LdrName);
+  IValueT Rt = encodeGPRegister(OpRt, "Rt", LdrName);
   const Type Ty = OpRt->getType();
   switch (Ty) {
   case IceType_i64:
@@ -1303,7 +1343,7 @@
                                  const Operand *OpAddress,
                                  const TargetInfo &TInfo,
                                  const char *InstName) {
-  IValueT Rd = encodeRegister(OpRd, "Rd", InstName);
+  IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
   IValueT MemExOpcode = IsLoad ? B0 : 0;
   switch (Ty) {
   default:
@@ -1327,9 +1367,9 @@
     llvm::report_fatal_error(std::string(InstName) +
                              ": Can't extract Rn from address");
   assert(Utils::IsAbsoluteUint(3, MemExOpcode));
-  verifyRegDefined(Rd, "Rd", InstName);
-  verifyRegDefined(Rt, "Rt", InstName);
-  verifyCondDefined(Cond, InstName);
+  assert(Rd < RegARM32::getNumGPRegs());
+  assert(Rt < RegARM32::getNumGPRegs());
+  assert(CondARM32::isDefined(Cond));
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   IValueT Encoding = (Cond << kConditionShift) | B24 | B23 | B11 | B10 | B9 |
                      B8 | B7 | B4 | (MemExOpcode << kMemExOpcodeShift) |
@@ -1372,10 +1412,10 @@
                                const Operand *OpSrc1, const bool SetFlags,
                                const char *InstName) {
   constexpr IValueT ShiftOpcode = B3 | B2 | B0; // 1101
-  IValueT Rd = encodeRegister(OpRd, "Rd", InstName);
-  IValueT Rm = encodeRegister(OpRm, "Rm", InstName);
+  IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
+  IValueT Rm = encodeGPRegister(OpRm, "Rm", InstName);
   IValueT Value;
-  switch (encodeOperand(OpSrc1, Value)) {
+  switch (encodeOperand(OpSrc1, Value, WantGPRegs)) {
   default:
     llvm::report_fatal_error(std::string(InstName) +
                              ": Last operand not understood");
@@ -1398,7 +1438,7 @@
     // cccc0001101s0000ddddssss0001mmmm where cccc=Cond, s=SetFlags, dddd=Rd,
     // mmmm=Rm, and ssss=Rs.
     constexpr IValueT Rn = 0; // Rn field is not used.
-    IValueT Rs = encodeRegister(OpSrc1, "Rs", InstName);
+    IValueT Rs = encodeGPRegister(OpSrc1, "Rs", InstName);
     verifyRegNotPc(Rd, "Rd", InstName);
     verifyRegNotPc(Rm, "Rm", InstName);
     verifyRegNotPc(Rs, "Rs", InstName);
@@ -1445,7 +1485,7 @@
   // and iiiiiiiiiiii=RotatedImm8=Src.  Note: We don't use movs in this
   // assembler.
   constexpr const char *MovName = "mov";
-  IValueT Rd = encodeRegister(OpRd, "Rd", MovName);
+  IValueT Rd = encodeGPRegister(OpRd, "Rd", MovName);
   constexpr bool SetFlags = false;
   constexpr IValueT Rn = 0;
   constexpr IValueT MovOpcode = B3 | B2 | B0; // 1101.
@@ -1457,17 +1497,17 @@
                                const Operand *OpRd, const Operand *OpSrc,
                                const char *MovName) {
   IValueT Opcode = B25 | B24 | (IsMovW ? 0 : B22);
-  IValueT Rd = encodeRegister(OpRd, "Rd", MovName);
+  IValueT Rd = encodeGPRegister(OpRd, "Rd", MovName);
   IValueT Imm16;
   if (const auto *Src = llvm::dyn_cast<ConstantRelocatable>(OpSrc)) {
     emitFixup(createMoveFixup(IsMovW, Src));
     // Use 0 for the lower 16 bits of the relocatable, and add a fixup to
     // install the correct bits.
     Imm16 = 0;
-  } else if (encodeOperand(OpSrc, Imm16) != EncodedAsConstI32) {
+  } else if (encodeOperand(OpSrc, Imm16, WantGPRegs) != EncodedAsConstI32) {
     llvm::report_fatal_error(std::string(MovName) + ": Not i32 constant");
   }
-  verifyCondDefined(Cond, MovName);
+  assert(CondARM32::isDefined(Cond));
   if (!Utils::IsAbsoluteUint(16, Imm16))
     llvm::report_fatal_error(std::string(MovName) + ": Constant not i16");
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
@@ -1515,7 +1555,7 @@
   // cccc0001111s0000ddddiiiiitt0mmmm where cccc=Cond, s=SetFlags=0, dddd=Rd,
   // mmmm=Rm, iiii defines shift constant, and tt=ShiftKind.
   constexpr const char *MvnName = "mvn";
-  IValueT Rd = encodeRegister(OpRd, "Rd", MvnName);
+  IValueT Rd = encodeGPRegister(OpRd, "Rd", MvnName);
   constexpr IValueT MvnOpcode = B3 | B2 | B1 | B0; // i.e. 1111
   constexpr IValueT Rn = 0;
   constexpr bool SetFlags = false;
@@ -1563,22 +1603,22 @@
   // cccc01110001dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and
   // mmmm=Rm.
   constexpr const char *SdivName = "sdiv";
-  IValueT Rd = encodeRegister(OpRd, "Rd", SdivName);
-  IValueT Rn = encodeRegister(OpRn, "Rn", SdivName);
-  IValueT Rm = encodeRegister(OpSrc1, "Rm", SdivName);
+  IValueT Rd = encodeGPRegister(OpRd, "Rd", SdivName);
+  IValueT Rn = encodeGPRegister(OpRn, "Rn", SdivName);
+  IValueT Rm = encodeGPRegister(OpSrc1, "Rm", SdivName);
   verifyRegNotPc(Rd, "Rd", SdivName);
   verifyRegNotPc(Rn, "Rn", SdivName);
   verifyRegNotPc(Rm, "Rm", SdivName);
   // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
   constexpr IValueT SdivOpcode = 0;
-  emitDivOp(Cond, SdivOpcode, Rd, Rn, Rm, SdivName);
+  emitDivOp(Cond, SdivOpcode, Rd, Rn, Rm);
 }
 
 void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
                          CondARM32::Cond Cond, const TargetInfo &TInfo) {
   constexpr const char *StrName = "str";
   constexpr bool IsLoad = false;
-  IValueT Rt = encodeRegister(OpRt, "Rt", StrName);
+  IValueT Rt = encodeGPRegister(OpRt, "Rt", StrName);
   const Type Ty = OpRt->getType();
   switch (Ty) {
   case IceType_i64:
@@ -1662,7 +1702,7 @@
   // nnnn=Rn.
   constexpr const char *StrexName = "strex";
   // Note: Rt uses Rm shift in encoding.
-  IValueT Rt = encodeRegister(OpRt, "Rt", StrexName);
+  IValueT Rt = encodeGPRegister(OpRt, "Rt", StrexName);
   const Type Ty = OpRt->getType();
   constexpr bool IsLoad = true;
   emitMemExOp(Cond, Ty, !IsLoad, OpRd, Rt, OpAddress, TInfo, StrexName);
@@ -1694,14 +1734,14 @@
   //
   // cccc010010011101dddd000000000100 where dddd=Rt and cccc=Cond.
   constexpr const char *Pop = "pop";
-  IValueT Rt = encodeRegister(OpRt, "Rt", Pop);
+  IValueT Rt = encodeGPRegister(OpRt, "Rt", Pop);
   verifyRegsNotEq(Rt, "Rt", RegARM32::Encoded_Reg_sp, "sp", Pop);
   // Same as load instruction.
   constexpr bool IsLoad = true;
   constexpr bool IsByte = false;
   IValueT Address = encodeImmRegOffset(RegARM32::Encoded_Reg_sp, kWordSize,
                                        OperandARM32Mem::PostIndex);
-  emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address, Pop);
+  emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address);
 }
 
 void AssemblerARM32::popList(const IValueT Registers, CondARM32::Cond Cond) {
@@ -1710,10 +1750,8 @@
   //
   // cccc100010111101rrrrrrrrrrrrrrrr where cccc=Cond and
   // rrrrrrrrrrrrrrrr=Registers (one bit for each GP register).
-  constexpr const char *PopListName = "pop {}";
   constexpr bool IsLoad = true;
-  emitMultiMemOp(Cond, IA_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers,
-                 PopListName);
+  emitMultiMemOp(Cond, IA_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers);
 }
 
 void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) {
@@ -1722,14 +1760,14 @@
   //
   // cccc010100101101dddd000000000100 where dddd=Rt and cccc=Cond.
   constexpr const char *Push = "push";
-  IValueT Rt = encodeRegister(OpRt, "Rt", Push);
+  IValueT Rt = encodeGPRegister(OpRt, "Rt", Push);
   verifyRegsNotEq(Rt, "Rt", RegARM32::Encoded_Reg_sp, "sp", Push);
   // Same as store instruction.
   constexpr bool isLoad = false;
   constexpr bool isByte = false;
   IValueT Address = encodeImmRegOffset(RegARM32::Encoded_Reg_sp, -kWordSize,
                                        OperandARM32Mem::PreIndex);
-  emitMemOp(Cond, kInstTypeMemImmediate, isLoad, isByte, Rt, Address, Push);
+  emitMemOp(Cond, kInstTypeMemImmediate, isLoad, isByte, Rt, Address);
 }
 
 void AssemblerARM32::pushList(const IValueT Registers, CondARM32::Cond Cond) {
@@ -1738,10 +1776,8 @@
   //
   // cccc100100101101rrrrrrrrrrrrrrrr where cccc=Cond and
   // rrrrrrrrrrrrrrrr=Registers (one bit for each GP register).
-  constexpr const char *PushListName = "push {}";
   constexpr bool IsLoad = false;
-  emitMultiMemOp(Cond, DB_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers,
-                 PushListName);
+  emitMultiMemOp(Cond, DB_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers);
 }
 
 void AssemblerARM32::mla(const Operand *OpRd, const Operand *OpRn,
@@ -1753,10 +1789,10 @@
   // cccc0000001sddddaaaammmm1001nnnn where cccc=Cond, s=SetFlags, dddd=Rd,
   // aaaa=Ra, mmmm=Rm, and nnnn=Rn.
   constexpr const char *MlaName = "mla";
-  IValueT Rd = encodeRegister(OpRd, "Rd", MlaName);
-  IValueT Rn = encodeRegister(OpRn, "Rn", MlaName);
-  IValueT Rm = encodeRegister(OpRm, "Rm", MlaName);
-  IValueT Ra = encodeRegister(OpRa, "Ra", MlaName);
+  IValueT Rd = encodeGPRegister(OpRd, "Rd", MlaName);
+  IValueT Rn = encodeGPRegister(OpRn, "Rn", MlaName);
+  IValueT Rm = encodeGPRegister(OpRm, "Rm", MlaName);
+  IValueT Ra = encodeGPRegister(OpRa, "Ra", MlaName);
   verifyRegNotPc(Rd, "Rd", MlaName);
   verifyRegNotPc(Rn, "Rn", MlaName);
   verifyRegNotPc(Rm, "Rm", MlaName);
@@ -1764,17 +1800,17 @@
   constexpr IValueT MlaOpcode = B21;
   constexpr bool SetFlags = true;
   // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
-  emitMulOp(Cond, MlaOpcode, Ra, Rd, Rn, Rm, !SetFlags, MlaName);
+  emitMulOp(Cond, MlaOpcode, Ra, Rd, Rn, Rm, !SetFlags);
 }
 
 void AssemblerARM32::mls(const Operand *OpRd, const Operand *OpRn,
                          const Operand *OpRm, const Operand *OpRa,
                          CondARM32::Cond Cond) {
   constexpr const char *MlsName = "mls";
-  IValueT Rd = encodeRegister(OpRd, "Rd", MlsName);
-  IValueT Rn = encodeRegister(OpRn, "Rn", MlsName);
-  IValueT Rm = encodeRegister(OpRm, "Rm", MlsName);
-  IValueT Ra = encodeRegister(OpRa, "Ra", MlsName);
+  IValueT Rd = encodeGPRegister(OpRd, "Rd", MlsName);
+  IValueT Rn = encodeGPRegister(OpRn, "Rn", MlsName);
+  IValueT Rm = encodeGPRegister(OpRm, "Rm", MlsName);
+  IValueT Ra = encodeGPRegister(OpRa, "Ra", MlsName);
   verifyRegNotPc(Rd, "Rd", MlsName);
   verifyRegNotPc(Rn, "Rn", MlsName);
   verifyRegNotPc(Rm, "Rm", MlsName);
@@ -1782,7 +1818,7 @@
   constexpr IValueT MlsOpcode = B22 | B21;
   constexpr bool SetFlags = true;
   // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
-  emitMulOp(Cond, MlsOpcode, Ra, Rd, Rn, Rm, !SetFlags, MlsName);
+  emitMulOp(Cond, MlsOpcode, Ra, Rd, Rn, Rm, !SetFlags);
 }
 
 void AssemblerARM32::mul(const Operand *OpRd, const Operand *OpRn,
@@ -1794,23 +1830,22 @@
   // cccc0000000sdddd0000mmmm1001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn,
   // mmmm=Rm, and s=SetFlags.
   constexpr const char *MulName = "mul";
-  IValueT Rd = encodeRegister(OpRd, "Rd", MulName);
-  IValueT Rn = encodeRegister(OpRn, "Rn", MulName);
-  IValueT Rm = encodeRegister(OpSrc1, "Rm", MulName);
+  IValueT Rd = encodeGPRegister(OpRd, "Rd", MulName);
+  IValueT Rn = encodeGPRegister(OpRn, "Rn", MulName);
+  IValueT Rm = encodeGPRegister(OpSrc1, "Rm", MulName);
   verifyRegNotPc(Rd, "Rd", MulName);
   verifyRegNotPc(Rn, "Rn", MulName);
   verifyRegNotPc(Rm, "Rm", MulName);
   // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
   constexpr IValueT MulOpcode = 0;
-  emitMulOp(Cond, MulOpcode, RegARM32::Encoded_Reg_r0, Rd, Rn, Rm, SetFlags,
-            MulName);
+  emitMulOp(Cond, MulOpcode, RegARM32::Encoded_Reg_r0, Rd, Rn, Rm, SetFlags);
 }
 
 void AssemblerARM32::emitRdRm(CondARM32::Cond Cond, IValueT Opcode,
                               const Operand *OpRd, const Operand *OpRm,
                               const char *InstName) {
-  IValueT Rd = encodeRegister(OpRd, "Rd", InstName);
-  IValueT Rm = encodeRegister(OpRm, "Rm", InstName);
+  IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
+  IValueT Rm = encodeGPRegister(OpRm, "Rm", InstName);
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   IValueT Encoding =
       (Cond << kConditionShift) | Opcode | (Rd << kRdShift) | (Rm << kRmShift);
@@ -1965,15 +2000,15 @@
   // cccc01110011dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and
   // mmmm=Rm.
   constexpr const char *UdivName = "udiv";
-  IValueT Rd = encodeRegister(OpRd, "Rd", UdivName);
-  IValueT Rn = encodeRegister(OpRn, "Rn", UdivName);
-  IValueT Rm = encodeRegister(OpSrc1, "Rm", UdivName);
+  IValueT Rd = encodeGPRegister(OpRd, "Rd", UdivName);
+  IValueT Rn = encodeGPRegister(OpRn, "Rn", UdivName);
+  IValueT Rm = encodeGPRegister(OpSrc1, "Rm", UdivName);
   verifyRegNotPc(Rd, "Rd", UdivName);
   verifyRegNotPc(Rn, "Rn", UdivName);
   verifyRegNotPc(Rm, "Rm", UdivName);
   // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
   constexpr IValueT UdivOpcode = B21;
-  emitDivOp(Cond, UdivOpcode, Rd, Rn, Rm, UdivName);
+  emitDivOp(Cond, UdivOpcode, Rd, Rn, Rm);
 }
 
 void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi,
@@ -1985,10 +2020,10 @@
   // cccc0000100shhhhllllmmmm1001nnnn where hhhh=RdHi, llll=RdLo, nnnn=Rn,
   // mmmm=Rm, and s=SetFlags
   constexpr const char *UmullName = "umull";
-  IValueT RdLo = encodeRegister(OpRdLo, "RdLo", UmullName);
-  IValueT RdHi = encodeRegister(OpRdHi, "RdHi", UmullName);
-  IValueT Rn = encodeRegister(OpRn, "Rn", UmullName);
-  IValueT Rm = encodeRegister(OpRm, "Rm", UmullName);
+  IValueT RdLo = encodeGPRegister(OpRdLo, "RdLo", UmullName);
+  IValueT RdHi = encodeGPRegister(OpRdHi, "RdHi", UmullName);
+  IValueT Rn = encodeGPRegister(OpRn, "Rn", UmullName);
+  IValueT Rm = encodeGPRegister(OpRm, "Rm", UmullName);
   verifyRegNotPc(RdLo, "RdLo", UmullName);
   verifyRegNotPc(RdHi, "RdHi", UmullName);
   verifyRegNotPc(Rn, "Rn", UmullName);
@@ -1996,7 +2031,7 @@
   verifyRegsNotEq(RdHi, "RdHi", RdLo, "RdLo", UmullName);
   constexpr IValueT UmullOpcode = B23;
   constexpr bool SetFlags = false;
-  emitMulOp(Cond, UmullOpcode, RdLo, RdHi, Rn, Rm, SetFlags, UmullName);
+  emitMulOp(Cond, UmullOpcode, RdLo, RdHi, Rn, Rm, SetFlags);
 }
 
 void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0,
@@ -2006,10 +2041,39 @@
   emitSignExtend(Cond, UxtOpcode, OpRd, OpSrc0, UxtName);
 }
 
+void AssemblerARM32::vadds(const Operand *OpSd, const Operand *OpSn,
+                           const Operand *OpSm, CondARM32::Cond Cond) {
+  // VADD (floating-point) - ARM section A8.8.283, encoding A2:
+  //   vadd<c>.f32 <Sd>, <Sn>, <Sm>
+  //
+  // cccc11100D11nnnndddd101sN0M0mmmm where cccc=Cond, s=0, ddddD=Rd, nnnnN=Rn,
+  // and mmmmM=Rm.
+  constexpr const char *Vadds = "vadds";
+  IValueT Sd = encodeSRegister(OpSd, "Sd", Vadds);
+  IValueT Sn = encodeSRegister(OpSn, "Sn", Vadds);
+  IValueT Sm = encodeSRegister(OpSm, "Sm", Vadds);
+  constexpr IValueT VaddsOpcode = B21 | B20;
+  emitVFPsss(Cond, VaddsOpcode, Sd, Sn, Sm);
+}
+
+void AssemblerARM32::vaddd(const Operand *OpDd, const Operand *OpDn,
+                           const Operand *OpDm, CondARM32::Cond Cond) {
+  // VADD (floating-point) - ARM section A8.8.283, encoding A2:
+  //   vadd<c>.f64 <Dd>, <Dn>, <Dm>
+  //
+  // cccc11100D11nnnndddd101sN0M0mmmm where cccc=Cond, s=1, Ddddd=Rd, Nnnnn=Rn,
+  // and Mmmmm=Rm.
+  constexpr const char *Vaddd = "vaddd";
+  IValueT Dd = encodeDRegister(OpDd, "Dd", Vaddd);
+  IValueT Dn = encodeDRegister(OpDn, "Dn", Vaddd);
+  IValueT Dm = encodeDRegister(OpDm, "Dm", Vaddd);
+  constexpr IValueT VadddOpcode = B21 | B20;
+  emitVFPddd(Cond, VadddOpcode, Dd, Dn, Dm);
+}
+
 void AssemblerARM32::emitVStackOp(CondARM32::Cond Cond, IValueT Opcode,
                                   const Variable *OpBaseReg,
-                                  SizeT NumConsecRegs, const char *InstName) {
-
+                                  SizeT NumConsecRegs) {
   const IValueT BaseReg = getEncodedSRegNum(OpBaseReg);
   const IValueT DLastBit = mask(BaseReg, 0, 1); // Last bit of base register.
   const IValueT Rd = mask(BaseReg, 1, 4);       // Top 4 bits of base register.
@@ -2017,7 +2081,7 @@
   (void)VpushVpopMaxConsecRegs;
   assert(NumConsecRegs <= VpushVpopMaxConsecRegs);
   assert((BaseReg + NumConsecRegs) <= RegARM32::getNumSRegs());
-  verifyCondDefined(Cond, InstName);
+  assert(CondARM32::isDefined(Cond));
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   const IValueT Encoding = Opcode | (Cond << kConditionShift) | DLastBit |
                            (Rd << kRdShift) | NumConsecRegs;
@@ -2034,10 +2098,9 @@
   //
   // cccc11001D111101dddd1010iiiiiiii where cccc=Cond, ddddD=BaseReg, and
   // iiiiiiii=NumConsecRegs.
-  constexpr const char *VpopName = "vpop";
   constexpr IValueT VpopOpcode =
       B27 | B26 | B23 | B21 | B20 | B19 | B18 | B16 | B11 | B9;
-  emitVStackOp(Cond, VpopOpcode, OpBaseReg, NumConsecRegs, VpopName);
+  emitVStackOp(Cond, VpopOpcode, OpBaseReg, NumConsecRegs);
 }
 
 void AssemblerARM32::vpush(const Variable *OpBaseReg, SizeT NumConsecRegs,
@@ -2050,10 +2113,9 @@
   //
   // cccc11010D101101dddd1010iiiiiiii where cccc=Cond, ddddD=BaseReg, and
   // iiiiiiii=NumConsecRegs.
-  constexpr const char *VpushName = "vpush";
   constexpr IValueT VpushOpcode =
       B27 | B26 | B24 | B21 | B19 | B18 | B16 | B11 | B9;
-  emitVStackOp(Cond, VpushOpcode, OpBaseReg, NumConsecRegs, VpushName);
+  emitVStackOp(Cond, VpushOpcode, OpBaseReg, NumConsecRegs);
 }
 
 } // end of namespace ARM32
diff --git a/src/IceAssemblerARM32.h b/src/IceAssemblerARM32.h
index 874d8ec..e11b6c9 100644
--- a/src/IceAssemblerARM32.h
+++ b/src/IceAssemblerARM32.h
@@ -318,6 +318,12 @@
   // Implements uxtb/uxth depending on type of OpSrc0.
   void uxt(const Operand *OpRd, const Operand *OpSrc0, CondARM32::Cond Cond);
 
+  void vaddd(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm,
+             CondARM32::Cond Cond);
+
+  void vadds(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm,
+             CondARM32::Cond Cond);
+
   void vpop(const Variable *OpBaseReg, SizeT NumConsecRegs,
             CondARM32::Cond Cond);
 
@@ -383,16 +389,14 @@
                   IValueT OpRn, const Operand *OpSrc1, bool SetFlags,
                   EmitChecks RuleChecks, const char *InstName);
 
-  void emitType05(CondARM32::Cond Cond, int32_t Offset, bool Link,
-                  const char *InstName);
+  void emitType05(CondARM32::Cond Cond, int32_t Offset, bool Link);
 
   // Emit ccccoooaabalnnnnttttaaaaaaaaaaaa where cccc=Cond,
   // ooo=InstType, l=isLoad, b=isByte, and
   // aaa0a0aaaa0000aaaaaaaaaaaa=Address. Note that Address is assumed to be
   // defined by decodeAddress() in IceAssemblerARM32.cpp.
   void emitMemOp(CondARM32::Cond Cond, IValueT InstType, bool IsLoad,
-                 bool IsByte, IValueT Rt, IValueT Address,
-                 const char *InstName);
+                 bool IsByte, IValueT Rt, IValueT Address);
 
   // Emit ccccxxxxxxxxxxxxddddxxxxxxxxmmmm where cccc=Cond,
   // xxxxxxxxxxxx0000xxxxxxxx0000=Opcode, dddd=Rd, and mmmm=Rm.
@@ -419,24 +423,22 @@
   // aaaa<<21=AddressMode, l=IsLoad, nnnn=BaseReg, and
   // rrrrrrrrrrrrrrrr is bitset of Registers.
   void emitMultiMemOp(CondARM32::Cond Cond, BlockAddressMode AddressMode,
-                      bool IsLoad, IValueT BaseReg, IValueT Registers,
-                      const char *InstName);
+                      bool IsLoad, IValueT BaseReg, IValueT Registers);
 
   // Pattern ccccxxxxxDxxxxxxddddxxxxiiiiiiii where cccc=Cond, ddddD=BaseReg,
   // iiiiiiii=NumConsecRegs, and xxxxx0xxxxxx0000xxxx00000000=Opcode.
   void emitVStackOp(CondARM32::Cond Cond, IValueT Opcode,
-                    const Variable *OpBaseReg, SizeT NumConsecRegs,
-                    const char *InstName);
+                    const Variable *OpBaseReg, SizeT NumConsecRegs);
 
   // Pattern cccc011100x1dddd1111mmmm0001nnn where cccc=Cond,
   // x=Opcode, dddd=Rd, nnnn=Rn, mmmm=Rm.
   void emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
-                 IValueT Rm, const char *InstName);
+                 IValueT Rm);
 
   // Pattern ccccxxxxxxxfnnnnddddssss1001mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
   // mmmm=Rm, ssss=Rs, f=SetFlags and xxxxxxx=Opcode.
   void emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
-                 IValueT Rm, IValueT Rs, bool SetFlags, const char *InstName);
+                 IValueT Rm, IValueT Rs, bool SetFlags);
 
   // Pattern cccc0001101s0000ddddxxxxxtt0mmmm where cccc=Cond, s=SetFlags,
   // dddd=Rd, mmmm=Rm, tt=Shift, and xxxxx is defined by OpSrc1. OpSrc1 defines
@@ -471,6 +473,14 @@
   // iiiiiiiiiiiiiiii=Imm16.
   void emitMovwt(CondARM32::Cond Cond, bool IsMovw, const Operand *OpRd,
                  const Operand *OpSrc, const char *MovName);
+
+  // Emit VFP instruction with 3 D registers.
+  void emitVFPddd(CondARM32::Cond Cond, IValueT Opcode, IValueT Dd, IValueT Dn,
+                  IValueT Dm);
+
+  // Emit VFP instruction with 3 S registers.
+  void emitVFPsss(CondARM32::Cond Cond, IValueT Opcode, IValueT Sd, IValueT Sn,
+                  IValueT Sm);
 };
 
 } // end of namespace ARM32
diff --git a/src/IceConditionCodesARM32.h b/src/IceConditionCodesARM32.h
index e7fc4d0..f137763 100644
--- a/src/IceConditionCodesARM32.h
+++ b/src/IceConditionCodesARM32.h
@@ -33,6 +33,8 @@
     ICEINSTARM32COND_TABLE
 #undef X
   };
+
+  static bool isDefined(Cond C) { return C != kNone; }
 };
 
 } // end of namespace Ice
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
index 4919600..02cf941 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -226,6 +226,11 @@
   emitUsingTextFixup(Func);
 }
 
+template <InstARM32::InstKindARM32 K>
+void InstARM32ThreeAddrFP<K>::emitIAS(const Cfg *Func) const {
+  emitUsingTextFixup(Func);
+}
+
 template <> void InstARM32Mla::emitIAS(const Cfg *Func) const {
   assert(getSrcSize() == 3);
   auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
@@ -592,6 +597,25 @@
     emitUsingTextFixup(Func);
 }
 
+template <> void InstARM32Vadd::emitIAS(const Cfg *Func) const {
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  const Variable *Dest = getDest();
+  switch (Dest->getType()) {
+  default:
+    // TODO(kschimpf) Figure if more cases are needed.
+    Asm->setNeedsTextFixup();
+    break;
+  case IceType_f32:
+    Asm->vadds(getDest(), getSrc(0), getSrc(1), CondARM32::AL);
+    break;
+  case IceType_f64:
+    Asm->vaddd(getDest(), getSrc(0), getSrc(1), CondARM32::AL);
+    break;
+  }
+  if (Asm->needsTextFixup())
+    emitUsingTextFixup(Func);
+}
+
 InstARM32Call::InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget)
     : InstARM32(Func, InstARM32::Call, 1, Dest) {
   HasSideEffects = true;
@@ -1404,7 +1428,7 @@
     const Variable *LastDest = nullptr;
     for (const Variable *Var : Dests) {
       assert(Var->hasReg() && "pop only applies to registers");
-      int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum());
+      int32_t Reg = RegARM32::getEncodedGPReg(Var->getRegNum());
       LastDest = Var;
       GPRegisters |= (1 << Reg);
       ++IntegerCount;
@@ -1536,7 +1560,7 @@
     const Variable *LastSrc = nullptr;
     for (SizeT Index = 0; Index < getSrcSize(); ++Index) {
       const auto *Var = llvm::cast<Variable>(getSrc(Index));
-      int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum());
+      int32_t Reg = RegARM32::getEncodedGPReg(Var->getRegNum());
       assert(Reg != RegARM32::Encoded_Not_GPR);
       LastSrc = Var;
       GPRegisters |= (1 << Reg);
diff --git a/src/IceInstARM32.h b/src/IceInstARM32.h
index 75f48a7..46e27de 100644
--- a/src/IceInstARM32.h
+++ b/src/IceInstARM32.h
@@ -732,6 +732,7 @@
       return;
     emitThreeAddrFP(Opcode, this, Func);
   }
+  void emitIAS(const Cfg *Func) const override;
   void dump(const Cfg *Func) const override {
     if (!BuildDefs::dump())
       return;
diff --git a/src/IceRegistersARM32.h b/src/IceRegistersARM32.h
index 0caa9cc..8ea5b01 100644
--- a/src/IceRegistersARM32.h
+++ b/src/IceRegistersARM32.h
@@ -146,56 +146,99 @@
 #undef X
   };
 
-  static inline GPRRegister getEncodedGPR(int32_t RegNum) {
-    assert(Reg_GPR_First <= RegNum);
-    assert(RegNum <= Reg_GPR_Last);
+  static inline void assertRegisterDefined(int32_t RegNum) {
+    (void)RegNum;
+    assert(RegNum >= 0);
+    assert(RegNum < Reg_NUM);
+  }
+
+  static inline bool isGPRegister(int32_t RegNum) {
+    assertRegisterDefined(RegNum);
+    return Table[RegNum].IsGPR;
+  }
+
+  static constexpr inline SizeT getNumGPRegs() {
+    return 0
+#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr,   \
+          isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init)       \
+  +(isGPR)
+        REGARM32_TABLE
+#undef X
+        ;
+  }
+
+  static inline GPRRegister getEncodedGPReg(int32_t RegNum) {
+    assert(isGPRegister(RegNum));
     return GPRRegister(Table[RegNum].Encoding);
   }
 
   static inline GPRRegister getI64PairFirstGPRNum(int32_t RegNum) {
-    assert(Reg_I64PAIR_First <= RegNum);
-    assert(RegNum <= Reg_I64PAIR_Last);
+    assert(isI64RegisterPair(RegNum));
     return GPRRegister(Table[RegNum].Encoding);
   }
 
   static inline GPRRegister getI64PairSecondGPRNum(int32_t RegNum) {
-    assert(Reg_I64PAIR_First <= RegNum);
-    assert(RegNum <= Reg_I64PAIR_Last);
+    assert(isI64RegisterPair(RegNum));
     return GPRRegister(Table[RegNum].Encoding + 1);
   }
 
   static inline bool isI64RegisterPair(int32_t RegNum) {
+    assertRegisterDefined(RegNum);
     return Table[RegNum].IsI64Pair;
   }
 
   static inline bool isEncodedSReg(int32_t RegNum) {
+    assertRegisterDefined(RegNum);
     return Table[RegNum].IsFP32;
   }
 
-  static inline SizeT getNumSRegs() {
-    return Reg_SREG_Last + 1 - Reg_SREG_First;
+  static constexpr inline SizeT getNumSRegs() {
+    return 0
+#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr,   \
+          isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init)       \
+  +(isFP32)
+        REGARM32_TABLE
+#undef X
+        ;
   }
 
   static inline SRegister getEncodedSReg(int32_t RegNum) {
-    assert(Reg_SREG_First <= RegNum);
-    assert(RegNum <= Reg_SREG_Last);
+    assert(isEncodedSReg(RegNum));
     return SRegister(Table[RegNum].Encoding);
   }
 
+  static inline bool isEncodedDReg(int32_t RegNum) {
+    assertRegisterDefined(RegNum);
+    return Table[RegNum].IsFP64;
+  }
+
+  static constexpr inline SizeT getNumDRegs() {
+    return 0
+#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr,   \
+          isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init)       \
+  +(isFP64)
+        REGARM32_TABLE
+#undef X
+        ;
+  }
+
   static inline DRegister getEncodedDReg(int32_t RegNum) {
-    assert(Reg_DREG_First <= RegNum);
-    assert(RegNum <= Reg_DREG_Last);
+    assert(isEncodedDReg(RegNum));
     return DRegister(Table[RegNum].Encoding);
   }
 
+  static inline bool isEncodedQReg(int32_t RegNum) {
+    assertRegisterDefined(RegNum);
+    return Table[RegNum].IsVec128;
+  }
+
   static inline QRegister getEncodedQReg(int32_t RegNum) {
-    assert(Reg_QREG_First <= RegNum);
-    assert(RegNum <= Reg_QREG_Last);
+    assert(isEncodedQReg(RegNum));
     return QRegister(Table[RegNum].Encoding);
   }
 
-  static inline IceString getRegName(SizeT RegNum) {
-    assert(RegNum < Reg_NUM);
+  static inline IceString getRegName(int32_t RegNum) {
+    assertRegisterDefined(RegNum);
     return Table[RegNum].Name;
   }
 };
diff --git a/tests_lit/assembler/arm32/vadd.ll b/tests_lit/assembler/arm32/vadd.ll
new file mode 100644
index 0000000..c861028
--- /dev/null
+++ b/tests_lit/assembler/arm32/vadd.ll
@@ -0,0 +1,42 @@
+; Show that we know how to translate vadd.
+
+; NOTE: We use -O2 to get rid of memory stores.
+
+; REQUIRES: allow_dump
+
+; Compile using standalone assembler.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 \
+; RUN:   | FileCheck %s --check-prefix=ASM
+
+; Show bytes in assembled standalone code.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
+; RUN:   --args -O2 | FileCheck %s --check-prefix=DIS
+
+; Compile using integrated assembler.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -O2 \
+; RUN:   | FileCheck %s --check-prefix=IASM
+
+; Show bytes in assembled integrated code.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
+; RUN:   --args -O2 | FileCheck %s --check-prefix=DIS
+
+define internal float @testVadd(float %v1, float %v2) {
+; ASM-LABEL: testVadd:
+; DIS-LABEL: 00000000 <testVadd>:
+; IASM-LABEL: testVadd:
+
+entry:
+; ASM-NEXT: .LtestVadd$entry:
+; IASM-NEXT: .LtestVadd$entry:
+
+  %res = fadd float %v1, %v2
+
+; ASM-NEXT:     vadd.f32        s0, s0, s1
+; DIS-NEXT:    0:       ee300a20
+; IASM-NEXT:    .byte 0x20
+; IASM-NEXT:    .byte 0xa
+; IASM-NEXT:    .byte 0x30
+; IASM-NEXT:    .byte 0xee
+
+  ret float %res
+}
diff --git a/tests_lit/assembler/arm32/vpush.ll b/tests_lit/assembler/arm32/vpush.ll
index ab73262..1eb4611 100644
--- a/tests_lit/assembler/arm32/vpush.ll
+++ b/tests_lit/assembler/arm32/vpush.ll
@@ -33,65 +33,68 @@
 
 ; ASM-NEXT:     vpush   {s28, s29, s30, s31}
 ; DIS-NEXT:    0:       ed2dea04
-; IASM-NEXT: 	.byte 0x4
-; IASM-NEXT: 	.byte 0xea
-; IASM-NEXT: 	.byte 0x2d
-; IASM-NEXT: 	.byte 0xed
+; IASM-NEXT:    .byte 0x4
+; IASM-NEXT:    .byte 0xea
+; IASM-NEXT:    .byte 0x2d
+; IASM-NEXT:    .byte 0xed
 
 ; ASM-NEXT:     push    {lr}
 ; DIS-NEXT:    4:       e52de004
-; IASM-NEXT: 	.byte 0x4
-; IASM-NEXT: 	.byte 0xe0
-; IASM-NEXT: 	.byte 0x2d
-; IASM-NEXT: 	.byte 0xe5
+; IASM-NEXT:    .byte 0x4
+; IASM-NEXT:    .byte 0xe0
+; IASM-NEXT:    .byte 0x2d
+; IASM-NEXT:    .byte 0xe5
 
 ; ASM-NEXT:     sub     sp, sp, #12
 ; DIS-NEXT:    8:       e24dd00c
-; IASM-NEXT: 	.byte 0xc
-; IASM-NEXT: 	.byte 0xd0
-; IASM-NEXT: 	.byte 0x4d
-; IASM-NEXT: 	.byte 0xe2
+; IASM-NEXT:    .byte 0xc
+; IASM-NEXT:    .byte 0xd0
+; IASM-NEXT:    .byte 0x4d
+; IASM-NEXT:    .byte 0xe2
 
 ; ASM-NEXT:     vmov.f64        d15, d0
 ; DIS-NEXT:    c:       eeb0fb40
-; IASM-NEXT: 	vmov.f64	d15, d0
+; IASM-NEXT:    vmov.f64        d15, d0
 
 ; ASM-NEXT:     vmov.f64        d14, d1
 ; DIS-NEXT:   10:       eeb0eb41
-; IASM-NEXT: 	vmov.f64	d14, d1
+; IASM-NEXT:    vmov.f64        d14, d1
 
   call void @foo()
 
 ; ASM-NEXT:     bl      foo
 ; DIS-NEXT:   14:       ebfffffe
-; IASM-NEXT: 	bl	foo	@ .word ebfffffe
+; IASM-NEXT:    bl      foo     @ .word ebfffffe
 
   %res = fadd double %v1, %v2
 
 ; ASM-NEXT:     vadd.f64        d15, d15, d14
 ; DIS-NEXT:   18:       ee3ffb0e
-; IASM-NEXT: 	vadd.f64	d15, d15, d14
+; IASM-NEXT:    .byte 0xe
+; IASM-NEXT:    .byte 0xfb
+; IASM-NEXT:    .byte 0x3f
+; IASM-NEXT:    .byte 0xee
 
 ; ASM-NEXT:     vmov.f64        d0, d15
 ; DIS-NEXT:   1c:       eeb00b4f
-; IASM-NEXT: 	vmov.f64	d0, d15
+; IASM-NEXT:    vmov.f64        d0, d15
 
   ret double %res
 
 ; ASM-NEXT:     add     sp, sp, #12
 ; DIS-NEXT:   20:       e28dd00c
-; IASM-NEXT: 	.byte 0xc
-; IASM-NEXT: 	.byte 0xd0
-; IASM-NEXT: 	.byte 0x8d
-; IASM-NEXT: 	.byte 0xe2
+; IASM-NEXT:    .byte 0xc
+; IASM-NEXT:    .byte 0xd0
+; IASM-NEXT:    .byte 0x8d
+; IASM-NEXT:    .byte 0xe2
 
 ; ASM-NEXT:     pop     {lr}
 ; ASM-NEXT:     # lr = def.pseudo 
 ; DIS-NEXT:   24:       e49de004
-; IASM-NEXT: 	.byte 0x4
-; IASM-NEXT: 	.byte 0xe0
-; IASM-NEXT: 	.byte 0x9d
-; IASM-NEXT: 	.byte 0xe4
+; IASM-NEXT:    .byte 0x4
+; IASM-NEXT:    .byte 0xe0
+; IASM-NEXT:    .byte 0x9d
+; IASM-NEXT:    .byte 0xe4
 
 ; ASM-NEXT:     vpop    {s28, s29, s30, s31}
 ; ASM-NEXT:     # s28 = def.pseudo 
@@ -99,17 +102,17 @@
 ; ASM-NEXT:     # s30 = def.pseudo 
 ; ASM-NEXT:     # s31 = def.pseudo 
 ; DIS-NEXT:   28:       ecbdea04
-; IASM-NEXT: 	.byte 0x4
-; IASM-NEXT: 	.byte 0xea
-; IASM-NEXT: 	.byte 0xbd
-; IASM-NEXT: 	.byte 0xec
+; IASM-NEXT:    .byte 0x4
+; IASM-NEXT:    .byte 0xea
+; IASM-NEXT:    .byte 0xbd
+; IASM-NEXT:    .byte 0xec
 
 ; ASM-NEXT:     bx      lr
 ; DIS-NEXT:   2c:       e12fff1e
-; IASM-NEXT: 	.byte 0x1e
-; IASM-NEXT: 	.byte 0xff
-; IASM-NEXT: 	.byte 0x2f
-; IASM-NEXT: 	.byte 0xe1
+; IASM-NEXT:    .byte 0x1e
+; IASM-NEXT:    .byte 0xff
+; IASM-NEXT:    .byte 0x2f
+; IASM-NEXT:    .byte 0xe1
 
 }