diff options
author | 2023-08-17 09:53:57 +0000 | |
---|---|---|
committer | 2023-08-21 06:52:16 +0000 | |
commit | b1a0d105523f17449f8d41c44f8a714cb1b31902 (patch) | |
tree | c25fa599187f3bef559e48c0750081a9d3f5464b | |
parent | 5655ec289c3ffd389a02108e2e601b16a9dedbd4 (diff) |
riscv64: Add support for Zba and Zbb extensions.
Test: m test-art-host-gtest
Test: Manually add calls to emit these instructions after
UNIMP in JNI assembler's `DeliverPendingException()`
and then `m dump-oat` and inspect the output.
Bug: 283082089
Change-Id: I4807d0b214e7896544dd74349e0637a1e37fc1bf
-rw-r--r-- | compiler/utils/assembler_test_base.h | 5 | ||||
-rw-r--r-- | compiler/utils/riscv64/assembler_riscv64.cc | 139 | ||||
-rw-r--r-- | compiler/utils/riscv64/assembler_riscv64.h | 35 | ||||
-rw-r--r-- | compiler/utils/riscv64/assembler_riscv64_test.cc | 156 | ||||
-rw-r--r-- | disassembler/disassembler_riscv64.cc | 33 |
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" |