Add assembler for riscv64, part 1.

Test: m test-art-host-gtest

Bug: 271573990
Signed-off-by: Lifang Xia <lifang_xia@linux.alibaba.com>
Signed-off-by: Wendong Wang <wangwd@xcvmbyte.com>
Signed-off-by: Cao Xia <caoxia@eswincomputing.com>
Change-Id: Ie1306521b8df28173b9be40f754e114bd849985b
diff --git a/compiler/Android.bp b/compiler/Android.bp
index a879bd8..ea45897 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -132,6 +132,7 @@
         },
         riscv64: {
             srcs: [
+                "utils/riscv64/assembler_riscv64.cc",
                 "utils/riscv64/managed_register_riscv64.cc",
             ],
         },
@@ -551,6 +552,11 @@
                 "utils/assembler_thumb_test.cc",
             ],
         },
+        riscv64 : {
+            srcs: [
+                "utils/riscv64/assembler_riscv64_test.cc",
+            ],
+        },
         x86: {
             srcs: [
                 "utils/x86/assembler_x86_test.cc",
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index d03e5a7..f8a7f61 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -488,6 +488,19 @@
                                                          fmt);
   }
 
+  std::string RepeatFFFF(void (Ass::*f)(FPReg, FPReg, FPReg, FPReg), const std::string& fmt) {
+    return RepeatTemplatedRegisters<FPReg, FPReg, FPReg, FPReg>(f,
+                                                                GetFPRegisters(),
+                                                                GetFPRegisters(),
+                                                                GetFPRegisters(),
+                                                                GetFPRegisters(),
+                                                                &AssemblerTest::GetFPRegName,
+                                                                &AssemblerTest::GetFPRegName,
+                                                                &AssemblerTest::GetFPRegName,
+                                                                &AssemblerTest::GetFPRegName,
+                                                                fmt);
+  }
+
   std::string RepeatFFR(void (Ass::*f)(FPReg, FPReg, Reg), const std::string& fmt) {
     return RepeatTemplatedRegisters<FPReg, FPReg, Reg>(
         f,
@@ -538,6 +551,32 @@
                                                                   fmt);
   }
 
+  std::string RepeatRFF(void (Ass::*f)(Reg, FPReg, FPReg), const std::string& fmt) {
+    return RepeatTemplatedRegisters<Reg, FPReg, FPReg>(
+        f,
+        GetRegisters(),
+        GetFPRegisters(),
+        GetFPRegisters(),
+        &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+        &AssemblerTest::GetFPRegName,
+        &AssemblerTest::GetFPRegName,
+        fmt);
+  }
+
+  template <typename ImmType>
+  std::string RepeatRFIb(void (Ass::*f)(Reg, FPReg, ImmType),
+                         int imm_bits,
+                         const std::string& fmt) {
+    return RepeatTemplatedRegistersImmBits<Reg, FPReg, ImmType>(
+        f,
+        imm_bits,
+        GetRegisters(),
+        GetFPRegisters(),
+        &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+        &AssemblerTest::GetFPRegName,
+        fmt);
+  }
+
   std::string RepeatFR(void (Ass::*f)(FPReg, Reg), const std::string& fmt) {
     return RepeatTemplatedRegisters<FPReg, Reg>(f,
         GetFPRegisters(),
@@ -1417,6 +1456,64 @@
     return str;
   }
 
+  template <typename Reg1, typename Reg2, typename Reg3, typename Reg4>
+  std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3, Reg4),
+                                       const std::vector<Reg1*>& reg1_registers,
+                                       const std::vector<Reg2*>& reg2_registers,
+                                       const std::vector<Reg3*>& reg3_registers,
+                                       const std::vector<Reg4*>& reg4_registers,
+                                       std::string (AssemblerTest::*GetName1)(const Reg1&),
+                                       std::string (AssemblerTest::*GetName2)(const Reg2&),
+                                       std::string (AssemblerTest::*GetName3)(const Reg3&),
+                                       std::string (AssemblerTest::*GetName4)(const Reg4&),
+                                       const std::string& fmt) {
+    std::string str;
+    for (auto reg1 : reg1_registers) {
+      for (auto reg2 : reg2_registers) {
+        for (auto reg3 : reg3_registers) {
+          for (auto reg4 : reg4_registers) {
+            if (f != nullptr) {
+              (assembler_.get()->*f)(*reg1, *reg2, *reg3, *reg4);
+            }
+            std::string base = fmt;
+
+            std::string reg1_string = (this->*GetName1)(*reg1);
+            size_t reg1_index;
+            while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
+              base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
+            }
+
+            std::string reg2_string = (this->*GetName2)(*reg2);
+            size_t reg2_index;
+            while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
+              base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
+            }
+
+            std::string reg3_string = (this->*GetName3)(*reg3);
+            size_t reg3_index;
+            while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
+              base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
+            }
+
+            std::string reg4_string = (this->*GetName4)(*reg4);
+            size_t reg4_index;
+            while ((reg4_index = base.find(REG4_TOKEN)) != std::string::npos) {
+              base.replace(reg4_index, ConstexprStrLen(REG3_TOKEN), reg4_string);
+            }
+
+            if (str.size() > 0) {
+              str += "\n";
+            }
+            str += base;
+          }
+        }
+      }
+    }
+    // Add a newline at the end.
+    str += "\n";
+    return str;
+  }
+
   template <typename Reg1, typename Reg2>
   std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
                                           const std::vector<Reg1*> reg1_registers,
@@ -1522,6 +1619,7 @@
   static constexpr const char* REG1_TOKEN = "{reg1}";
   static constexpr const char* REG2_TOKEN = "{reg2}";
   static constexpr const char* REG3_TOKEN = "{reg3}";
+  static constexpr const char* REG4_TOKEN = "{reg4}";
   static constexpr const char* IMM_TOKEN = "{imm}";
 
  private:
diff --git a/compiler/utils/assembler_test_base.h b/compiler/utils/assembler_test_base.h
index 73f3657..8b76643 100644
--- a/compiler/utils/assembler_test_base.h
+++ b/compiler/utils/assembler_test_base.h
@@ -141,6 +141,9 @@
   virtual std::vector<std::string> GetAssemblerCommand() {
     InstructionSet isa = GetIsa();
     switch (isa) {
+      case InstructionSet::kRiscv64:
+        // TODO: Support compression (RV32C) in assembler and tests (add `c` to `-march=`).
+        return {FindTool("clang"), "--compile", "-target", "riscv64-linux-gnu", "-march=rv64imafd"};
       case InstructionSet::kX86:
         return {FindTool("clang"), "--compile", "-target", "i386-linux-gnu"};
       case InstructionSet::kX86_64:
@@ -159,6 +162,13 @@
                 "--no-print-imm-hex",
                 "--triple",
                 "thumbv7a-linux-gnueabi"};
+      case InstructionSet::kRiscv64:
+        return {FindTool("llvm-objdump"),
+                "--disassemble",
+                "--no-print-imm-hex",
+                "--no-show-raw-insn",
+                "-M",
+                "no-aliases"};
       default:
         return {
             FindTool("llvm-objdump"), "--disassemble", "--no-print-imm-hex", "--no-show-raw-insn"};
diff --git a/compiler/utils/riscv64/assembler_riscv64.cc b/compiler/utils/riscv64/assembler_riscv64.cc
new file mode 100644
index 0000000..cc2d526
--- /dev/null
+++ b/compiler/utils/riscv64/assembler_riscv64.cc
@@ -0,0 +1,621 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "assembler_riscv64.h"
+
+#include "base/bit_utils.h"
+#include "base/casts.h"
+#include "base/memory_region.h"
+
+namespace art {
+namespace riscv64 {
+
+static_assert(static_cast<size_t>(kRiscv64PointerSize) == kRiscv64DoublewordSize,
+              "Unexpected Riscv64 pointer size.");
+static_assert(kRiscv64PointerSize == PointerSize::k64, "Unexpected Riscv64 pointer size.");
+
+void Riscv64Assembler::FinalizeCode() {
+}
+
+void Riscv64Assembler::FinalizeInstructions(const MemoryRegion& region) {
+  Assembler::FinalizeInstructions(region);
+}
+
+void Riscv64Assembler::Emit(uint32_t value) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  buffer_.Emit<uint32_t>(value);
+}
+
+/////////////////////////////// RV64 VARIANTS extension ///////////////////////////////
+
+/////////////////////////////// RV64 "IM" Instructions ///////////////////////////////
+
+// Load instructions (RV32I+RV64I): opcode = 0x03, funct3 from 0x0 ~ 0x6
+
+void Riscv64Assembler::Lb(XRegister rd, XRegister rs1, int32_t offset) {
+  EmitI(offset, rs1, 0x0, rd, 0x03);
+}
+
+void Riscv64Assembler::Lh(XRegister rd, XRegister rs1, int32_t offset) {
+  EmitI(offset, rs1, 0x1, rd, 0x03);
+}
+
+void Riscv64Assembler::Lw(XRegister rd, XRegister rs1, int32_t offset) {
+  EmitI(offset, rs1, 0x2, rd, 0x03);
+}
+
+void Riscv64Assembler::Ld(XRegister rd, XRegister rs1, int32_t offset) {
+  EmitI(offset, rs1, 0x3, rd, 0x03);
+}
+
+void Riscv64Assembler::Lbu(XRegister rd, XRegister rs1, int32_t offset) {
+  EmitI(offset, rs1, 0x4, rd, 0x03);
+}
+
+void Riscv64Assembler::Lhu(XRegister rd, XRegister rs1, int32_t offset) {
+  EmitI(offset, rs1, 0x5, rd, 0x03);
+}
+
+void Riscv64Assembler::Lwu(XRegister rd, XRegister rs1, int32_t offset) {
+  EmitI(offset, rs1, 0x6, rd, 0x3);
+}
+
+// Store instructions (RV32I+RV64I): opcode = 0x23, funct3 from 0x0 ~ 0x3
+
+void Riscv64Assembler::Sb(XRegister rs2, XRegister rs1, int32_t offset) {
+  EmitS(offset, rs2, rs1, 0x0, 0x23);
+}
+
+void Riscv64Assembler::Sh(XRegister rs2, XRegister rs1, int32_t offset) {
+  EmitS(offset, rs2, rs1, 0x1, 0x23);
+}
+
+void Riscv64Assembler::Sw(XRegister rs2, XRegister rs1, int32_t offset) {
+  EmitS(offset, rs2, rs1, 0x2, 0x23);
+}
+
+void Riscv64Assembler::Sd(XRegister rs2, XRegister rs1, int32_t offset) {
+  EmitS(offset, rs2, rs1, 0x3, 0x23);
+}
+
+// IMM ALU instructions (RV32I): opcode = 0x13, funct3 from 0x0 ~ 0x7
+
+void Riscv64Assembler::Addi(XRegister rd, XRegister rs1, int32_t imm12) {
+  EmitI(imm12, rs1, 0x0, rd, 0x13);
+}
+
+void Riscv64Assembler::Slti(XRegister rd, XRegister rs1, int32_t imm12) {
+  EmitI(imm12, rs1, 0x2, rd, 0x13);
+}
+
+void Riscv64Assembler::Sltiu(XRegister rd, XRegister rs1, int32_t imm12) {
+  EmitI(imm12, rs1, 0x3, rd, 0x13);
+}
+
+void Riscv64Assembler::Xori(XRegister rd, XRegister rs1, int32_t imm12) {
+  EmitI(imm12, rs1, 0x4, rd, 0x13);
+}
+
+void Riscv64Assembler::Ori(XRegister rd, XRegister rs1, int32_t imm12) {
+  EmitI(imm12, rs1, 0x6, rd, 0x13);
+}
+
+void Riscv64Assembler::Andi(XRegister rd, XRegister rs1, int32_t imm12) {
+  EmitI(imm12, rs1, 0x7, rd, 0x13);
+}
+
+// 0x1 Split: 0x0(6b) + imm12(6b)
+void Riscv64Assembler::Slli(XRegister rd, XRegister rs1, int32_t shamt) {
+  CHECK(static_cast<uint32_t>(shamt) < 64) << shamt;
+  EmitI6(0x0, shamt, rs1, 0x1, rd, 0x13);
+}
+
+// 0x5 Split: 0x0(6b) + imm12(6b)
+void Riscv64Assembler::Srli(XRegister rd, XRegister rs1, int32_t shamt) {
+  CHECK(static_cast<uint32_t>(shamt) < 64) << shamt;
+  EmitI6(0x0, shamt, rs1, 0x5, rd, 0x13);
+}
+
+// 0x5 Split: 0x10(6b) + imm12(6b)
+void Riscv64Assembler::Srai(XRegister rd, XRegister rs1, int32_t shamt) {
+  CHECK(static_cast<uint32_t>(shamt) < 64) << shamt;
+  EmitI6(0x10, shamt, rs1, 0x5, rd, 0x13);
+}
+
+// ALU instructions (RV32I): opcode = 0x33, funct3 from 0x0 ~ 0x7
+
+void Riscv64Assembler::Add(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x0, rs2, rs1, 0x0, rd, 0x33);
+}
+
+void Riscv64Assembler::Sub(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x20, rs2, rs1, 0x0, rd, 0x33);
+}
+
+void Riscv64Assembler::Slt(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x0, rs2, rs1, 0x02, rd, 0x33);
+}
+
+void Riscv64Assembler::Sltu(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x0, rs2, rs1, 0x03, rd, 0x33);
+}
+
+void Riscv64Assembler::Xor(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x0, rs2, rs1, 0x04, rd, 0x33);
+}
+
+void Riscv64Assembler::Or(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x0, rs2, rs1, 0x06, rd, 0x33);
+}
+
+void Riscv64Assembler::And(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x0, rs2, rs1, 0x07, rd, 0x33);
+}
+
+void Riscv64Assembler::Sll(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x0, rs2, rs1, 0x01, rd, 0x33);
+}
+
+void Riscv64Assembler::Srl(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x0, rs2, rs1, 0x05, rd, 0x33);
+}
+
+void Riscv64Assembler::Sra(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x20, rs2, rs1, 0x05, rd, 0x33);
+}
+
+// 32bit Imm ALU instructions (RV64I): opcode = 0x1b, funct3 from 0x0, 0x1, 0x5
+
+void Riscv64Assembler::Addiw(XRegister rd, XRegister rs1, int32_t imm12) {
+  EmitI(imm12, rs1, 0x0, rd, 0x1b);
+}
+
+void Riscv64Assembler::Slliw(XRegister rd, XRegister rs1, int32_t shamt) {
+  CHECK(static_cast<uint32_t>(shamt) < 32) << shamt;
+  EmitR(0x0, shamt, rs1, 0x1, rd, 0x1b);
+}
+
+void Riscv64Assembler::Srliw(XRegister rd, XRegister rs1, int32_t shamt) {
+  CHECK(static_cast<uint32_t>(shamt) < 32) << shamt;
+  EmitR(0x0, shamt, rs1, 0x5, rd, 0x1b);
+}
+
+void Riscv64Assembler::Sraiw(XRegister rd, XRegister rs1, int32_t shamt) {
+  CHECK(static_cast<uint32_t>(shamt) < 32) << shamt;
+  EmitR(0x20, shamt, rs1, 0x5, rd, 0x1b);
+}
+
+// 32bit ALU instructions (RV64I): opcode = 0x3b, funct3 from 0x0 ~ 0x7
+
+void Riscv64Assembler::Addw(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x0, rs2, rs1, 0x0, rd, 0x3b);
+}
+
+void Riscv64Assembler::Subw(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x20, rs2, rs1, 0x0, rd, 0x3b);
+}
+
+void Riscv64Assembler::Sllw(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x0, rs2, rs1, 0x1, rd, 0x3b);
+}
+
+void Riscv64Assembler::Srlw(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x0, rs2, rs1, 0x5, rd, 0x3b);
+}
+
+void Riscv64Assembler::Sraw(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x20, rs2, rs1, 0x5, rd, 0x3b);
+}
+
+// RV32M Standard Extension: opcode = 0x33, funct3 from 0x0 ~ 0x7
+
+void Riscv64Assembler::Mul(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x1, rs2, rs1, 0x0, rd, 0x33);
+}
+
+void Riscv64Assembler::Mulh(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x1, rs2, rs1, 0x1, rd, 0x33);
+}
+
+void Riscv64Assembler::Mulhsu(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x1, rs2, rs1, 0x2, rd, 0x33);
+}
+
+void Riscv64Assembler::Mulhu(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x1, rs2, rs1, 0x3, rd, 0x33);
+}
+
+void Riscv64Assembler::Div(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x1, rs2, rs1, 0x4, rd, 0x33);
+}
+
+void Riscv64Assembler::Divu(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x1, rs2, rs1, 0x5, rd, 0x33);
+}
+
+void Riscv64Assembler::Rem(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x1, rs2, rs1, 0x6, rd, 0x33);
+}
+
+void Riscv64Assembler::Remu(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x1, rs2, rs1, 0x7, rd, 0x33);
+}
+
+// RV64M Standard Extension: opcode = 0x3b, funct3 0x0 and from 0x4 ~ 0x7
+
+void Riscv64Assembler::Mulw(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x1, rs2, rs1, 0x0, rd, 0x3b);
+}
+
+void Riscv64Assembler::Divw(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x1, rs2, rs1, 0x4, rd, 0x3b);
+}
+
+void Riscv64Assembler::Divuw(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x1, rs2, rs1, 0x5, rd, 0x3b);
+}
+
+void Riscv64Assembler::Remw(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x1, rs2, rs1, 0x6, rd, 0x3b);
+}
+
+void Riscv64Assembler::Remuw(XRegister rd, XRegister rs1, XRegister rs2) {
+  EmitR(0x1, rs2, rs1, 0x7, rd, 0x3b);
+}
+
+/////////////////////////////// RV64 "IM" Instructions  END ///////////////////////////////
+
+/////////////////////////////// RV64 "FD" Instructions  START ///////////////////////////////
+
+// FP load/store instructions (RV32F+RV32D): opcode = 0x07, 0x27
+
+void Riscv64Assembler::FLw(FRegister rd, XRegister rs1, int32_t offset) {
+  EmitI(offset, rs1, 0x2, rd, 0x07);
+}
+
+void Riscv64Assembler::FLd(FRegister rd, XRegister rs1, int32_t offset) {
+  EmitI(offset, rs1, 0x3, rd, 0x07);
+}
+
+void Riscv64Assembler::FSw(FRegister rs2, XRegister rs1, int32_t offset) {
+  EmitS(offset, rs2, rs1, 0x2, 0x27);
+}
+
+void Riscv64Assembler::FSd(FRegister rs2, XRegister rs1, int32_t offset) {
+  EmitS(offset, rs2, rs1, 0x3, 0x27);
+}
+
+// FP FMA instructions (RV32F+RV32D): opcode = 0x43, 0x47, 0x4b, 0x4f
+
+void Riscv64Assembler::FMAddS(
+    FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm) {
+  EmitR4(rs3, 0x0, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x43);
+}
+
+void Riscv64Assembler::FMAddD(
+    FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm) {
+  EmitR4(rs3, 0x1, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x43);
+}
+
+void Riscv64Assembler::FMSubS(
+    FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm) {
+  EmitR4(rs3, 0x0, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x47);
+}
+
+void Riscv64Assembler::FMSubD(
+    FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm) {
+  EmitR4(rs3, 0x1, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x47);
+}
+
+void Riscv64Assembler::FNMSubS(
+    FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm) {
+  EmitR4(rs3, 0x0, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x4b);
+}
+
+void Riscv64Assembler::FNMSubD(
+    FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm) {
+  EmitR4(rs3, 0x1, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x4b);
+}
+
+void Riscv64Assembler::FNMAddS(
+    FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm) {
+  EmitR4(rs3, 0x0, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x4f);
+}
+
+void Riscv64Assembler::FNMAddD(
+    FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm) {
+  EmitR4(rs3, 0x1, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x4f);
+}
+
+// Simple FP instructions (RV32F+RV32D): opcode = 0x53, funct7 = 0b0XXXX0D
+
+void Riscv64Assembler::FAddS(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm) {
+  EmitR(0x0, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FAddD(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm) {
+  EmitR(0x1, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FSubS(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm) {
+  EmitR(0x4, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FSubD(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm) {
+  EmitR(0x5, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FMulS(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm) {
+  EmitR(0x8, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FMulD(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm) {
+  EmitR(0x9, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FDivS(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm) {
+  EmitR(0xc, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FDivD(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm) {
+  EmitR(0xd, rs2, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FSqrtS(FRegister rd, FRegister rs1, FPRoundingMode frm) {
+  EmitR(0x2c, 0x0, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FSqrtD(FRegister rd, FRegister rs1, FPRoundingMode frm) {
+  EmitR(0x2d, 0x0, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FSgnjS(FRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x10, rs2, rs1, 0x0, rd, 0x53);
+}
+
+void Riscv64Assembler::FSgnjD(FRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x11, rs2, rs1, 0x0, rd, 0x53);
+}
+
+void Riscv64Assembler::FSgnjnS(FRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x10, rs2, rs1, 0x1, rd, 0x53);
+}
+
+void Riscv64Assembler::FSgnjnD(FRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x11, rs2, rs1, 0x1, rd, 0x53);
+}
+
+void Riscv64Assembler::FSgnjxS(FRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x10, rs2, rs1, 0x2, rd, 0x53);
+}
+
+void Riscv64Assembler::FSgnjxD(FRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x11, rs2, rs1, 0x2, rd, 0x53);
+}
+
+void Riscv64Assembler::FMinS(FRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x14, rs2, rs1, 0x0, rd, 0x53);
+}
+
+void Riscv64Assembler::FMinD(FRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x15, rs2, rs1, 0x0, rd, 0x53);
+}
+
+void Riscv64Assembler::FMaxS(FRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x14, rs2, rs1, 0x1, rd, 0x53);
+}
+
+void Riscv64Assembler::FMaxD(FRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x15, rs2, rs1, 0x1, rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtSD(FRegister rd, FRegister rs1, FPRoundingMode frm) {
+  EmitR(0x20, 0x1, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtDS(FRegister rd, FRegister rs1, FPRoundingMode frm) {
+  // Note: The `frm` is useless, the result can represent every value of the source exactly.
+  EmitR(0x21, 0x0, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+// FP compare instructions (RV32F+RV32D): opcode = 0x53, funct7 = 0b101000D
+
+void Riscv64Assembler::FEqS(XRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x50, rs2, rs1, 0x2, rd, 0x53);
+}
+
+void Riscv64Assembler::FEqD(XRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x51, rs2, rs1, 0x2, rd, 0x53);
+}
+
+void Riscv64Assembler::FLtS(XRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x50, rs2, rs1, 0x1, rd, 0x53);
+}
+
+void Riscv64Assembler::FLtD(XRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x51, rs2, rs1, 0x1, rd, 0x53);
+}
+
+void Riscv64Assembler::FLeS(XRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x50, rs2, rs1, 0x0, rd, 0x53);
+}
+
+void Riscv64Assembler::FLeD(XRegister rd, FRegister rs1, FRegister rs2) {
+  EmitR(0x51, rs2, rs1, 0x0, rd, 0x53);
+}
+
+// FP conversion instructions (RV32F+RV32D+RV64F+RV64D): opcode = 0x53, funct7 = 0b110X00D
+
+void Riscv64Assembler::FCvtWS(XRegister rd, FRegister rs1, FPRoundingMode frm) {
+  EmitR(0x60, 0x0, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtWD(XRegister rd, FRegister rs1, FPRoundingMode frm) {
+  EmitR(0x61, 0x0, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtWuS(XRegister rd, FRegister rs1, FPRoundingMode frm) {
+  EmitR(0x60, 0x1, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtWuD(XRegister rd, FRegister rs1, FPRoundingMode frm) {
+  EmitR(0x61, 0x1, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtLS(XRegister rd, FRegister rs1, FPRoundingMode frm) {
+  EmitR(0x60, 0x2, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtLD(XRegister rd, FRegister rs1, FPRoundingMode frm) {
+  EmitR(0x61, 0x2, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtLuS(XRegister rd, FRegister rs1, FPRoundingMode frm) {
+  EmitR(0x60, 0x3, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtLuD(XRegister rd, FRegister rs1, FPRoundingMode frm) {
+  EmitR(0x61, 0x3, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtSW(FRegister rd, XRegister rs1, FPRoundingMode frm) {
+  EmitR(0x68, 0x0, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtDW(FRegister rd, XRegister rs1, FPRoundingMode frm) {
+  // Note: The `frm` is useless, the result can represent every value of the source exactly.
+  EmitR(0x69, 0x0, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtSWu(FRegister rd, XRegister rs1, FPRoundingMode frm) {
+  EmitR(0x68, 0x1, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtDWu(FRegister rd, XRegister rs1, FPRoundingMode frm) {
+  // Note: The `frm` is useless, the result can represent every value of the source exactly.
+  EmitR(0x69, 0x1, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtSL(FRegister rd, XRegister rs1, FPRoundingMode frm) {
+  EmitR(0x68, 0x2, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtDL(FRegister rd, XRegister rs1, FPRoundingMode frm) {
+  EmitR(0x69, 0x2, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtSLu(FRegister rd, XRegister rs1, FPRoundingMode frm) {
+  EmitR(0x68, 0x3, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+void Riscv64Assembler::FCvtDLu(FRegister rd, XRegister rs1, FPRoundingMode frm) {
+  EmitR(0x69, 0x3, rs1, enum_cast<uint32_t>(frm), rd, 0x53);
+}
+
+// FP move instructions (RV32F+RV32D): opcode = 0x53, funct3 = 0x0, funct7 = 0b111X00D
+
+void Riscv64Assembler::FMvXW(XRegister rd, FRegister rs1) {
+  EmitR(0x70, 0x0, rs1, 0x0, rd, 0x53);
+}
+
+void Riscv64Assembler::FMvXD(XRegister rd, FRegister rs1) {
+  EmitR(0x71, 0x0, rs1, 0x0, rd, 0x53);
+}
+
+void Riscv64Assembler::FMvWX(FRegister rd, XRegister rs1) {
+  EmitR(0x78, 0x0, rs1, 0x0, rd, 0x53);
+}
+
+void Riscv64Assembler::FMvDX(FRegister rd, XRegister rs1) {
+  EmitR(0x79, 0x0, rs1, 0x0, rd, 0x53);
+}
+
+// FP classify instructions (RV32F+RV32D): opcode = 0x53, funct3 = 0x1, funct7 = 0b111X00D
+
+void Riscv64Assembler::FClassS(XRegister rd, FRegister rs1) {
+  EmitR(0x70, 0x0, rs1, 0x1, rd, 0x53);
+}
+
+void Riscv64Assembler::FClassD(XRegister rd, FRegister rs1) {
+  EmitR(0x71, 0x0, rs1, 0x1, rd, 0x53);
+}
+
+/////////////////////////////// RV64 "FD" Instructions  END ///////////////////////////////
+
+////////////////////////////// RV64 MACRO Instructions  START ///////////////////////////////
+
+// Pseudo instructions
+
+void Riscv64Assembler::Nop() { Addi(Zero, Zero, 0); }
+
+void Riscv64Assembler::Mv(XRegister rd, XRegister rs) { Addi(rd, rs, 0); }
+
+void Riscv64Assembler::Not(XRegister rd, XRegister rs) { Xori(rd, rs, -1); }
+
+void Riscv64Assembler::Neg(XRegister rd, XRegister rs) { Sub(rd, Zero, rs); }
+
+void Riscv64Assembler::NegW(XRegister rd, XRegister rs) { Subw(rd, Zero, rs); }
+
+void Riscv64Assembler::SextB(XRegister rd, XRegister rs) {
+  Slli(rd, rs, kXlen - 8u);
+  Srai(rd, rd, kXlen - 8u);
+}
+
+void Riscv64Assembler::SextH(XRegister rd, XRegister rs) {
+  Slli(rd, rs, kXlen - 16u);
+  Srai(rd, rd, kXlen - 16u);
+}
+
+void Riscv64Assembler::SextW(XRegister rd, XRegister rs) { Addiw(rd, rs, 0); }
+
+void Riscv64Assembler::ZextB(XRegister rd, XRegister rs) { Andi(rd, rs, 0xff); }
+
+void Riscv64Assembler::ZextH(XRegister rd, XRegister rs) {
+  Slli(rd, rs, kXlen - 16u);
+  Srli(rd, rd, kXlen - 16u);
+}
+
+void Riscv64Assembler::ZextW(XRegister rd, XRegister rs) {
+  Slli(rd, rs, kXlen - 32u);
+  Srli(rd, rd, kXlen - 32u);
+}
+
+void Riscv64Assembler::Seqz(XRegister rd, XRegister rs) { Sltiu(rd, rs, 1); }
+
+void Riscv64Assembler::Snez(XRegister rd, XRegister rs) { Sltu(rd, Zero, rs); }
+
+void Riscv64Assembler::Sltz(XRegister rd, XRegister rs) { Slt(rd, rs, Zero); }
+
+void Riscv64Assembler::Sgtz(XRegister rd, XRegister rs) { Slt(rd, Zero, rs); }
+
+void Riscv64Assembler::FMvS(FRegister rd, FRegister rs) { FSgnjS(rd, rs, rs); }
+
+void Riscv64Assembler::FAbsS(FRegister rd, FRegister rs) { FSgnjxS(rd, rs, rs); }
+
+void Riscv64Assembler::FNegS(FRegister rd, FRegister rs) { FSgnjnS(rd, rs, rs); }
+
+void Riscv64Assembler::FMvD(FRegister rd, FRegister rs) { FSgnjS(rd, rs, rs); }
+
+void Riscv64Assembler::FAbsD(FRegister rd, FRegister rs) { FSgnjxS(rd, rs, rs); }
+
+void Riscv64Assembler::FNegD(FRegister rd, FRegister rs) { FSgnjnS(rd, rs, rs); }
+
+/////////////////////////////// RV64 MACRO Instructions END ///////////////////////////////
+
+/////////////////////////////// RV64 VARIANTS extension end ////////////
+
+}  // namespace riscv64
+}  // namespace art
diff --git a/compiler/utils/riscv64/assembler_riscv64.h b/compiler/utils/riscv64/assembler_riscv64.h
new file mode 100644
index 0000000..b648a71
--- /dev/null
+++ b/compiler/utils/riscv64/assembler_riscv64.h
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_UTILS_RISCV64_ASSEMBLER_RISCV64_H_
+#define ART_COMPILER_UTILS_RISCV64_ASSEMBLER_RISCV64_H_
+
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "arch/riscv64/instruction_set_features_riscv64.h"
+#include "base/arena_containers.h"
+#include "base/enums.h"
+#include "base/globals.h"
+#include "base/macros.h"
+#include "managed_register_riscv64.h"
+#include "utils/assembler.h"
+#include "utils/label.h"
+
+namespace art {
+namespace riscv64 {
+
+enum class FPRoundingMode : uint32_t {
+    kRNE = 0x0,  // Round to Nearest, ties to Even
+    kRTZ = 0x1,  // Round towards Zero
+    kRDN = 0x2,  // Round Down (towards −Infinity)
+    kRUP = 0x3,  // Round Up (towards +Infinity)
+    kRMM = 0x4,  // Round to Nearest, ties to Max Magnitude
+    kDYN = 0x7,  // Dynamic rounding mode
+    kDefault = kDYN
+};
+
+static constexpr size_t kRiscv64HalfwordSize = 2;
+static constexpr size_t kRiscv64WordSize = 4;
+static constexpr size_t kRiscv64DoublewordSize = 8;
+
+class Riscv64Label : public Label {
+};
+
+class Riscv64Assembler final : public Assembler {
+ public:
+  explicit Riscv64Assembler(ArenaAllocator* allocator,
+                            const Riscv64InstructionSetFeatures* instruction_set_features = nullptr)
+      : Assembler(allocator) {
+    UNUSED(instruction_set_features);
+  }
+
+  virtual ~Riscv64Assembler() {
+  }
+
+  size_t CodeSize() const override { return Assembler::CodeSize(); }
+  DebugFrameOpCodeWriterForAssembler& cfi() { return Assembler::cfi(); }
+
+  // Load instructions (RV32I+RV64I): opcode = 0x03, funct3 from 0x0 ~ 0x6
+  void Lb(XRegister rd, XRegister rs1, int32_t offset);
+  void Lh(XRegister rd, XRegister rs1, int32_t offset);
+  void Lw(XRegister rd, XRegister rs1, int32_t offset);
+  void Ld(XRegister rd, XRegister rs1, int32_t offset);
+  void Lbu(XRegister rd, XRegister rs1, int32_t offset);
+  void Lhu(XRegister rd, XRegister rs1, int32_t offset);
+  void Lwu(XRegister rd, XRegister rs1, int32_t offset);
+
+  // Store instructions (RV32I+RV64I): opcode = 0x23, funct3 from 0x0 ~ 0x3
+  void Sb(XRegister rs2, XRegister rs1, int32_t offset);
+  void Sh(XRegister rs2, XRegister rs1, int32_t offset);
+  void Sw(XRegister rs2, XRegister rs1, int32_t offset);
+  void Sd(XRegister rs2, XRegister rs1, int32_t offset);
+
+  // IMM ALU instructions (RV32I): opcode = 0x13, funct3 from 0x0 ~ 0x7
+  void Addi(XRegister rd, XRegister rs1, int32_t imm12);
+  void Slti(XRegister rd, XRegister rs1, int32_t imm12);
+  void Sltiu(XRegister rd, XRegister rs1, int32_t imm12);
+  void Xori(XRegister rd, XRegister rs1, int32_t imm12);
+  void Ori(XRegister rd, XRegister rs1, int32_t imm12);
+  void Andi(XRegister rd, XRegister rs1, int32_t imm12);
+  void Slli(XRegister rd, XRegister rs1, int32_t shamt);
+  void Srli(XRegister rd, XRegister rs1, int32_t shamt);
+  void Srai(XRegister rd, XRegister rs1, int32_t shamt);
+
+  // ALU instructions (RV32I): opcode = 0x33, funct3 from 0x0 ~ 0x7
+  void Add(XRegister rd, XRegister rs1, XRegister rs2);
+  void Sub(XRegister rd, XRegister rs1, XRegister rs2);
+  void Slt(XRegister rd, XRegister rs1, XRegister rs2);
+  void Sltu(XRegister rd, XRegister rs1, XRegister rs2);
+  void Xor(XRegister rd, XRegister rs1, XRegister rs2);
+  void Or(XRegister rd, XRegister rs1, XRegister rs2);
+  void And(XRegister rd, XRegister rs1, XRegister rs2);
+  void Sll(XRegister rd, XRegister rs1, XRegister rs2);
+  void Srl(XRegister rd, XRegister rs1, XRegister rs2);
+  void Sra(XRegister rd, XRegister rs1, XRegister rs2);
+
+  // 32bit Imm ALU instructions (RV64I): opcode = 0x1b, funct3 from 0x0, 0x1, 0x5
+  void Addiw(XRegister rd, XRegister rs1, int32_t imm12);
+  void Slliw(XRegister rd, XRegister rs1, int32_t shamt);
+  void Srliw(XRegister rd, XRegister rs1, int32_t shamt);
+  void Sraiw(XRegister rd, XRegister rs1, int32_t shamt);
+
+  // 32bit ALU instructions (RV64I): opcode = 0x3b, funct3 from 0x0 ~ 0x7
+  void Addw(XRegister rd, XRegister rs1, XRegister rs2);
+  void Subw(XRegister rd, XRegister rs1, XRegister rs2);
+  void Sllw(XRegister rd, XRegister rs1, XRegister rs2);
+  void Srlw(XRegister rd, XRegister rs1, XRegister rs2);
+  void Sraw(XRegister rd, XRegister rs1, XRegister rs2);
+
+  // RV32M Standard Extension: opcode = 0x33, funct3 from 0x0 ~ 0x7
+  void Mul(XRegister rd, XRegister rs1, XRegister rs2);
+  void Mulh(XRegister rd, XRegister rs1, XRegister rs2);
+  void Mulhsu(XRegister rd, XRegister rs1, XRegister rs2);
+  void Mulhu(XRegister rd, XRegister rs1, XRegister rs2);
+  void Div(XRegister rd, XRegister rs1, XRegister rs2);
+  void Divu(XRegister rd, XRegister rs1, XRegister rs2);
+  void Rem(XRegister rd, XRegister rs1, XRegister rs2);
+  void Remu(XRegister rd, XRegister rs1, XRegister rs2);
+
+  // RV64M Standard Extension: opcode = 0x3b, funct3 0x0 and from 0x4 ~ 0x7
+  void Mulw(XRegister rd, XRegister rs1, XRegister rs2);
+  void Divw(XRegister rd, XRegister rs1, XRegister rs2);
+  void Divuw(XRegister rd, XRegister rs1, XRegister rs2);
+  void Remw(XRegister rd, XRegister rs1, XRegister rs2);
+  void Remuw(XRegister rd, XRegister rs1, XRegister rs2);
+
+  // FP load/store instructions (RV32F+RV32D): opcode = 0x07, 0x27
+  void FLw(FRegister rd, XRegister rs1, int32_t offset);
+  void FLd(FRegister rd, XRegister rs1, int32_t offset);
+  void FSw(FRegister rs2, XRegister rs1, int32_t offset);
+  void FSd(FRegister rs2, XRegister rs1, int32_t offset);
+
+  // FP FMA instructions (RV32F+RV32D): opcode = 0x43, 0x47, 0x4b, 0x4f
+  void FMAddS(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm);
+  void FMAddD(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm);
+  void FMSubS(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm);
+  void FMSubD(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm);
+  void FNMSubS(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm);
+  void FNMSubD(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm);
+  void FNMAddS(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm);
+  void FNMAddD(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3, FPRoundingMode frm);
+
+  // FP FMA instruction helpers passing the default rounding mode.
+  void FMAddS(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3) {
+    FMAddS(rd, rs1, rs2, rs3, FPRoundingMode::kDefault);
+  }
+  void FMAddD(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3) {
+    FMAddD(rd, rs1, rs2, rs3, FPRoundingMode::kDefault);
+  }
+  void FMSubS(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3) {
+    FMSubS(rd, rs1, rs2, rs3, FPRoundingMode::kDefault);
+  }
+  void FMSubD(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3) {
+    FMSubD(rd, rs1, rs2, rs3, FPRoundingMode::kDefault);
+  }
+  void FNMSubS(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3) {
+    FNMSubS(rd, rs1, rs2, rs3, FPRoundingMode::kDefault);
+  }
+  void FNMSubD(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3) {
+    FNMSubD(rd, rs1, rs2, rs3, FPRoundingMode::kDefault);
+  }
+  void FNMAddS(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3) {
+    FNMAddS(rd, rs1, rs2, rs3, FPRoundingMode::kDefault);
+  }
+  void FNMAddD(FRegister rd, FRegister rs1, FRegister rs2, FRegister rs3) {
+    FNMAddD(rd, rs1, rs2, rs3, FPRoundingMode::kDefault);
+  }
+
+  // Simple FP instructions (RV32F+RV32D): opcode = 0x53, funct7 = 0b0XXXX0D
+  void FAddS(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm);
+  void FAddD(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm);
+  void FSubS(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm);
+  void FSubD(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm);
+  void FMulS(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm);
+  void FMulD(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm);
+  void FDivS(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm);
+  void FDivD(FRegister rd, FRegister rs1, FRegister rs2, FPRoundingMode frm);
+  void FSqrtS(FRegister rd, FRegister rs1, FPRoundingMode frm);
+  void FSqrtD(FRegister rd, FRegister rs1, FPRoundingMode frm);
+  void FSgnjS(FRegister rd, FRegister rs1, FRegister rs2);
+  void FSgnjD(FRegister rd, FRegister rs1, FRegister rs2);
+  void FSgnjnS(FRegister rd, FRegister rs1, FRegister rs2);
+  void FSgnjnD(FRegister rd, FRegister rs1, FRegister rs2);
+  void FSgnjxS(FRegister rd, FRegister rs1, FRegister rs2);
+  void FSgnjxD(FRegister rd, FRegister rs1, FRegister rs2);
+  void FMinS(FRegister rd, FRegister rs1, FRegister rs2);
+  void FMinD(FRegister rd, FRegister rs1, FRegister rs2);
+  void FMaxS(FRegister rd, FRegister rs1, FRegister rs2);
+  void FMaxD(FRegister rd, FRegister rs1, FRegister rs2);
+  void FCvtSD(FRegister rd, FRegister rs1, FPRoundingMode frm);
+  void FCvtDS(FRegister rd, FRegister rs1, FPRoundingMode frm);
+
+  // Simple FP instruction helpers passing the default rounding mode.
+  void FAddS(FRegister rd, FRegister rs1, FRegister rs2) {
+    FAddS(rd, rs1, rs2, FPRoundingMode::kDefault);
+  }
+  void FAddD(FRegister rd, FRegister rs1, FRegister rs2) {
+    FAddD(rd, rs1, rs2, FPRoundingMode::kDefault);
+  }
+  void FSubS(FRegister rd, FRegister rs1, FRegister rs2) {
+    FSubS(rd, rs1, rs2, FPRoundingMode::kDefault);
+  }
+  void FSubD(FRegister rd, FRegister rs1, FRegister rs2) {
+    FSubD(rd, rs1, rs2, FPRoundingMode::kDefault);
+  }
+  void FMulS(FRegister rd, FRegister rs1, FRegister rs2) {
+    FMulS(rd, rs1, rs2, FPRoundingMode::kDefault);
+  }
+  void FMulD(FRegister rd, FRegister rs1, FRegister rs2) {
+    FMulD(rd, rs1, rs2, FPRoundingMode::kDefault);
+  }
+  void FDivS(FRegister rd, FRegister rs1, FRegister rs2) {
+    FDivS(rd, rs1, rs2, FPRoundingMode::kDefault);
+  }
+  void FDivD(FRegister rd, FRegister rs1, FRegister rs2) {
+    FDivD(rd, rs1, rs2, FPRoundingMode::kDefault);
+  }
+  void FSqrtS(FRegister rd, FRegister rs1) {
+    FSqrtS(rd, rs1, FPRoundingMode::kDefault);
+  }
+  void FSqrtD(FRegister rd, FRegister rs1) {
+    FSqrtD(rd, rs1, FPRoundingMode::kDefault);
+  }
+  void FCvtSD(FRegister rd, FRegister rs1) {
+    FCvtSD(rd, rs1, FPRoundingMode::kDefault);
+  }
+  void FCvtDS(FRegister rd, FRegister rs1) {
+    FCvtDS(rd, rs1, FPRoundingMode::kDefault);
+  }
+
+  // FP compare instructions (RV32F+RV32D): opcode = 0x53, funct7 = 0b101000D
+  void FEqS(XRegister rd, FRegister rs1, FRegister rs2);
+  void FEqD(XRegister rd, FRegister rs1, FRegister rs2);
+  void FLtS(XRegister rd, FRegister rs1, FRegister rs2);
+  void FLtD(XRegister rd, FRegister rs1, FRegister rs2);
+  void FLeS(XRegister rd, FRegister rs1, FRegister rs2);
+  void FLeD(XRegister rd, FRegister rs1, FRegister rs2);
+
+  // FP conversion instructions (RV32F+RV32D+RV64F+RV64D): opcode = 0x53, funct7 = 0b110X00D
+  void FCvtWS(XRegister rd, FRegister rs1, FPRoundingMode frm);
+  void FCvtWD(XRegister rd, FRegister rs1, FPRoundingMode frm);
+  void FCvtWuS(XRegister rd, FRegister rs1, FPRoundingMode frm);
+  void FCvtWuD(XRegister rd, FRegister rs1, FPRoundingMode frm);
+  void FCvtLS(XRegister rd, FRegister rs1, FPRoundingMode frm);
+  void FCvtLD(XRegister rd, FRegister rs1, FPRoundingMode frm);
+  void FCvtLuS(XRegister rd, FRegister rs1, FPRoundingMode frm);
+  void FCvtLuD(XRegister rd, FRegister rs1, FPRoundingMode frm);
+  void FCvtSW(FRegister rd, XRegister rs1, FPRoundingMode frm);
+  void FCvtDW(FRegister rd, XRegister rs1, FPRoundingMode frm);
+  void FCvtSWu(FRegister rd, XRegister rs1, FPRoundingMode frm);
+  void FCvtDWu(FRegister rd, XRegister rs1, FPRoundingMode frm);
+  void FCvtSL(FRegister rd, XRegister rs1, FPRoundingMode frm);
+  void FCvtDL(FRegister rd, XRegister rs1, FPRoundingMode frm);
+  void FCvtSLu(FRegister rd, XRegister rs1, FPRoundingMode frm);
+  void FCvtDLu(FRegister rd, XRegister rs1, FPRoundingMode frm);
+
+  // FP conversion instruction helpers passing the default rounding mode.
+  void FCvtWS(XRegister rd, FRegister rs1) { FCvtWS(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtWD(XRegister rd, FRegister rs1) { FCvtWD(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtWuS(XRegister rd, FRegister rs1) { FCvtWuS(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtWuD(XRegister rd, FRegister rs1) { FCvtWuD(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtLS(XRegister rd, FRegister rs1) { FCvtLS(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtLD(XRegister rd, FRegister rs1) { FCvtLD(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtLuS(XRegister rd, FRegister rs1) { FCvtLuS(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtLuD(XRegister rd, FRegister rs1) { FCvtLuD(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtSW(FRegister rd, XRegister rs1) { FCvtSW(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtDW(FRegister rd, XRegister rs1) { FCvtDW(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtSWu(FRegister rd, XRegister rs1) { FCvtSWu(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtDWu(FRegister rd, XRegister rs1) { FCvtDWu(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtSL(FRegister rd, XRegister rs1) { FCvtSL(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtDL(FRegister rd, XRegister rs1) { FCvtDL(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtSLu(FRegister rd, XRegister rs1) { FCvtSLu(rd, rs1, FPRoundingMode::kDefault); }
+  void FCvtDLu(FRegister rd, XRegister rs1) { FCvtDLu(rd, rs1, FPRoundingMode::kDefault); }
+
+  // FP move instructions (RV32F+RV32D): opcode = 0x53, funct3 = 0x0, funct7 = 0b111X00D
+  void FMvXW(XRegister rd, FRegister rs1);
+  void FMvXD(XRegister rd, FRegister rs1);
+  void FMvWX(FRegister rd, XRegister rs1);
+  void FMvDX(FRegister rd, XRegister rs1);
+
+  // FP classify instructions (RV32F+RV32D): opcode = 0x53, funct3 = 0x1, funct7 = 0b111X00D
+  void FClassS(XRegister rd, FRegister rs1);
+  void FClassD(XRegister rd, FRegister rs1);
+
+  ////////////////////////////// RV64 MACRO Instructions  START ///////////////////////////////
+  // These pseudo instructions are from "RISC-V ASM manual".
+  void Nop();
+  void Mv(XRegister rd, XRegister rs);
+  void Not(XRegister rd, XRegister rs);
+  void Neg(XRegister rd, XRegister rs);
+  void NegW(XRegister rd, XRegister rs);
+  void SextB(XRegister rd, XRegister rs);
+  void SextH(XRegister rd, XRegister rs);
+  void SextW(XRegister rd, XRegister rs);
+  void ZextB(XRegister rd, XRegister rs);
+  void ZextH(XRegister rd, XRegister rs);
+  void ZextW(XRegister rd, XRegister rs);
+  void Seqz(XRegister rd, XRegister rs);
+  void Snez(XRegister rd, XRegister rs);
+  void Sltz(XRegister rd, XRegister rs);
+  void Sgtz(XRegister rd, XRegister rs);
+  void FMvS(FRegister rd, FRegister rs);
+  void FAbsS(FRegister rd, FRegister rs);
+  void FNegS(FRegister rd, FRegister rs);
+  void FMvD(FRegister rd, FRegister rs);
+  void FAbsD(FRegister rd, FRegister rs);
+  void FNegD(FRegister rd, FRegister rs);
+  /////////////////////////////// RV64 MACRO Instructions END ///////////////////////////////
+
+  void Bind(Label* label ATTRIBUTE_UNUSED) override {
+    UNIMPLEMENTED(FATAL) << "TODO: Support branches.";
+  }
+  void Jump(Label* label ATTRIBUTE_UNUSED) override {
+    UNIMPLEMENTED(FATAL) << "Do not use Jump for RISCV64";
+  }
+
+ public:
+  // Emit data (e.g. encoded instruction or immediate) to the instruction stream.
+  void Emit(uint32_t value);
+
+  // Emit slow paths queued during assembly and promote short branches to long if needed.
+  void FinalizeCode() override;
+
+  // Emit branches and finalize all instructions.
+  void FinalizeInstructions(const MemoryRegion& region) override;
+
+ private:
+  template <typename Reg1, typename Reg2>
+  void EmitI(int32_t imm12, Reg1 rs1, uint32_t funct3, Reg2 rd, uint32_t opcode) {
+    DCHECK(IsInt<12>(imm12)) << imm12;
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rs1)));
+    DCHECK(IsUint<3>(funct3));
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rd)));
+    DCHECK(IsUint<7>(opcode));
+    uint32_t encoding = static_cast<uint32_t>(imm12) << 20 | static_cast<uint32_t>(rs1) << 15 |
+                        funct3 << 12 | static_cast<uint32_t>(rd) << 7 | opcode;
+    Emit(encoding);
+  }
+
+  template <typename Reg1, typename Reg2, typename Reg3>
+  void EmitR(uint32_t funct7, Reg1 rs2, Reg2 rs1, uint32_t funct3, Reg3 rd, uint32_t opcode) {
+    DCHECK(IsUint<7>(funct7));
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rs2)));
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rs1)));
+    DCHECK(IsUint<3>(funct3));
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rd)));
+    DCHECK(IsUint<7>(opcode));
+    uint32_t encoding = funct7 << 25 | static_cast<uint32_t>(rs2) << 20 |
+                        static_cast<uint32_t>(rs1) << 15 | funct3 << 12 |
+                        static_cast<uint32_t>(rd) << 7 | opcode;
+    Emit(encoding);
+  }
+
+  template <typename Reg1, typename Reg2, typename Reg3, typename Reg4>
+  void EmitR4(Reg1 rs3,
+              uint32_t funct2,
+              Reg2 rs2,
+              Reg3 rs1,
+              uint32_t funct3,
+              Reg4 rd,
+              uint32_t opcode) {
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rs3)));
+    DCHECK(IsUint<2>(funct2));
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rs2)));
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rs1)));
+    DCHECK(IsUint<3>(funct3));
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rd)));
+    DCHECK(IsUint<7>(opcode));
+    uint32_t encoding = static_cast<uint32_t>(rs3) << 27 | static_cast<uint32_t>(funct2) << 25 |
+                        static_cast<uint32_t>(rs2) << 20 | static_cast<uint32_t>(rs1) << 15 |
+                        static_cast<uint32_t>(funct3) << 12 | static_cast<uint32_t>(rd) << 7 |
+                        opcode;
+    Emit(encoding);
+  }
+
+  template <typename Reg1, typename Reg2>
+  void EmitS(int32_t imm12, Reg1 rs2, Reg2 rs1, uint32_t funct3, uint32_t opcode) {
+    DCHECK(IsInt<12>(imm12)) << imm12;
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rs2)));
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rs1)));
+    DCHECK(IsUint<3>(funct3));
+    DCHECK(IsUint<7>(opcode));
+    uint32_t encoding = (static_cast<uint32_t>(imm12) & 0xFE0) << 20 |
+                        static_cast<uint32_t>(rs2) << 20 | static_cast<uint32_t>(rs1) << 15 |
+                        static_cast<uint32_t>(funct3) << 12 |
+                        (static_cast<uint32_t>(imm12) & 0x1F) << 7 | opcode;
+    Emit(encoding);
+  }
+
+  void EmitI6(uint32_t funct6,
+              uint32_t imm6,
+              XRegister rs1,
+              uint32_t funct3,
+              XRegister rd,
+              uint32_t opcode) {
+    DCHECK(IsUint<6>(funct6));
+    DCHECK(IsUint<6>(imm6)) << imm6;
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rs1)));
+    DCHECK(IsUint<3>(funct3));
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rd)));
+    DCHECK(IsUint<7>(opcode));
+    uint32_t encoding = funct6 << 26 | static_cast<uint32_t>(imm6) << 20 |
+                        static_cast<uint32_t>(rs1) << 15 | funct3 << 12 |
+                        static_cast<uint32_t>(rd) << 7 | opcode;
+    Emit(encoding);
+  }
+
+  static constexpr uint32_t kXlen = 64;
+
+  DISALLOW_COPY_AND_ASSIGN(Riscv64Assembler);
+};
+
+}  // namespace riscv64
+}  // namespace art
+
+#endif  // ART_COMPILER_UTILS_RISCV64_ASSEMBLER_RISCV64_H_
diff --git a/compiler/utils/riscv64/assembler_riscv64_test.cc b/compiler/utils/riscv64/assembler_riscv64_test.cc
new file mode 100644
index 0000000..019191c
--- /dev/null
+++ b/compiler/utils/riscv64/assembler_riscv64_test.cc
@@ -0,0 +1,774 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "assembler_riscv64.h"
+
+#include <inttypes.h>
+
+#include <map>
+
+#include "base/bit_utils.h"
+#include "utils/assembler_test.h"
+
+#define __ GetAssembler()->
+
+namespace art {
+
+struct RISCV64CpuRegisterCompare {
+  bool operator()(const riscv64::XRegister& a, const riscv64::XRegister& b) const { return a < b; }
+};
+
+class AssemblerRISCV64Test : public AssemblerTest<riscv64::Riscv64Assembler,
+                                                  riscv64::Riscv64Label,
+                                                  riscv64::XRegister,
+                                                  riscv64::FRegister,
+                                                  uint32_t> {
+ public:
+  using Base = AssemblerTest<riscv64::Riscv64Assembler,
+                             riscv64::Riscv64Label,
+                             riscv64::XRegister,
+                             riscv64::FRegister,
+                             uint32_t>;
+
+  AssemblerRISCV64Test()
+      : instruction_set_features_(Riscv64InstructionSetFeatures::FromVariant("default", nullptr)) {}
+
+ protected:
+  riscv64::Riscv64Assembler* CreateAssembler(ArenaAllocator* allocator) override {
+    return new (allocator) riscv64::Riscv64Assembler(allocator, instruction_set_features_.get());
+  }
+
+  InstructionSet GetIsa() override { return InstructionSet::kRiscv64; }
+
+  void SetUpHelpers() override {
+    if (registers_.size() == 0) {
+      registers_.push_back(new riscv64::XRegister(riscv64::Zero));
+      registers_.push_back(new riscv64::XRegister(riscv64::RA));
+      registers_.push_back(new riscv64::XRegister(riscv64::SP));
+      registers_.push_back(new riscv64::XRegister(riscv64::GP));
+      registers_.push_back(new riscv64::XRegister(riscv64::TP));
+      registers_.push_back(new riscv64::XRegister(riscv64::T0));
+      registers_.push_back(new riscv64::XRegister(riscv64::T1));
+      registers_.push_back(new riscv64::XRegister(riscv64::T2));
+      registers_.push_back(new riscv64::XRegister(riscv64::S0));
+      registers_.push_back(new riscv64::XRegister(riscv64::S1));
+      registers_.push_back(new riscv64::XRegister(riscv64::A0));
+      registers_.push_back(new riscv64::XRegister(riscv64::A1));
+      registers_.push_back(new riscv64::XRegister(riscv64::A2));
+      registers_.push_back(new riscv64::XRegister(riscv64::A3));
+      registers_.push_back(new riscv64::XRegister(riscv64::A4));
+      registers_.push_back(new riscv64::XRegister(riscv64::A5));
+      registers_.push_back(new riscv64::XRegister(riscv64::A6));
+      registers_.push_back(new riscv64::XRegister(riscv64::A7));
+      registers_.push_back(new riscv64::XRegister(riscv64::S2));
+      registers_.push_back(new riscv64::XRegister(riscv64::S3));
+      registers_.push_back(new riscv64::XRegister(riscv64::S4));
+      registers_.push_back(new riscv64::XRegister(riscv64::S5));
+      registers_.push_back(new riscv64::XRegister(riscv64::S6));
+      registers_.push_back(new riscv64::XRegister(riscv64::S7));
+      registers_.push_back(new riscv64::XRegister(riscv64::S8));
+      registers_.push_back(new riscv64::XRegister(riscv64::S9));
+      registers_.push_back(new riscv64::XRegister(riscv64::S10));
+      registers_.push_back(new riscv64::XRegister(riscv64::S11));
+      registers_.push_back(new riscv64::XRegister(riscv64::T3));
+      registers_.push_back(new riscv64::XRegister(riscv64::T4));
+      registers_.push_back(new riscv64::XRegister(riscv64::T5));
+      registers_.push_back(new riscv64::XRegister(riscv64::T6));
+
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::Zero), "zero");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::RA), "ra");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::SP), "sp");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::GP), "gp");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::TP), "tp");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::T0), "t0");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::T1), "t1");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::T2), "t2");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::S0), "s0");  // s0/fp
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::S1), "s1");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::A0), "a0");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::A1), "a1");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::A2), "a2");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::A3), "a3");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::A4), "a4");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::A5), "a5");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::A6), "a6");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::A7), "a7");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::S2), "s2");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::S3), "s3");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::S4), "s4");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::S5), "s5");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::S6), "s6");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::S7), "s7");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::S8), "s8");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::S9), "s9");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::S10), "s10");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::S11), "s11");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::T3), "t3");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::T4), "t4");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::T5), "t5");
+      secondary_register_names_.emplace(riscv64::XRegister(riscv64::T6), "t6");
+
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FT0));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FT1));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FT2));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FT3));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FT4));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FT5));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FT6));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FT7));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FS0));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FS1));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FA0));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FA1));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FA2));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FA3));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FA4));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FA5));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FA6));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FA7));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FS2));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FS3));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FS4));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FS5));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FS6));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FS7));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FS8));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FS9));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FS10));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FS11));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FT8));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FT9));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FT10));
+      fp_registers_.push_back(new riscv64::FRegister(riscv64::FT11));
+    }
+  }
+
+  void TearDown() override {
+    AssemblerTest::TearDown();
+    STLDeleteElements(&registers_);
+    STLDeleteElements(&fp_registers_);
+  }
+
+  std::vector<riscv64::Riscv64Label> GetAddresses() override {
+    UNIMPLEMENTED(FATAL) << "Feature not implemented yet";
+    UNREACHABLE();
+  }
+
+  std::vector<riscv64::XRegister*> GetRegisters() override { return registers_; }
+
+  std::vector<riscv64::FRegister*> GetFPRegisters() override { return fp_registers_; }
+
+  std::string GetSecondaryRegisterName(const riscv64::XRegister& reg) override {
+    CHECK(secondary_register_names_.find(reg) != secondary_register_names_.end());
+    return secondary_register_names_[reg];
+  }
+
+  uint32_t CreateImmediate(int64_t imm_value) override { return imm_value; }
+
+ private:
+  std::vector<riscv64::XRegister*> registers_;
+  std::map<riscv64::XRegister, std::string, RISCV64CpuRegisterCompare> secondary_register_names_;
+
+  std::vector<riscv64::FRegister*> fp_registers_;
+
+  std::unique_ptr<const Riscv64InstructionSetFeatures> instruction_set_features_;
+};
+
+TEST_F(AssemblerRISCV64Test, Toolchain) { EXPECT_TRUE(CheckTools()); }
+
+TEST_F(AssemblerRISCV64Test, Lb) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lb, -11, "lb {reg1}, {imm}({reg2})"), "Lb");
+}
+
+TEST_F(AssemblerRISCV64Test, Lh) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lh, -11, "lh {reg1}, {imm}({reg2})"), "Lh");
+}
+
+TEST_F(AssemblerRISCV64Test, Lw) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lw, -11, "lw {reg1}, {imm}({reg2})"), "Lw");
+}
+
+TEST_F(AssemblerRISCV64Test, Ld) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Ld, -11, "ld {reg1}, {imm}({reg2})"), "Ld");
+}
+
+TEST_F(AssemblerRISCV64Test, Lbu) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lbu, -11, "lbu {reg1}, {imm}({reg2})"), "Lbu");
+}
+
+TEST_F(AssemblerRISCV64Test, Lhu) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lhu, -11, "lhu {reg1}, {imm}({reg2})"), "Lhu");
+}
+
+TEST_F(AssemblerRISCV64Test, Lwu) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lwu, -11, "lwu {reg1}, {imm}({reg2})"), "Lwu");
+}
+
+TEST_F(AssemblerRISCV64Test, Sb) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sb, -11, "sb {reg1}, {imm}({reg2})"), "Sb");
+}
+
+TEST_F(AssemblerRISCV64Test, Sh) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sh, -11, "sh {reg1}, {imm}({reg2})"), "Sh");
+}
+
+TEST_F(AssemblerRISCV64Test, Sw) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sw, -11, "sw {reg1}, {imm}({reg2})"), "Sw");
+}
+
+TEST_F(AssemblerRISCV64Test, Sd) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sd, -11, "sd {reg1}, {imm}({reg2})"), "Sd");
+}
+
+TEST_F(AssemblerRISCV64Test, Addi) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Addi, -11, "addi {reg1}, {reg2}, {imm}"),
+            "Addi");
+}
+
+TEST_F(AssemblerRISCV64Test, Slti) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Slti, -11, "slti {reg1}, {reg2}, {imm}"),
+            "Slti");
+}
+
+TEST_F(AssemblerRISCV64Test, Sltiu) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sltiu, -11, "sltiu {reg1}, {reg2}, {imm}"),
+            "Sltiu");
+}
+
+TEST_F(AssemblerRISCV64Test, Xori) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Xori, 11, "xori {reg1}, {reg2}, {imm}"), "Xori");
+}
+
+TEST_F(AssemblerRISCV64Test, Ori) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Ori, -11, "ori {reg1}, {reg2}, {imm}"), "Ori");
+}
+
+TEST_F(AssemblerRISCV64Test, Andi) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Andi, -11, "andi {reg1}, {reg2}, {imm}"),
+            "Andi");
+}
+
+TEST_F(AssemblerRISCV64Test, Slli) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Slli, 6, "slli {reg1}, {reg2}, {imm}"), "Slli");
+}
+
+TEST_F(AssemblerRISCV64Test, Srli) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Srli, 6, "srli {reg1}, {reg2}, {imm}"), "Srli");
+}
+
+TEST_F(AssemblerRISCV64Test, Srai) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Srai, 6, "srai {reg1}, {reg2}, {imm}"), "Srai");
+}
+
+TEST_F(AssemblerRISCV64Test, Add) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Add, "add {reg1}, {reg2}, {reg3}"), "Add");
+}
+
+TEST_F(AssemblerRISCV64Test, Sub) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Sub, "sub {reg1}, {reg2}, {reg3}"), "Sub");
+}
+
+TEST_F(AssemblerRISCV64Test, Slt) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Slt, "slt {reg1}, {reg2}, {reg3}"), "Slt");
+}
+
+TEST_F(AssemblerRISCV64Test, Sltu) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Sltu, "sltu {reg1}, {reg2}, {reg3}"), "Sltu");
+}
+
+TEST_F(AssemblerRISCV64Test, Xor) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Xor, "xor {reg1}, {reg2}, {reg3}"), "Xor");
+}
+
+TEST_F(AssemblerRISCV64Test, Or) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Or, "or {reg1}, {reg2}, {reg3}"), "Or");
+}
+
+TEST_F(AssemblerRISCV64Test, And) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::And, "and {reg1}, {reg2}, {reg3}"), "And");
+}
+
+TEST_F(AssemblerRISCV64Test, Sll) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Sll, "sll {reg1}, {reg2}, {reg3}"), "Sll");
+}
+
+TEST_F(AssemblerRISCV64Test, Srl) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Srl, "srl {reg1}, {reg2}, {reg3}"), "Srl");
+}
+
+TEST_F(AssemblerRISCV64Test, Sra) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Sra, "sra {reg1}, {reg2}, {reg3}"), "Sra");
+}
+
+TEST_F(AssemblerRISCV64Test, Addiw) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Addiw, -11, "addiw {reg1}, {reg2}, {imm}"),
+            "Addiw");
+}
+
+TEST_F(AssemblerRISCV64Test, Slliw) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Slliw, 5, "slliw {reg1}, {reg2}, {imm}"),
+            "Slliw");
+}
+
+TEST_F(AssemblerRISCV64Test, Srliw) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Srliw, 5, "srliw {reg1}, {reg2}, {imm}"),
+            "Srliw");
+}
+
+TEST_F(AssemblerRISCV64Test, Sraiw) {
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sraiw, 5, "sraiw {reg1}, {reg2}, {imm}"),
+            "Sraiw");
+}
+
+TEST_F(AssemblerRISCV64Test, Addw) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Addw, "addw {reg1}, {reg2}, {reg3}"), "Addw");
+}
+
+TEST_F(AssemblerRISCV64Test, Subw) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Subw, "subw {reg1}, {reg2}, {reg3}"), "Subw");
+}
+
+TEST_F(AssemblerRISCV64Test, Sllw) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Sllw, "sllw {reg1}, {reg2}, {reg3}"), "Sllw");
+}
+
+TEST_F(AssemblerRISCV64Test, Srlw) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Srlw, "srlw {reg1}, {reg2}, {reg3}"), "Srlw");
+}
+
+TEST_F(AssemblerRISCV64Test, Sraw) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Sraw, "sraw {reg1}, {reg2}, {reg3}"), "Sraw");
+}
+
+TEST_F(AssemblerRISCV64Test, Mul) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Mul, "mul {reg1}, {reg2}, {reg3}"), "Mul");
+}
+
+TEST_F(AssemblerRISCV64Test, Mulh) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Mulh, "mul {reg1}, {reg2}, {reg3}"), "Mulh");
+}
+
+TEST_F(AssemblerRISCV64Test, Mulhsu) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Mulhsu, "mul {reg1}, {reg2}, {reg3}"), "Mulhsu");
+}
+
+TEST_F(AssemblerRISCV64Test, Mulhu) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Mulhu, "mul {reg1}, {reg2}, {reg3}"), "Mulhu");
+}
+
+TEST_F(AssemblerRISCV64Test, Div) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Div, "div {reg1}, {reg2}, {reg3}"), "Div");
+}
+
+TEST_F(AssemblerRISCV64Test, Divu) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Divu, "divu {reg1}, {reg2}, {reg3}"), "Divu");
+}
+
+TEST_F(AssemblerRISCV64Test, Rem) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Rem, "remw {reg1}, {reg2}, {reg3}"), "Rem");
+}
+
+TEST_F(AssemblerRISCV64Test, Remu) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Remu, "remw {reg1}, {reg2}, {reg3}"), "Remu");
+}
+
+TEST_F(AssemblerRISCV64Test, Mulw) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Mulw, "mulw {reg1}, {reg2}, {reg3}"), "Mulw");
+}
+
+TEST_F(AssemblerRISCV64Test, Divw) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Divw, "divw {reg1}, {reg2}, {reg3}"), "Divw");
+}
+
+TEST_F(AssemblerRISCV64Test, Divuw) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Divuw, "div {reg1}, {reg2}, {reg3}"), "Divuw");
+}
+
+TEST_F(AssemblerRISCV64Test, Remw) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Remw, "remw {reg1}, {reg2}, {reg3}"), "Remw");
+}
+
+TEST_F(AssemblerRISCV64Test, Remuw) {
+  DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Remuw, "remuw {reg1}, {reg2}, {reg3}"), "Remuw");
+}
+
+TEST_F(AssemblerRISCV64Test, FLw) {
+  DriverStr(RepeatFRIb(&riscv64::Riscv64Assembler::FLw, -11, "flw {reg1}, {imm}({reg2})"), "FLw");
+}
+
+TEST_F(AssemblerRISCV64Test, FLd) {
+  DriverStr(RepeatFRIb(&riscv64::Riscv64Assembler::FLd, -11, "fld {reg1}, {imm}({reg2})"), "FLw");
+}
+
+TEST_F(AssemblerRISCV64Test, FSw) {
+  DriverStr(RepeatFRIb(&riscv64::Riscv64Assembler::FSw, 2, "fsw {reg1}, {imm}({reg2})"), "FSw");
+}
+
+TEST_F(AssemblerRISCV64Test, FSd) {
+  DriverStr(RepeatFRIb(&riscv64::Riscv64Assembler::FSd, 2, "fsd {reg1}, {imm}({reg2})"), "FSd");
+}
+
+TEST_F(AssemblerRISCV64Test, FMAddS) {
+  DriverStr(RepeatFFFF(&riscv64::Riscv64Assembler::FMAddS,
+                       "fmadd.s {reg1}, {reg2}, {reg3}, {reg4}"), "FMAddS");
+}
+
+TEST_F(AssemblerRISCV64Test, FMAddD) {
+  DriverStr(RepeatFFFF(&riscv64::Riscv64Assembler::FMAddD,
+                       "fmadd.d {reg1}, {reg2}, {reg3}, {reg4}"), "FMAddD");
+}
+
+TEST_F(AssemblerRISCV64Test, FMSubS) {
+  DriverStr(RepeatFFFF(&riscv64::Riscv64Assembler::FMSubS,
+                       "fmsub.s {reg1}, {reg2}, {reg3}, {reg4}"), "FMSubS");
+}
+
+TEST_F(AssemblerRISCV64Test, FMSubD) {
+  DriverStr(RepeatFFFF(&riscv64::Riscv64Assembler::FMSubD,
+                       "fmsub.d {reg1}, {reg2}, {reg3}, {reg4}"), "FMSubD");
+}
+
+TEST_F(AssemblerRISCV64Test, FNMSubS) {
+  DriverStr(RepeatFFFF(&riscv64::Riscv64Assembler::FNMSubS,
+                       "fnmsub.s {reg1}, {reg2}, {reg3}, {reg4}"), "FNMSubS");
+}
+
+TEST_F(AssemblerRISCV64Test, FNMSubD) {
+  DriverStr(RepeatFFFF(&riscv64::Riscv64Assembler::FNMSubD,
+                       "fnmsub.d {reg1}, {reg2}, {reg3}, {reg4}"), "FNMSubD");
+}
+
+TEST_F(AssemblerRISCV64Test, FNMAddS) {
+  DriverStr(RepeatFFFF(&riscv64::Riscv64Assembler::FNMAddS,
+                       "fnmadd.s {reg1}, {reg2}, {reg3}, {reg4}"), "FNMAddS");
+}
+
+TEST_F(AssemblerRISCV64Test, FNMAddD) {
+  DriverStr(RepeatFFFF(&riscv64::Riscv64Assembler::FNMAddD,
+                       "fnmadd.d {reg1}, {reg2}, {reg3}, {reg4}"), "FNMAddD");
+}
+
+TEST_F(AssemblerRISCV64Test, FAddS) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FAddS, "fadd.s {reg1}, {reg2}, {reg3}"), "FAddS");
+}
+
+TEST_F(AssemblerRISCV64Test, FAddD) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FAddD, "fadd.d {reg1}, {reg2}, {reg3}"), "FAddD");
+}
+
+TEST_F(AssemblerRISCV64Test, FSubS) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FSubS, "fsub.s {reg1}, {reg2}, {reg3}"), "FSubS");
+}
+
+TEST_F(AssemblerRISCV64Test, FSubD) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FSubD, "fsub.d {reg1}, {reg2}, {reg3}"), "FSubD");
+}
+
+TEST_F(AssemblerRISCV64Test, FMulS) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FMulS, "fmul.s {reg1}, {reg2}, {reg3}"), "FMulS");
+}
+
+TEST_F(AssemblerRISCV64Test, FMulD) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FMulD, "fmul.d {reg1}, {reg2}, {reg3}"), "FMulD");
+}
+
+TEST_F(AssemblerRISCV64Test, FDivS) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FDivS, "fdiv.s {reg1}, {reg2}, {reg3}"), "FDivS");
+}
+
+TEST_F(AssemblerRISCV64Test, FDivD) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FDivD, "fdiv.d {reg1}, {reg2}, {reg3}"), "FDivD");
+}
+
+TEST_F(AssemblerRISCV64Test, FSqrtS) {
+  DriverStr(RepeatFF(&riscv64::Riscv64Assembler::FSqrtS, "fsqrt.s {reg1}, {reg2}"), "FSqrtS");
+}
+
+TEST_F(AssemblerRISCV64Test, FSqrtD) {
+  DriverStr(RepeatFF(&riscv64::Riscv64Assembler::FSqrtD, "fsqrt.d {reg1}, {reg2}"), "FSqrtD");
+}
+
+TEST_F(AssemblerRISCV64Test, FSgnjS) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FSgnjS, "fsgnj.s {reg1}, {reg2}, {reg3}"),
+            "FSgnjS");
+}
+
+TEST_F(AssemblerRISCV64Test, FSgnjD) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FSgnjD, "fsgnj.d {reg1}, {reg2}, {reg3}"),
+            "FSgnjD");
+}
+
+TEST_F(AssemblerRISCV64Test, FSgnjnS) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FSgnjnS, "fsgnjn.s {reg1}, {reg2}, {reg3}"),
+            "FSgnjnS");
+}
+
+TEST_F(AssemblerRISCV64Test, FSgnjnD) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FSgnjnD, "fsgnjn.d {reg1}, {reg2}, {reg3}"),
+            "FSgnjnD");
+}
+
+TEST_F(AssemblerRISCV64Test, FSgnjxS) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FSgnjxS, "fsgnjx.s {reg1}, {reg2}, {reg3}"),
+            "FSgnjxS");
+}
+
+TEST_F(AssemblerRISCV64Test, FSgnjxD) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FSgnjxD, "fsgnjx.d {reg1}, {reg2}, {reg3}"),
+            "FSgnjxD");
+}
+
+TEST_F(AssemblerRISCV64Test, FMinS) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FMinS, "fmin.s {reg1}, {reg2}, {reg3}"), "FMinS");
+}
+
+TEST_F(AssemblerRISCV64Test, FMinD) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FMinD, "fmin.d {reg1}, {reg2}, {reg3}"), "FMinD");
+}
+
+TEST_F(AssemblerRISCV64Test, FMaxS) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FMaxS, "fmax.s {reg1}, {reg2}, {reg3}"), "FMaxS");
+}
+
+TEST_F(AssemblerRISCV64Test, FMaxD) {
+  DriverStr(RepeatFFF(&riscv64::Riscv64Assembler::FMaxD, "fmax.d {reg1}, {reg2}, {reg3}"), "FMaxD");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtSD) {
+  DriverStr(RepeatFF(&riscv64::Riscv64Assembler::FCvtSD, "fcvt.s.d {reg1}, {reg2}"), "FCvtSD");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtDS) {
+  DriverStr(RepeatFF(&riscv64::Riscv64Assembler::FCvtDS, "fcvt.d.s {reg1}, {reg2}"), "FCvtDS");
+}
+
+TEST_F(AssemblerRISCV64Test, FEqS) {
+  DriverStr(RepeatRFF(&riscv64::Riscv64Assembler::FEqS, "feq.s {reg1}, {reg2}, {reg3}"), "FEqS");
+}
+
+TEST_F(AssemblerRISCV64Test, FEqD) {
+  DriverStr(RepeatRFF(&riscv64::Riscv64Assembler::FEqD, "feq.d {reg1}, {reg2}, {reg3}"), "FEqD");
+}
+
+TEST_F(AssemblerRISCV64Test, FLtS) {
+  DriverStr(RepeatRFF(&riscv64::Riscv64Assembler::FLtS, "flt.s {reg1}, {reg2}, {reg3}"), "FLtS");
+}
+
+TEST_F(AssemblerRISCV64Test, FLtD) {
+  DriverStr(RepeatRFF(&riscv64::Riscv64Assembler::FLtD, "flt.d {reg1}, {reg2}, {reg3}"), "FLtD");
+}
+
+TEST_F(AssemblerRISCV64Test, FLeS) {
+  DriverStr(RepeatRFF(&riscv64::Riscv64Assembler::FLeS, "fle.s {reg1}, {reg2}, {reg3}"), "FLeS");
+}
+
+TEST_F(AssemblerRISCV64Test, FLeD) {
+  DriverStr(RepeatRFF(&riscv64::Riscv64Assembler::FLeD, "fle.d {reg1}, {reg2}, {reg3}"), "FLeD");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtWS) {
+  DriverStr(RepeatrF(&riscv64::Riscv64Assembler::FCvtWS, "fcvt.w.s {reg1}, {reg2}"), "FCvtWS");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtWD) {
+  DriverStr(RepeatrF(&riscv64::Riscv64Assembler::FCvtWD, "fcvt.w.d {reg1}, {reg2}"), "FCvtWD");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtWuS) {
+  DriverStr(RepeatrF(&riscv64::Riscv64Assembler::FCvtWuS, "fcvt.wu.s {reg1}, {reg2}"), "FCvtWuS");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtWuD) {
+  DriverStr(RepeatrF(&riscv64::Riscv64Assembler::FCvtWuD, "fcvt.wu.d {reg1}, {reg2}"), "FCvtWuD");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtLS) {
+  DriverStr(RepeatRF(&riscv64::Riscv64Assembler::FCvtLS, "fcvt.l.s {reg1}, {reg2}"), "FCvtLS");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtLD) {
+  DriverStr(RepeatRF(&riscv64::Riscv64Assembler::FCvtLD, "fcvt.l.d {reg1}, {reg2}"), "FCvtLD");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtLuS) {
+  DriverStr(RepeatRF(&riscv64::Riscv64Assembler::FCvtLuS, "fcvt.lu.s {reg1}, {reg2}"), "FCvtLuS");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtLuD) {
+  DriverStr(RepeatRF(&riscv64::Riscv64Assembler::FCvtLuD, "fcvt.lu.d {reg1}, {reg2}"), "FCvtLuD");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtSW) {
+  DriverStr(RepeatFR(&riscv64::Riscv64Assembler::FCvtSW, "fcvt.s.w {reg1}, {reg2}"), "FCvtSW");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtDW) {
+  DriverStr(RepeatFR(&riscv64::Riscv64Assembler::FCvtDW, "fcvt.d.w {reg1}, {reg2}"), "FCvtDW");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtSWu) {
+  DriverStr(RepeatFR(&riscv64::Riscv64Assembler::FCvtSWu, "fcvt.s.wu {reg1}, {reg2}"), "FCvtSWu");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtDWu) {
+  DriverStr(RepeatFR(&riscv64::Riscv64Assembler::FCvtDWu, "fcvt.d.wu {reg1}, {reg2}"), "FCvtDWu");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtSL) {
+  DriverStr(RepeatFR(&riscv64::Riscv64Assembler::FCvtSL, "fcvt.s.l {reg1}, {reg2}"), "FCvtSL");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtDL) {
+  DriverStr(RepeatFR(&riscv64::Riscv64Assembler::FCvtDL, "fcvt.d.l {reg1}, {reg2}"), "FCvtDL");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtSLu) {
+  DriverStr(RepeatFR(&riscv64::Riscv64Assembler::FCvtSLu, "fcvt.s.lu {reg1}, {reg2}"), "FCvtSLu");
+}
+
+TEST_F(AssemblerRISCV64Test, FCvtDLu) {
+  DriverStr(RepeatFR(&riscv64::Riscv64Assembler::FCvtDLu, "fcvt.d.lu {reg1}, {reg2}"), "FCvtDLu");
+}
+
+TEST_F(AssemblerRISCV64Test, FMvXW) {
+  DriverStr(RepeatRF(&riscv64::Riscv64Assembler::FMvXW, "fmv.x.w {reg1}, {reg2}"), "FMvXW");
+}
+
+TEST_F(AssemblerRISCV64Test, FMvXD) {
+  DriverStr(RepeatRF(&riscv64::Riscv64Assembler::FMvXD, "fmv.x.d {reg1}, {reg2}"), "FMvXD");
+}
+
+TEST_F(AssemblerRISCV64Test, FMvWX) {
+  DriverStr(RepeatFR(&riscv64::Riscv64Assembler::FMvWX, "fmv.w.x {reg1}, {reg2}"), "FMvWX");
+}
+
+TEST_F(AssemblerRISCV64Test, FMvDX) {
+  DriverStr(RepeatFR(&riscv64::Riscv64Assembler::FMvDX, "fmv.d.x {reg1}, {reg2}"), "FMvDX");
+}
+
+TEST_F(AssemblerRISCV64Test, FClassS) {
+  DriverStr(RepeatRF(&riscv64::Riscv64Assembler::FClassS, "fclass.s {reg1}, {reg2}"), "FClassS");
+}
+
+TEST_F(AssemblerRISCV64Test, FClassD) {
+  DriverStr(RepeatrF(&riscv64::Riscv64Assembler::FClassD, "fclass.d {reg1}, {reg2}"), "FClassD");
+}
+
+// Pseudo instructions.
+TEST_F(AssemblerRISCV64Test, Nop) {
+  __ Nop();
+  DriverStr("addi zero,zero,0", "Nop");
+}
+
+TEST_F(AssemblerRISCV64Test, Mv) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::Mv, "addi {reg1}, {reg2}, 0"), "Mv");
+}
+
+TEST_F(AssemblerRISCV64Test, Not) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::Not, "xori {reg1}, {reg2}, -1"), "Not");
+}
+
+TEST_F(AssemblerRISCV64Test, Neg) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::Neg, "sub {reg1}, x0, {reg2}"), "Neg");
+}
+
+TEST_F(AssemblerRISCV64Test, NegW) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::NegW, "subw {reg1}, x0, {reg2}"), "Neg");
+}
+
+TEST_F(AssemblerRISCV64Test, SextB) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::SextB,
+                     "slli {reg1}, {reg2}, 56\n"
+                     "srai {reg1}, {reg1}, 56"),
+            "SextB");
+}
+
+TEST_F(AssemblerRISCV64Test, SextH) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::SextH,
+                     "slli {reg1}, {reg2}, 48\n"
+                     "srai {reg1}, {reg1}, 48"),
+            "SextH");
+}
+
+TEST_F(AssemblerRISCV64Test, SextW) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::SextW, "addiw {reg1}, {reg2}, 0\n"), "SextW");
+}
+
+TEST_F(AssemblerRISCV64Test, ZextB) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::ZextB, "andi {reg1}, {reg2}, 255"), "ZextB");
+}
+
+TEST_F(AssemblerRISCV64Test, ZextH) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::ZextH,
+                     "slli {reg1}, {reg2}, 48\n"
+                     "srli {reg1}, {reg1}, 48"),
+            "SextH");
+}
+
+TEST_F(AssemblerRISCV64Test, ZextW) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::ZextW,
+                     "slli {reg1}, {reg2}, 32\n"
+                     "srli {reg1}, {reg1}, 32"),
+            "SextW");
+}
+
+TEST_F(AssemblerRISCV64Test, Seqz) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::Seqz, "sltiu {reg1}, {reg2}, 1\n"), "Seqz");
+}
+
+TEST_F(AssemblerRISCV64Test, Snez) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::Snez, "sltu {reg1}, zero, {reg2}\n"), "Snez");
+}
+
+TEST_F(AssemblerRISCV64Test, Sltz) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::Sltz, "slt {reg1}, {reg2}, zero\n"), "Sltz");
+}
+
+TEST_F(AssemblerRISCV64Test, Sgtz) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::Sgtz, "slt {reg1}, zero, {reg2}\n"), "Sgtz");
+}
+
+TEST_F(AssemblerRISCV64Test, FMvS) {
+  DriverStr(RepeatFF(&riscv64::Riscv64Assembler::FMvS, "fsgnj.s {reg1}, {reg2}, {reg2}\n"), "FMvS");
+}
+
+TEST_F(AssemblerRISCV64Test, FAbsS) {
+  DriverStr(RepeatFF(&riscv64::Riscv64Assembler::FAbsS, "fsgnjx.s {reg1}, {reg2}, {reg2}\n"),
+            "FAbsS");
+}
+
+TEST_F(AssemblerRISCV64Test, FNegS) {
+  DriverStr(RepeatFF(&riscv64::Riscv64Assembler::FNegS, "fsgnjn.s {reg1}, {reg2}, {reg2}\n"),
+            "FNegS");
+}
+
+TEST_F(AssemblerRISCV64Test, FMvD) {
+  DriverStr(RepeatFF(&riscv64::Riscv64Assembler::FMvD, "fsgnj.d {reg1}, {reg2}, {reg2}\n"), "FMvD");
+}
+
+TEST_F(AssemblerRISCV64Test, FAbsD) {
+  DriverStr(RepeatFF(&riscv64::Riscv64Assembler::FAbsD, "fsgnjx.d {reg1}, {reg2}, {reg2}\n"),
+            "FAbsD");
+}
+
+TEST_F(AssemblerRISCV64Test, FNegD) {
+  DriverStr(RepeatFF(&riscv64::Riscv64Assembler::FNegD, "fsgnjn.d {reg1}, {reg2}, {reg2}\n"),
+            "FNegD");
+}
+
+#undef __
+
+}  // namespace art