Import "Add the ratified portions of the B extension: Zba, Zbb, Zbc, Zbs."

TEST=ci
Change-Id: I7676dabc67762c0c2e4a1a9975100c59edcda769
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/271441
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
This commit is contained in:
Ryan Macnak 2022-11-23 18:39:07 +00:00 committed by Commit Queue
parent 38ac261884
commit b166d909c3
7 changed files with 1912 additions and 22 deletions

View file

@ -1086,12 +1086,12 @@ void MicroAssembler::fsgnjxs(FRegister rd, FRegister rs1, FRegister rs2) {
void MicroAssembler::fmins(FRegister rd, FRegister rs1, FRegister rs2) {
ASSERT(Supports(RV_F));
EmitRType(FMINMAXS, rs2, rs1, MIN, rd, OPFP);
EmitRType(FMINMAXS, rs2, rs1, FMIN, rd, OPFP);
}
void MicroAssembler::fmaxs(FRegister rd, FRegister rs1, FRegister rs2) {
ASSERT(Supports(RV_F));
EmitRType(FMINMAXS, rs2, rs1, MAX, rd, OPFP);
EmitRType(FMINMAXS, rs2, rs1, FMAX, rd, OPFP);
}
void MicroAssembler::feqs(Register rd, FRegister rs1, FRegister rs2) {
@ -1296,12 +1296,12 @@ void MicroAssembler::fsgnjxd(FRegister rd, FRegister rs1, FRegister rs2) {
void MicroAssembler::fmind(FRegister rd, FRegister rs1, FRegister rs2) {
ASSERT(Supports(RV_D));
EmitRType(FMINMAXD, rs2, rs1, MIN, rd, OPFP);
EmitRType(FMINMAXD, rs2, rs1, FMIN, rd, OPFP);
}
void MicroAssembler::fmaxd(FRegister rd, FRegister rs1, FRegister rs2) {
ASSERT(Supports(RV_D));
EmitRType(FMINMAXD, rs2, rs1, MAX, rd, OPFP);
EmitRType(FMINMAXD, rs2, rs1, FMAX, rd, OPFP);
}
void MicroAssembler::fcvtsd(FRegister rd,
@ -1398,6 +1398,242 @@ void MicroAssembler::fmvdx(FRegister rd, Register rs1) {
}
#endif // XLEN >= 64
#if XLEN >= 64
void MicroAssembler::adduw(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zba));
EmitRType(ADDUW, rs2, rs1, F3_0, rd, OP32);
}
#endif
void MicroAssembler::sh1add(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zba));
EmitRType(SHADD, rs2, rs1, SH1ADD, rd, OP);
}
#if XLEN >= 64
void MicroAssembler::sh1adduw(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zba));
EmitRType(SHADD, rs2, rs1, SH1ADD, rd, OP32);
}
#endif
void MicroAssembler::sh2add(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zba));
EmitRType(SHADD, rs2, rs1, SH2ADD, rd, OP);
}
#if XLEN >= 64
void MicroAssembler::sh2adduw(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zba));
EmitRType(SHADD, rs2, rs1, SH2ADD, rd, OP32);
}
#endif
void MicroAssembler::sh3add(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zba));
EmitRType(SHADD, rs2, rs1, SH3ADD, rd, OP);
}
#if XLEN >= 64
void MicroAssembler::sh3adduw(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zba));
EmitRType(SHADD, rs2, rs1, SH3ADD, rd, OP32);
}
void MicroAssembler::slliuw(Register rd, Register rs1, intx_t shamt) {
ASSERT((shamt > 0) && (shamt < 32));
ASSERT(Supports(RV_Zba));
EmitRType(SLLIUW, shamt, rs1, SLLI, rd, OPIMM32);
}
#endif
void MicroAssembler::andn(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbb));
EmitRType(SUB, rs2, rs1, AND, rd, OP);
}
void MicroAssembler::orn(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbb));
EmitRType(SUB, rs2, rs1, OR, rd, OP);
}
void MicroAssembler::xnor(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbb));
EmitRType(SUB, rs2, rs1, XOR, rd, OP);
}
void MicroAssembler::clz(Register rd, Register rs1) {
ASSERT(Supports(RV_Zbb));
EmitRType(COUNT, 0b00000, rs1, F3_COUNT, rd, OPIMM);
}
void MicroAssembler::clzw(Register rd, Register rs1) {
ASSERT(Supports(RV_Zbb));
EmitRType(COUNT, 0b00000, rs1, F3_COUNT, rd, OPIMM32);
}
void MicroAssembler::ctz(Register rd, Register rs1) {
ASSERT(Supports(RV_Zbb));
EmitRType(COUNT, 0b00001, rs1, F3_COUNT, rd, OPIMM);
}
void MicroAssembler::ctzw(Register rd, Register rs1) {
ASSERT(Supports(RV_Zbb));
EmitRType(COUNT, 0b00001, rs1, F3_COUNT, rd, OPIMM32);
}
void MicroAssembler::cpop(Register rd, Register rs1) {
ASSERT(Supports(RV_Zbb));
EmitRType(COUNT, 0b00010, rs1, F3_COUNT, rd, OPIMM);
}
void MicroAssembler::cpopw(Register rd, Register rs1) {
ASSERT(Supports(RV_Zbb));
EmitRType(COUNT, 0b00010, rs1, F3_COUNT, rd, OPIMM32);
}
void MicroAssembler::max(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbb));
EmitRType(MINMAXCLMUL, rs2, rs1, MAX, rd, OP);
}
void MicroAssembler::maxu(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbb));
EmitRType(MINMAXCLMUL, rs2, rs1, MAXU, rd, OP);
}
void MicroAssembler::min(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbb));
EmitRType(MINMAXCLMUL, rs2, rs1, MIN, rd, OP);
}
void MicroAssembler::minu(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbb));
EmitRType(MINMAXCLMUL, rs2, rs1, MINU, rd, OP);
}
void MicroAssembler::sextb(Register rd, Register rs1) {
ASSERT(Supports(RV_Zbb));
EmitRType((Funct7)0b0110000, 0b00100, rs1, SEXT, rd, OPIMM);
}
void MicroAssembler::sexth(Register rd, Register rs1) {
ASSERT(Supports(RV_Zbb));
EmitRType((Funct7)0b0110000, 0b00101, rs1, SEXT, rd, OPIMM);
}
void MicroAssembler::zexth(Register rd, Register rs1) {
ASSERT(Supports(RV_Zbb));
#if XLEN == 32
EmitRType((Funct7)0b0000100, 0b00000, rs1, ZEXT, rd, OP);
#elif XLEN == 64
EmitRType((Funct7)0b0000100, 0b00000, rs1, ZEXT, rd, OP32);
#else
UNIMPLEMENTED();
#endif
}
void MicroAssembler::rol(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbb));
EmitRType(ROTATE, rs2, rs1, ROL, rd, OP);
}
void MicroAssembler::rolw(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbb));
EmitRType(ROTATE, rs2, rs1, ROL, rd, OP32);
}
void MicroAssembler::ror(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbb));
EmitRType(ROTATE, rs2, rs1, ROR, rd, OP);
}
void MicroAssembler::rori(Register rd, Register rs1, intx_t shamt) {
ASSERT(Supports(RV_Zbb));
EmitRType(ROTATE, shamt, rs1, ROR, rd, OPIMM);
}
void MicroAssembler::roriw(Register rd, Register rs1, intx_t shamt) {
ASSERT(Supports(RV_Zbb));
EmitRType(ROTATE, shamt, rs1, ROR, rd, OPIMM32);
}
void MicroAssembler::rorw(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbb));
EmitRType(ROTATE, rs2, rs1, ROR, rd, OP32);
}
void MicroAssembler::orcb(Register rd, Register rs1) {
ASSERT(Supports(RV_Zbb));
EmitRType((Funct7)0b0010100, 0b00111, rs1, (Funct3)0b101, rd, OPIMM);
}
void MicroAssembler::rev8(Register rd, Register rs1) {
ASSERT(Supports(RV_Zbb));
#if XLEN == 32
EmitRType((Funct7)0b0110100, 0b11000, rs1, (Funct3)0b101, rd, OPIMM);
#elif XLEN == 64
EmitRType((Funct7)0b0110101, 0b11000, rs1, (Funct3)0b101, rd, OPIMM);
#else
UNIMPLEMENTED();
#endif
}
void MicroAssembler::clmul(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbc));
EmitRType(MINMAXCLMUL, rs2, rs1, CLMUL, rd, OP);
}
void MicroAssembler::clmulh(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbc));
EmitRType(MINMAXCLMUL, rs2, rs1, CLMULH, rd, OP);
}
void MicroAssembler::clmulr(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbc));
EmitRType(MINMAXCLMUL, rs2, rs1, CLMULR, rd, OP);
}
void MicroAssembler::bclr(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbs));
EmitRType(BCLRBEXT, rs2, rs1, BCLR, rd, OP);
}
void MicroAssembler::bclri(Register rd, Register rs1, intx_t shamt) {
ASSERT(Supports(RV_Zbs));
EmitRType(BCLRBEXT, shamt, rs1, BCLR, rd, OPIMM);
}
void MicroAssembler::bext(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbs));
EmitRType(BCLRBEXT, rs2, rs1, BEXT, rd, OP);
}
void MicroAssembler::bexti(Register rd, Register rs1, intx_t shamt) {
ASSERT(Supports(RV_Zbs));
EmitRType(BCLRBEXT, shamt, rs1, BEXT, rd, OPIMM);
}
void MicroAssembler::binv(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbs));
EmitRType(BINV, rs2, rs1, F3_BINV, rd, OP);
}
void MicroAssembler::binvi(Register rd, Register rs1, intx_t shamt) {
ASSERT(Supports(RV_Zbs));
EmitRType(BINV, shamt, rs1, F3_BINV, rd, OPIMM);
}
void MicroAssembler::bset(Register rd, Register rs1, Register rs2) {
ASSERT(Supports(RV_Zbs));
EmitRType(BSET, rs2, rs1, F3_BSET, rd, OP);
}
void MicroAssembler::bseti(Register rd, Register rs1, intx_t shamt) {
ASSERT(Supports(RV_Zbs));
EmitRType(BSET, shamt, rs1, F3_BSET, rd, OPIMM);
}
void MicroAssembler::c_lwsp(Register rd, Address addr) {
ASSERT(rd != ZR);
ASSERT(addr.base() == SP);

View file

@ -547,6 +547,57 @@ class MicroAssembler : public AssemblerBase {
void fmvdx(FRegister rd, Register rs1);
#endif // XLEN >= 64
// ==== Zba: Address generation ====
void adduw(Register rd, Register rs1, Register rs2);
void sh1add(Register rd, Register rs1, Register rs2);
void sh1adduw(Register rd, Register rs1, Register rs2);
void sh2add(Register rd, Register rs1, Register rs2);
void sh2adduw(Register rd, Register rs1, Register rs2);
void sh3add(Register rd, Register rs1, Register rs2);
void sh3adduw(Register rd, Register rs1, Register rs2);
void slliuw(Register rd, Register rs1, intx_t imm);
// ==== Zbb: Basic bit-manipulation ====
void andn(Register rd, Register rs1, Register rs2);
void orn(Register rd, Register rs1, Register rs2);
void xnor(Register rd, Register rs1, Register rs2);
void clz(Register rd, Register rs);
void clzw(Register rd, Register rs);
void ctz(Register rd, Register rs);
void ctzw(Register rd, Register rs);
void cpop(Register rd, Register rs);
void cpopw(Register rd, Register rs);
void max(Register rd, Register rs1, Register rs2);
void maxu(Register rd, Register rs1, Register rs2);
void min(Register rd, Register rs1, Register rs2);
void minu(Register rd, Register rs1, Register rs2);
void sextb(Register rd, Register rs);
void sexth(Register rd, Register rs);
void zexth(Register rd, Register rs);
void rol(Register rd, Register rs1, Register rs2);
void rolw(Register rd, Register rs1, Register rs2);
void ror(Register rd, Register rs1, Register rs2);
void rori(Register rd, Register rs1, intx_t imm);
void roriw(Register rd, Register rs1, intx_t imm);
void rorw(Register rd, Register rs1, Register rs2);
void orcb(Register rd, Register rs);
void rev8(Register rd, Register rs);
// ==== Zbc: Carry-less multiplication ====
void clmul(Register rd, Register rs1, Register rs2);
void clmulh(Register rd, Register rs1, Register rs2);
void clmulr(Register rd, Register rs1, Register rs2);
// ==== Zbs: Single-bit instructions ====
void bclr(Register rd, Register rs1, Register rs2);
void bclri(Register rd, Register rs1, intx_t shamt);
void bext(Register rd, Register rs1, Register rs2);
void bexti(Register rd, Register rs1, intx_t shamt);
void binv(Register rd, Register rs1, Register rs2);
void binvi(Register rd, Register rs1, intx_t shamt);
void bset(Register rd, Register rs1, Register rs2);
void bseti(Register rd, Register rs1, intx_t shamt);
// ==== Dart Simulator Debugging ====
void SimulatorPrintObject(Register rs1);

View file

@ -6165,6 +6165,952 @@ ASSEMBLER_TEST_RUN(CompressedEnvironmentBreak, test) {
// Not running: would trap.
}
#if XLEN >= 64
ASSEMBLER_TEST_GENERATE(AddUnsignedWord, assembler) {
__ SetExtensions(RV_GCB);
__ adduw(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(AddUnsignedWord, test) {
EXPECT_DISASSEMBLY(
"08b5053b add.uw a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(0x200000001, Call(test->entry(), 0x1, 0x200000000));
EXPECT_EQ(0x200000001, Call(test->entry(), 0x100000001, 0x200000000));
EXPECT_EQ(0x2FFFFFFFF, Call(test->entry(), -0x1, 0x200000000));
}
#endif
ASSEMBLER_TEST_GENERATE(Shift1Add, assembler) {
__ SetExtensions(RV_GCB);
__ sh1add(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(Shift1Add, test) {
EXPECT_DISASSEMBLY(
"20b52533 sh1add a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(1002, Call(test->entry(), 1, 1000));
EXPECT_EQ(1000, Call(test->entry(), 0, 1000));
EXPECT_EQ(998, Call(test->entry(), -1, 1000));
}
ASSEMBLER_TEST_GENERATE(Shift2Add, assembler) {
__ SetExtensions(RV_GCB);
__ sh2add(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(Shift2Add, test) {
EXPECT_DISASSEMBLY(
"20b54533 sh2add a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(1004, Call(test->entry(), 1, 1000));
EXPECT_EQ(1000, Call(test->entry(), 0, 1000));
EXPECT_EQ(996, Call(test->entry(), -1, 1000));
}
ASSEMBLER_TEST_GENERATE(Shift3Add, assembler) {
__ SetExtensions(RV_GCB);
__ sh3add(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(Shift3Add, test) {
EXPECT_DISASSEMBLY(
"20b56533 sh3add a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(1008, Call(test->entry(), 1, 1000));
EXPECT_EQ(1000, Call(test->entry(), 0, 1000));
EXPECT_EQ(992, Call(test->entry(), -1, 1000));
}
#if XLEN >= 64
ASSEMBLER_TEST_GENERATE(Shift1AddUnsignedWord, assembler) {
__ SetExtensions(RV_GCB);
__ sh1adduw(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(Shift1AddUnsignedWord, test) {
EXPECT_DISASSEMBLY(
"20b5253b sh1add.uw a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(1002, Call(test->entry(), 1, 1000));
EXPECT_EQ(1002, Call(test->entry(), 0x100000001, 1000));
EXPECT_EQ(1000, Call(test->entry(), 0, 1000));
EXPECT_EQ(8589935590, Call(test->entry(), -1, 1000));
}
ASSEMBLER_TEST_GENERATE(Shift2AddUnsignedWord, assembler) {
__ SetExtensions(RV_GCB);
__ sh2adduw(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(Shift2AddUnsignedWord, test) {
EXPECT_DISASSEMBLY(
"20b5453b sh2add.uw a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(1004, Call(test->entry(), 1, 1000));
EXPECT_EQ(1004, Call(test->entry(), 0x100000001, 1000));
EXPECT_EQ(1000, Call(test->entry(), 0, 1000));
EXPECT_EQ(17179870180, Call(test->entry(), -1, 1000));
}
ASSEMBLER_TEST_GENERATE(Shift3AddUnsignedWord, assembler) {
__ SetExtensions(RV_GCB);
__ sh3adduw(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(Shift3AddUnsignedWord, test) {
EXPECT_DISASSEMBLY(
"20b5653b sh3add.uw a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(1008, Call(test->entry(), 1, 1000));
EXPECT_EQ(1008, Call(test->entry(), 0x100000001, 1000));
EXPECT_EQ(1000, Call(test->entry(), 0, 1000));
EXPECT_EQ(34359739360, Call(test->entry(), -1, 1000));
}
ASSEMBLER_TEST_GENERATE(ShiftLeftLogicalImmediateUnsignedWord, assembler) {
__ SetExtensions(RV_GCB);
__ slliuw(A0, A0, 8);
__ ret();
}
ASSEMBLER_TEST_RUN(ShiftLeftLogicalImmediateUnsignedWord, test) {
EXPECT_DISASSEMBLY(
"0885151b slli.uw a0, a0, 0x8\n"
" 8082 ret\n");
EXPECT_EQ(0x100, Call(test->entry(), 0x1));
EXPECT_EQ(0x1000000000, Call(test->entry(), 0x10000000));
EXPECT_EQ(0, Call(test->entry(), 0x100000000));
EXPECT_EQ(0x100, Call(test->entry(), 0x100000001));
}
#endif
ASSEMBLER_TEST_GENERATE(AndNot, assembler) {
__ SetExtensions(RV_GCB);
__ andn(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(AndNot, test) {
EXPECT_DISASSEMBLY(
"40b57533 andn a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(6, Call(test->entry(), 7, 17));
EXPECT_EQ(0, Call(test->entry(), 7, -17));
EXPECT_EQ(-24, Call(test->entry(), -7, 17));
EXPECT_EQ(16, Call(test->entry(), -7, -17));
EXPECT_EQ(16, Call(test->entry(), 17, 7));
EXPECT_EQ(0, Call(test->entry(), 17, -7));
EXPECT_EQ(-24, Call(test->entry(), -17, 7));
EXPECT_EQ(6, Call(test->entry(), -17, -7));
}
ASSEMBLER_TEST_GENERATE(OrNot, assembler) {
__ SetExtensions(RV_GCB);
__ orn(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(OrNot, test) {
EXPECT_DISASSEMBLY(
"40b56533 orn a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(-17, Call(test->entry(), 7, 17));
EXPECT_EQ(23, Call(test->entry(), 7, -17));
EXPECT_EQ(-1, Call(test->entry(), -7, 17));
EXPECT_EQ(-7, Call(test->entry(), -7, -17));
EXPECT_EQ(-7, Call(test->entry(), 17, 7));
EXPECT_EQ(23, Call(test->entry(), 17, -7));
EXPECT_EQ(-1, Call(test->entry(), -17, 7));
EXPECT_EQ(-17, Call(test->entry(), -17, -7));
}
ASSEMBLER_TEST_GENERATE(XorNot, assembler) {
__ SetExtensions(RV_GCB);
__ xnor(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(XorNot, test) {
EXPECT_DISASSEMBLY(
"40b54533 xnor a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(-23, Call(test->entry(), 7, 17));
EXPECT_EQ(23, Call(test->entry(), 7, -17));
EXPECT_EQ(23, Call(test->entry(), -7, 17));
EXPECT_EQ(-23, Call(test->entry(), -7, -17));
EXPECT_EQ(-23, Call(test->entry(), 17, 7));
EXPECT_EQ(23, Call(test->entry(), 17, -7));
EXPECT_EQ(23, Call(test->entry(), -17, 7));
EXPECT_EQ(-23, Call(test->entry(), -17, -7));
}
ASSEMBLER_TEST_GENERATE(CountLeadingZeroes, assembler) {
__ SetExtensions(RV_GCB);
__ clz(A0, A0);
__ ret();
}
ASSEMBLER_TEST_RUN(CountLeadingZeroes, test) {
EXPECT_DISASSEMBLY(
"60051513 clz a0, a0\n"
" 8082 ret\n");
EXPECT_EQ(XLEN, Call(test->entry(), 0));
EXPECT_EQ(XLEN - 1, Call(test->entry(), 1));
EXPECT_EQ(XLEN - 2, Call(test->entry(), 2));
EXPECT_EQ(XLEN - 3, Call(test->entry(), 4));
EXPECT_EQ(XLEN - 8, Call(test->entry(), 240));
EXPECT_EQ(0, Call(test->entry(), -1));
EXPECT_EQ(0, Call(test->entry(), -2));
EXPECT_EQ(0, Call(test->entry(), -4));
EXPECT_EQ(0, Call(test->entry(), -240));
}
ASSEMBLER_TEST_GENERATE(CountTrailingZeroes, assembler) {
__ SetExtensions(RV_GCB);
__ ctz(A0, A0);
__ ret();
}
ASSEMBLER_TEST_RUN(CountTrailingZeroes, test) {
EXPECT_DISASSEMBLY(
"60151513 ctz a0, a0\n"
" 8082 ret\n");
EXPECT_EQ(XLEN, Call(test->entry(), 0));
EXPECT_EQ(0, Call(test->entry(), 1));
EXPECT_EQ(1, Call(test->entry(), 2));
EXPECT_EQ(2, Call(test->entry(), 4));
EXPECT_EQ(4, Call(test->entry(), 240));
EXPECT_EQ(0, Call(test->entry(), -1));
EXPECT_EQ(1, Call(test->entry(), -2));
EXPECT_EQ(2, Call(test->entry(), -4));
EXPECT_EQ(4, Call(test->entry(), -240));
}
ASSEMBLER_TEST_GENERATE(CountPopulation, assembler) {
__ SetExtensions(RV_GCB);
__ cpop(A0, A0);
__ ret();
}
ASSEMBLER_TEST_RUN(CountPopulation, test) {
EXPECT_DISASSEMBLY(
"60251513 cpop a0, a0\n"
" 8082 ret\n");
EXPECT_EQ(0, Call(test->entry(), 0));
EXPECT_EQ(1, Call(test->entry(), 1));
EXPECT_EQ(3, Call(test->entry(), 7));
EXPECT_EQ(4, Call(test->entry(), 30));
EXPECT_EQ(XLEN, Call(test->entry(), -1));
EXPECT_EQ(XLEN - 2, Call(test->entry(), -7));
EXPECT_EQ(XLEN - 4, Call(test->entry(), -30));
}
#if XLEN >= 64
ASSEMBLER_TEST_GENERATE(CountLeadingZeroesWord, assembler) {
__ SetExtensions(RV_GCB);
__ clzw(A0, A0);
__ ret();
}
ASSEMBLER_TEST_RUN(CountLeadingZeroesWord, test) {
EXPECT_DISASSEMBLY(
"6005151b clzw a0, a0\n"
" 8082 ret\n");
EXPECT_EQ(32, Call(test->entry(), 0));
EXPECT_EQ(31, Call(test->entry(), 1));
EXPECT_EQ(30, Call(test->entry(), 2));
EXPECT_EQ(29, Call(test->entry(), 4));
EXPECT_EQ(24, Call(test->entry(), 240));
EXPECT_EQ(0, Call(test->entry(), -1));
EXPECT_EQ(0, Call(test->entry(), -2));
EXPECT_EQ(0, Call(test->entry(), -4));
EXPECT_EQ(0, Call(test->entry(), -240));
}
ASSEMBLER_TEST_GENERATE(CountTrailingZeroesWord, assembler) {
__ SetExtensions(RV_GCB);
__ ctzw(A0, A0);
__ ret();
}
ASSEMBLER_TEST_RUN(CountTrailingZeroesWord, test) {
EXPECT_DISASSEMBLY(
"6015151b ctzw a0, a0\n"
" 8082 ret\n");
EXPECT_EQ(32, Call(test->entry(), 0));
EXPECT_EQ(0, Call(test->entry(), 1));
EXPECT_EQ(1, Call(test->entry(), 2));
EXPECT_EQ(2, Call(test->entry(), 4));
EXPECT_EQ(4, Call(test->entry(), 240));
EXPECT_EQ(0, Call(test->entry(), -1));
EXPECT_EQ(1, Call(test->entry(), -2));
EXPECT_EQ(2, Call(test->entry(), -4));
EXPECT_EQ(4, Call(test->entry(), -240));
}
ASSEMBLER_TEST_GENERATE(CountPopulationWord, assembler) {
__ SetExtensions(RV_GCB);
__ cpopw(A0, A0);
__ ret();
}
ASSEMBLER_TEST_RUN(CountPopulationWord, test) {
EXPECT_DISASSEMBLY(
"6025151b cpopw a0, a0\n"
" 8082 ret\n");
EXPECT_EQ(0, Call(test->entry(), 0));
EXPECT_EQ(1, Call(test->entry(), 1));
EXPECT_EQ(3, Call(test->entry(), 7));
EXPECT_EQ(4, Call(test->entry(), 30));
EXPECT_EQ(32, Call(test->entry(), -1));
EXPECT_EQ(30, Call(test->entry(), -7));
EXPECT_EQ(28, Call(test->entry(), -30));
EXPECT_EQ(0, Call(test->entry(), 0x7FFFFFFF00000000));
}
#endif
ASSEMBLER_TEST_GENERATE(Max, assembler) {
__ SetExtensions(RV_GCB);
__ max(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(Max, test) {
EXPECT_DISASSEMBLY(
"0ab56533 max a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(17, Call(test->entry(), 7, 17));
EXPECT_EQ(17, Call(test->entry(), -7, 17));
EXPECT_EQ(7, Call(test->entry(), 7, -17));
EXPECT_EQ(-7, Call(test->entry(), -7, -17));
}
ASSEMBLER_TEST_GENERATE(MaxUnsigned, assembler) {
__ SetExtensions(RV_GCB);
__ maxu(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(MaxUnsigned, test) {
EXPECT_DISASSEMBLY(
"0ab57533 maxu a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(17, Call(test->entry(), 7, 17));
EXPECT_EQ(-7, Call(test->entry(), -7, 17));
EXPECT_EQ(-17, Call(test->entry(), 7, -17));
EXPECT_EQ(-7, Call(test->entry(), -7, -17));
}
ASSEMBLER_TEST_GENERATE(Min, assembler) {
__ SetExtensions(RV_GCB);
__ min(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(Min, test) {
EXPECT_DISASSEMBLY(
"0ab54533 min a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(7, Call(test->entry(), 7, 17));
EXPECT_EQ(-7, Call(test->entry(), -7, 17));
EXPECT_EQ(-17, Call(test->entry(), 7, -17));
EXPECT_EQ(-17, Call(test->entry(), -7, -17));
}
ASSEMBLER_TEST_GENERATE(MinUnsigned, assembler) {
__ SetExtensions(RV_GCB);
__ minu(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(MinUnsigned, test) {
EXPECT_DISASSEMBLY(
"0ab55533 minu a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(7, Call(test->entry(), 7, 17));
EXPECT_EQ(17, Call(test->entry(), -7, 17));
EXPECT_EQ(7, Call(test->entry(), 7, -17));
EXPECT_EQ(-17, Call(test->entry(), -7, -17));
}
ASSEMBLER_TEST_GENERATE(SignExtendByte, assembler) {
__ SetExtensions(RV_GCB);
__ sextb(A0, A0);
__ ret();
}
ASSEMBLER_TEST_RUN(SignExtendByte, test) {
EXPECT_DISASSEMBLY(
"60451513 sext.b a0, a0\n"
" 8082 ret\n");
EXPECT_EQ(1, Call(test->entry(), 1));
EXPECT_EQ(127, Call(test->entry(), 127));
EXPECT_EQ(-128, Call(test->entry(), 128));
}
ASSEMBLER_TEST_GENERATE(SignExtendHalfWord, assembler) {
__ SetExtensions(RV_GCB);
__ sexth(A0, A0);
__ ret();
}
ASSEMBLER_TEST_RUN(SignExtendHalfWord, test) {
EXPECT_DISASSEMBLY(
"60551513 sext.h a0, a0\n"
" 8082 ret\n");
EXPECT_EQ(0, Call(test->entry(), 0));
EXPECT_EQ(0x7BCD, Call(test->entry(), 0x12347BCD));
EXPECT_EQ(-1, Call(test->entry(), 0xFFFF));
EXPECT_EQ(-1, Call(test->entry(), -1));
}
ASSEMBLER_TEST_GENERATE(ZeroExtendHalfWord, assembler) {
__ SetExtensions(RV_GCB);
__ zexth(A0, A0);
__ ret();
}
ASSEMBLER_TEST_RUN(ZeroExtendHalfWord, test) {
#if XLEN == 32
EXPECT_DISASSEMBLY(
"08054533 zext.h a0, a0\n"
" 8082 ret\n");
#else
EXPECT_DISASSEMBLY(
"0805453b zext.h a0, a0\n"
" 8082 ret\n");
#endif
EXPECT_EQ(0, Call(test->entry(), 0));
EXPECT_EQ(0xABCD, Call(test->entry(), 0x1234ABCD));
EXPECT_EQ(0xFFFF, Call(test->entry(), 0xFFFF));
EXPECT_EQ(0xFFFF, Call(test->entry(), -1));
}
ASSEMBLER_TEST_GENERATE(RotateRight, assembler) {
__ SetExtensions(RV_GCB);
__ ror(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(RotateRight, test) {
EXPECT_DISASSEMBLY(
"60b55533 ror a0, a0, a1\n"
" 8082 ret\n");
#if XLEN == 32
EXPECT_EQ(static_cast<intx_t>(0x12345678),
Call(test->entry(), 0x12345678, 0));
EXPECT_EQ(static_cast<intx_t>(0x81234567),
Call(test->entry(), 0x12345678, 4));
EXPECT_EQ(static_cast<intx_t>(0x23456781),
Call(test->entry(), 0x12345678, 28));
EXPECT_EQ(static_cast<intx_t>(0x81234567),
Call(test->entry(), 0x12345678, 36));
#else
EXPECT_EQ(static_cast<intx_t>(0x0123456789ABCDEF),
Call(test->entry(), 0x0123456789ABCDEF, 0));
EXPECT_EQ(static_cast<intx_t>(0xF0123456789ABCDE),
Call(test->entry(), 0x0123456789ABCDEF, 4));
EXPECT_EQ(static_cast<intx_t>(0x123456789ABCDEF0),
Call(test->entry(), 0x0123456789ABCDEF, 60));
EXPECT_EQ(static_cast<intx_t>(0xF0123456789ABCDE),
Call(test->entry(), 0x0123456789ABCDEF, 68));
#endif
}
ASSEMBLER_TEST_GENERATE(RotateLeft, assembler) {
__ SetExtensions(RV_GCB);
__ rol(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(RotateLeft, test) {
EXPECT_DISASSEMBLY(
"60b51533 rol a0, a0, a1\n"
" 8082 ret\n");
#if XLEN == 32
EXPECT_EQ(static_cast<intx_t>(0x12345678),
Call(test->entry(), 0x12345678, 0));
EXPECT_EQ(static_cast<intx_t>(0x23456781),
Call(test->entry(), 0x12345678, 4));
EXPECT_EQ(static_cast<intx_t>(0x81234567),
Call(test->entry(), 0x12345678, 28));
EXPECT_EQ(static_cast<intx_t>(0x23456781),
Call(test->entry(), 0x12345678, 36));
#else
EXPECT_EQ(static_cast<intx_t>(0x0123456789ABCDEF),
Call(test->entry(), 0x0123456789ABCDEF, 0));
EXPECT_EQ(static_cast<intx_t>(0x123456789ABCDEF0),
Call(test->entry(), 0x0123456789ABCDEF, 4));
EXPECT_EQ(static_cast<intx_t>(0xF0123456789ABCDE),
Call(test->entry(), 0x0123456789ABCDEF, 60));
EXPECT_EQ(static_cast<intx_t>(0x123456789ABCDEF0),
Call(test->entry(), 0x0123456789ABCDEF, 68));
#endif
}
ASSEMBLER_TEST_GENERATE(RotateRightImmediate, assembler) {
__ SetExtensions(RV_GCB);
__ rori(A0, A0, 4);
__ ret();
}
ASSEMBLER_TEST_RUN(RotateRightImmediate, test) {
EXPECT_DISASSEMBLY(
"60455513 rori a0, a0, 0x4\n"
" 8082 ret\n");
#if XLEN == 32
EXPECT_EQ(static_cast<intx_t>(0x81234567), Call(test->entry(), 0x12345678));
#else
EXPECT_EQ(static_cast<intx_t>(0xF0123456789ABCDE),
Call(test->entry(), 0x0123456789ABCDEF));
#endif
}
#if XLEN >= 64
ASSEMBLER_TEST_GENERATE(RotateRightWord, assembler) {
__ SetExtensions(RV_GCB);
__ rorw(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(RotateRightWord, test) {
EXPECT_DISASSEMBLY(
"60b5553b rorw a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(sign_extend(0x12345678), Call(test->entry(), 0x12345678, 0));
EXPECT_EQ(sign_extend(0x81234567), Call(test->entry(), 0x12345678, 4));
EXPECT_EQ(sign_extend(0x23456781), Call(test->entry(), 0x12345678, 28));
EXPECT_EQ(sign_extend(0x81234567), Call(test->entry(), 0x12345678, 36));
}
ASSEMBLER_TEST_GENERATE(RotateLeftWord, assembler) {
__ SetExtensions(RV_GCB);
__ rolw(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(RotateLeftWord, test) {
EXPECT_DISASSEMBLY(
"60b5153b rolw a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(sign_extend(0x12345678), Call(test->entry(), 0x12345678, 0));
EXPECT_EQ(sign_extend(0x23456781), Call(test->entry(), 0x12345678, 4));
EXPECT_EQ(sign_extend(0x81234567), Call(test->entry(), 0x12345678, 28));
EXPECT_EQ(sign_extend(0x23456781), Call(test->entry(), 0x12345678, 36));
}
ASSEMBLER_TEST_GENERATE(RotateRightImmediateWord, assembler) {
__ SetExtensions(RV_GCB);
__ roriw(A0, A0, 4);
__ ret();
}
ASSEMBLER_TEST_RUN(RotateRightImmediateWord, test) {
EXPECT_DISASSEMBLY(
"6045551b roriw a0, a0, 0x4\n"
" 8082 ret\n");
EXPECT_EQ(sign_extend(0x81234567), Call(test->entry(), 0x12345678));
}
#endif
ASSEMBLER_TEST_GENERATE(OrCombineBytes, assembler) {
__ SetExtensions(RV_GCB);
__ orcb(A0, A0);
__ ret();
}
ASSEMBLER_TEST_RUN(OrCombineBytes, test) {
EXPECT_DISASSEMBLY(
"28755513 orc.b a0, a0\n"
" 8082 ret\n");
EXPECT_EQ(0, Call(test->entry(), 0));
EXPECT_EQ(-1, Call(test->entry(), -1));
EXPECT_EQ(0x00FF00FF, Call(test->entry(), 0x00010001));
#if XLEN >= 64
EXPECT_EQ(0x00FF00FF00FF00FF, Call(test->entry(), 0x0001000100010001));
#endif
}
ASSEMBLER_TEST_GENERATE(ByteReverse, assembler) {
__ SetExtensions(RV_GCB);
__ rev8(A0, A0);
__ ret();
}
ASSEMBLER_TEST_RUN(ByteReverse, test) {
#if XLEN == 32
EXPECT_DISASSEMBLY(
"69855513 rev8 a0, a0\n"
" 8082 ret\n");
#else
EXPECT_DISASSEMBLY(
"6b855513 rev8 a0, a0\n"
" 8082 ret\n");
#endif
EXPECT_EQ(0, Call(test->entry(), 0));
EXPECT_EQ(-1, Call(test->entry(), -1));
#if XLEN == 32
EXPECT_EQ(0x11223344, Call(test->entry(), 0x44332211));
#elif XLEN == 64
EXPECT_EQ(0x1122334455667788, Call(test->entry(), 0x8877665544332211));
#endif
}
ASSEMBLER_TEST_GENERATE(CarrylessMultiply, assembler) {
__ SetExtensions(RV_GCB);
__ clmul(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(CarrylessMultiply, test) {
EXPECT_DISASSEMBLY(
"0ab51533 clmul a0, a0, a1\n"
" 8082 ret\n");
#if XLEN == 32
EXPECT_EQ(0x55555555, Call(test->entry(), -1, -1));
#else
EXPECT_EQ(0x5555555555555555, Call(test->entry(), -1, -1));
#endif
EXPECT_EQ(0, Call(test->entry(), -1, 0));
EXPECT_EQ(-1, Call(test->entry(), -1, 1));
EXPECT_EQ(0, Call(test->entry(), 0, -1));
EXPECT_EQ(0, Call(test->entry(), 0, 0));
EXPECT_EQ(0, Call(test->entry(), 0, 1));
EXPECT_EQ(-1, Call(test->entry(), 1, -1));
EXPECT_EQ(0, Call(test->entry(), 1, 0));
EXPECT_EQ(1, Call(test->entry(), 1, 1));
EXPECT_EQ(4, Call(test->entry(), 2, 2));
EXPECT_EQ(5, Call(test->entry(), 3, 3));
EXPECT_EQ(16, Call(test->entry(), 4, 4));
EXPECT_EQ(20, Call(test->entry(), 6, 6));
}
ASSEMBLER_TEST_GENERATE(CarrylessMultiplyHigh, assembler) {
__ SetExtensions(RV_GCB);
__ clmulh(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(CarrylessMultiplyHigh, test) {
EXPECT_DISASSEMBLY(
"0ab53533 clmulh a0, a0, a1\n"
" 8082 ret\n");
#if XLEN == 32
EXPECT_EQ(0x55555555, Call(test->entry(), -1, -1));
#else
EXPECT_EQ(0x5555555555555555, Call(test->entry(), -1, -1));
#endif
EXPECT_EQ(0, Call(test->entry(), -1, 0));
EXPECT_EQ(0, Call(test->entry(), -1, 1));
EXPECT_EQ(0, Call(test->entry(), 0, -1));
EXPECT_EQ(0, Call(test->entry(), 0, 0));
EXPECT_EQ(0, Call(test->entry(), 0, 1));
EXPECT_EQ(0, Call(test->entry(), 1, -1));
EXPECT_EQ(0, Call(test->entry(), 1, 0));
EXPECT_EQ(0, Call(test->entry(), 1, 1));
EXPECT_EQ(0, Call(test->entry(), 2, 2));
EXPECT_EQ(0, Call(test->entry(), 3, 3));
EXPECT_EQ(0, Call(test->entry(), 4, 4));
EXPECT_EQ(0, Call(test->entry(), 6, 6));
}
ASSEMBLER_TEST_GENERATE(CarrylessMultiplyReversed, assembler) {
__ SetExtensions(RV_GCB);
__ clmulr(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(CarrylessMultiplyReversed, test) {
EXPECT_DISASSEMBLY(
"0ab52533 clmulr a0, a0, a1\n"
" 8082 ret\n");
#if XLEN == 32
EXPECT_EQ(-0x55555556, Call(test->entry(), -1, -1));
#else
EXPECT_EQ(-0x5555555555555556, Call(test->entry(), -1, -1));
#endif
EXPECT_EQ(0, Call(test->entry(), -1, 0));
EXPECT_EQ(1, Call(test->entry(), -1, 1));
EXPECT_EQ(0, Call(test->entry(), 0, -1));
EXPECT_EQ(0, Call(test->entry(), 0, 0));
EXPECT_EQ(0, Call(test->entry(), 0, 1));
EXPECT_EQ(1, Call(test->entry(), 1, -1));
EXPECT_EQ(0, Call(test->entry(), 1, 0));
EXPECT_EQ(0, Call(test->entry(), 1, 1));
EXPECT_EQ(0, Call(test->entry(), 2, 2));
EXPECT_EQ(0, Call(test->entry(), 3, 3));
EXPECT_EQ(0, Call(test->entry(), 4, 4));
EXPECT_EQ(0, Call(test->entry(), 6, 6));
}
ASSEMBLER_TEST_GENERATE(BitClear, assembler) {
__ SetExtensions(RV_GCB);
__ bclr(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(BitClear, test) {
EXPECT_DISASSEMBLY(
"48b51533 bclr a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(42, Call(test->entry(), 42, 0));
EXPECT_EQ(40, Call(test->entry(), 42, 1));
EXPECT_EQ(42, Call(test->entry(), 42, 2));
EXPECT_EQ(34, Call(test->entry(), 42, 3));
EXPECT_EQ(42, Call(test->entry(), 42, 4));
EXPECT_EQ(10, Call(test->entry(), 42, 5));
EXPECT_EQ(42, Call(test->entry(), 42, 6));
EXPECT_EQ(42, Call(test->entry(), 42, 7));
EXPECT_EQ(42, Call(test->entry(), 42, 8));
EXPECT_EQ(42, Call(test->entry(), 42, 64));
EXPECT_EQ(40, Call(test->entry(), 42, 65));
}
ASSEMBLER_TEST_GENERATE(BitClearImmediate, assembler) {
__ SetExtensions(RV_GCB);
__ bclri(A0, A0, 3);
__ ret();
}
ASSEMBLER_TEST_RUN(BitClearImmediate, test) {
EXPECT_DISASSEMBLY(
"48351513 bclri a0, a0, 0x3\n"
" 8082 ret\n");
EXPECT_EQ(0, Call(test->entry(), 0));
EXPECT_EQ(7, Call(test->entry(), 7));
EXPECT_EQ(0, Call(test->entry(), 8));
EXPECT_EQ(1, Call(test->entry(), 9));
EXPECT_EQ(-15, Call(test->entry(), -7));
EXPECT_EQ(-16, Call(test->entry(), -8));
EXPECT_EQ(-9, Call(test->entry(), -9));
}
ASSEMBLER_TEST_GENERATE(BitClearImmediate2, assembler) {
__ SetExtensions(RV_GCB);
__ bclri(A0, A0, XLEN - 1);
__ ret();
}
ASSEMBLER_TEST_RUN(BitClearImmediate2, test) {
#if XLEN == 32
EXPECT_DISASSEMBLY(
"49f51513 bclri a0, a0, 0x1f\n"
" 8082 ret\n");
#elif XLEN == 64
EXPECT_DISASSEMBLY(
"4bf51513 bclri a0, a0, 0x3f\n"
" 8082 ret\n");
#endif
EXPECT_EQ(0, Call(test->entry(), 0));
EXPECT_EQ(1, Call(test->entry(), 1));
EXPECT_EQ(kMaxIntX, Call(test->entry(), -1));
}
ASSEMBLER_TEST_GENERATE(BitExtract, assembler) {
__ SetExtensions(RV_GCB);
__ bext(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(BitExtract, test) {
EXPECT_DISASSEMBLY(
"48b55533 bext a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(0, Call(test->entry(), 42, 0));
EXPECT_EQ(1, Call(test->entry(), 42, 1));
EXPECT_EQ(0, Call(test->entry(), 42, 2));
EXPECT_EQ(1, Call(test->entry(), 42, 3));
EXPECT_EQ(0, Call(test->entry(), 42, 4));
EXPECT_EQ(1, Call(test->entry(), 42, 5));
EXPECT_EQ(0, Call(test->entry(), 42, 6));
EXPECT_EQ(0, Call(test->entry(), 42, 7));
EXPECT_EQ(0, Call(test->entry(), 42, 8));
EXPECT_EQ(0, Call(test->entry(), 42, 64));
EXPECT_EQ(1, Call(test->entry(), 42, 65));
}
ASSEMBLER_TEST_GENERATE(BitExtractImmediate, assembler) {
__ SetExtensions(RV_GCB);
__ bexti(A0, A0, 3);
__ ret();
}
ASSEMBLER_TEST_RUN(BitExtractImmediate, test) {
EXPECT_DISASSEMBLY(
"48355513 bexti a0, a0, 0x3\n"
" 8082 ret\n");
EXPECT_EQ(0, Call(test->entry(), 0));
EXPECT_EQ(0, Call(test->entry(), 7));
EXPECT_EQ(1, Call(test->entry(), 8));
EXPECT_EQ(1, Call(test->entry(), 9));
EXPECT_EQ(1, Call(test->entry(), -7));
EXPECT_EQ(1, Call(test->entry(), -8));
EXPECT_EQ(0, Call(test->entry(), -9));
}
ASSEMBLER_TEST_GENERATE(BitExtractImmediate2, assembler) {
__ SetExtensions(RV_GCB);
__ bexti(A0, A0, XLEN - 1);
__ ret();
}
ASSEMBLER_TEST_RUN(BitExtractImmediate2, test) {
#if XLEN == 32
EXPECT_DISASSEMBLY(
"49f55513 bexti a0, a0, 0x1f\n"
" 8082 ret\n");
#elif XLEN == 64
EXPECT_DISASSEMBLY(
"4bf55513 bexti a0, a0, 0x3f\n"
" 8082 ret\n");
#endif
EXPECT_EQ(0, Call(test->entry(), 0));
EXPECT_EQ(0, Call(test->entry(), 1));
EXPECT_EQ(1, Call(test->entry(), -1));
}
ASSEMBLER_TEST_GENERATE(BitInvert, assembler) {
__ SetExtensions(RV_GCB);
__ binv(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(BitInvert, test) {
EXPECT_DISASSEMBLY(
"68b51533 binv a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(43, Call(test->entry(), 42, 0));
EXPECT_EQ(40, Call(test->entry(), 42, 1));
EXPECT_EQ(46, Call(test->entry(), 42, 2));
EXPECT_EQ(34, Call(test->entry(), 42, 3));
EXPECT_EQ(58, Call(test->entry(), 42, 4));
EXPECT_EQ(10, Call(test->entry(), 42, 5));
EXPECT_EQ(106, Call(test->entry(), 42, 6));
EXPECT_EQ(170, Call(test->entry(), 42, 7));
EXPECT_EQ(298, Call(test->entry(), 42, 8));
EXPECT_EQ(43, Call(test->entry(), 42, 64));
EXPECT_EQ(40, Call(test->entry(), 42, 65));
}
ASSEMBLER_TEST_GENERATE(BitInvertImmediate, assembler) {
__ SetExtensions(RV_GCB);
__ binvi(A0, A0, 3);
__ ret();
}
ASSEMBLER_TEST_RUN(BitInvertImmediate, test) {
EXPECT_DISASSEMBLY(
"68351513 binvi a0, a0, 0x3\n"
" 8082 ret\n");
EXPECT_EQ(8, Call(test->entry(), 0));
EXPECT_EQ(15, Call(test->entry(), 7));
EXPECT_EQ(0, Call(test->entry(), 8));
EXPECT_EQ(1, Call(test->entry(), 9));
EXPECT_EQ(-15, Call(test->entry(), -7));
EXPECT_EQ(-16, Call(test->entry(), -8));
EXPECT_EQ(-1, Call(test->entry(), -9));
}
ASSEMBLER_TEST_GENERATE(BitInvertImmediate2, assembler) {
__ SetExtensions(RV_GCB);
__ binvi(A0, A0, XLEN - 1);
__ ret();
}
ASSEMBLER_TEST_RUN(BitInvertImmediate2, test) {
#if XLEN == 32
EXPECT_DISASSEMBLY(
"69f51513 binvi a0, a0, 0x1f\n"
" 8082 ret\n");
#elif XLEN == 64
EXPECT_DISASSEMBLY(
"6bf51513 binvi a0, a0, 0x3f\n"
" 8082 ret\n");
#endif
EXPECT_EQ(kMinIntX, Call(test->entry(), 0));
EXPECT_EQ(kMinIntX + 1, Call(test->entry(), 1));
EXPECT_EQ(kMaxIntX, Call(test->entry(), -1));
}
ASSEMBLER_TEST_GENERATE(BitSet, assembler) {
__ SetExtensions(RV_GCB);
__ bset(A0, A0, A1);
__ ret();
}
ASSEMBLER_TEST_RUN(BitSet, test) {
EXPECT_DISASSEMBLY(
"28b51533 bset a0, a0, a1\n"
" 8082 ret\n");
EXPECT_EQ(43, Call(test->entry(), 42, 0));
EXPECT_EQ(42, Call(test->entry(), 42, 1));
EXPECT_EQ(46, Call(test->entry(), 42, 2));
EXPECT_EQ(42, Call(test->entry(), 42, 3));
EXPECT_EQ(58, Call(test->entry(), 42, 4));
EXPECT_EQ(42, Call(test->entry(), 42, 5));
EXPECT_EQ(106, Call(test->entry(), 42, 6));
EXPECT_EQ(170, Call(test->entry(), 42, 7));
EXPECT_EQ(298, Call(test->entry(), 42, 8));
EXPECT_EQ(43, Call(test->entry(), 42, 64));
EXPECT_EQ(42, Call(test->entry(), 42, 65));
}
ASSEMBLER_TEST_GENERATE(BitSetImmediate, assembler) {
__ SetExtensions(RV_GCB);
__ bseti(A0, A0, 3);
__ ret();
}
ASSEMBLER_TEST_RUN(BitSetImmediate, test) {
EXPECT_DISASSEMBLY(
"28351513 bseti a0, a0, 0x3\n"
" 8082 ret\n");
EXPECT_EQ(8, Call(test->entry(), 0));
EXPECT_EQ(15, Call(test->entry(), 7));
EXPECT_EQ(8, Call(test->entry(), 8));
EXPECT_EQ(9, Call(test->entry(), 9));
EXPECT_EQ(-7, Call(test->entry(), -7));
EXPECT_EQ(-8, Call(test->entry(), -8));
EXPECT_EQ(-1, Call(test->entry(), -9));
}
ASSEMBLER_TEST_GENERATE(BitSetImmediate2, assembler) {
__ SetExtensions(RV_GCB);
__ bseti(A0, A0, XLEN - 1);
__ ret();
}
ASSEMBLER_TEST_RUN(BitSetImmediate2, test) {
#if XLEN == 32
EXPECT_DISASSEMBLY(
"29f51513 bseti a0, a0, 0x1f\n"
" 8082 ret\n");
#elif XLEN == 64
EXPECT_DISASSEMBLY(
"2bf51513 bseti a0, a0, 0x3f\n"
" 8082 ret\n");
#endif
EXPECT_EQ(kMinIntX, Call(test->entry(), 0));
EXPECT_EQ(kMinIntX + 1, Call(test->entry(), 1));
EXPECT_EQ(-1, Call(test->entry(), -1));
}
ASSEMBLER_TEST_GENERATE(LoadImmediate_MaxInt32, assembler) {
FLAG_use_compressed_instructions = true;
__ SetExtensions(RV_GC);
@ -6346,6 +7292,7 @@ ASSEMBLER_TEST_RUN(AddBranchOverflow_NonDestructive, test) {
EXPECT_EQ(kMinIntX + 1, Call(test->entry(), 42, kMinIntX, 1));
EXPECT_EQ(kMinIntX, Call(test->entry(), 42, kMinIntX, 0));
}
ASSEMBLER_TEST_GENERATE(AddBranchOverflow_Destructive, assembler) {
FLAG_use_compressed_instructions = true;
__ SetExtensions(RV_GC);
@ -6357,7 +7304,6 @@ ASSEMBLER_TEST_GENERATE(AddBranchOverflow_Destructive, assembler) {
__ li(A0, 0);
__ ret();
}
ASSEMBLER_TEST_RUN(AddBranchOverflow_Destructive, test) {
EXPECT_DISASSEMBLY(
"00052693 slti tmp, a0, 0\n"

View file

@ -65,10 +65,17 @@ class RISCVDisassembler {
void DisassembleOP_0(Instr instr);
void DisassembleOP_SUB(Instr instr);
void DisassembleOP_MULDIV(Instr instr);
void DisassembleOP_SHADD(Instr instr);
void DisassembleOP_MINMAXCLMUL(Instr instr);
void DisassembleOP_ROTATE(Instr instr);
void DisassembleOP_BCLRBEXT(Instr instr);
void DisassembleOP32(Instr instr);
void DisassembleOP32_0(Instr instr);
void DisassembleOP32_SUB(Instr instr);
void DisassembleOP32_MULDIV(Instr instr);
void DisassembleOP32_SHADD(Instr instr);
void DisassembleOP32_ADDUW(Instr instr);
void DisassembleOP32_ROTATE(Instr instr);
void DisassembleMISCMEM(Instr instr);
void DisassembleSYSTEM(Instr instr);
void DisassembleAMO(Instr instr);
@ -579,11 +586,46 @@ void RISCVDisassembler::DisassembleOPIMM(Instr instr) {
Print("andi 'rd, 'rs1, 'iimm", instr, RV_I);
break;
case SLLI:
Print("slli 'rd, 'rs1, 'shamt", instr, RV_I);
if (instr.funct7() == COUNT) {
if (instr.shamt() == 0b00000) {
Print("clz 'rd, 'rs1", instr, RV_Zbb);
} else if (instr.shamt() == 0b00001) {
Print("ctz 'rd, 'rs1", instr, RV_Zbb);
} else if (instr.shamt() == 0b00010) {
Print("cpop 'rd, 'rs1", instr, RV_Zbb);
} else if (instr.shamt() == 0b00100) {
Print("sext.b 'rd, 'rs1", instr, RV_Zbb);
} else if (instr.shamt() == 0b00101) {
Print("sext.h 'rd, 'rs1", instr, RV_Zbb);
} else {
UnknownInstruction(instr);
}
} else if ((instr.funct7() & 0b1111110) == BCLRBEXT) {
Print("bclri 'rd, 'rs1, 'shamt", instr, RV_Zbs);
} else if ((instr.funct7() & 0b1111110) == BINV) {
Print("binvi 'rd, 'rs1, 'shamt", instr, RV_Zbs);
} else if ((instr.funct7() & 0b1111110) == BSET) {
Print("bseti 'rd, 'rs1, 'shamt", instr, RV_Zbs);
} else {
Print("slli 'rd, 'rs1, 'shamt", instr, RV_I);
}
break;
case SRI:
if ((instr.funct7() & 0b1111110) == SRA) {
Print("srai 'rd, 'rs1, 'shamt", instr, RV_I);
} else if ((instr.funct7() & 0b1111110) == ROTATE) {
Print("rori 'rd, 'rs1, 'shamt", instr, RV_Zbb);
} else if (instr.funct7() == 0b0010100) {
Print("orc.b 'rd, 'rs1", instr, RV_Zbb);
#if XLEN == 32
} else if (instr.funct7() == 0b0110100) {
Print("rev8 'rd, 'rs1", instr, RV_Zbb);
#else
} else if (instr.funct7() == 0b0110101) {
Print("rev8 'rd, 'rs1", instr, RV_Zbb);
#endif
} else if ((instr.funct7() & 0b1111110) == BCLRBEXT) {
Print("bexti 'rd, 'rs1, 'shamt", instr, RV_Zbs);
} else {
Print("srli 'rd, 'rs1, 'shamt", instr, RV_I);
}
@ -604,11 +646,27 @@ void RISCVDisassembler::DisassembleOPIMM32(Instr instr) {
}
break;
case SLLI:
Print("slliw 'rd, 'rs1, 'shamt", instr, RV_I);
if (instr.funct7() == SLLIUW) {
Print("slli.uw 'rd, 'rs1, 'shamt", instr, RV_Zba);
} else if (instr.funct7() == COUNT) {
if (instr.shamt() == 0b00000) {
Print("clzw 'rd, 'rs1", instr, RV_Zbb);
} else if (instr.shamt() == 0b00001) {
Print("ctzw 'rd, 'rs1", instr, RV_Zbb);
} else if (instr.shamt() == 0b00010) {
Print("cpopw 'rd, 'rs1", instr, RV_Zbb);
} else {
UnknownInstruction(instr);
}
} else {
Print("slliw 'rd, 'rs1, 'shamt", instr, RV_I);
}
break;
case SRI:
if (instr.funct7() == SRA) {
Print("sraiw 'rd, 'rs1, 'shamt", instr, RV_I);
} else if (instr.funct7() == ROTATE) {
Print("roriw 'rd, 'rs1, 'shamt", instr, RV_Zbb);
} else {
Print("srliw 'rd, 'rs1, 'shamt", instr, RV_I);
}
@ -630,6 +688,29 @@ void RISCVDisassembler::DisassembleOP(Instr instr) {
case MULDIV:
DisassembleOP_MULDIV(instr);
break;
case SHADD:
DisassembleOP_SHADD(instr);
break;
case MINMAXCLMUL:
DisassembleOP_MINMAXCLMUL(instr);
break;
case ROTATE:
DisassembleOP_ROTATE(instr);
break;
case BCLRBEXT:
DisassembleOP_BCLRBEXT(instr);
break;
case BINV:
Print("binv 'rd, 'rs1, 'rs2", instr, RV_Zbs);
break;
case BSET:
Print("bset 'rd, 'rs1, 'rs2", instr, RV_Zbs);
break;
#if XLEN == 32
case 0b0000100:
Print("zext.h 'rd, 'rs1", instr, RV_Zbb);
break;
#endif
default:
UnknownInstruction(instr);
}
@ -688,6 +769,15 @@ void RISCVDisassembler::DisassembleOP_SUB(Instr instr) {
case SR:
Print("sra 'rd, 'rs1, 'rs2", instr, RV_I);
break;
case AND:
Print("andn 'rd, 'rs1, 'rs2", instr, RV_Zbb);
break;
case OR:
Print("orn 'rd, 'rs1, 'rs2", instr, RV_Zbb);
break;
case XOR:
Print("xnor 'rd, 'rs1, 'rs2", instr, RV_Zbb);
break;
default:
UnknownInstruction(instr);
}
@ -724,6 +814,76 @@ void RISCVDisassembler::DisassembleOP_MULDIV(Instr instr) {
}
}
void RISCVDisassembler::DisassembleOP_SHADD(Instr instr) {
switch (instr.funct3()) {
case SH1ADD:
Print("sh1add 'rd, 'rs1, 'rs2", instr, RV_Zba);
break;
case SH2ADD:
Print("sh2add 'rd, 'rs1, 'rs2", instr, RV_Zba);
break;
case SH3ADD:
Print("sh3add 'rd, 'rs1, 'rs2", instr, RV_Zba);
break;
default:
UnknownInstruction(instr);
}
}
void RISCVDisassembler::DisassembleOP_MINMAXCLMUL(Instr instr) {
switch (instr.funct3()) {
case MAX:
Print("max 'rd, 'rs1, 'rs2", instr, RV_Zbb);
break;
case MAXU:
Print("maxu 'rd, 'rs1, 'rs2", instr, RV_Zbb);
break;
case MIN:
Print("min 'rd, 'rs1, 'rs2", instr, RV_Zbb);
break;
case MINU:
Print("minu 'rd, 'rs1, 'rs2", instr, RV_Zbb);
break;
case CLMUL:
Print("clmul 'rd, 'rs1, 'rs2", instr, RV_Zbc);
break;
case CLMULH:
Print("clmulh 'rd, 'rs1, 'rs2", instr, RV_Zbc);
break;
case CLMULR:
Print("clmulr 'rd, 'rs1, 'rs2", instr, RV_Zbc);
break;
default:
UnknownInstruction(instr);
}
}
void RISCVDisassembler::DisassembleOP_ROTATE(Instr instr) {
switch (instr.funct3()) {
case ROR:
Print("ror 'rd, 'rs1, 'rs2", instr, RV_Zbb);
break;
case ROL:
Print("rol 'rd, 'rs1, 'rs2", instr, RV_Zbb);
break;
default:
UnknownInstruction(instr);
}
}
void RISCVDisassembler::DisassembleOP_BCLRBEXT(Instr instr) {
switch (instr.funct3()) {
case BCLR:
Print("bclr 'rd, 'rs1, 'rs2", instr, RV_Zbs);
break;
case BEXT:
Print("bext 'rd, 'rs1, 'rs2", instr, RV_Zbs);
break;
default:
UnknownInstruction(instr);
}
}
void RISCVDisassembler::DisassembleOP32(Instr instr) {
switch (instr.funct7()) {
case 0:
@ -735,6 +895,15 @@ void RISCVDisassembler::DisassembleOP32(Instr instr) {
case MULDIV:
DisassembleOP32_MULDIV(instr);
break;
case SHADD:
DisassembleOP32_SHADD(instr);
break;
case ADDUW:
DisassembleOP32_ADDUW(instr);
break;
case ROTATE:
DisassembleOP32_ROTATE(instr);
break;
default:
UnknownInstruction(instr);
}
@ -802,6 +971,50 @@ void RISCVDisassembler::DisassembleOP32_MULDIV(Instr instr) {
}
}
void RISCVDisassembler::DisassembleOP32_SHADD(Instr instr) {
switch (instr.funct3()) {
case SH1ADD:
Print("sh1add.uw 'rd, 'rs1, 'rs2", instr, RV_Zba);
break;
case SH2ADD:
Print("sh2add.uw 'rd, 'rs1, 'rs2", instr, RV_Zba);
break;
case SH3ADD:
Print("sh3add.uw 'rd, 'rs1, 'rs2", instr, RV_Zba);
break;
default:
UnknownInstruction(instr);
}
}
void RISCVDisassembler::DisassembleOP32_ADDUW(Instr instr) {
switch (instr.funct3()) {
#if XLEN >= 64
case F3_0:
Print("add.uw 'rd, 'rs1, 'rs2", instr, RV_Zba);
break;
case ZEXT:
Print("zext.h 'rd, 'rs1", instr, RV_Zbb);
break;
#endif
default:
UnknownInstruction(instr);
}
}
void RISCVDisassembler::DisassembleOP32_ROTATE(Instr instr) {
switch (instr.funct3()) {
case ROR:
Print("rorw 'rd, 'rs1, 'rs2", instr, RV_Zbb);
break;
case ROL:
Print("rolw 'rd, 'rs1, 'rs2", instr, RV_Zbb);
break;
default:
UnknownInstruction(instr);
}
}
void RISCVDisassembler::DisassembleMISCMEM(Instr instr) {
switch (instr.funct3()) {
case FENCE:
@ -1076,10 +1289,10 @@ void RISCVDisassembler::DisassembleOPFP(Instr instr) {
}
case FMINMAXS: {
switch (instr.funct3()) {
case MIN:
case FMIN:
Print("fmin.s 'frd, 'frs1, 'frs2", instr, RV_F);
break;
case MAX:
case FMAX:
Print("fmax.s 'frd, 'frs1, 'frs2", instr, RV_F);
break;
default:
@ -1203,10 +1416,10 @@ void RISCVDisassembler::DisassembleOPFP(Instr instr) {
}
case FMINMAXD: {
switch (instr.funct3()) {
case MIN:
case FMIN:
Print("fmin.d 'frd, 'frs1, 'frs2", instr, RV_D);
break;
case MAX:
case FMAX:
Print("fmax.d 'frd, 'frs1, 'frs2", instr, RV_D);
break;
default:

View file

@ -780,11 +780,36 @@ enum Funct3 {
J = 0b000,
JN = 0b001,
JX = 0b010,
MIN = 0b000,
MAX = 0b001,
FMIN = 0b000,
FMAX = 0b001,
FEQ = 0b010,
FLT = 0b001,
FLE = 0b000,
SH1ADD = 0b010,
SH2ADD = 0b100,
SH3ADD = 0b110,
F3_COUNT = 0b001,
MAX = 0b110,
MAXU = 0b111,
MIN = 0b100,
MINU = 0b101,
CLMUL = 0b001,
CLMULH = 0b011,
CLMULR = 0b010,
SEXT = 0b001,
ZEXT = 0b100,
ROL = 0b001,
ROR = 0b101,
BCLR = 0b001,
BEXT = 0b101,
F3_BINV = 0b001,
F3_BSET = 0b001,
};
enum Funct7 {
@ -822,6 +847,16 @@ enum Funct7 {
FCVTDint = 0b1101001,
FMVXD = 0b1110001,
FMVDX = 0b1111001,
ADDUW = 0b0000100,
SHADD = 0b0010000,
SLLIUW = 0b0000100,
COUNT = 0b0110000,
MINMAXCLMUL = 0b0000101,
ROTATE = 0b0110000,
BCLRBEXT = 0b0100100,
BINV = 0b0110100,
BSET = 0b0010100,
};
enum Funct5 {
@ -1515,6 +1550,12 @@ static constexpr Extension RV_D(4); // Double-precision floating point
static constexpr Extension RV_C(5); // Compressed instructions
static constexpr ExtensionSet RV_G = RV_I | RV_M | RV_A | RV_F | RV_D;
static constexpr ExtensionSet RV_GC = RV_G | RV_C;
static constexpr Extension RV_Zba(6); // Address generation
static constexpr Extension RV_Zbb(7); // Basic bit-manipulation
static constexpr Extension RV_Zbc(8); // Carry-less multiplicatio
static constexpr Extension RV_Zbs(9); // Single-bit instructions
static constexpr ExtensionSet RV_B = RV_Zba | RV_Zbb | RV_Zbc | RV_Zbs;
static constexpr ExtensionSet RV_GCB = RV_GC | RV_B;
#undef R

View file

@ -1007,6 +1007,162 @@ void Simulator::InterpretSTOREFP(Instr instr) {
pc_ += instr.length();
}
static uintx_t clz(uintx_t a) {
for (int bit = XLEN - 1; bit >= 0; bit--) {
if ((a & (static_cast<uintx_t>(1) << bit)) != 0) {
return XLEN - bit - 1;
}
}
return XLEN;
}
static uintx_t ctz(uintx_t a) {
for (int bit = 0; bit < XLEN; bit++) {
if ((a & (static_cast<uintx_t>(1) << bit)) != 0) {
return bit;
}
}
return XLEN;
}
static uintx_t cpop(uintx_t a) {
uintx_t count = 0;
for (int bit = 0; bit < XLEN; bit++) {
if ((a & (static_cast<uintx_t>(1) << bit)) != 0) {
count++;
}
}
return count;
}
static uintx_t clzw(uint32_t a) {
for (int bit = 32 - 1; bit >= 0; bit--) {
if ((a & (static_cast<uint32_t>(1) << bit)) != 0) {
return 32 - bit - 1;
}
}
return 32;
}
static uintx_t ctzw(uint32_t a) {
for (int bit = 0; bit < 32; bit++) {
if ((a & (static_cast<uint32_t>(1) << bit)) != 0) {
return bit;
}
}
return 32;
}
static uintx_t cpopw(uint32_t a) {
uintx_t count = 0;
for (int bit = 0; bit < 32; bit++) {
if ((a & (static_cast<uint32_t>(1) << bit)) != 0) {
count++;
}
}
return count;
}
static intx_t max(intx_t a, intx_t b) {
return a > b ? a : b;
}
static uintx_t maxu(uintx_t a, uintx_t b) {
return a > b ? a : b;
}
static intx_t min(intx_t a, intx_t b) {
return a < b ? a : b;
}
static uintx_t minu(uintx_t a, uintx_t b) {
return a < b ? a : b;
}
static uintx_t clmul(uintx_t a, uintx_t b) {
uintx_t result = 0;
for (int bit = 0; bit < XLEN; bit++) {
if (((b >> bit) & 1) != 0) {
result ^= a << bit;
}
}
return result;
}
static uintx_t clmulh(uintx_t a, uintx_t b) {
uintx_t result = 0;
for (int bit = 1; bit < XLEN; bit++) {
if (((b >> bit) & 1) != 0) {
result ^= a >> (XLEN - bit);
}
}
return result;
}
static uintx_t clmulr(uintx_t a, uintx_t b) {
uintx_t result = 0;
for (int bit = 0; bit < XLEN; bit++) {
if (((b >> bit) & 1) != 0) {
result ^= a >> (XLEN - bit - 1);
}
}
return result;
}
static uintx_t sextb(uintx_t a) {
return static_cast<intx_t>(a << (XLEN - 8)) >> (XLEN - 8);
}
static uintx_t sexth(uintx_t a) {
return static_cast<intx_t>(a << (XLEN - 16)) >> (XLEN - 16);
}
static uintx_t zexth(uintx_t a) {
return a << (XLEN - 16) >> (XLEN - 16);
}
static uintx_t ror(uintx_t a, uintx_t b) {
uintx_t r = b & (XLEN - 1);
uintx_t l = (XLEN - r) & (XLEN - 1);
return (a << l) | (a >> r);
}
static uintx_t rol(uintx_t a, uintx_t b) {
uintx_t l = b & (XLEN - 1);
uintx_t r = (XLEN - l) & (XLEN - 1);
return (a << l) | (a >> r);
}
static uintx_t rorw(uintx_t a, uintx_t b) {
uint32_t r = b & (XLEN - 1);
uint32_t l = (XLEN - r) & (XLEN - 1);
uint32_t x = a;
return sign_extend((x << l) | (x >> r));
}
static uintx_t rolw(uintx_t a, uintx_t b) {
uint32_t l = b & (XLEN - 1);
uint32_t r = (XLEN - l) & (XLEN - 1);
uint32_t x = a;
return sign_extend((x << l) | (x >> r));
}
static uintx_t orcb(uintx_t a) {
uintx_t result = 0;
for (int shift = 0; shift < XLEN; shift += 8) {
if (((a >> shift) & 0xFF) != 0) {
result |= static_cast<uintx_t>(0xFF) << shift;
}
}
return result;
}
static uintx_t rev8(uintx_t a) {
uintx_t result = 0;
for (int shift = 0; shift < XLEN; shift += 8) {
result <<= 8;
result |= (a >> shift) & 0xFF;
}
return result;
}
static uintx_t bclr(uintx_t a, uintx_t b) {
return a & ~(static_cast<uintx_t>(1) << (b & (XLEN - 1)));
}
static uintx_t bext(uintx_t a, uintx_t b) {
return (a >> (b & (XLEN - 1))) & 1;
}
static uintx_t binv(uintx_t a, uintx_t b) {
return a ^ (static_cast<uintx_t>(1) << (b & (XLEN - 1)));
}
static uintx_t bset(uintx_t a, uintx_t b) {
return a | (static_cast<uintx_t>(1) << (b & (XLEN - 1)));
}
DART_FORCE_INLINE
void Simulator::InterpretOPIMM(Instr instr) {
switch (instr.funct3()) {
@ -1034,15 +1190,48 @@ void Simulator::InterpretOPIMM(Instr instr) {
break;
case ANDI:
set_xreg(instr.rd(), get_xreg(instr.rs1()) & instr.itype_imm());
break;
case SLLI:
set_xreg(instr.rd(), get_xreg(instr.rs1()) << instr.shamt());
if (instr.funct7() == COUNT) {
if (instr.shamt() == 0b00000) {
set_xreg(instr.rd(), clz(get_xreg(instr.rs1())));
} else if (instr.shamt() == 0b00001) {
set_xreg(instr.rd(), ctz(get_xreg(instr.rs1())));
} else if (instr.shamt() == 0b00010) {
set_xreg(instr.rd(), cpop(get_xreg(instr.rs1())));
} else if (instr.shamt() == 0b00100) {
set_xreg(instr.rd(), sextb(get_xreg(instr.rs1())));
} else if (instr.shamt() == 0b00101) {
set_xreg(instr.rd(), sexth(get_xreg(instr.rs1())));
} else {
IllegalInstruction(instr);
}
} else if ((instr.funct7() & 0b1111110) == BCLRBEXT) {
set_xreg(instr.rd(), bclr(get_xreg(instr.rs1()), instr.shamt()));
} else if ((instr.funct7() & 0b1111110) == BINV) {
set_xreg(instr.rd(), binv(get_xreg(instr.rs1()), instr.shamt()));
} else if ((instr.funct7() & 0b1111110) == BSET) {
set_xreg(instr.rd(), bset(get_xreg(instr.rs1()), instr.shamt()));
} else {
set_xreg(instr.rd(), get_xreg(instr.rs1()) << instr.shamt());
}
break;
case SRI:
if ((instr.funct7() & 0b1111110) == SRA) {
set_xreg(instr.rd(),
static_cast<intx_t>(get_xreg(instr.rs1())) >> instr.shamt());
} else if ((instr.funct7() & 0b1111110) == ROTATE) {
set_xreg(instr.rd(), ror(get_xreg(instr.rs1()), instr.shamt()));
} else if (instr.funct7() == 0b0010100) {
set_xreg(instr.rd(), orcb(get_xreg(instr.rs1())));
#if XLEN == 32
} else if (instr.funct7() == 0b0110100) {
#else
} else if (instr.funct7() == 0b0110101) {
#endif
set_xreg(instr.rd(), rev8(get_xreg(instr.rs1())));
} else if ((instr.funct7() & 0b1111110) == BCLRBEXT) {
set_xreg(instr.rd(), bext(get_xreg(instr.rs1()), instr.shamt()));
} else {
set_xreg(instr.rd(),
static_cast<uintx_t>(get_xreg(instr.rs1())) >> instr.shamt());
@ -1064,9 +1253,25 @@ void Simulator::InterpretOPIMM32(Instr instr) {
break;
}
case SLLI: {
uint32_t a = get_xreg(instr.rs1());
uint32_t b = instr.shamt();
set_xreg(instr.rd(), sign_extend(a << b));
if (instr.funct7() == SLLIUW) {
uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
uintx_t b = instr.shamt();
set_xreg(instr.rd(), a << b);
} else if (instr.funct7() == COUNT) {
if (instr.shamt() == 0b00000) {
set_xreg(instr.rd(), clzw(get_xreg(instr.rs1())));
} else if (instr.shamt() == 0b00001) {
set_xreg(instr.rd(), ctzw(get_xreg(instr.rs1())));
} else if (instr.shamt() == 0b00010) {
set_xreg(instr.rd(), cpopw(get_xreg(instr.rs1())));
} else {
IllegalInstruction(instr);
}
} else {
uint32_t a = get_xreg(instr.rs1());
uint32_t b = instr.shamt();
set_xreg(instr.rd(), sign_extend(a << b));
}
break;
}
case SRI:
@ -1074,6 +1279,8 @@ void Simulator::InterpretOPIMM32(Instr instr) {
int32_t a = get_xreg(instr.rs1());
int32_t b = instr.shamt();
set_xreg(instr.rd(), sign_extend(a >> b));
} else if (instr.funct7() == ROTATE) {
set_xreg(instr.rd(), rorw(get_xreg(instr.rs1()), instr.shamt()));
} else {
uint32_t a = get_xreg(instr.rs1());
uint32_t b = instr.shamt();
@ -1098,6 +1305,32 @@ void Simulator::InterpretOP(Instr instr) {
case MULDIV:
InterpretOP_MULDIV(instr);
break;
case SHADD:
InterpretOP_SHADD(instr);
break;
case MINMAXCLMUL:
InterpretOP_MINMAXCLMUL(instr);
break;
case ROTATE:
InterpretOP_ROTATE(instr);
break;
case BCLRBEXT:
InterpretOP_BCLRBEXT(instr);
break;
case BINV:
set_xreg(instr.rd(), binv(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
pc_ += instr.length();
break;
case BSET:
set_xreg(instr.rd(), bset(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
pc_ += instr.length();
break;
#if XLEN == 32
case 0b0000100:
set_xreg(instr.rd(), zexth(get_xreg(instr.rs1())));
pc_ += instr.length();
break;
#endif
default:
IllegalInstruction(instr);
}
@ -1331,6 +1564,98 @@ void Simulator::InterpretOP_SUB(Instr instr) {
set_xreg(instr.rd(), static_cast<intx_t>(get_xreg(instr.rs1())) >> shamt);
break;
}
case AND:
set_xreg(instr.rd(), get_xreg(instr.rs1()) & ~get_xreg(instr.rs2()));
break;
case OR:
set_xreg(instr.rd(), get_xreg(instr.rs1()) | ~get_xreg(instr.rs2()));
break;
case XOR:
set_xreg(instr.rd(), get_xreg(instr.rs1()) ^ ~get_xreg(instr.rs2()));
break;
default:
IllegalInstruction(instr);
}
pc_ += instr.length();
}
DART_FORCE_INLINE
void Simulator::InterpretOP_SHADD(Instr instr) {
switch (instr.funct3()) {
case SH1ADD:
set_xreg(instr.rd(),
(get_xreg(instr.rs1()) << 1) + get_xreg(instr.rs2()));
break;
case SH2ADD:
set_xreg(instr.rd(),
(get_xreg(instr.rs1()) << 2) + get_xreg(instr.rs2()));
break;
case SH3ADD:
set_xreg(instr.rd(),
(get_xreg(instr.rs1()) << 3) + get_xreg(instr.rs2()));
break;
default:
IllegalInstruction(instr);
}
pc_ += instr.length();
}
DART_FORCE_INLINE
void Simulator::InterpretOP_MINMAXCLMUL(Instr instr) {
switch (instr.funct3()) {
case MAX:
set_xreg(instr.rd(), max(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
break;
case MAXU:
set_xreg(instr.rd(), maxu(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
break;
case MIN:
set_xreg(instr.rd(), min(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
break;
case MINU:
set_xreg(instr.rd(), minu(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
break;
case CLMUL:
set_xreg(instr.rd(), clmul(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
break;
case CLMULH:
set_xreg(instr.rd(),
clmulh(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
break;
case CLMULR:
set_xreg(instr.rd(),
clmulr(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
break;
default:
IllegalInstruction(instr);
}
pc_ += instr.length();
}
DART_FORCE_INLINE
void Simulator::InterpretOP_ROTATE(Instr instr) {
switch (instr.funct3()) {
case ROR:
set_xreg(instr.rd(), ror(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
break;
case ROL:
set_xreg(instr.rd(), rol(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
break;
default:
IllegalInstruction(instr);
}
pc_ += instr.length();
}
DART_FORCE_INLINE
void Simulator::InterpretOP_BCLRBEXT(Instr instr) {
switch (instr.funct3()) {
case BCLR:
set_xreg(instr.rd(), bclr(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
break;
case BEXT:
set_xreg(instr.rd(), bext(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
break;
default:
IllegalInstruction(instr);
}
@ -1350,6 +1675,15 @@ void Simulator::InterpretOP32(Instr instr) {
case MULDIV:
InterpretOP32_MULDIV(instr);
break;
case SHADD:
InterpretOP32_SHADD(instr);
break;
case ADDUW:
InterpretOP32_ADDUW(instr);
break;
case ROTATE:
InterpretOP32_ROTATE(instr);
break;
#endif // XLEN >= 64
default:
IllegalInstruction(instr);
@ -1439,6 +1773,68 @@ void Simulator::InterpretOP32_MULDIV(Instr instr) {
pc_ += instr.length();
}
DART_FORCE_INLINE
void Simulator::InterpretOP32_SHADD(Instr instr) {
switch (instr.funct3()) {
case SH1ADD: {
uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
uintx_t b = get_xreg(instr.rs2());
set_xreg(instr.rd(), (a << 1) + b);
break;
}
case SH2ADD: {
uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
uintx_t b = get_xreg(instr.rs2());
set_xreg(instr.rd(), (a << 2) + b);
break;
}
case SH3ADD: {
uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
uintx_t b = get_xreg(instr.rs2());
set_xreg(instr.rd(), (a << 3) + b);
break;
}
default:
IllegalInstruction(instr);
}
pc_ += instr.length();
}
DART_FORCE_INLINE
void Simulator::InterpretOP32_ADDUW(Instr instr) {
switch (instr.funct3()) {
#if XLEN >= 64
case F3_0: {
uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
uintx_t b = get_xreg(instr.rs2());
set_xreg(instr.rd(), a + b);
break;
}
case ZEXT:
set_xreg(instr.rd(), zexth(get_xreg(instr.rs1())));
break;
#endif // XLEN >= 64
default:
IllegalInstruction(instr);
}
pc_ += instr.length();
}
DART_FORCE_INLINE
void Simulator::InterpretOP32_ROTATE(Instr instr) {
switch (instr.funct3()) {
case ROR:
set_xreg(instr.rd(), rorw(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
break;
case ROL:
set_xreg(instr.rd(), rolw(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
break;
default:
IllegalInstruction(instr);
}
pc_ += instr.length();
}
void Simulator::InterpretMISCMEM(Instr instr) {
switch (instr.funct3()) {
case FENCE:
@ -2295,10 +2691,10 @@ void Simulator::InterpretOPFP(Instr instr) {
float rs1 = get_fregs(instr.frs1());
float rs2 = get_fregs(instr.frs2());
switch (instr.funct3()) {
case MIN:
case FMIN:
set_fregs(instr.frd(), rv_fminf(rs1, rs2));
break;
case MAX:
case FMAX:
set_fregs(instr.frd(), rv_fmaxf(rs1, rs2));
break;
default:
@ -2449,10 +2845,10 @@ void Simulator::InterpretOPFP(Instr instr) {
double rs1 = get_fregd(instr.frs1());
double rs2 = get_fregd(instr.frs2());
switch (instr.funct3()) {
case MIN:
case FMIN:
set_fregd(instr.frd(), rv_fmin(rs1, rs2));
break;
case MAX:
case FMAX:
set_fregd(instr.frd(), rv_fmax(rs1, rs2));
break;
default:

View file

@ -208,10 +208,17 @@ class Simulator {
void InterpretOP_0(Instr instr);
void InterpretOP_SUB(Instr instr);
void InterpretOP_MULDIV(Instr instr);
void InterpretOP_SHADD(Instr instr);
void InterpretOP_MINMAXCLMUL(Instr instr);
void InterpretOP_ROTATE(Instr instr);
void InterpretOP_BCLRBEXT(Instr instr);
void InterpretOP32(Instr instr);
void InterpretOP32_0(Instr instr);
void InterpretOP32_SUB(Instr instr);
void InterpretOP32_MULDIV(Instr instr);
void InterpretOP32_SHADD(Instr instr);
void InterpretOP32_ADDUW(Instr instr);
void InterpretOP32_ROTATE(Instr instr);
void InterpretMISCMEM(Instr instr);
void InterpretSYSTEM(Instr instr);
void InterpretECALL(Instr instr);