Add assembler for riscv64, part 2.

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: I51a5c17f0d1d4e10d3b3b2f4e2ae88a75ca13bd1
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index f8a7f61..d375302 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -411,6 +411,179 @@
     return str;
   }
 
+  template <typename RegType, typename ImmType>
+  std::string RepeatTemplatedRegisterImmBitsShift(
+      void (Ass::*f)(RegType, ImmType),
+      int imm_bits,
+      int shift,
+      const std::vector<RegType*> registers,
+      std::string (AssemblerTest::*GetName)(const RegType&),
+      const std::string& fmt,
+      int bias) {
+    std::string str;
+    std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0), shift);
+
+    for (auto reg : registers) {
+      for (int64_t imm : imms) {
+        ImmType new_imm = CreateImmediate(imm);
+        if (f != nullptr) {
+          (assembler_.get()->*f)(*reg, new_imm + bias);
+        }
+        std::string base = fmt;
+
+        std::string reg_string = (this->*GetName)(*reg);
+        size_t reg_index;
+        while ((reg_index = base.find(REG_TOKEN)) != std::string::npos) {
+          base.replace(reg_index, ConstexprStrLen(REG_TOKEN), reg_string);
+        }
+
+        size_t imm_index = base.find(IMM_TOKEN);
+        if (imm_index != std::string::npos) {
+          std::ostringstream sreg;
+          sreg << imm + bias;
+          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 ImmType>
+  std::string RepeatTemplatedImmBitsShift(
+      void (Ass::*f)(ImmType), int imm_bits, int shift, const std::string& fmt, int bias = 0) {
+    std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0), shift);
+
+    WarnOnCombinations(imms.size());
+
+    std::string str;
+
+    for (int64_t imm : imms) {
+      ImmType new_imm = CreateImmediate(imm);
+      if (f != nullptr) {
+        (assembler_.get()->*f)(new_imm + bias);
+      }
+      std::string base = fmt;
+
+      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 Reg1, typename Reg2, typename ImmType>
+  std::string RepeatTemplatedRegistersImmBitsShift(
+      void (Ass::*f)(Reg1, Reg2, ImmType),
+      int imm_bits,
+      int shift,
+      const std::vector<Reg1*> reg1_registers,
+      const std::vector<Reg2*> reg2_registers,
+      std::string (AssemblerTest::*GetName1)(const Reg1&),
+      std::string (AssemblerTest::*GetName2)(const Reg2&),
+      const std::string& fmt,
+      int bias = 0,
+      int multiplier = 1) {
+    std::string str;
+    std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0), shift);
+
+    for (auto reg1 : reg1_registers) {
+      for (auto reg2 : reg2_registers) {
+        for (int64_t imm : imms) {
+          ImmType new_imm = CreateImmediate(imm);
+          if (f != nullptr) {
+            (assembler_.get()->*f)(*reg1, *reg2, new_imm * multiplier + bias);
+          }
+          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);
+          }
+
+          size_t imm_index = base.find(IMM_TOKEN);
+          if (imm_index != std::string::npos) {
+            std::ostringstream sreg;
+            sreg << imm * multiplier + bias;
+            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 ImmType>
+  std::string RepeatIbS(
+      void (Ass::*f)(ImmType), int imm_bits, int shift, const std::string& fmt, int bias = 0) {
+    return RepeatTemplatedImmBitsShift<ImmType>(f, imm_bits, shift, fmt, bias);
+  }
+
+  template <typename ImmType>
+  std::string RepeatRIbS(
+      void (Ass::*f)(Reg, ImmType), int imm_bits, int shift, const std::string& fmt, int bias = 0) {
+    return RepeatTemplatedRegisterImmBitsShift<Reg, ImmType>(
+        f,
+        imm_bits,
+        shift,
+        GetRegisters(),
+        &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+        fmt,
+        bias);
+  }
+
+  template <typename ImmType>
+  std::string RepeatRRIbS(void (Ass::*f)(Reg, Reg, ImmType),
+                          int imm_bits,
+                          int shift,
+                          const std::string& fmt,
+                          int bias = 0) {
+    return RepeatTemplatedRegistersImmBitsShift<Reg, Reg, ImmType>(
+        f,
+        imm_bits,
+        shift,
+        GetRegisters(),
+        GetRegisters(),
+        &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+        &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+        fmt,
+        bias);
+  }
+
   template <typename ImmType>
   std::string RepeatRRIb(void (Ass::*f)(Reg, Reg, ImmType),
                          int imm_bits,
@@ -857,7 +1030,9 @@
   const int kMaxBitsExhaustiveTest = 8;
 
   // Create a couple of immediate values up to the number of bits given.
-  virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) {
+  virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits,
+                                                         bool as_uint = false,
+                                                         int shift = 0) {
     CHECK_GT(imm_bits, 0);
     CHECK_LE(imm_bits, 64);
     std::vector<int64_t> res;
@@ -865,11 +1040,11 @@
     if (imm_bits <= kMaxBitsExhaustiveTest) {
       if (as_uint) {
         for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) {
-          res.push_back(static_cast<int64_t>(i));
+          res.push_back(static_cast<int64_t>(i << shift));
         }
       } else {
         for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) {
-          res.push_back(i);
+          res.push_back(i << shift);
         }
       }
     } else {
@@ -877,14 +1052,14 @@
         for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest);
              i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest);
              i++) {
-          res.push_back(static_cast<int64_t>(i));
+          res.push_back(static_cast<int64_t>(i << shift));
         }
         for (int i = 0; i <= imm_bits; i++) {
           uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) +
                        ((MaxInt<uint64_t>(imm_bits) -
                         (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1))
                         * i / imm_bits);
-          res.push_back(static_cast<int64_t>(j));
+          res.push_back(static_cast<int64_t>(j << shift));
         }
       } else {
         for (int i = 0; i <= imm_bits; i++) {
@@ -892,18 +1067,18 @@
                       ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) -
                          MinInt<int64_t>(imm_bits))
                         * i) / imm_bits);
-          res.push_back(static_cast<int64_t>(j));
+          res.push_back(static_cast<int64_t>(j << shift));
         }
         for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest);
              i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest);
              i++) {
-          res.push_back(static_cast<int64_t>(i));
+          res.push_back(static_cast<int64_t>(i << shift));
         }
         for (int i = 0; i <= imm_bits; i++) {
           int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) +
                       ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1))
                        * i / imm_bits);
-          res.push_back(static_cast<int64_t>(j));
+          res.push_back(static_cast<int64_t>(j << shift));
         }
       }
     }
diff --git a/compiler/utils/riscv64/assembler_riscv64.cc b/compiler/utils/riscv64/assembler_riscv64.cc
index cc2d526..fd6fae3 100644
--- a/compiler/utils/riscv64/assembler_riscv64.cc
+++ b/compiler/utils/riscv64/assembler_riscv64.cc
@@ -43,6 +43,52 @@
 
 /////////////////////////////// RV64 "IM" Instructions ///////////////////////////////
 
+// LUI/AUIPC (RV32I, with sign-extension on RV64I), opcode = 0x17, 0x37
+
+void Riscv64Assembler::Lui(XRegister rd, uint32_t imm20) {
+  EmitU(imm20, rd, 0x37);
+}
+
+void Riscv64Assembler::Auipc(XRegister rd, uint32_t imm20) {
+  EmitU(imm20, rd, 0x17);
+}
+
+// Jump instructions (RV32I), opcode = 0x67, 0x6f
+
+void Riscv64Assembler::Jal(XRegister rd, int32_t offset) {
+  EmitJ(offset, rd, 0x6F);
+}
+
+void Riscv64Assembler::Jalr(XRegister rd, XRegister rs1, int32_t offset) {
+  EmitI(offset, rs1, 0x0, rd, 0x67);
+}
+
+// Branch instructions, opcode = 0x63 (subfunc from 0x0 ~ 0x7), 0x67, 0x6f
+
+void Riscv64Assembler::Beq(XRegister rs1, XRegister rs2, int32_t offset) {
+  EmitB(offset, rs2, rs1, 0x0, 0x63);
+}
+
+void Riscv64Assembler::Bne(XRegister rs1, XRegister rs2, int32_t offset) {
+  EmitB(offset, rs2, rs1, 0x1, 0x63);
+}
+
+void Riscv64Assembler::Blt(XRegister rs1, XRegister rs2, int32_t offset) {
+  EmitB(offset, rs2, rs1, 0x4, 0x63);
+}
+
+void Riscv64Assembler::Bge(XRegister rs1, XRegister rs2, int32_t offset) {
+  EmitB(offset, rs2, rs1, 0x5, 0x63);
+}
+
+void Riscv64Assembler::Bltu(XRegister rs1, XRegister rs2, int32_t offset) {
+  EmitB(offset, rs2, rs1, 0x6, 0x63);
+}
+
+void Riscv64Assembler::Bgeu(XRegister rs1, XRegister rs2, int32_t offset) {
+  EmitB(offset, rs2, rs1, 0x7, 0x63);
+}
+
 // Load instructions (RV32I+RV64I): opcode = 0x03, funct3 from 0x0 ~ 0x6
 
 void Riscv64Assembler::Lb(XRegister rd, XRegister rs1, int32_t offset) {
@@ -613,6 +659,58 @@
 
 void Riscv64Assembler::FNegD(FRegister rd, FRegister rs) { FSgnjnS(rd, rs, rs); }
 
+void Riscv64Assembler::Beqz(XRegister rs, int32_t offset) {
+  Beq(rs, Zero, offset);
+}
+
+void Riscv64Assembler::Bnez(XRegister rs, int32_t offset) {
+  Bne(rs, Zero, offset);
+}
+
+void Riscv64Assembler::Blez(XRegister rt, int32_t offset) {
+  Bge(Zero, rt, offset);
+}
+
+void Riscv64Assembler::Bgez(XRegister rt, int32_t offset) {
+  Bge(rt, Zero, offset);
+}
+
+void Riscv64Assembler::Bltz(XRegister rt, int32_t offset) {
+  Blt(rt, Zero, offset);
+}
+
+void Riscv64Assembler::Bgtz(XRegister rt, int32_t offset) {
+  Blt(Zero, rt, offset);
+}
+
+void Riscv64Assembler::Bgt(XRegister rs, XRegister rt, int32_t offset) {
+  Blt(rt, rs, offset);
+}
+
+void Riscv64Assembler::Ble(XRegister rs, XRegister rt, int32_t offset) {
+  Bge(rt, rs, offset);
+}
+
+void Riscv64Assembler::Bgtu(XRegister rs, XRegister rt, int32_t offset) {
+  Bltu(rt, rs, offset);
+}
+
+void Riscv64Assembler::Bleu(XRegister rs, XRegister rt, int32_t offset) {
+  Bgeu(rt, rs, offset);
+}
+
+void Riscv64Assembler::J(int32_t offset) { Jal(Zero, offset); }
+
+void Riscv64Assembler::Jal(int32_t offset) { Jal(RA, offset); }
+
+void Riscv64Assembler::Jr(XRegister rs) { Jalr(Zero, rs, 0); }
+
+void Riscv64Assembler::Jalr(XRegister rs) { Jalr(RA, rs, 0); }
+
+void Riscv64Assembler::Jalr(XRegister rd, XRegister rs) { Jalr(rd, rs, 0); }
+
+void Riscv64Assembler::Ret() { Jalr(Zero, RA, 0); }
+
 /////////////////////////////// RV64 MACRO Instructions END ///////////////////////////////
 
 /////////////////////////////// RV64 VARIANTS extension end ////////////
diff --git a/compiler/utils/riscv64/assembler_riscv64.h b/compiler/utils/riscv64/assembler_riscv64.h
index b648a71..13e7826 100644
--- a/compiler/utils/riscv64/assembler_riscv64.h
+++ b/compiler/utils/riscv64/assembler_riscv64.h
@@ -35,13 +35,13 @@
 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
+  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;
@@ -65,6 +65,26 @@
   size_t CodeSize() const override { return Assembler::CodeSize(); }
   DebugFrameOpCodeWriterForAssembler& cfi() { return Assembler::cfi(); }
 
+  // According to "The RISC-V Instruction Set Manual"
+
+  // LUI/AUIPC (RV32I, with sign-extension on RV64I), opcode = 0x17, 0x37
+  // Note: These take a 20-bit unsigned value to align with the clang assembler for testing,
+  // but the value stored in the register shall actually be sign-extended to 64 bits.
+  void Lui(XRegister rd, uint32_t imm20);
+  void Auipc(XRegister rd, uint32_t imm20);
+
+  // Jump instructions (RV32I), opcode = 0x67, 0x6f
+  void Jal(XRegister rd, int32_t offset);
+  void Jalr(XRegister rd, XRegister rs1, int32_t offset);
+
+  // Branch instructions (RV32I), opcode = 0x63, funct3 from 0x0 ~ 0x1 and 0x4 ~ 0x7
+  void Beq(XRegister rs1, XRegister rs2, int32_t offset);
+  void Bne(XRegister rs1, XRegister rs2, int32_t offset);
+  void Blt(XRegister rs1, XRegister rs2, int32_t offset);
+  void Bge(XRegister rs1, XRegister rs2, int32_t offset);
+  void Bltu(XRegister rs1, XRegister rs2, int32_t offset);
+  void Bgeu(XRegister rs1, XRegister rs2, int32_t offset);
+
   // 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);
@@ -292,7 +312,8 @@
   void FClassD(XRegister rd, FRegister rs1);
 
   ////////////////////////////// RV64 MACRO Instructions  START ///////////////////////////////
-  // These pseudo instructions are from "RISC-V ASM manual".
+  // These pseudo instructions are from "RISC-V Assembly Programmer's Manual".
+
   void Nop();
   void Mv(XRegister rd, XRegister rs);
   void Not(XRegister rd, XRegister rs);
@@ -314,6 +335,27 @@
   void FMvD(FRegister rd, FRegister rs);
   void FAbsD(FRegister rd, FRegister rs);
   void FNegD(FRegister rd, FRegister rs);
+
+  // Branch pseudo instructions
+  void Beqz(XRegister rs, int32_t offset);
+  void Bnez(XRegister rs, int32_t offset);
+  void Blez(XRegister rs, int32_t offset);
+  void Bgez(XRegister rs, int32_t offset);
+  void Bltz(XRegister rs, int32_t offset);
+  void Bgtz(XRegister rs, int32_t offset);
+  void Bgt(XRegister rs, XRegister rt, int32_t offset);
+  void Ble(XRegister rs, XRegister rt, int32_t offset);
+  void Bgtu(XRegister rs, XRegister rt, int32_t offset);
+  void Bleu(XRegister rs, XRegister rt, int32_t offset);
+
+  // Jump pseudo instructions
+  void J(int32_t offset);
+  void Jal(int32_t offset);
+  void Jr(XRegister rs);
+  void Jalr(XRegister rs);
+  void Jalr(XRegister rd, XRegister rs);
+  void Ret();
+
   /////////////////////////////// RV64 MACRO Instructions END ///////////////////////////////
 
   void Bind(Label* label ATTRIBUTE_UNUSED) override {
@@ -414,6 +456,41 @@
     Emit(encoding);
   }
 
+  void EmitB(int32_t offset, XRegister rs2, XRegister rs1, uint32_t funct3, uint32_t opcode) {
+    DCHECK_ALIGNED(offset, 2);
+    DCHECK(IsInt<13>(offset)) << offset;
+    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 imm12 = (static_cast<uint32_t>(offset) >> 1) & 0xfffu;
+    uint32_t encoding = (imm12 & 0x800u) << (31 - 11) | (imm12 & 0x03f0u) << (25 - 4) |
+                        static_cast<uint32_t>(rs2) << 20 | static_cast<uint32_t>(rs1) << 15 |
+                        static_cast<uint32_t>(funct3) << 12 |
+                        (imm12 & 0xfu) << 8 | (imm12 & 0x400u) >> (10 - 7) | opcode;
+    Emit(encoding);
+  }
+
+  void EmitU(uint32_t imm20, XRegister rd, uint32_t opcode) {
+    CHECK(IsUint<20>(imm20)) << imm20;
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rd)));
+    DCHECK(IsUint<7>(opcode));
+    uint32_t encoding = imm20 << 12 | static_cast<uint32_t>(rd) << 7 | opcode;
+    Emit(encoding);
+  }
+
+  void EmitJ(int32_t offset, XRegister rd, uint32_t opcode) {
+    DCHECK_ALIGNED(offset, 2);
+    CHECK(IsInt<21>(offset)) << offset;
+    DCHECK(IsUint<5>(static_cast<uint32_t>(rd)));
+    DCHECK(IsUint<7>(opcode));
+    uint32_t imm20 = (static_cast<uint32_t>(offset) >> 1) & 0xfffffu;
+    uint32_t encoding = (imm20 & 0x80000u) << (31 - 19) | (imm20 & 0x03ffu) << 21 |
+                        (imm20 & 0x400u) << (20 - 10) | (imm20 & 0x7f800u) << (12 - 11) |
+                        static_cast<uint32_t>(rd) << 7 | opcode;
+    Emit(encoding);
+  }
+
   static constexpr uint32_t kXlen = 64;
 
   DISALLOW_COPY_AND_ASSIGN(Riscv64Assembler);
diff --git a/compiler/utils/riscv64/assembler_riscv64_test.cc b/compiler/utils/riscv64/assembler_riscv64_test.cc
index 019191c..20d607b 100644
--- a/compiler/utils/riscv64/assembler_riscv64_test.cc
+++ b/compiler/utils/riscv64/assembler_riscv64_test.cc
@@ -189,62 +189,118 @@
 
 TEST_F(AssemblerRISCV64Test, Toolchain) { EXPECT_TRUE(CheckTools()); }
 
+TEST_F(AssemblerRISCV64Test, Lui) {
+  DriverStr(RepeatRIb(&riscv64::Riscv64Assembler::Lui, 20, "lui {reg}, {imm}"), "Lui");
+}
+
+TEST_F(AssemblerRISCV64Test, Auipc) {
+  DriverStr(RepeatRIb(&riscv64::Riscv64Assembler::Auipc, 20, "auipc {reg}, {imm}"), "Auipc");
+}
+
+TEST_F(AssemblerRISCV64Test, Jal) {
+  // TODO(riscv64): Change "-19, 2" to "-20, 1" for "C" Standard Extension.
+  DriverStr(RepeatRIbS(&riscv64::Riscv64Assembler::Jal, -19, 2, "jal {reg}, {imm}\n"),
+            "Jal");
+}
+
+TEST_F(AssemblerRISCV64Test, Jalr) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Jalr, -12, "jalr {reg1}, {reg2}, {imm}\n"),
+            "Jalr");
+}
+
+TEST_F(AssemblerRISCV64Test, Beq) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRRIbS(&riscv64::Riscv64Assembler::Beq, -11, 2, "beq {reg1}, {reg2}, {imm}\n"),
+            "Beq");
+}
+
+TEST_F(AssemblerRISCV64Test, Bne) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRRIbS(&riscv64::Riscv64Assembler::Bne, -11, 2, "bne {reg1}, {reg2}, {imm}\n"),
+            "Bne");
+}
+
+TEST_F(AssemblerRISCV64Test, Blt) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRRIbS(&riscv64::Riscv64Assembler::Blt, -11, 2, "blt {reg1}, {reg2}, {imm}\n"),
+            "Blt");
+}
+
+TEST_F(AssemblerRISCV64Test, Bge) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRRIbS(&riscv64::Riscv64Assembler::Bge, -11, 2, "bge {reg1}, {reg2}, {imm}\n"),
+            "Bge");
+}
+
+TEST_F(AssemblerRISCV64Test, Bltu) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRRIbS(&riscv64::Riscv64Assembler::Bltu, -11, 2, "bltu {reg1}, {reg2}, {imm}\n"),
+            "Bltu");
+}
+
+TEST_F(AssemblerRISCV64Test, Bgeu) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRRIbS(&riscv64::Riscv64Assembler::Bgeu, -11, 2, "bgeu {reg1}, {reg2}, {imm}\n"),
+            "Bgeu");
+}
+
 TEST_F(AssemblerRISCV64Test, Lb) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lb, -11, "lb {reg1}, {imm}({reg2})"), "Lb");
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lb, -12, "lb {reg1}, {imm}({reg2})"), "Lb");
 }
 
 TEST_F(AssemblerRISCV64Test, Lh) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lh, -11, "lh {reg1}, {imm}({reg2})"), "Lh");
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lh, -12, "lh {reg1}, {imm}({reg2})"), "Lh");
 }
 
 TEST_F(AssemblerRISCV64Test, Lw) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lw, -11, "lw {reg1}, {imm}({reg2})"), "Lw");
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lw, -12, "lw {reg1}, {imm}({reg2})"), "Lw");
 }
 
 TEST_F(AssemblerRISCV64Test, Ld) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Ld, -11, "ld {reg1}, {imm}({reg2})"), "Ld");
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Ld, -12, "ld {reg1}, {imm}({reg2})"), "Ld");
 }
 
 TEST_F(AssemblerRISCV64Test, Lbu) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lbu, -11, "lbu {reg1}, {imm}({reg2})"), "Lbu");
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lbu, -12, "lbu {reg1}, {imm}({reg2})"), "Lbu");
 }
 
 TEST_F(AssemblerRISCV64Test, Lhu) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lhu, -11, "lhu {reg1}, {imm}({reg2})"), "Lhu");
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lhu, -12, "lhu {reg1}, {imm}({reg2})"), "Lhu");
 }
 
 TEST_F(AssemblerRISCV64Test, Lwu) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lwu, -11, "lwu {reg1}, {imm}({reg2})"), "Lwu");
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Lwu, -12, "lwu {reg1}, {imm}({reg2})"), "Lwu");
 }
 
 TEST_F(AssemblerRISCV64Test, Sb) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sb, -11, "sb {reg1}, {imm}({reg2})"), "Sb");
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sb, -12, "sb {reg1}, {imm}({reg2})"), "Sb");
 }
 
 TEST_F(AssemblerRISCV64Test, Sh) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sh, -11, "sh {reg1}, {imm}({reg2})"), "Sh");
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sh, -12, "sh {reg1}, {imm}({reg2})"), "Sh");
 }
 
 TEST_F(AssemblerRISCV64Test, Sw) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sw, -11, "sw {reg1}, {imm}({reg2})"), "Sw");
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sw, -12, "sw {reg1}, {imm}({reg2})"), "Sw");
 }
 
 TEST_F(AssemblerRISCV64Test, Sd) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sd, -11, "sd {reg1}, {imm}({reg2})"), "Sd");
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sd, -12, "sd {reg1}, {imm}({reg2})"), "Sd");
 }
 
 TEST_F(AssemblerRISCV64Test, Addi) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Addi, -11, "addi {reg1}, {reg2}, {imm}"),
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Addi, -12, "addi {reg1}, {reg2}, {imm}"),
             "Addi");
 }
 
 TEST_F(AssemblerRISCV64Test, Slti) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Slti, -11, "slti {reg1}, {reg2}, {imm}"),
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Slti, -12, "slti {reg1}, {reg2}, {imm}"),
             "Slti");
 }
 
 TEST_F(AssemblerRISCV64Test, Sltiu) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sltiu, -11, "sltiu {reg1}, {reg2}, {imm}"),
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Sltiu, -12, "sltiu {reg1}, {reg2}, {imm}"),
             "Sltiu");
 }
 
@@ -253,11 +309,11 @@
 }
 
 TEST_F(AssemblerRISCV64Test, Ori) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Ori, -11, "ori {reg1}, {reg2}, {imm}"), "Ori");
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Ori, -12, "ori {reg1}, {reg2}, {imm}"), "Ori");
 }
 
 TEST_F(AssemblerRISCV64Test, Andi) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Andi, -11, "andi {reg1}, {reg2}, {imm}"),
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Andi, -12, "andi {reg1}, {reg2}, {imm}"),
             "Andi");
 }
 
@@ -314,7 +370,7 @@
 }
 
 TEST_F(AssemblerRISCV64Test, Addiw) {
-  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Addiw, -11, "addiw {reg1}, {reg2}, {imm}"),
+  DriverStr(RepeatRRIb(&riscv64::Riscv64Assembler::Addiw, -12, "addiw {reg1}, {reg2}, {imm}"),
             "Addiw");
 }
 
@@ -406,11 +462,11 @@
 }
 
 TEST_F(AssemblerRISCV64Test, FLw) {
-  DriverStr(RepeatFRIb(&riscv64::Riscv64Assembler::FLw, -11, "flw {reg1}, {imm}({reg2})"), "FLw");
+  DriverStr(RepeatFRIb(&riscv64::Riscv64Assembler::FLw, -12, "flw {reg1}, {imm}({reg2})"), "FLw");
 }
 
 TEST_F(AssemblerRISCV64Test, FLd) {
-  DriverStr(RepeatFRIb(&riscv64::Riscv64Assembler::FLd, -11, "fld {reg1}, {imm}({reg2})"), "FLw");
+  DriverStr(RepeatFRIb(&riscv64::Riscv64Assembler::FLd, -12, "fld {reg1}, {imm}({reg2})"), "FLw");
 }
 
 TEST_F(AssemblerRISCV64Test, FSw) {
@@ -769,6 +825,93 @@
             "FNegD");
 }
 
+TEST_F(AssemblerRISCV64Test, Beqz) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRIbS(&riscv64::Riscv64Assembler::Beqz, -11, 2, "beq {reg}, zero, {imm}\n"),
+            "Beqz");
+}
+
+TEST_F(AssemblerRISCV64Test, Bnez) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRIbS(&riscv64::Riscv64Assembler::Bnez, -11, 2, "bne {reg}, zero, {imm}\n"),
+            "Bnez");
+}
+
+TEST_F(AssemblerRISCV64Test, Blez) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRIbS(&riscv64::Riscv64Assembler::Blez, -11, 2, "bge zero, {reg}, {imm}\n"),
+            "Blez");
+}
+
+TEST_F(AssemblerRISCV64Test, Bgez) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRIbS(&riscv64::Riscv64Assembler::Bgez, -11, 2, "bge {reg}, zero, {imm}\n"),
+            "Bgez");
+}
+
+TEST_F(AssemblerRISCV64Test, Bltz) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRIbS(&riscv64::Riscv64Assembler::Bltz, -11, 2, "blt {reg}, zero, {imm}\n"),
+            "Bltz");
+}
+
+TEST_F(AssemblerRISCV64Test, Bgtz) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRIbS(&riscv64::Riscv64Assembler::Bgtz, -11, 2, "blt zero, {reg}, {imm}\n"),
+            "Bgtz");
+}
+
+TEST_F(AssemblerRISCV64Test, Bgt) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRRIbS(&riscv64::Riscv64Assembler::Bgt, -11, 2, "blt {reg2}, {reg1}, {imm}\n"),
+            "Bgt");
+}
+
+TEST_F(AssemblerRISCV64Test, Ble) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRRIbS(&riscv64::Riscv64Assembler::Ble, -11, 2, "bge {reg2}, {reg1}, {imm}\n"),
+            "Bge");
+}
+
+TEST_F(AssemblerRISCV64Test, Bgtu) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRRIbS(&riscv64::Riscv64Assembler::Bgtu, -11, 2, "bltu {reg2}, {reg1}, {imm}\n"),
+            "Bgtu");
+}
+
+TEST_F(AssemblerRISCV64Test, Bleu) {
+  // TODO(riscv64): Change "-11, 2" to "-12, 1" for "C" Standard Extension.
+  DriverStr(RepeatRRIbS(&riscv64::Riscv64Assembler::Bleu, -11, 2, "bgeu {reg2}, {reg1}, {imm}\n"),
+            "Bgeu");
+}
+
+TEST_F(AssemblerRISCV64Test, J) {
+  // TODO(riscv64): Change "-19, 2" to "-20, 1" for "C" Standard Extension.
+  DriverStr(RepeatIbS<int32_t>(&riscv64::Riscv64Assembler::J, -19, 2, "j {imm}\n"), "J");
+}
+
+TEST_F(AssemblerRISCV64Test, JalRA) {
+  // TODO(riscv64): Change "-19, 2" to "-20, 1" for "C" Standard Extension.
+  DriverStr(RepeatIbS<int32_t>(&riscv64::Riscv64Assembler::Jal, -19, 2, "jal {imm}\n"), "JalRA");
+}
+
+TEST_F(AssemblerRISCV64Test, Jr) {
+  DriverStr(RepeatR(&riscv64::Riscv64Assembler::Jr, "jr {reg}\n"), "Jr");
+}
+
+TEST_F(AssemblerRISCV64Test, JalrRA) {
+  DriverStr(RepeatR(&riscv64::Riscv64Assembler::Jalr, "jalr {reg}\n"), "JalrRA");
+}
+
+TEST_F(AssemblerRISCV64Test, Jalr0) {
+  DriverStr(RepeatRR(&riscv64::Riscv64Assembler::Jalr, "jalr {reg1}, {reg2}\n"), "Jalr0");
+}
+
+TEST_F(AssemblerRISCV64Test, Ret) {
+  GetAssembler()->Ret();
+  DriverStr("ret\n", "Ret");
+}
+
 #undef __
 
 }  // namespace art