[vm] Add the RISC-V Zicond extension.
TEST=ci, local qemu
Change-Id: I0d367b762d989b3f9bae0937c7670b175d111453
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/394620
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/vm/compiler/assembler/assembler_riscv.cc b/runtime/vm/compiler/assembler/assembler_riscv.cc
index ca4c559..db4a4f8 100644
--- a/runtime/vm/compiler/assembler/assembler_riscv.cc
+++ b/runtime/vm/compiler/assembler/assembler_riscv.cc
@@ -1634,6 +1634,16 @@
EmitRType(BSET, shamt, rs1, F3_BSET, rd, OPIMM);
}
+void MicroAssembler::czeroeqz(Register rd, Register rs1, Register rs2) {
+ ASSERT(Supports(RV_Zicond));
+ EmitRType(CZERO, rs2, rs1, CZEROEQZ, rd, OP);
+}
+
+void MicroAssembler::czeronez(Register rd, Register rs1, Register rs2) {
+ ASSERT(Supports(RV_Zicond));
+ EmitRType(CZERO, rs2, rs1, CZERONEZ, rd, OP);
+}
+
void MicroAssembler::lb(Register rd, Address addr, std::memory_order order) {
ASSERT(addr.offset() == 0);
ASSERT((order == std::memory_order_acquire) ||
diff --git a/runtime/vm/compiler/assembler/assembler_riscv.h b/runtime/vm/compiler/assembler/assembler_riscv.h
index b6d5d07..1adbfe3 100644
--- a/runtime/vm/compiler/assembler/assembler_riscv.h
+++ b/runtime/vm/compiler/assembler/assembler_riscv.h
@@ -606,6 +606,12 @@
void bset(Register rd, Register rs1, Register rs2);
void bseti(Register rd, Register rs1, intx_t shamt);
+ // ==== Zicond: Integer conditional operations ====
+ // rd := rs2 == 0 ? 0 : rs1
+ void czeroeqz(Register rd, Register rs1, Register rs2);
+ // rd := rs2 != 0 ? 0 : rs1
+ void czeronez(Register rd, Register rs1, Register rs2);
+
// ==== Zalasr: Load-acquire, store-release ====
void lb(Register rd, Address addr, std::memory_order order);
void lh(Register rd, Address addr, std::memory_order order);
diff --git a/runtime/vm/compiler/assembler/assembler_riscv_test.cc b/runtime/vm/compiler/assembler/assembler_riscv_test.cc
index 4ecb945..d115882 100644
--- a/runtime/vm/compiler/assembler/assembler_riscv_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_riscv_test.cc
@@ -6924,6 +6924,36 @@
EXPECT_EQ(-1, Call(test->entry(), -1));
}
+ASSEMBLER_TEST_GENERATE(ConditionalZeroIfEqualsZero, assembler) {
+ __ SetExtensions(RV_GC | RV_Zicond);
+ __ czeroeqz(A0, A0, A1);
+ __ ret();
+}
+ASSEMBLER_TEST_RUN(ConditionalZeroIfEqualsZero, test) {
+ EXPECT_DISASSEMBLY(
+ "0eb55533 czero.eqz a0, a0, a1\n"
+ " 8082 ret\n");
+
+ EXPECT_EQ(0, Call(test->entry(), 42, 0));
+ EXPECT_EQ(42, Call(test->entry(), 42, 1));
+ EXPECT_EQ(42, Call(test->entry(), 42, -1));
+}
+
+ASSEMBLER_TEST_GENERATE(ConditionalZeroIfNotEqualsZero, assembler) {
+ __ SetExtensions(RV_GC | RV_Zicond);
+ __ czeronez(A0, A0, A1);
+ __ ret();
+}
+ASSEMBLER_TEST_RUN(ConditionalZeroIfNotEqualsZero, test) {
+ EXPECT_DISASSEMBLY(
+ "0eb57533 czero.nez a0, a0, a1\n"
+ " 8082 ret\n");
+
+ EXPECT_EQ(42, Call(test->entry(), 42, 0));
+ EXPECT_EQ(0, Call(test->entry(), 42, 1));
+ EXPECT_EQ(0, Call(test->entry(), 42, -1));
+}
+
ASSEMBLER_TEST_GENERATE(LoadByteAcquire, assembler) {
__ SetExtensions(RV_GC | RV_Zalasr);
__ lb(A0, Address(A1), std::memory_order_acquire);
diff --git a/runtime/vm/compiler/assembler/disassembler_riscv.cc b/runtime/vm/compiler/assembler/disassembler_riscv.cc
index b2634a9..9c1a412 100644
--- a/runtime/vm/compiler/assembler/disassembler_riscv.cc
+++ b/runtime/vm/compiler/assembler/disassembler_riscv.cc
@@ -69,6 +69,7 @@
void DisassembleOP_MINMAXCLMUL(Instr instr);
void DisassembleOP_ROTATE(Instr instr);
void DisassembleOP_BCLRBEXT(Instr instr);
+ void DisassembleOP_CZERO(Instr instr);
void DisassembleOP32(Instr instr);
void DisassembleOP32_0(Instr instr);
void DisassembleOP32_SUB(Instr instr);
@@ -713,6 +714,9 @@
Print("zext.h 'rd, 'rs1", instr, RV_Zbb);
break;
#endif
+ case CZERO:
+ DisassembleOP_CZERO(instr);
+ break;
default:
UnknownInstruction(instr);
}
@@ -886,6 +890,19 @@
}
}
+void RISCVDisassembler::DisassembleOP_CZERO(Instr instr) {
+ switch (instr.funct3()) {
+ case CZEROEQZ:
+ Print("czero.eqz 'rd, 'rs1, 'rs2", instr, RV_Zicond);
+ break;
+ case CZERONEZ:
+ Print("czero.nez 'rd, 'rs1, 'rs2", instr, RV_Zicond);
+ break;
+ default:
+ UnknownInstruction(instr);
+ }
+}
+
void RISCVDisassembler::DisassembleOP32(Instr instr) {
switch (instr.funct7()) {
case 0:
diff --git a/runtime/vm/constants_riscv.h b/runtime/vm/constants_riscv.h
index 8200b11..fa1b73d 100644
--- a/runtime/vm/constants_riscv.h
+++ b/runtime/vm/constants_riscv.h
@@ -838,6 +838,9 @@
BEXT = 0b101,
F3_BINV = 0b001,
F3_BSET = 0b001,
+
+ CZEROEQZ = 0b101,
+ CZERONEZ = 0b111,
};
enum Funct7 {
@@ -885,6 +888,8 @@
BCLRBEXT = 0b0100100,
BINV = 0b0110100,
BSET = 0b0010100,
+
+ CZERO = 0b0000111,
};
enum Funct5 {
@@ -1617,10 +1622,11 @@
static constexpr Extension RV_Zba(6); // Address generation
static constexpr Extension RV_Zbb(7); // Basic bit-manipulation
static constexpr Extension RV_Zbs(8); // Single-bit instructions
+static constexpr Extension RV_Zbc(9); // Carry-less multiplication
static constexpr ExtensionSet RV_B = RV_Zba | RV_Zbb | RV_Zbs;
static constexpr ExtensionSet RV_GCB = RV_GC | RV_B;
-static constexpr Extension RV_Zbc(9); // Carry-less multiplication
-static constexpr Extension RV_Zalasr(10); // Load-acquire, store-release
+static constexpr Extension RV_Zicond(10); // Integer conditional operations
+static constexpr Extension RV_Zalasr(11); // Load-acquire, store-release
#if defined(DART_TARGET_OS_FUCHSIA) || defined(DART_TARGET_OS_ANDROID)
static constexpr ExtensionSet RV_baseline = RV_GCB;
diff --git a/runtime/vm/simulator_riscv.cc b/runtime/vm/simulator_riscv.cc
index eb44c25..353127a 100644
--- a/runtime/vm/simulator_riscv.cc
+++ b/runtime/vm/simulator_riscv.cc
@@ -1332,6 +1332,9 @@
pc_ += instr.length();
break;
#endif
+ case CZERO:
+ InterpretOP_CZERO(instr);
+ break;
default:
IllegalInstruction(instr);
}
@@ -1664,6 +1667,23 @@
}
DART_FORCE_INLINE
+void Simulator::InterpretOP_CZERO(Instr instr) {
+ switch (instr.funct3()) {
+ case CZEROEQZ:
+ set_xreg(instr.rd(),
+ get_xreg(instr.rs2()) == 0 ? 0 : get_xreg(instr.rs1()));
+ break;
+ case CZERONEZ:
+ set_xreg(instr.rd(),
+ get_xreg(instr.rs2()) != 0 ? 0 : get_xreg(instr.rs1()));
+ break;
+ default:
+ IllegalInstruction(instr);
+ }
+ pc_ += instr.length();
+}
+
+DART_FORCE_INLINE
void Simulator::InterpretOP32(Instr instr) {
switch (instr.funct7()) {
#if XLEN >= 64
diff --git a/runtime/vm/simulator_riscv.h b/runtime/vm/simulator_riscv.h
index 1f9e6f3..ee655839 100644
--- a/runtime/vm/simulator_riscv.h
+++ b/runtime/vm/simulator_riscv.h
@@ -211,6 +211,7 @@
void InterpretOP_MINMAXCLMUL(Instr instr);
void InterpretOP_ROTATE(Instr instr);
void InterpretOP_BCLRBEXT(Instr instr);
+ void InterpretOP_CZERO(Instr instr);
void InterpretOP32(Instr instr);
void InterpretOP32_0(Instr instr);
void InterpretOP32_SUB(Instr instr);