summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/utils/assembler_test_base.h5
-rw-r--r--compiler/utils/riscv64/assembler_riscv64.cc139
-rw-r--r--compiler/utils/riscv64/assembler_riscv64.h35
-rw-r--r--compiler/utils/riscv64/assembler_riscv64_test.cc156
-rw-r--r--disassembler/disassembler_riscv64.cc33
5 files changed, 358 insertions, 10 deletions
diff --git a/compiler/utils/assembler_test_base.h b/compiler/utils/assembler_test_base.h
index 47ce8e65ae..6f836d3718 100644
--- a/compiler/utils/assembler_test_base.h
+++ b/compiler/utils/assembler_test_base.h
@@ -147,7 +147,7 @@ class AssemblerTestBase : public testing::Test {
"--compile",
"-target",
"riscv64-linux-gnu",
- "-march=rv64imafd",
+ "-march=rv64imafd_zba_zbb",
// Force the assembler to fully emit branch instructions instead of leaving
// offsets unresolved with relocation information for the linker.
"-mno-relax"};
@@ -174,7 +174,8 @@ class AssemblerTestBase : public testing::Test {
"--disassemble",
"--no-print-imm-hex",
"--no-show-raw-insn",
- "--mattr=+F,+D,+A", // Disassemble "F", "D" and "A" Standard Extensions.
+ // Disassemble Standard Extensions supported by the assembler.
+ "--mattr=+F,+D,+A,+Zba,+Zbb",
"-M",
"no-aliases"};
default:
diff --git a/compiler/utils/riscv64/assembler_riscv64.cc b/compiler/utils/riscv64/assembler_riscv64.cc
index 8662129604..c07a714b90 100644
--- a/compiler/utils/riscv64/assembler_riscv64.cc
+++ b/compiler/utils/riscv64/assembler_riscv64.cc
@@ -197,19 +197,19 @@ void Riscv64Assembler::Andi(XRegister rd, XRegister rs1, int32_t imm12) {
// 0x1 Split: 0x0(6b) + imm12(6b)
void Riscv64Assembler::Slli(XRegister rd, XRegister rs1, int32_t shamt) {
- CHECK(static_cast<uint32_t>(shamt) < 64) << shamt;
+ CHECK_LT(static_cast<uint32_t>(shamt), 64u);
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;
+ CHECK_LT(static_cast<uint32_t>(shamt), 64u);
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;
+ CHECK_LT(static_cast<uint32_t>(shamt), 64u);
EmitI6(0x10, shamt, rs1, 0x5, rd, 0x13);
}
@@ -262,17 +262,17 @@ void Riscv64Assembler::Addiw(XRegister rd, XRegister rs1, int32_t imm12) {
}
void Riscv64Assembler::Slliw(XRegister rd, XRegister rs1, int32_t shamt) {
- CHECK(static_cast<uint32_t>(shamt) < 32) << shamt;
+ CHECK_LT(static_cast<uint32_t>(shamt), 32u);
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;
+ CHECK_LT(static_cast<uint32_t>(shamt), 32u);
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;
+ CHECK_LT(static_cast<uint32_t>(shamt), 32u);
EmitR(0x20, shamt, rs1, 0x5, rd, 0x1b);
}
@@ -786,6 +786,132 @@ void Riscv64Assembler::FClassD(XRegister rd, FRegister rs1) {
/////////////////////////////// RV64 "FD" Instructions END ///////////////////////////////
+////////////////////////////// RV64 "Zba" Instructions START /////////////////////////////
+
+void Riscv64Assembler::AddUw(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x4, rs2, rs1, 0x0, rd, 0x3b);
+}
+
+void Riscv64Assembler::Sh1Add(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x10, rs2, rs1, 0x2, rd, 0x33);
+}
+
+void Riscv64Assembler::Sh1AddUw(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x10, rs2, rs1, 0x2, rd, 0x3b);
+}
+
+void Riscv64Assembler::Sh2Add(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x10, rs2, rs1, 0x4, rd, 0x33);
+}
+
+void Riscv64Assembler::Sh2AddUw(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x10, rs2, rs1, 0x4, rd, 0x3b);
+}
+
+void Riscv64Assembler::Sh3Add(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x10, rs2, rs1, 0x6, rd, 0x33);
+}
+
+void Riscv64Assembler::Sh3AddUw(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x10, rs2, rs1, 0x6, rd, 0x3b);
+}
+
+void Riscv64Assembler::SlliUw(XRegister rd, XRegister rs1, int32_t shamt) {
+ EmitI6(0x2, shamt, rs1, 0x1, rd, 0x1b);
+}
+
+/////////////////////////////// RV64 "Zba" Instructions END //////////////////////////////
+
+////////////////////////////// RV64 "Zbb" Instructions START /////////////////////////////
+
+void Riscv64Assembler::Andn(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x20, rs2, rs1, 0x7, rd, 0x33);
+}
+
+void Riscv64Assembler::Orn(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x20, rs2, rs1, 0x6, rd, 0x33);
+}
+
+void Riscv64Assembler::Xnor(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x20, rs2, rs1, 0x4, rd, 0x33);
+}
+
+void Riscv64Assembler::Clz(XRegister rd, XRegister rs1) {
+ EmitR(0x30, 0x0, rs1, 0x1, rd, 0x13);
+}
+
+void Riscv64Assembler::Clzw(XRegister rd, XRegister rs1) {
+ EmitR(0x30, 0x0, rs1, 0x1, rd, 0x1b);
+}
+
+void Riscv64Assembler::Ctz(XRegister rd, XRegister rs1) {
+ EmitR(0x30, 0x1, rs1, 0x1, rd, 0x13);
+}
+
+void Riscv64Assembler::Ctzw(XRegister rd, XRegister rs1) {
+ EmitR(0x30, 0x1, rs1, 0x1, rd, 0x1b);
+}
+
+void Riscv64Assembler::Cpop(XRegister rd, XRegister rs1) {
+ EmitR(0x30, 0x2, rs1, 0x1, rd, 0x13);
+}
+
+void Riscv64Assembler::Cpopw(XRegister rd, XRegister rs1) {
+ EmitR(0x30, 0x2, rs1, 0x1, rd, 0x1b);
+}
+
+void Riscv64Assembler::Min(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x5, rs2, rs1, 0x4, rd, 0x33);
+}
+
+void Riscv64Assembler::Minu(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x5, rs2, rs1, 0x5, rd, 0x33);
+}
+
+void Riscv64Assembler::Max(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x5, rs2, rs1, 0x6, rd, 0x33);
+}
+
+void Riscv64Assembler::Maxu(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x5, rs2, rs1, 0x7, rd, 0x33);
+}
+
+void Riscv64Assembler::Rol(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x30, rs2, rs1, 0x1, rd, 0x33);
+}
+
+void Riscv64Assembler::Rolw(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x30, rs2, rs1, 0x1, rd, 0x3b);
+}
+
+void Riscv64Assembler::Ror(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x30, rs2, rs1, 0x5, rd, 0x33);
+}
+
+void Riscv64Assembler::Rorw(XRegister rd, XRegister rs1, XRegister rs2) {
+ EmitR(0x30, rs2, rs1, 0x5, rd, 0x3b);
+}
+
+void Riscv64Assembler::Rori(XRegister rd, XRegister rs1, int32_t shamt) {
+ CHECK_LT(static_cast<uint32_t>(shamt), 64u);
+ EmitI6(0x18, shamt, rs1, 0x5, rd, 0x13);
+}
+
+void Riscv64Assembler::Roriw(XRegister rd, XRegister rs1, int32_t shamt) {
+ CHECK_LT(static_cast<uint32_t>(shamt), 32u);
+ EmitI6(0x18, shamt, rs1, 0x5, rd, 0x1b);
+}
+
+void Riscv64Assembler::OrcB(XRegister rd, XRegister rs1) {
+ EmitR(0x14, 0x7, rs1, 0x5, rd, 0x13);
+}
+
+void Riscv64Assembler::Rev8(XRegister rd, XRegister rs1) {
+ EmitR(0x35, 0x18, rs1, 0x5, rd, 0x13);
+}
+
+/////////////////////////////// RV64 "Zbb" Instructions END //////////////////////////////
+
////////////////////////////// RV64 MACRO Instructions START ///////////////////////////////
// Pseudo instructions
@@ -824,6 +950,7 @@ void Riscv64Assembler::ZextH(XRegister rd, XRegister rs) {
}
void Riscv64Assembler::ZextW(XRegister rd, XRegister rs) {
+ // TODO(riscv64): Use the ZEXT.W alias for ADD.UW from the Zba extension.
Slli(rd, rs, kXlen - 32u);
Srli(rd, rd, kXlen - 32u);
}
diff --git a/compiler/utils/riscv64/assembler_riscv64.h b/compiler/utils/riscv64/assembler_riscv64.h
index 7f990b0ea3..d7583459b4 100644
--- a/compiler/utils/riscv64/assembler_riscv64.h
+++ b/compiler/utils/riscv64/assembler_riscv64.h
@@ -475,6 +475,41 @@ class Riscv64Assembler final : public Assembler {
void FClassS(XRegister rd, FRegister rs1);
void FClassD(XRegister rd, FRegister rs1);
+ // "Zba" Standard Extension, opcode = 0x1b, 0x33 or 0x3b, funct3 and funct7 varies.
+ void AddUw(XRegister rd, XRegister rs1, XRegister rs2);
+ void Sh1Add(XRegister rd, XRegister rs1, XRegister rs2);
+ void Sh1AddUw(XRegister rd, XRegister rs1, XRegister rs2);
+ void Sh2Add(XRegister rd, XRegister rs1, XRegister rs2);
+ void Sh2AddUw(XRegister rd, XRegister rs1, XRegister rs2);
+ void Sh3Add(XRegister rd, XRegister rs1, XRegister rs2);
+ void Sh3AddUw(XRegister rd, XRegister rs1, XRegister rs2);
+ void SlliUw(XRegister rd, XRegister rs1, int32_t shamt);
+
+ // "Zbb" Standard Extension, opcode = 0x13, 0x1b or 0x33, funct3 and funct7 varies.
+ // Note: We do not support 32-bit sext.b, sext.h and zext.h from the Zbb extension.
+ // (Neither does the clang-r498229's assembler which we currently test against.)
+ void Andn(XRegister rd, XRegister rs1, XRegister rs2);
+ void Orn(XRegister rd, XRegister rs1, XRegister rs2);
+ void Xnor(XRegister rd, XRegister rs1, XRegister rs2);
+ void Clz(XRegister rd, XRegister rs1);
+ void Clzw(XRegister rd, XRegister rs1);
+ void Ctz(XRegister rd, XRegister rs1);
+ void Ctzw(XRegister rd, XRegister rs1);
+ void Cpop(XRegister rd, XRegister rs1);
+ void Cpopw(XRegister rd, XRegister rs1);
+ void Min(XRegister rd, XRegister rs1, XRegister rs2);
+ void Minu(XRegister rd, XRegister rs1, XRegister rs2);
+ void Max(XRegister rd, XRegister rs1, XRegister rs2);
+ void Maxu(XRegister rd, XRegister rs1, XRegister rs2);
+ void Rol(XRegister rd, XRegister rs1, XRegister rs2);
+ void Rolw(XRegister rd, XRegister rs1, XRegister rs2);
+ void Ror(XRegister rd, XRegister rs1, XRegister rs2);
+ void Rorw(XRegister rd, XRegister rs1, XRegister rs2);
+ void Rori(XRegister rd, XRegister rs1, int32_t shamt);
+ void Roriw(XRegister rd, XRegister rs1, int32_t shamt);
+ void OrcB(XRegister rd, XRegister rs1);
+ void Rev8(XRegister rd, XRegister rs1);
+
////////////////////////////// RV64 MACRO Instructions START ///////////////////////////////
// These pseudo instructions are from "RISC-V Assembly Programmer's Manual".
diff --git a/compiler/utils/riscv64/assembler_riscv64_test.cc b/compiler/utils/riscv64/assembler_riscv64_test.cc
index a345d6956c..bb093d35a7 100644
--- a/compiler/utils/riscv64/assembler_riscv64_test.cc
+++ b/compiler/utils/riscv64/assembler_riscv64_test.cc
@@ -54,6 +54,37 @@ class AssemblerRISCV64Test : public AssemblerTest<Riscv64Assembler,
InstructionSet GetIsa() override { return InstructionSet::kRiscv64; }
+ // Clang's assembler takes advantage of certain extensions for emitting constants with `li`
+ // but our assembler does not. For now, we use a simple `-march` to avoid the divergence.
+ // TODO(riscv64): Implement these more efficient patterns in assembler.
+ void SetUseSimpleMarch(bool value) {
+ use_simple_march_ = value;
+ }
+
+ std::vector<std::string> GetAssemblerCommand() override {
+ std::vector<std::string> result = Base::GetAssemblerCommand();
+ if (use_simple_march_) {
+ auto it = std::find_if(result.begin(),
+ result.end(),
+ [](const std::string& s) { return StartsWith(s, "-march="); });
+ CHECK(it != result.end());
+ *it = "-march=rv64imafd";
+ }
+ return result;
+ }
+
+ std::vector<std::string> GetDisassemblerCommand() override {
+ std::vector<std::string> result = Base::GetDisassemblerCommand();
+ if (use_simple_march_) {
+ auto it = std::find_if(result.begin(),
+ result.end(),
+ [](const std::string& s) { return StartsWith(s, "--mattr="); });
+ CHECK(it != result.end());
+ *it = "--mattr=+F,+D,+A";
+ }
+ return result;
+ }
+
void SetUpHelpers() override {
if (secondary_register_names_.empty()) {
secondary_register_names_.emplace(Zero, "zero");
@@ -1190,6 +1221,7 @@ class AssemblerRISCV64Test : public AssemblerTest<Riscv64Assembler,
std::map<XRegister, std::string, RISCV64CpuRegisterCompare> secondary_register_names_;
std::unique_ptr<const Riscv64InstructionSetFeatures> instruction_set_features_;
+ bool use_simple_march_ = false;
};
TEST_F(AssemblerRISCV64Test, Toolchain) { EXPECT_TRUE(CheckTools()); }
@@ -2077,6 +2109,122 @@ TEST_F(AssemblerRISCV64Test, FClassD) {
DriverStr(RepeatrF(&Riscv64Assembler::FClassD, "fclass.d {reg1}, {reg2}"), "FClassD");
}
+TEST_F(AssemblerRISCV64Test, AddUw) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::AddUw, "add.uw {reg1}, {reg2}, {reg3}"), "AddUw");
+}
+
+TEST_F(AssemblerRISCV64Test, Sh1Add) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Sh1Add, "sh1add {reg1}, {reg2}, {reg3}"), "Sh1Add");
+}
+
+TEST_F(AssemblerRISCV64Test, Sh1AddUw) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Sh1AddUw, "sh1add.uw {reg1}, {reg2}, {reg3}"), "Sh1AddUw");
+}
+
+TEST_F(AssemblerRISCV64Test, Sh2Add) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Sh2Add, "sh2add {reg1}, {reg2}, {reg3}"), "Sh2Add");
+}
+
+TEST_F(AssemblerRISCV64Test, Sh2AddUw) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Sh2AddUw, "sh2add.uw {reg1}, {reg2}, {reg3}"), "Sh2AddUw");
+}
+
+TEST_F(AssemblerRISCV64Test, Sh3Add) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Sh3Add, "sh3add {reg1}, {reg2}, {reg3}"), "Sh3Add");
+}
+
+TEST_F(AssemblerRISCV64Test, Sh3AddUw) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Sh3AddUw, "sh3add.uw {reg1}, {reg2}, {reg3}"), "Sh3AddUw");
+}
+
+TEST_F(AssemblerRISCV64Test, SlliUw) {
+ DriverStr(RepeatRRIb(&Riscv64Assembler::SlliUw, 6, "slli.uw {reg1}, {reg2}, {imm}"), "SlliUw");
+}
+
+TEST_F(AssemblerRISCV64Test, Andn) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Andn, "andn {reg1}, {reg2}, {reg3}"), "Andn");
+}
+
+TEST_F(AssemblerRISCV64Test, Orn) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Orn, "orn {reg1}, {reg2}, {reg3}"), "Orn");
+}
+
+TEST_F(AssemblerRISCV64Test, Xnor) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Xnor, "xnor {reg1}, {reg2}, {reg3}"), "Xnor");
+}
+
+TEST_F(AssemblerRISCV64Test, Clz) {
+ DriverStr(RepeatRR(&Riscv64Assembler::Clz, "clz {reg1}, {reg2}"), "Clz");
+}
+
+TEST_F(AssemblerRISCV64Test, Clzw) {
+ DriverStr(RepeatRR(&Riscv64Assembler::Clzw, "clzw {reg1}, {reg2}"), "Clzw");
+}
+
+TEST_F(AssemblerRISCV64Test, Ctz) {
+ DriverStr(RepeatRR(&Riscv64Assembler::Ctz, "ctz {reg1}, {reg2}"), "Ctz");
+}
+
+TEST_F(AssemblerRISCV64Test, Ctzw) {
+ DriverStr(RepeatRR(&Riscv64Assembler::Ctzw, "ctzw {reg1}, {reg2}"), "Ctzw");
+}
+
+TEST_F(AssemblerRISCV64Test, Cpop) {
+ DriverStr(RepeatRR(&Riscv64Assembler::Cpop, "cpop {reg1}, {reg2}"), "Cpop");
+}
+
+TEST_F(AssemblerRISCV64Test, Cpopw) {
+ DriverStr(RepeatRR(&Riscv64Assembler::Cpopw, "cpopw {reg1}, {reg2}"), "Cpopw");
+}
+
+TEST_F(AssemblerRISCV64Test, Min) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Min, "min {reg1}, {reg2}, {reg3}"), "Min");
+}
+
+TEST_F(AssemblerRISCV64Test, Minu) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Minu, "minu {reg1}, {reg2}, {reg3}"), "Minu");
+}
+
+TEST_F(AssemblerRISCV64Test, Max) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Max, "max {reg1}, {reg2}, {reg3}"), "Max");
+}
+
+TEST_F(AssemblerRISCV64Test, Maxu) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Maxu, "maxu {reg1}, {reg2}, {reg3}"), "Maxu");
+}
+
+TEST_F(AssemblerRISCV64Test, Rol) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Rol, "rol {reg1}, {reg2}, {reg3}"), "Rol");
+}
+
+TEST_F(AssemblerRISCV64Test, Rolw) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Rolw, "rolw {reg1}, {reg2}, {reg3}"), "Rolw");
+}
+
+TEST_F(AssemblerRISCV64Test, Ror) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Ror, "ror {reg1}, {reg2}, {reg3}"), "Ror");
+}
+
+TEST_F(AssemblerRISCV64Test, Rorw) {
+ DriverStr(RepeatRRR(&Riscv64Assembler::Rorw, "rorw {reg1}, {reg2}, {reg3}"), "Rorw");
+}
+
+TEST_F(AssemblerRISCV64Test, Rori) {
+ DriverStr(RepeatRRIb(&Riscv64Assembler::Rori, 6, "rori {reg1}, {reg2}, {imm}"), "Rori");
+}
+
+TEST_F(AssemblerRISCV64Test, Roriw) {
+ DriverStr(RepeatRRIb(&Riscv64Assembler::Roriw, 5, "roriw {reg1}, {reg2}, {imm}"), "Roriw");
+}
+
+TEST_F(AssemblerRISCV64Test, OrcB) {
+ DriverStr(RepeatRR(&Riscv64Assembler::OrcB, "orc.b {reg1}, {reg2}"), "OrcB");
+}
+
+TEST_F(AssemblerRISCV64Test, Rev8) {
+ DriverStr(RepeatRR(&Riscv64Assembler::Rev8, "rev8 {reg1}, {reg2}"), "Rev8");
+}
+
// Pseudo instructions.
TEST_F(AssemblerRISCV64Test, Nop) {
__ Nop();
@@ -2084,6 +2232,7 @@ TEST_F(AssemblerRISCV64Test, Nop) {
}
TEST_F(AssemblerRISCV64Test, Li) {
+ SetUseSimpleMarch(true);
TestLoadConst64("Li",
/*can_use_tmp=*/ false,
[&](XRegister rd, int64_t value) { __ Li(rd, value); });
@@ -2106,6 +2255,7 @@ TEST_F(AssemblerRISCV64Test, NegW) {
}
TEST_F(AssemblerRISCV64Test, SextB) {
+ // Note: SEXT.B from the Zbb extension is not supported.
DriverStr(RepeatRR(&Riscv64Assembler::SextB,
"slli {reg1}, {reg2}, 56\n"
"srai {reg1}, {reg1}, 56"),
@@ -2113,6 +2263,7 @@ TEST_F(AssemblerRISCV64Test, SextB) {
}
TEST_F(AssemblerRISCV64Test, SextH) {
+ // Note: SEXT.H from the Zbb extension is not supported.
DriverStr(RepeatRR(&Riscv64Assembler::SextH,
"slli {reg1}, {reg2}, 48\n"
"srai {reg1}, {reg1}, 48"),
@@ -2128,6 +2279,7 @@ TEST_F(AssemblerRISCV64Test, ZextB) {
}
TEST_F(AssemblerRISCV64Test, ZextH) {
+ // Note: ZEXT.H from the Zbb extension is not supported.
DriverStr(RepeatRR(&Riscv64Assembler::ZextH,
"slli {reg1}, {reg2}, 48\n"
"srli {reg1}, {reg1}, 48"),
@@ -2138,7 +2290,7 @@ TEST_F(AssemblerRISCV64Test, ZextW) {
DriverStr(RepeatRR(&Riscv64Assembler::ZextW,
"slli {reg1}, {reg2}, 32\n"
"srli {reg1}, {reg1}, 32"),
- "SextW");
+ "ZextW");
}
TEST_F(AssemblerRISCV64Test, Seqz) {
@@ -2314,6 +2466,7 @@ TEST_F(AssemblerRISCV64Test, LoadConst32) {
}
TEST_F(AssemblerRISCV64Test, LoadConst64) {
+ SetUseSimpleMarch(true);
TestLoadConst64("LoadConst64",
/*can_use_tmp=*/ true,
[&](XRegister rd, int64_t value) { __ LoadConst64(rd, value); });
@@ -2327,6 +2480,7 @@ TEST_F(AssemblerRISCV64Test, AddConst32) {
}
TEST_F(AssemblerRISCV64Test, AddConst64) {
+ SetUseSimpleMarch(true);
auto emit_op = [&](XRegister rd, XRegister rs1, int64_t value) {
__ AddConst64(rd, rs1, value);
};
diff --git a/disassembler/disassembler_riscv64.cc b/disassembler/disassembler_riscv64.cc
index cdb0390ce0..1dcf1a31cd 100644
--- a/disassembler/disassembler_riscv64.cc
+++ b/disassembler/disassembler_riscv64.cc
@@ -393,6 +393,19 @@ void DisassemblerRiscv64::Printer::Print32BinOpImm(uint32_t insn32) {
os_ << "zextb " << XRegName(rd) << ", " << XRegName(rs1);
} else if (!narrow && funct3 == /*SLTIU*/ 3u && imm == 1) {
os_ << "seqz " << XRegName(rd) << ", " << XRegName(rs1);
+ } else if ((insn32 & 0xfc00707fu) == 0x0800101bu) {
+ os_ << "slli.uw " << XRegName(rd) << ", " << XRegName(rs1) << ", " << (imm & 0x3fu);
+ } else if ((imm ^ 0x600u) < 3u && funct3 == 1u) {
+ static const char* const kBitOpcodes[] = { "clz", "ctz", "cpop" };
+ os_ << kBitOpcodes[imm ^ 0x600u] << (narrow ? "w " : " ")
+ << XRegName(rd) << ", " << XRegName(rs1);
+ } else if ((imm ^ 0x600u) < (narrow ? 32 : 64) && funct3 == 5u) {
+ os_ << "rori" << (narrow ? "w " : " ")
+ << XRegName(rd) << ", " << XRegName(rs1) << ", " << (imm ^ 0x600u);
+ } else if (imm == 0x287u && !narrow && funct3 == 5u) {
+ os_ << "orc.b " << XRegName(rd) << ", " << XRegName(rs1);
+ } else if (imm == 0x6b8u && !narrow && funct3 == 5u) {
+ os_ << "rev8 " << XRegName(rd) << ", " << XRegName(rs1);
} else {
bool bad_high_bits = false;
if (funct3 == /*SLLI*/ 1u || funct3 == /*SRLI/SRAI*/ 5u) {
@@ -439,16 +452,34 @@ void DisassemblerRiscv64::Printer::Print32BinOp(uint32_t insn32) {
os_ << "sgtz " << XRegName(rd) << ", " << XRegName(rs2);
} else if (!narrow && funct3 == /*SLTU*/ 3u && rs1 == Zero) {
os_ << "snez " << XRegName(rd) << ", " << XRegName(rs2);
+ } else if (narrow && high_bits == 0x08000000u && funct3 == /*ADD.UW*/ 0u && rs2 == Zero) {
+ os_ << "zext.w " << XRegName(rd) << ", " << XRegName(rs1);
} else {
bool bad_high_bits = false;
if (high_bits == 0x40000000u && (funct3 == /*SUB*/ 0u || funct3 == /*SRA*/ 5u)) {
os_ << ((funct3 == /*SUB*/ 0u) ? "sub" : "sra");
- } else if (high_bits == 0x02000000 &&
+ } else if (high_bits == 0x02000000u &&
(!narrow || (funct3 == /*MUL*/ 0u || funct3 >= /*DIV/DIVU/REM/REMU*/ 4u))) {
static const char* const kOpcodes[] = {
"mul", "mulh", "mulhsu", "mulhu", "div", "divu", "rem", "remu"
};
os_ << kOpcodes[funct3];
+ } else if (high_bits == 0x08000000u && narrow && funct3 == /*ADD.UW*/ 0u) {
+ os_ << "add.u"; // "w" is added below.
+ } else if (high_bits == 0x20000000u && (funct3 & 1u) == 0u && funct3 != 0u) {
+ static const char* const kZbaOpcodes[] = { nullptr, "sh1add", "sh2add", "sh3add" };
+ DCHECK(kZbaOpcodes[funct3 >> 1] != nullptr);
+ os_ << kZbaOpcodes[funct3 >> 1] << (narrow ? ".u" /* "w" is added below. */ : "");
+ } else if (high_bits == 0x40000000u && !narrow && funct3 >= 4u && funct3 != 5u) {
+ static const char* const kZbbNegOpcodes[] = { "xnor", nullptr, "orn", "andn" };
+ DCHECK(kZbbNegOpcodes[funct3 - 4u] != nullptr);
+ os_ << kZbbNegOpcodes[funct3 - 4u];
+ } else if (high_bits == 0x0a000000u && !narrow && funct3 >= 4u) {
+ static const char* const kZbbMinMaxOpcodes[] = { "min", "minu", "max", "maxu" };
+ DCHECK(kZbbMinMaxOpcodes[funct3 - 4u] != nullptr);
+ os_ << kZbbMinMaxOpcodes[funct3 - 4u];
+ } else if (high_bits == 0x60000000u && (funct3 == /*ROL*/ 1u || funct3 == /*ROL*/ 5u)) {
+ os_ << (funct3 == /*ROL*/ 1u ? "rol" : "ror");
} else if (!narrow || (funct3 == /*ADD*/ 0u || funct3 == /*SLL*/ 1u || funct3 == /*SRL*/ 5u)) {
static const char* const kOpcodes[] = {
"add", "sll", "slt", "sltu", "xor", "srl", "or", "and"