Add repeat support for memory addresses.

Rationale:
This enables exhaustive testing of instructions
that use memory addresses. First use case of
the generics is x86.

Bug: 18380245
Bug: 18380559
Bug: 18380348

Test: assembler_x86[_64]_test

Change-Id: Ib0ad6fa65477b0c6fc04642ff980a4b9543d16d5
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index 5ab558b..12954a4 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -46,7 +46,12 @@
 // For use in the template as the default type to get a nonvector registers version.
 struct NoVectorRegs {};
 
-template<typename Ass, typename Reg, typename FPReg, typename Imm, typename VecReg = NoVectorRegs>
+template<typename Ass,
+         typename Addr,
+         typename Reg,
+         typename FPReg,
+         typename Imm,
+         typename VecReg = NoVectorRegs>
 class AssemblerTest : public testing::Test {
  public:
   Ass* GetAssembler() {
@@ -64,6 +69,10 @@
     DriverWrapper(assembly_string, test_name);
   }
 
+  //
+  // Register repeats.
+  //
+
   std::string RepeatR(void (Ass::*f)(Reg), const std::string& fmt) {
     return RepeatTemplatedRegister<Reg>(f,
         GetRegisters(),
@@ -636,13 +645,23 @@
 
   // The following functions are public so that TestFn can use them...
 
+  // Returns a vector of address used by any of the repeat methods
+  // involving an "A" (e.g. RepeatA).
+  virtual std::vector<Addr> GetAddresses() = 0;
+
+  // Returns a vector of registers used by any of the repeat methods
+  // involving an "R" (e.g. RepeatR).
   virtual std::vector<Reg*> GetRegisters() = 0;
 
+  // Returns a vector of fp-registers used by any of the repeat methods
+  // involving an "F" (e.g. RepeatFF).
   virtual std::vector<FPReg*> GetFPRegisters() {
     UNIMPLEMENTED(FATAL) << "Architecture does not support floating-point registers";
     UNREACHABLE();
   }
 
+  // Returns a vector of dedicated simd-registers used by any of the repeat
+  // methods involving an "V" (e.g. RepeatVV).
   virtual std::vector<VecReg*> GetVectorRegisters() {
     UNIMPLEMENTED(FATAL) << "Architecture does not support vector registers";
     UNREACHABLE();
@@ -838,6 +857,268 @@
   // Create an immediate from the specific value.
   virtual Imm CreateImmediate(int64_t imm_value) = 0;
 
+  //
+  // Addresses repeats.
+  //
+
+  // Repeats over addresses provided by fixture.
+  std::string RepeatA(void (Ass::*f)(const Addr&), const std::string& fmt) {
+    return RepeatA(f, GetAddresses(), fmt);
+  }
+
+  // Variant that takes explicit vector of addresss
+  // (to test restricted addressing modes set).
+  std::string RepeatA(void (Ass::*f)(const Addr&),
+                      const std::vector<Addr>& a,
+                      const std::string& fmt) {
+    return RepeatTemplatedMem<Addr>(f, a, &AssemblerTest::GetAddrName, fmt);
+  }
+
+  // Repeats over addresses and immediates provided by fixture.
+  std::string RepeatAI(void (Ass::*f)(const Addr&, const Imm&),
+                       size_t imm_bytes,
+                       const std::string& fmt) {
+    return RepeatAI(f, imm_bytes, GetAddresses(), fmt);
+  }
+
+  // Variant that takes explicit vector of addresss
+  // (to test restricted addressing modes set).
+  std::string RepeatAI(void (Ass::*f)(const Addr&, const Imm&),
+                       size_t imm_bytes,
+                       const std::vector<Addr>& a,
+                       const std::string& fmt) {
+    return RepeatTemplatedMemImm<Addr>(f, imm_bytes, a, &AssemblerTest::GetAddrName, fmt);
+  }
+
+  // Repeats over registers and addresses provided by fixture.
+  std::string RepeatRA(void (Ass::*f)(Reg, const Addr&), const std::string& fmt) {
+    return RepeatRA(f, GetAddresses(), fmt);
+  }
+
+  // Variant that takes explicit vector of addresss
+  // (to test restricted addressing modes set).
+  std::string RepeatRA(void (Ass::*f)(Reg, const Addr&),
+                       const std::vector<Addr>& a,
+                       const std::string& fmt) {
+    return RepeatTemplatedRegMem<Reg, Addr>(
+        f,
+        GetRegisters(),
+        a,
+        &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+        &AssemblerTest::GetAddrName,
+        fmt);
+  }
+
+  // Repeats over fp-registers and addresses provided by fixture.
+  std::string RepeatFA(void (Ass::*f)(FPReg, const Addr&), const std::string& fmt) {
+    return RepeatFA(f, GetAddresses(), fmt);
+  }
+
+  // Variant that takes explicit vector of addresss
+  // (to test restricted addressing modes set).
+  std::string RepeatFA(void (Ass::*f)(FPReg, const Addr&),
+                       const std::vector<Addr>& a,
+                       const std::string& fmt) {
+    return RepeatTemplatedRegMem<FPReg, Addr>(
+        f,
+        GetFPRegisters(),
+        a,
+        &AssemblerTest::GetFPRegName,
+        &AssemblerTest::GetAddrName,
+        fmt);
+  }
+
+  // Repeats over addresses and registers provided by fixture.
+  std::string RepeatAR(void (Ass::*f)(const Addr&, Reg), const std::string& fmt) {
+    return RepeatAR(f, GetAddresses(), fmt);
+  }
+
+  // Variant that takes explicit vector of addresss
+  // (to test restricted addressing modes set).
+  std::string RepeatAR(void (Ass::*f)(const Addr&, Reg),
+                       const std::vector<Addr>& a,
+                       const std::string& fmt) {
+    return RepeatTemplatedMemReg<Addr, Reg>(
+        f,
+        a,
+        GetRegisters(),
+        &AssemblerTest::GetAddrName,
+        &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+        fmt);
+  }
+
+  // Repeats over addresses and fp-registers provided by fixture.
+  std::string RepeatAF(void (Ass::*f)(const Addr&, FPReg), const std::string& fmt) {
+    return RepeatAF(f, GetAddresses(), fmt);
+  }
+
+  // Variant that takes explicit vector of addresss
+  // (to test restricted addressing modes set).
+  std::string RepeatAF(void (Ass::*f)(const Addr&, FPReg),
+                       const std::vector<Addr>& a,
+                       const std::string& fmt) {
+    return RepeatTemplatedMemReg<Addr, FPReg>(
+        f,
+        a,
+        GetFPRegisters(),
+        &AssemblerTest::GetAddrName,
+        &AssemblerTest::GetFPRegName,
+        fmt);
+  }
+
+  template <typename AddrType>
+  std::string RepeatTemplatedMem(void (Ass::*f)(const AddrType&),
+                                 const std::vector<AddrType> addresses,
+                                 std::string (AssemblerTest::*GetAName)(const AddrType&),
+                                 const std::string& fmt) {
+    WarnOnCombinations(addresses.size());
+    std::string str;
+    for (auto addr : addresses) {
+      if (f != nullptr) {
+        (assembler_.get()->*f)(addr);
+      }
+      std::string base = fmt;
+
+      std::string addr_string = (this->*GetAName)(addr);
+      size_t addr_index;
+      if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) {
+        base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string);
+      }
+
+      if (str.size() > 0) {
+        str += "\n";
+      }
+      str += base;
+    }
+    // Add a newline at the end.
+    str += "\n";
+    return str;
+  }
+
+  template <typename AddrType>
+  std::string RepeatTemplatedMemImm(void (Ass::*f)(const AddrType&, const Imm&),
+                                    size_t imm_bytes,
+                                    const std::vector<AddrType> addresses,
+                                    std::string (AssemblerTest::*GetAName)(const AddrType&),
+                                    const std::string& fmt) {
+    std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
+    WarnOnCombinations(addresses.size() * imms.size());
+    std::string str;
+    for (auto addr : addresses) {
+      for (int64_t imm : imms) {
+        Imm new_imm = CreateImmediate(imm);
+        if (f != nullptr) {
+          (assembler_.get()->*f)(addr, new_imm);
+        }
+        std::string base = fmt;
+
+        std::string addr_string = (this->*GetAName)(addr);
+        size_t addr_index;
+        if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) {
+          base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string);
+        }
+
+        size_t imm_index = base.find(IMM_TOKEN);
+        if (imm_index != std::string::npos) {
+          std::ostringstream sreg;
+          sreg << imm;
+          std::string imm_string = sreg.str();
+          base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
+        }
+
+        if (str.size() > 0) {
+          str += "\n";
+        }
+        str += base;
+      }
+    }
+    // Add a newline at the end.
+    str += "\n";
+    return str;
+  }
+
+  template <typename RegType, typename AddrType>
+  std::string RepeatTemplatedRegMem(void (Ass::*f)(RegType, const AddrType&),
+                                    const std::vector<RegType*> registers,
+                                    const std::vector<AddrType> addresses,
+                                    std::string (AssemblerTest::*GetRName)(const RegType&),
+                                    std::string (AssemblerTest::*GetAName)(const AddrType&),
+                                    const std::string& fmt) {
+    WarnOnCombinations(addresses.size() * registers.size());
+    std::string str;
+    for (auto reg : registers) {
+      for (auto addr : addresses) {
+        if (f != nullptr) {
+          (assembler_.get()->*f)(*reg, addr);
+        }
+        std::string base = fmt;
+
+        std::string reg_string = (this->*GetRName)(*reg);
+        size_t reg_index;
+        if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
+          base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
+        }
+
+        std::string addr_string = (this->*GetAName)(addr);
+        size_t addr_index;
+        if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) {
+          base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string);
+        }
+
+        if (str.size() > 0) {
+          str += "\n";
+        }
+        str += base;
+      }
+    }
+    // Add a newline at the end.
+    str += "\n";
+    return str;
+  }
+
+  template <typename AddrType, typename RegType>
+  std::string RepeatTemplatedMemReg(void (Ass::*f)(const AddrType&, RegType),
+                                    const std::vector<AddrType> addresses,
+                                    const std::vector<RegType*> registers,
+                                    std::string (AssemblerTest::*GetAName)(const AddrType&),
+                                    std::string (AssemblerTest::*GetRName)(const RegType&),
+                                    const std::string& fmt) {
+    WarnOnCombinations(addresses.size() * registers.size());
+    std::string str;
+    for (auto addr : addresses) {
+      for (auto reg : registers) {
+        if (f != nullptr) {
+          (assembler_.get()->*f)(addr, *reg);
+        }
+        std::string base = fmt;
+
+        std::string addr_string = (this->*GetAName)(addr);
+        size_t addr_index;
+        if ((addr_index = base.find(ADDRESS_TOKEN)) != std::string::npos) {
+          base.replace(addr_index, ConstexprStrLen(ADDRESS_TOKEN), addr_string);
+        }
+
+        std::string reg_string = (this->*GetRName)(*reg);
+        size_t reg_index;
+        if ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
+          base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
+        }
+
+        if (str.size() > 0) {
+          str += "\n";
+        }
+        str += base;
+      }
+    }
+    // Add a newline at the end.
+    str += "\n";
+    return str;
+  }
+
+  //
+  // Register repeats.
+  //
+
   template <typename RegType>
   std::string RepeatTemplatedRegister(void (Ass::*f)(RegType),
                                       const std::vector<RegType*> registers,
@@ -1048,6 +1329,12 @@
     return str;
   }
 
+  std::string GetAddrName(const Addr& addr) {
+    std::ostringstream saddr;
+    saddr << addr;
+    return saddr.str();
+  }
+
   template <RegisterView kRegView>
   std::string GetRegName(const Reg& reg) {
     std::ostringstream sreg;
@@ -1094,6 +1381,7 @@
     }
   }
 
+  static constexpr const char* ADDRESS_TOKEN = "{mem}";
   static constexpr const char* REG_TOKEN = "{reg}";
   static constexpr const char* REG1_TOKEN = "{reg1}";
   static constexpr const char* REG2_TOKEN = "{reg2}";
diff --git a/compiler/utils/mips/assembler_mips32r5_test.cc b/compiler/utils/mips/assembler_mips32r5_test.cc
index 24b09b5..a3662db 100644
--- a/compiler/utils/mips/assembler_mips32r5_test.cc
+++ b/compiler/utils/mips/assembler_mips32r5_test.cc
@@ -32,12 +32,14 @@
 };
 
 class AssemblerMIPS32r5Test : public AssemblerTest<mips::MipsAssembler,
+                                                   mips::MipsLabel,
                                                    mips::Register,
                                                    mips::FRegister,
                                                    uint32_t,
                                                    mips::VectorRegister> {
  public:
   typedef AssemblerTest<mips::MipsAssembler,
+                        mips::MipsLabel,
                         mips::Register,
                         mips::FRegister,
                         uint32_t,
@@ -217,6 +219,11 @@
     STLDeleteElements(&vec_registers_);
   }
 
+  std::vector<mips::MipsLabel> GetAddresses() {
+    UNIMPLEMENTED(FATAL) << "Feature not implemented yet";
+    UNREACHABLE();
+  }
+
   std::vector<mips::Register*> GetRegisters() OVERRIDE {
     return registers_;
   }
diff --git a/compiler/utils/mips/assembler_mips32r6_test.cc b/compiler/utils/mips/assembler_mips32r6_test.cc
index a5cd5a7..b6cb30a 100644
--- a/compiler/utils/mips/assembler_mips32r6_test.cc
+++ b/compiler/utils/mips/assembler_mips32r6_test.cc
@@ -32,12 +32,14 @@
 };
 
 class AssemblerMIPS32r6Test : public AssemblerTest<mips::MipsAssembler,
+                                                   mips::MipsLabel,
                                                    mips::Register,
                                                    mips::FRegister,
                                                    uint32_t,
                                                    mips::VectorRegister> {
  public:
   typedef AssemblerTest<mips::MipsAssembler,
+                        mips::MipsLabel,
                         mips::Register,
                         mips::FRegister,
                         uint32_t,
@@ -230,6 +232,11 @@
     STLDeleteElements(&vec_registers_);
   }
 
+  std::vector<mips::MipsLabel> GetAddresses() {
+    UNIMPLEMENTED(FATAL) << "Feature not implemented yet";
+    UNREACHABLE();
+  }
+
   std::vector<mips::Register*> GetRegisters() OVERRIDE {
     return registers_;
   }
diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc
index 680c347..eed83a5 100644
--- a/compiler/utils/mips/assembler_mips_test.cc
+++ b/compiler/utils/mips/assembler_mips_test.cc
@@ -32,11 +32,16 @@
 };
 
 class AssemblerMIPSTest : public AssemblerTest<mips::MipsAssembler,
+                                               mips::MipsLabel,
                                                mips::Register,
                                                mips::FRegister,
                                                uint32_t> {
  public:
-  typedef AssemblerTest<mips::MipsAssembler, mips::Register, mips::FRegister, uint32_t> Base;
+  typedef AssemblerTest<mips::MipsAssembler,
+                        mips::MipsLabel,
+                        mips::Register,
+                        mips::FRegister,
+                        uint32_t> Base;
 
  protected:
   // Get the typically used name for this architecture, e.g., aarch64, x86-64, ...
@@ -161,6 +166,11 @@
     STLDeleteElements(&fp_registers_);
   }
 
+  std::vector<mips::MipsLabel> GetAddresses() {
+    UNIMPLEMENTED(FATAL) << "Feature not implemented yet";
+    UNREACHABLE();
+  }
+
   std::vector<mips::Register*> GetRegisters() OVERRIDE {
     return registers_;
   }
diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc
index fc0bd36..16a36f9 100644
--- a/compiler/utils/mips64/assembler_mips64_test.cc
+++ b/compiler/utils/mips64/assembler_mips64_test.cc
@@ -35,12 +35,14 @@
 };
 
 class AssemblerMIPS64Test : public AssemblerTest<mips64::Mips64Assembler,
+                                                 mips64::Mips64Label,
                                                  mips64::GpuRegister,
                                                  mips64::FpuRegister,
                                                  uint32_t,
                                                  mips64::VectorRegister> {
  public:
   typedef AssemblerTest<mips64::Mips64Assembler,
+                        mips64::Mips64Label,
                         mips64::GpuRegister,
                         mips64::FpuRegister,
                         uint32_t,
@@ -228,6 +230,11 @@
     STLDeleteElements(&vec_registers_);
   }
 
+  std::vector<mips64::Mips64Label> GetAddresses() {
+    UNIMPLEMENTED(FATAL) << "Feature not implemented yet";
+    UNREACHABLE();
+  }
+
   std::vector<mips64::GpuRegister*> GetRegisters() OVERRIDE {
     return registers_;
   }
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index b89af10..3162a32 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -32,6 +32,33 @@
   return os << "ST" << static_cast<int>(reg);
 }
 
+std::ostream& operator<<(std::ostream& os, const Address& addr) {
+  switch (addr.mod()) {
+    case 0:
+      if (addr.rm() == ESP && addr.index() != ESP) {
+        return os << "(%" << addr.base() << ",%"
+                  << addr.index() << "," << (1 << addr.scale()) << ")";
+      }
+      return os << "(%" << addr.rm() << ")";
+    case 1:
+      if (addr.rm() == ESP && addr.index() != ESP) {
+        return os << static_cast<int>(addr.disp8())
+                  << "(%" << addr.base() << ",%"
+                  << addr.index() << "," << (1 << addr.scale()) << ")";
+      }
+      return os << static_cast<int>(addr.disp8()) << "(%" << addr.rm() << ")";
+    case 2:
+      if (addr.rm() == ESP && addr.index() != ESP) {
+        return os << static_cast<int>(addr.disp32())
+                  << "(%" << addr.base() << ",%"
+                  << addr.index() << "," << (1 << addr.scale()) << ")";
+      }
+      return os << static_cast<int>(addr.disp32()) << "(%" << addr.rm() << ")";
+    default:
+      return os << "<address?>";
+  }
+}
+
 void X86Assembler::call(Register reg) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xFF);
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 511eeb9..2964dba 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -235,6 +235,7 @@
   }
 };
 
+std::ostream& operator<<(std::ostream& os, const Address& addr);
 
 // This is equivalent to the Label class, used in a slightly different context. We
 // inherit the functionality of the Label class, but prevent unintended
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index 48e4117..c28ed3b 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -37,11 +37,17 @@
 // Test fixture.
 //
 
-class AssemblerX86Test : public AssemblerTest<x86::X86Assembler, x86::Register,
-                                              x86::XmmRegister, x86::Immediate> {
+class AssemblerX86Test : public AssemblerTest<x86::X86Assembler,
+                                              x86::Address,
+                                              x86::Register,
+                                              x86::XmmRegister,
+                                              x86::Immediate> {
  public:
-  typedef AssemblerTest<x86::X86Assembler, x86::Register,
-                         x86::XmmRegister, x86::Immediate> Base;
+  typedef AssemblerTest<x86::X86Assembler,
+                        x86::Address,
+                        x86::Register,
+                        x86::XmmRegister,
+                        x86::Immediate> Base;
 
  protected:
   std::string GetArchitectureString() OVERRIDE {
@@ -57,6 +63,31 @@
   }
 
   void SetUpHelpers() OVERRIDE {
+    if (addresses_singleton_.size() == 0) {
+      // One addressing mode to test the repeat drivers.
+      addresses_singleton_.push_back(x86::Address(x86::EAX, x86::EBX, x86::TIMES_1, 2));
+    }
+
+    if (addresses_.size() == 0) {
+      // Several addressing modes.
+      addresses_.push_back(x86::Address(x86::EDI, x86::EAX, x86::TIMES_1, 15));
+      addresses_.push_back(x86::Address(x86::EDI, x86::EBX, x86::TIMES_2, 16));
+      addresses_.push_back(x86::Address(x86::EDI, x86::ECX, x86::TIMES_4, 17));
+      addresses_.push_back(x86::Address(x86::EDI, x86::EDX, x86::TIMES_8, 18));
+      addresses_.push_back(x86::Address(x86::EAX, -1));
+      addresses_.push_back(x86::Address(x86::EBX, 0));
+      addresses_.push_back(x86::Address(x86::ESI, 1));
+      addresses_.push_back(x86::Address(x86::EDI, 987654321));
+      // Several addressing modes with the special ESP.
+      addresses_.push_back(x86::Address(x86::ESP, x86::EAX, x86::TIMES_1, 15));
+      addresses_.push_back(x86::Address(x86::ESP, x86::EBX, x86::TIMES_2, 16));
+      addresses_.push_back(x86::Address(x86::ESP, x86::ECX, x86::TIMES_4, 17));
+      addresses_.push_back(x86::Address(x86::ESP, x86::EDX, x86::TIMES_8, 18));
+      addresses_.push_back(x86::Address(x86::ESP, -1));
+      addresses_.push_back(x86::Address(x86::ESP, 0));
+      addresses_.push_back(x86::Address(x86::ESP, 1));
+      addresses_.push_back(x86::Address(x86::ESP, 987654321));
+    }
     if (registers_.size() == 0) {
       registers_.insert(end(registers_),
                         {  // NOLINT(whitespace/braces)
@@ -92,6 +123,10 @@
     STLDeleteElements(&fp_registers_);
   }
 
+  std::vector<x86::Address> GetAddresses() OVERRIDE {
+    return addresses_;
+  }
+
   std::vector<x86::Register*> GetRegisters() OVERRIDE {
     return registers_;
   }
@@ -104,7 +139,10 @@
     return x86::Immediate(imm_value);
   }
 
+  std::vector<x86::Address> addresses_singleton_;
+
  private:
+  std::vector<x86::Address> addresses_;
   std::vector<x86::Register*> registers_;
   std::vector<x86::XmmRegister*> fp_registers_;
 };
@@ -128,10 +166,10 @@
 }
 
 TEST_F(AssemblerX86Test, RepeatRI) {
-  EXPECT_EQ("%eax %0\n%eax %-1\n%eax %18\n%ebx %0\n%ebx %-1\n%ebx %18\n%ecx %0\n%ecx %-1\n"
-            "%ecx %18\n%edx %0\n%edx %-1\n%edx %18\n%ebp %0\n%ebp %-1\n%ebp %18\n%esp %0\n"
-            "%esp %-1\n%esp %18\n%esi %0\n%esi %-1\n%esi %18\n%edi %0\n%edi %-1\n%edi %18\n",
-            RepeatRI(/*f*/ nullptr, /*imm_bytes*/ 1U, "%{reg} %{imm}"));
+  EXPECT_EQ("%eax $0\n%eax $-1\n%eax $18\n%ebx $0\n%ebx $-1\n%ebx $18\n%ecx $0\n%ecx $-1\n"
+            "%ecx $18\n%edx $0\n%edx $-1\n%edx $18\n%ebp $0\n%ebp $-1\n%ebp $18\n%esp $0\n"
+            "%esp $-1\n%esp $18\n%esi $0\n%esi $-1\n%esi $18\n%edi $0\n%edi $-1\n%edi $18\n",
+            RepeatRI(/*f*/ nullptr, /*imm_bytes*/ 1U, "%{reg} ${imm}"));
 }
 
 TEST_F(AssemblerX86Test, RepeatFF) {
@@ -150,30 +188,67 @@
 }
 
 TEST_F(AssemblerX86Test, RepeatFFI) {
-  EXPECT_NE(RepeatFFI(/*f*/ nullptr, /*imm_bytes*/ 1U, "%{reg1} %{reg2} %{imm}")
-            .find("%XMM0 %XMM0 %0\n%XMM0 %XMM0 %-1\n%XMM0 %XMM0 %18\n"
-                  "%XMM0 %XMM1 %0\n%XMM0 %XMM1 %-1\n%XMM0 %XMM1 %18\n"),
+  EXPECT_NE(RepeatFFI(/*f*/ nullptr, /*imm_bytes*/ 1U, "%{reg1} %{reg2} ${imm}")
+            .find("%XMM0 %XMM0 $0\n%XMM0 %XMM0 $-1\n%XMM0 %XMM0 $18\n"
+                  "%XMM0 %XMM1 $0\n%XMM0 %XMM1 $-1\n%XMM0 %XMM1 $18\n"),
             std::string::npos);
 }
 
+TEST_F(AssemblerX86Test, RepeatA) {
+  EXPECT_EQ("2(%eax,%ebx,1)\n", RepeatA(/*f*/ nullptr, addresses_singleton_, "{mem}"));
+}
+
+TEST_F(AssemblerX86Test, RepeatAI) {
+  EXPECT_EQ("2(%eax,%ebx,1) $0\n2(%eax,%ebx,1) $-1\n2(%eax,%ebx,1) $18\n",
+            RepeatAI(/*f*/ nullptr, /*imm_bytes*/ 1U, addresses_singleton_, "{mem} ${imm}"));
+}
+
+TEST_F(AssemblerX86Test, RepeatRA) {
+  EXPECT_EQ("%eax 2(%eax,%ebx,1)\n%ebx 2(%eax,%ebx,1)\n%ecx 2(%eax,%ebx,1)\n"
+            "%edx 2(%eax,%ebx,1)\n%ebp 2(%eax,%ebx,1)\n%esp 2(%eax,%ebx,1)\n"
+            "%esi 2(%eax,%ebx,1)\n%edi 2(%eax,%ebx,1)\n",
+            RepeatRA(/*f*/ nullptr, addresses_singleton_, "%{reg} {mem}"));
+}
+
+TEST_F(AssemblerX86Test, RepeatAR) {
+  EXPECT_EQ("2(%eax,%ebx,1) %eax\n2(%eax,%ebx,1) %ebx\n2(%eax,%ebx,1) %ecx\n"
+            "2(%eax,%ebx,1) %edx\n2(%eax,%ebx,1) %ebp\n2(%eax,%ebx,1) %esp\n"
+            "2(%eax,%ebx,1) %esi\n2(%eax,%ebx,1) %edi\n",
+            RepeatAR(/*f*/ nullptr, addresses_singleton_, "{mem} %{reg}"));
+}
+
+TEST_F(AssemblerX86Test, RepeatFA) {
+  EXPECT_EQ("%XMM0 2(%eax,%ebx,1)\n%XMM1 2(%eax,%ebx,1)\n%XMM2 2(%eax,%ebx,1)\n"
+            "%XMM3 2(%eax,%ebx,1)\n%XMM4 2(%eax,%ebx,1)\n%XMM5 2(%eax,%ebx,1)\n"
+            "%XMM6 2(%eax,%ebx,1)\n%XMM7 2(%eax,%ebx,1)\n",
+            RepeatFA(/*f*/ nullptr, addresses_singleton_, "%{reg} {mem}"));
+}
+
+TEST_F(AssemblerX86Test, RepeatAF) {
+  EXPECT_EQ("2(%eax,%ebx,1) %XMM0\n2(%eax,%ebx,1) %XMM1\n2(%eax,%ebx,1) %XMM2\n"
+            "2(%eax,%ebx,1) %XMM3\n2(%eax,%ebx,1) %XMM4\n2(%eax,%ebx,1) %XMM5\n"
+            "2(%eax,%ebx,1) %XMM6\n2(%eax,%ebx,1) %XMM7\n",
+            RepeatAF(/*f*/ nullptr, addresses_singleton_, "{mem} %{reg}"));
+}
+
 //
 // Actual x86 instruction assembler tests.
 //
 
 TEST_F(AssemblerX86Test, Movl) {
-  GetAssembler()->movl(x86::EAX, x86::EBX);
-  const char* expected = "mov %ebx, %eax\n";
-  DriverStr(expected, "movl");
+  DriverStr(RepeatRR(&x86::X86Assembler::movl, "movl %{reg2}, %{reg1}"), "movl");
+}
+
+TEST_F(AssemblerX86Test, MovlLoad) {
+  DriverStr(RepeatRA(&x86::X86Assembler::movl, "movl {mem}, %{reg}"), "movl-load");
+}
+
+TEST_F(AssemblerX86Test, MovlStore) {
+  DriverStr(RepeatAR(&x86::X86Assembler::movl, "movl %{reg}, {mem}"), "movl-store");
 }
 
 TEST_F(AssemblerX86Test, Movntl) {
-  GetAssembler()->movntl(x86::Address(x86::EDI, x86::EBX, x86::TIMES_4, 12), x86::EAX);
-  GetAssembler()->movntl(x86::Address(x86::EDI, 0), x86::EAX);
-  const char* expected =
-    "movntil %EAX, 0xc(%EDI,%EBX,4)\n"
-    "movntil %EAX, (%EDI)\n";
-
-  DriverStr(expected, "movntl");
+  DriverStr(RepeatAR(&x86::X86Assembler::movntl, "movntil %{reg}, {mem}"), "movntl");
 }
 
 TEST_F(AssemblerX86Test, LoadLongConstant) {
@@ -187,66 +262,29 @@
 }
 
 TEST_F(AssemblerX86Test, LockCmpxchgl) {
-  GetAssembler()->LockCmpxchgl(x86::Address(
-        x86::Register(x86::EDI), x86::Register(x86::EBX), x86::TIMES_4, 12),
-      x86::Register(x86::ESI));
-  GetAssembler()->LockCmpxchgl(x86::Address(
-        x86::Register(x86::EDI), x86::Register(x86::ESI), x86::TIMES_4, 12),
-      x86::Register(x86::ESI));
-  GetAssembler()->LockCmpxchgl(x86::Address(
-        x86::Register(x86::EDI), x86::Register(x86::ESI), x86::TIMES_4, 12),
-      x86::Register(x86::EDI));
-  GetAssembler()->LockCmpxchgl(x86::Address(
-      x86::Register(x86::EBP), 0), x86::Register(x86::ESI));
-  GetAssembler()->LockCmpxchgl(x86::Address(
-        x86::Register(x86::EBP), x86::Register(x86::ESI), x86::TIMES_1, 0),
-      x86::Register(x86::ESI));
-  const char* expected =
-    "lock cmpxchgl %ESI, 0xc(%EDI,%EBX,4)\n"
-    "lock cmpxchgl %ESI, 0xc(%EDI,%ESI,4)\n"
-    "lock cmpxchgl %EDI, 0xc(%EDI,%ESI,4)\n"
-    "lock cmpxchgl %ESI, (%EBP)\n"
-    "lock cmpxchgl %ESI, (%EBP,%ESI,1)\n";
-
-  DriverStr(expected, "lock_cmpxchgl");
+  DriverStr(RepeatAR(&x86::X86Assembler::LockCmpxchgl,
+                     "lock cmpxchgl %{reg}, {mem}"), "lock_cmpxchgl");
 }
 
 TEST_F(AssemblerX86Test, LockCmpxchg8b) {
-  GetAssembler()->LockCmpxchg8b(x86::Address(
-      x86::Register(x86::EDI), x86::Register(x86::EBX), x86::TIMES_4, 12));
-  GetAssembler()->LockCmpxchg8b(x86::Address(
-      x86::Register(x86::EDI), x86::Register(x86::ESI), x86::TIMES_4, 12));
-  GetAssembler()->LockCmpxchg8b(x86::Address(
-      x86::Register(x86::EDI), x86::Register(x86::ESI), x86::TIMES_4, 12));
-  GetAssembler()->LockCmpxchg8b(x86::Address(x86::Register(x86::EBP), 0));
-  GetAssembler()->LockCmpxchg8b(x86::Address(
-      x86::Register(x86::EBP), x86::Register(x86::ESI), x86::TIMES_1, 0));
-  const char* expected =
-    "lock cmpxchg8b 0xc(%EDI,%EBX,4)\n"
-    "lock cmpxchg8b 0xc(%EDI,%ESI,4)\n"
-    "lock cmpxchg8b 0xc(%EDI,%ESI,4)\n"
-    "lock cmpxchg8b (%EBP)\n"
-    "lock cmpxchg8b (%EBP,%ESI,1)\n";
-
-  DriverStr(expected, "lock_cmpxchg8b");
+  DriverStr(RepeatA(&x86::X86Assembler::LockCmpxchg8b,
+                    "lock cmpxchg8b {mem}"), "lock_cmpxchg8b");
 }
 
-TEST_F(AssemblerX86Test, FPUIntegerLoad) {
-  GetAssembler()->filds(x86::Address(x86::Register(x86::ESP), 4));
-  GetAssembler()->fildl(x86::Address(x86::Register(x86::ESP), 12));
-  const char* expected =
-      "fildl 0x4(%ESP)\n"
-      "fildll 0xc(%ESP)\n";
-  DriverStr(expected, "FPUIntegerLoad");
+TEST_F(AssemblerX86Test, FPUIntegerLoadS) {
+  DriverStr(RepeatA(&x86::X86Assembler::filds, "fildl {mem}"), "fildd");
 }
 
-TEST_F(AssemblerX86Test, FPUIntegerStore) {
-  GetAssembler()->fistps(x86::Address(x86::Register(x86::ESP), 16));
-  GetAssembler()->fistpl(x86::Address(x86::Register(x86::ESP), 24));
-  const char* expected =
-      "fistpl 0x10(%ESP)\n"
-      "fistpll 0x18(%ESP)\n";
-  DriverStr(expected, "FPUIntegerStore");
+TEST_F(AssemblerX86Test, FPUIntegerLoadL) {
+  DriverStr(RepeatA(&x86::X86Assembler::fildl, "fildll {mem}"), "fildl");
+}
+
+TEST_F(AssemblerX86Test, FPUIntegerStoreS) {
+  DriverStr(RepeatA(&x86::X86Assembler::fistps, "fistpl {mem}"), "fistps");
+}
+
+TEST_F(AssemblerX86Test, FPUIntegerStoreL) {
+  DriverStr(RepeatA(&x86::X86Assembler::fistpl, "fistpll {mem}"), "fistpl");
 }
 
 TEST_F(AssemblerX86Test, Repnescasb) {
@@ -296,12 +334,7 @@
 }
 
 TEST_F(AssemblerX86Test, BsflAddress) {
-  GetAssembler()->bsfl(x86::Register(x86::EDI), x86::Address(
-      x86::Register(x86::EDI), x86::Register(x86::EBX), x86::TIMES_4, 12));
-  const char* expected =
-    "bsfl 0xc(%EDI,%EBX,4), %EDI\n";
-
-  DriverStr(expected, "bsfl_address");
+  DriverStr(RepeatRA(&x86::X86Assembler::bsfl, "bsfl {mem}, %{reg}"), "bsfl_address");
 }
 
 TEST_F(AssemblerX86Test, Bsrl) {
@@ -309,12 +342,7 @@
 }
 
 TEST_F(AssemblerX86Test, BsrlAddress) {
-  GetAssembler()->bsrl(x86::Register(x86::EDI), x86::Address(
-      x86::Register(x86::EDI), x86::Register(x86::EBX), x86::TIMES_4, 12));
-  const char* expected =
-    "bsrl 0xc(%EDI,%EBX,4), %EDI\n";
-
-  DriverStr(expected, "bsrl_address");
+  DriverStr(RepeatRA(&x86::X86Assembler::bsrl, "bsrl {mem}, %{reg}"), "bsrl_address");
 }
 
 TEST_F(AssemblerX86Test, Popcntl) {
@@ -322,26 +350,18 @@
 }
 
 TEST_F(AssemblerX86Test, PopcntlAddress) {
-  GetAssembler()->popcntl(x86::Register(x86::EDI), x86::Address(
-      x86::Register(x86::EDI), x86::Register(x86::EBX), x86::TIMES_4, 12));
-  const char* expected =
-    "popcntl 0xc(%EDI,%EBX,4), %EDI\n";
-
-  DriverStr(expected, "popcntl_address");
+  DriverStr(RepeatRA(&x86::X86Assembler::popcntl, "popcntl {mem}, %{reg}"), "popcntl_address");
 }
 
 // Rorl only allows CL as the shift count.
 std::string rorl_fn(AssemblerX86Test::Base* assembler_test, x86::X86Assembler* assembler) {
   std::ostringstream str;
-
   std::vector<x86::Register*> registers = assembler_test->GetRegisters();
-
   x86::Register shifter(x86::ECX);
   for (auto reg : registers) {
     assembler->rorl(*reg, shifter);
     str << "rorl %cl, %" << assembler_test->GetRegisterName(*reg) << "\n";
   }
-
   return str.str();
 }
 
@@ -356,15 +376,12 @@
 // Roll only allows CL as the shift count.
 std::string roll_fn(AssemblerX86Test::Base* assembler_test, x86::X86Assembler* assembler) {
   std::ostringstream str;
-
   std::vector<x86::Register*> registers = assembler_test->GetRegisters();
-
   x86::Register shifter(x86::ECX);
   for (auto reg : registers) {
     assembler->roll(*reg, shifter);
     str << "roll %cl, %" << assembler_test->GetRegisterName(*reg) << "\n";
   }
-
   return str.str();
 }
 
@@ -385,41 +402,29 @@
 }
 
 TEST_F(AssemblerX86Test, ComissAddr) {
-  GetAssembler()->comiss(x86::XmmRegister(x86::XMM0), x86::Address(x86::EAX, 0));
-  const char* expected = "comiss 0(%EAX), %xmm0\n";
-  DriverStr(expected, "comiss");
+  DriverStr(RepeatFA(&x86::X86Assembler::comiss, "comiss {mem}, %{reg}"), "comiss");
 }
 
 TEST_F(AssemblerX86Test, UComissAddr) {
-  GetAssembler()->ucomiss(x86::XmmRegister(x86::XMM0), x86::Address(x86::EAX, 0));
-  const char* expected = "ucomiss 0(%EAX), %xmm0\n";
-  DriverStr(expected, "ucomiss");
+  DriverStr(RepeatFA(&x86::X86Assembler::ucomiss, "ucomiss {mem}, %{reg}"), "ucomiss");
 }
 
 TEST_F(AssemblerX86Test, ComisdAddr) {
-  GetAssembler()->comisd(x86::XmmRegister(x86::XMM0), x86::Address(x86::EAX, 0));
-  const char* expected = "comisd 0(%EAX), %xmm0\n";
-  DriverStr(expected, "comisd");
+  DriverStr(RepeatFA(&x86::X86Assembler::comisd, "comisd {mem}, %{reg}"), "comisd");
 }
 
 TEST_F(AssemblerX86Test, UComisdAddr) {
-  GetAssembler()->ucomisd(x86::XmmRegister(x86::XMM0), x86::Address(x86::EAX, 0));
-  const char* expected = "ucomisd 0(%EAX), %xmm0\n";
-  DriverStr(expected, "ucomisd");
+  DriverStr(RepeatFA(&x86::X86Assembler::ucomisd, "ucomisd {mem}, %{reg}"), "ucomisd");
 }
 
 TEST_F(AssemblerX86Test, RoundSS) {
-  GetAssembler()->roundss(
-      x86::XmmRegister(x86::XMM0), x86::XmmRegister(x86::XMM1), x86::Immediate(1));
-  const char* expected = "roundss $1, %xmm1, %xmm0\n";
-  DriverStr(expected, "roundss");
+  DriverStr(RepeatFFI(&x86::X86Assembler::roundss, 1U,
+                      "roundss ${imm}, %{reg2}, %{reg1}"), "roundss");
 }
 
 TEST_F(AssemblerX86Test, RoundSD) {
-  GetAssembler()->roundsd(
-      x86::XmmRegister(x86::XMM0), x86::XmmRegister(x86::XMM1), x86::Immediate(1));
-  const char* expected = "roundsd $1, %xmm1, %xmm0\n";
-  DriverStr(expected, "roundsd");
+  DriverStr(RepeatFFI(&x86::X86Assembler::roundsd, 1U,
+                      "roundsd ${imm}, %{reg2}, %{reg1}"), "roundsd");
 }
 
 TEST_F(AssemblerX86Test, CmovlAddress) {
@@ -433,110 +438,75 @@
     "cmovzl 0xc(%EDI,%EBX,4), %eax\n"
     "cmovnzl 0xc(%ESI,%EBX,4), %edi\n"
     "cmovzl 0xc(%EDI,%EAX,4), %edi\n";
-
   DriverStr(expected, "cmovl_address");
 }
 
 TEST_F(AssemblerX86Test, TestbAddressImmediate) {
-  GetAssembler()->testb(
-      x86::Address(x86::Register(x86::EDI), x86::Register(x86::EBX), x86::TIMES_4, 12),
-      x86::Immediate(1));
-  GetAssembler()->testb(
-      x86::Address(x86::Register(x86::ESP), FrameOffset(7)),
-      x86::Immediate(-128));
-  GetAssembler()->testb(
-      x86::Address(x86::Register(x86::EBX), MemberOffset(130)),
-      x86::Immediate(127));
-  const char* expected =
-      "testb $1, 0xc(%EDI,%EBX,4)\n"
-      "testb $-128, 0x7(%ESP)\n"
-      "testb $127, 0x82(%EBX)\n";
-
-  DriverStr(expected, "TestbAddressImmediate");
+  DriverStr(RepeatAI(&x86::X86Assembler::testb, /*imm_bytes*/ 1U, "testb ${imm}, {mem}"), "testb");
 }
 
 TEST_F(AssemblerX86Test, TestlAddressImmediate) {
-  GetAssembler()->testl(
-      x86::Address(x86::Register(x86::EDI), x86::Register(x86::EBX), x86::TIMES_4, 12),
-      x86::Immediate(1));
-  GetAssembler()->testl(
-      x86::Address(x86::Register(x86::ESP), FrameOffset(7)),
-      x86::Immediate(-100000));
-  GetAssembler()->testl(
-      x86::Address(x86::Register(x86::EBX), MemberOffset(130)),
-      x86::Immediate(77777777));
-  const char* expected =
-      "testl $1, 0xc(%EDI,%EBX,4)\n"
-      "testl $-100000, 0x7(%ESP)\n"
-      "testl $77777777, 0x82(%EBX)\n";
-
-  DriverStr(expected, "TestlAddressImmediate");
+  DriverStr(RepeatAI(&x86::X86Assembler::testl, /*imm_bytes*/ 4U, "testl ${imm}, {mem}"), "testl");
 }
 
 TEST_F(AssemblerX86Test, Movaps) {
   DriverStr(RepeatFF(&x86::X86Assembler::movaps, "movaps %{reg2}, %{reg1}"), "movaps");
 }
 
-TEST_F(AssemblerX86Test, MovapsAddr) {
-  GetAssembler()->movaps(x86::XmmRegister(x86::XMM0), x86::Address(x86::Register(x86::ESP), 4));
-  GetAssembler()->movaps(x86::Address(x86::Register(x86::ESP), 2), x86::XmmRegister(x86::XMM1));
-  const char* expected =
-    "movaps 0x4(%ESP), %xmm0\n"
-    "movaps %xmm1, 0x2(%ESP)\n";
-  DriverStr(expected, "movaps_address");
+TEST_F(AssemblerX86Test, MovapsLoad) {
+  DriverStr(RepeatFA(&x86::X86Assembler::movaps, "movaps {mem}, %{reg}"), "movaps_load");
 }
 
-TEST_F(AssemblerX86Test, MovupsAddr) {
-  GetAssembler()->movups(x86::XmmRegister(x86::XMM0), x86::Address(x86::Register(x86::ESP), 4));
-  GetAssembler()->movups(x86::Address(x86::Register(x86::ESP), 2), x86::XmmRegister(x86::XMM1));
-  const char* expected =
-    "movups 0x4(%ESP), %xmm0\n"
-    "movups %xmm1, 0x2(%ESP)\n";
-  DriverStr(expected, "movups_address");
+TEST_F(AssemblerX86Test, MovapsStore) {
+  DriverStr(RepeatAF(&x86::X86Assembler::movaps, "movaps %{reg}, {mem}"), "movaps_store");
+}
+
+TEST_F(AssemblerX86Test, MovupsLoad) {
+  DriverStr(RepeatFA(&x86::X86Assembler::movups, "movups {mem}, %{reg}"), "movups_load");
+}
+
+TEST_F(AssemblerX86Test, MovupsStore) {
+  DriverStr(RepeatAF(&x86::X86Assembler::movups, "movups %{reg}, {mem}"), "movups_store");
 }
 
 TEST_F(AssemblerX86Test, Movapd) {
   DriverStr(RepeatFF(&x86::X86Assembler::movapd, "movapd %{reg2}, %{reg1}"), "movapd");
 }
 
-TEST_F(AssemblerX86Test, MovapdAddr) {
-  GetAssembler()->movapd(x86::XmmRegister(x86::XMM0), x86::Address(x86::Register(x86::ESP), 4));
-  GetAssembler()->movapd(x86::Address(x86::Register(x86::ESP), 2), x86::XmmRegister(x86::XMM1));
-  const char* expected =
-    "movapd 0x4(%ESP), %xmm0\n"
-    "movapd %xmm1, 0x2(%ESP)\n";
-  DriverStr(expected, "movapd_address");
+TEST_F(AssemblerX86Test, MovapdLoad) {
+  DriverStr(RepeatFA(&x86::X86Assembler::movapd, "movapd {mem}, %{reg}"), "movapd_load");
 }
 
-TEST_F(AssemblerX86Test, MovupdAddr) {
-  GetAssembler()->movupd(x86::XmmRegister(x86::XMM0), x86::Address(x86::Register(x86::ESP), 4));
-  GetAssembler()->movupd(x86::Address(x86::Register(x86::ESP), 2), x86::XmmRegister(x86::XMM1));
-  const char* expected =
-    "movupd 0x4(%ESP), %xmm0\n"
-    "movupd %xmm1, 0x2(%ESP)\n";
-  DriverStr(expected, "movupd_address");
+TEST_F(AssemblerX86Test, MovapdStore) {
+  DriverStr(RepeatAF(&x86::X86Assembler::movapd, "movapd %{reg}, {mem}"), "movapd_store");
+}
+
+TEST_F(AssemblerX86Test, MovupdLoad) {
+  DriverStr(RepeatFA(&x86::X86Assembler::movupd, "movupd {mem}, %{reg}"), "movupd_load");
+}
+
+TEST_F(AssemblerX86Test, MovupdStore) {
+  DriverStr(RepeatAF(&x86::X86Assembler::movupd, "movupd %{reg}, {mem}"), "movupd_store");
 }
 
 TEST_F(AssemblerX86Test, Movdqa) {
   DriverStr(RepeatFF(&x86::X86Assembler::movdqa, "movdqa %{reg2}, %{reg1}"), "movdqa");
 }
 
-TEST_F(AssemblerX86Test, MovdqaAddr) {
-  GetAssembler()->movdqa(x86::XmmRegister(x86::XMM0), x86::Address(x86::Register(x86::ESP), 4));
-  GetAssembler()->movdqa(x86::Address(x86::Register(x86::ESP), 2), x86::XmmRegister(x86::XMM1));
-  const char* expected =
-    "movdqa 0x4(%ESP), %xmm0\n"
-    "movdqa %xmm1, 0x2(%ESP)\n";
-  DriverStr(expected, "movdqa_address");
+TEST_F(AssemblerX86Test, MovdqaLoad) {
+  DriverStr(RepeatFA(&x86::X86Assembler::movdqa, "movdqa {mem}, %{reg}"), "movdqa_load");
 }
 
-TEST_F(AssemblerX86Test, MovdquAddr) {
-  GetAssembler()->movdqu(x86::XmmRegister(x86::XMM0), x86::Address(x86::Register(x86::ESP), 4));
-  GetAssembler()->movdqu(x86::Address(x86::Register(x86::ESP), 2), x86::XmmRegister(x86::XMM1));
-  const char* expected =
-    "movdqu 0x4(%ESP), %xmm0\n"
-    "movdqu %xmm1, 0x2(%ESP)\n";
-  DriverStr(expected, "movdqu_address");
+TEST_F(AssemblerX86Test, MovdqaStore) {
+  DriverStr(RepeatAF(&x86::X86Assembler::movdqa, "movdqa %{reg}, {mem}"), "movdqa_store");
+}
+
+TEST_F(AssemblerX86Test, MovdquLoad) {
+  DriverStr(RepeatFA(&x86::X86Assembler::movdqu, "movdqu {mem}, %{reg}"), "movdqu_load");
+}
+
+TEST_F(AssemblerX86Test, MovdquStore) {
+  DriverStr(RepeatAF(&x86::X86Assembler::movdqu, "movdqu %{reg}, {mem}"), "movdqu_store");
 }
 
 TEST_F(AssemblerX86Test, AddPS) {
@@ -901,7 +871,6 @@
     "jecxz 1f\n"
     "addl 4(%ESP),%EDI\n"
     "1:\n";
-
   DriverStr(expected, "jecxz");
 }
 
@@ -923,14 +892,11 @@
     "addl 4(%ESP),%EDI\n"
     "2: jne 1b\n"
     "jmp 1b\n";
-
   DriverStr(expected, "near_label");
 }
 
 TEST_F(AssemblerX86Test, Cmpb) {
-  GetAssembler()->cmpb(x86::Address(x86::EDI, 128), x86::Immediate(0));
-  const char* expected = "cmpb $0, 128(%EDI)\n";
-  DriverStr(expected, "cmpb");
+  DriverStr(RepeatAI(&x86::X86Assembler::cmpb, /*imm_bytes*/ 1U, "cmpb ${imm}, {mem}"), "cmpb");
 }
 
 }  // namespace art
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index 29de925..3e6110d 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -130,11 +130,17 @@
 // Test fixture.
 //
 
-class AssemblerX86_64Test : public AssemblerTest<x86_64::X86_64Assembler, x86_64::CpuRegister,
-                                                 x86_64::XmmRegister, x86_64::Immediate> {
+class AssemblerX86_64Test : public AssemblerTest<x86_64::X86_64Assembler,
+                                                 x86_64::Address,
+                                                 x86_64::CpuRegister,
+                                                 x86_64::XmmRegister,
+                                                 x86_64::Immediate> {
  public:
-  typedef AssemblerTest<x86_64::X86_64Assembler, x86_64::CpuRegister,
-                        x86_64::XmmRegister, x86_64::Immediate> Base;
+  typedef AssemblerTest<x86_64::X86_64Assembler,
+                        x86_64::Address,
+                        x86_64::CpuRegister,
+                        x86_64::XmmRegister,
+                        x86_64::Immediate> Base;
 
  protected:
   // Get the typically used name for this architecture, e.g., aarch64, x86-64, ...
@@ -241,6 +247,11 @@
     STLDeleteElements(&fp_registers_);
   }
 
+  std::vector<x86_64::Address> GetAddresses() {
+    UNIMPLEMENTED(FATAL) << "Feature not implemented yet";
+    UNREACHABLE();
+  }
+
   std::vector<x86_64::CpuRegister*> GetRegisters() OVERRIDE {
     return registers_;
   }