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(®isters_);
+ 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