Add assembler for riscv64, part 4.
Implement fences, LR/SC and atomic operations.
Test: m test-art-host-gtest
Bug: 283082089
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: If10463d33071db577c4cc775ad3700c1746e093d
diff --git a/compiler/utils/assembler_test_base.h b/compiler/utils/assembler_test_base.h
index fb950f8..47ce8e6 100644
--- a/compiler/utils/assembler_test_base.h
+++ b/compiler/utils/assembler_test_base.h
@@ -174,7 +174,7 @@
"--disassemble",
"--no-print-imm-hex",
"--no-show-raw-insn",
- "--mattr=+F,+D", // Disassemble "F" and "D" Standard Extensions.
+ "--mattr=+F,+D,+A", // Disassemble "F", "D" and "A" Standard Extensions.
"-M",
"no-aliases"};
default:
diff --git a/compiler/utils/riscv64/assembler_riscv64.cc b/compiler/utils/riscv64/assembler_riscv64.cc
index 80b97a3..8787005 100644
--- a/compiler/utils/riscv64/assembler_riscv64.cc
+++ b/compiler/utils/riscv64/assembler_riscv64.cc
@@ -70,7 +70,7 @@
/////////////////////////////// RV64 VARIANTS extension ///////////////////////////////
-/////////////////////////////// RV64 "IM" Instructions ///////////////////////////////
+//////////////////////////////// RV64 "I" Instructions ////////////////////////////////
// LUI/AUIPC (RV32I, with sign-extension on RV64I), opcode = 0x17, 0x37
@@ -295,6 +295,24 @@
EmitR(0x20, rs2, rs1, 0x5, rd, 0x3b);
}
+// Fence instruction (RV32I): opcode = 0xf, funct3 = 0
+void Riscv64Assembler::Fence(uint32_t pred, uint32_t succ) {
+ DCHECK(IsUint<4>(pred));
+ DCHECK(IsUint<4>(succ));
+ EmitI(/* normal fence */ 0x0 << 8 | pred << 4 | succ, 0x0, 0x0, 0x0, 0xf);
+}
+
+//////////////////////////////// RV64 "I" Instructions END ////////////////////////////////
+
+/////////////////////////// RV64 "Zifencei" Instructions START ////////////////////////////
+
+// "Zifencei" Standard Extension, opcode = 0xf, funct3 = 1
+void Riscv64Assembler::FenceI() { EmitI(0x0, 0x0, 0x1, 0x0, 0xf); }
+
+//////////////////////////// RV64 "Zifencei" Instructions END /////////////////////////////
+
+/////////////////////////////// RV64 "M" Instructions START ///////////////////////////////
+
// RV32M Standard Extension: opcode = 0x33, funct3 from 0x0 ~ 0x7
void Riscv64Assembler::Mul(XRegister rd, XRegister rs1, XRegister rs2) {
@@ -351,7 +369,99 @@
EmitR(0x1, rs2, rs1, 0x7, rd, 0x3b);
}
-/////////////////////////////// RV64 "IM" Instructions END ///////////////////////////////
+//////////////////////////////// RV64 "M" Instructions END ////////////////////////////////
+
+/////////////////////////////// RV64 "A" Instructions START ///////////////////////////////
+
+void Riscv64Assembler::LrW(XRegister rd, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x2, aqrl, 0x0, rs1, 0x2, rd, 0x2f);
+}
+
+void Riscv64Assembler::LrD(XRegister rd, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x2, aqrl, 0x0, rs1, 0x3, rd, 0x2f);
+}
+
+void Riscv64Assembler::ScW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x3, aqrl, rs2, rs1, 0x2, rd, 0x2f);
+}
+
+void Riscv64Assembler::ScD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x3, aqrl, rs2, rs1, 0x3, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoSwapW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x1, aqrl, rs2, rs1, 0x2, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoSwapD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x1, aqrl, rs2, rs1, 0x3, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoAddW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x0, aqrl, rs2, rs1, 0x2, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoAddD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x0, aqrl, rs2, rs1, 0x3, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoXorW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x4, aqrl, rs2, rs1, 0x2, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoXorD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x4, aqrl, rs2, rs1, 0x3, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoAndW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0xc, aqrl, rs2, rs1, 0x2, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoAndD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0xc, aqrl, rs2, rs1, 0x3, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoOrW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x8, aqrl, rs2, rs1, 0x2, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoOrD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x8, aqrl, rs2, rs1, 0x3, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoMinW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x10, aqrl, rs2, rs1, 0x2, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoMinD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x10, aqrl, rs2, rs1, 0x3, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoMaxW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x14, aqrl, rs2, rs1, 0x2, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoMaxD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x14, aqrl, rs2, rs1, 0x3, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoMinuW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x18, aqrl, rs2, rs1, 0x2, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoMinuD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x18, aqrl, rs2, rs1, 0x3, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoMaxuW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x1c, aqrl, rs2, rs1, 0x2, rd, 0x2f);
+}
+
+void Riscv64Assembler::AmoMaxuD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl) {
+ EmitR4(0x1c, aqrl, rs2, rs1, 0x3, rd, 0x2f);
+}
+
+/////////////////////////////// RV64 "A" Instructions END ///////////////////////////////
/////////////////////////////// RV64 "FD" Instructions START ///////////////////////////////
diff --git a/compiler/utils/riscv64/assembler_riscv64.h b/compiler/utils/riscv64/assembler_riscv64.h
index 1071add..5f7c246 100644
--- a/compiler/utils/riscv64/assembler_riscv64.h
+++ b/compiler/utils/riscv64/assembler_riscv64.h
@@ -52,6 +52,16 @@
static constexpr size_t kRiscv64WordSize = 4;
static constexpr size_t kRiscv64DoublewordSize = 8;
+// the type for fence
+enum FenceType {
+ kFenceNone = 0,
+ kFenceWrite = 1,
+ kFenceRead = 2,
+ kFenceOutput = 4,
+ kFenceInput = 8,
+ kFenceDefault = 0xf,
+};
+
class Riscv64Label : public Label {
public:
Riscv64Label() : prev_branch_id_(kNoPrevBranchId) {}
@@ -220,6 +230,12 @@
void Srlw(XRegister rd, XRegister rs1, XRegister rs2);
void Sraw(XRegister rd, XRegister rs1, XRegister rs2);
+ // Fence instruction (RV32I): opcode = 0xf, funct3 = 0
+ void Fence(uint32_t pred = kFenceDefault, uint32_t succ = kFenceDefault);
+
+ // "Zifencei" Standard Extension, opcode = 0xf, funct3 = 1
+ void FenceI();
+
// 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);
@@ -237,6 +253,30 @@
void Remw(XRegister rd, XRegister rs1, XRegister rs2);
void Remuw(XRegister rd, XRegister rs1, XRegister rs2);
+ // RV32A/RV64A Standard Extension
+ void LrW(XRegister rd, XRegister rs1, uint32_t aqrl);
+ void LrD(XRegister rd, XRegister rs1, uint32_t aqrl);
+ void ScW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void ScD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoSwapW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoSwapD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoAddW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoAddD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoXorW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoXorD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoAndW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoAndD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoOrW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoOrD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoMinW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoMinD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoMaxW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoMaxD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoMinuW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoMinuD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoMaxuW(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+ void AmoMaxuD(XRegister rd, XRegister rs2, XRegister rs1, uint32_t aqrl);
+
// 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);
diff --git a/compiler/utils/riscv64/assembler_riscv64_test.cc b/compiler/utils/riscv64/assembler_riscv64_test.cc
index be20faa..f936cb6 100644
--- a/compiler/utils/riscv64/assembler_riscv64_test.cc
+++ b/compiler/utils/riscv64/assembler_riscv64_test.cc
@@ -531,7 +531,83 @@
DriverStr(expected, test_name);
}
+ std::string RepeatRRAqRl(void (Riscv64Assembler::*f)(XRegister, XRegister, uint32_t),
+ const std::string& fmt) {
+ CHECK(f != nullptr);
+ std::vector<int64_t> imms = CreateImmediateValuesBits(2, /*as_uint=*/ true);
+ std::string str;
+ for (XRegister* reg1 : GetRegisters()) {
+ for (XRegister* reg2 : GetRegisters()) {
+ for (int64_t imm : imms) {
+ (GetAssembler()->*f)(*reg1, *reg2, dchecked_integral_cast<uint32_t>(imm));
+ std::string base = fmt;
+
+ ReplaceReg(REG1_TOKEN, GetRegisterName(*reg1), &base);
+ ReplaceReg(REG2_TOKEN, GetRegisterName(*reg2), &base);
+ ReplaceAqRl(imm, &base);
+
+ str += base;
+ str += "\n";
+ }
+ }
+ }
+ return str;
+ }
+
+ std::string RepeatRRRAqRl(void (Riscv64Assembler::*f)(XRegister, XRegister, XRegister, uint32_t),
+ const std::string& fmt) {
+ CHECK(f != nullptr);
+ std::vector<int64_t> imms = CreateImmediateValuesBits(2, /*as_uint=*/ true);
+ std::string str;
+ for (XRegister* reg1 : GetRegisters()) {
+ for (XRegister* reg2 : GetRegisters()) {
+ for (XRegister* reg3 : GetRegisters()) {
+ for (int64_t imm : imms) {
+ (GetAssembler()->*f)(*reg1, *reg2, *reg3, dchecked_integral_cast<uint32_t>(imm));
+ std::string base = fmt;
+
+ ReplaceReg(REG1_TOKEN, GetRegisterName(*reg1), &base);
+ ReplaceReg(REG2_TOKEN, GetRegisterName(*reg2), &base);
+ ReplaceReg(REG3_TOKEN, GetRegisterName(*reg3), &base);
+ ReplaceAqRl(imm, &base);
+
+ str += base;
+ str += "\n";
+ }
+ }
+ }
+ }
+ return str;
+ }
+
private:
+ static constexpr const char* AQRL_TOKEN = "{aqrl}";
+
+ void ReplaceAqRl(int64_t aqrl, /*inout*/ std::string* str) {
+ const char* replacement;
+ switch (aqrl) {
+ case 0:
+ replacement = "";
+ break;
+ case 1:
+ replacement = ".rl";
+ break;
+ case 2:
+ replacement = ".aq";
+ break;
+ case 3:
+ replacement = ".aqrl";
+ break;
+ default:
+ LOG(FATAL) << "Unexpected value for `aqrl`: " << aqrl;
+ UNREACHABLE();
+ }
+ size_t aqrl_index = str->find(AQRL_TOKEN);
+ if (aqrl_index != std::string::npos) {
+ str->replace(aqrl_index, ConstexprStrLen(AQRL_TOKEN), replacement);
+ }
+ }
+
std::vector<riscv64::XRegister*> registers_;
std::map<riscv64::XRegister, std::string, RISCV64CpuRegisterCompare> secondary_register_names_;
@@ -762,6 +838,46 @@
DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Sraw, "sraw {reg1}, {reg2}, {reg3}"), "Sraw");
}
+TEST_F(AssemblerRISCV64Test, Fence) {
+ auto get_fence_type_string = [](uint32_t fence_type) {
+ CHECK_LE(fence_type, 0xfu);
+ std::string result;
+ if ((fence_type & kFenceInput) != 0u) {
+ result += "i";
+ }
+ if ((fence_type & kFenceOutput) != 0u) {
+ result += "o";
+ }
+ if ((fence_type & kFenceRead) != 0u) {
+ result += "r";
+ }
+ if ((fence_type & kFenceWrite) != 0u) {
+ result += "w";
+ }
+ if (result.empty()) {
+ result += "0";
+ }
+ return result;
+ };
+
+ std::string expected;
+ // Note: The `pred` and `succ` are 4 bits each.
+ // Some combinations are not really useful but the assembler can emit them all.
+ for (uint32_t pred = 0u; pred != 0x10; ++pred) {
+ for (uint32_t succ = 0u; succ != 0x10; ++succ) {
+ __ Fence(pred, succ);
+ expected +=
+ "fence " + get_fence_type_string(pred) + ", " + get_fence_type_string(succ) + "\n";
+ }
+ }
+ DriverStr(expected, "Fence");
+}
+
+TEST_F(AssemblerRISCV64Test, FenceI) {
+ __ FenceI();
+ DriverStr("fence.i", "FenceI");
+}
+
TEST_F(AssemblerRISCV64Test, Mul) {
DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Mul, "mul {reg1}, {reg2}, {reg3}"), "Mul");
}
@@ -814,6 +930,132 @@
DriverStr(RepeatRRR(&riscv64::Riscv64Assembler::Remuw, "remuw {reg1}, {reg2}, {reg3}"), "Remuw");
}
+TEST_F(AssemblerRISCV64Test, LrW) {
+ DriverStr(RepeatRRAqRl(&riscv64::Riscv64Assembler::LrW, "lr.w{aqrl} {reg1}, ({reg2})"), "LrW");
+}
+
+TEST_F(AssemblerRISCV64Test, LrD) {
+ DriverStr(RepeatRRAqRl(&riscv64::Riscv64Assembler::LrD, "lr.d{aqrl} {reg1}, ({reg2})"), "LrD");
+}
+
+TEST_F(AssemblerRISCV64Test, ScW) {
+ DriverStr(RepeatRRRAqRl(&riscv64::Riscv64Assembler::ScW, "sc.w{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "ScW");
+}
+
+TEST_F(AssemblerRISCV64Test, ScD) {
+ DriverStr(RepeatRRRAqRl(&riscv64::Riscv64Assembler::ScD, "sc.d{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "ScD");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoSwapW) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoSwapW, "amoswap.w{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoSwapW");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoSwapD) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoSwapD, "amoswap.d{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoSwapD");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoAddW) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoAddW, "amoadd.w{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoAddW");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoAddD) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoAddD, "amoadd.d{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoAddD");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoXorW) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoXorW, "amoxor.w{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoXorW");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoXorD) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoXorD, "amoxor.d{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoXorD");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoAndW) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoAndW, "amoand.w{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoAndW");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoAndD) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoAndD, "amoand.d{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoAndD");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoOrW) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoOrW, "amoor.w{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoOrW");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoOrD) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoOrD, "amoor.d{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoOrD");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoMinW) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoMinW, "amomin.w{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoMinW");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoMinD) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoMinD, "amomin.d{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoMinD");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoMaxW) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoMaxW, "amomax.w{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoMaxW");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoMaxD) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoMaxD, "amomax.d{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoMaxD");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoMinuW) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoMinuW, "amominu.w{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoMinuW");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoMinuD) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoMinuD, "amominu.d{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoMinuD");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoMaxuW) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoMaxuW, "amomaxu.w{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoMaxuW");
+}
+
+TEST_F(AssemblerRISCV64Test, AmoMaxuD) {
+ DriverStr(RepeatRRRAqRl(
+ &riscv64::Riscv64Assembler::AmoMaxuD, "amomaxu.d{aqrl} {reg1}, {reg2}, ({reg3})"),
+ "AmoMaxuD");
+}
+
TEST_F(AssemblerRISCV64Test, FLw) {
DriverStr(RepeatFRIb(&riscv64::Riscv64Assembler::FLw, -12, "flw {reg1}, {imm}({reg2})"), "FLw");
}