diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp index bd2788446efb34..9fc8ae902d7e7d 100644 --- a/src/coreclr/jit/emitriscv64.cpp +++ b/src/coreclr/jit/emitriscv64.cpp @@ -732,6 +732,11 @@ void emitter::emitIns_R_R( void emitter::emitIns_R_R_I( instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt /* = INS_OPTS_NONE */) { + if (tryEmitCompressedIns_R_R_I(ins, attr, reg1, reg2, imm, opt)) + { + return; + } + code_t code = emitInsCode(ins); instrDesc* id = emitNewInstr(attr); @@ -790,6 +795,113 @@ void emitter::emitIns_R_R_I( appendToCurIG(id); } +bool emitter::tryEmitCompressedIns_R_R_I( + instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt) +{ + instruction compressedIns = tryGetCompressedIns_R_R_I(ins, attr, reg1, reg2, imm, opt); + if (compressedIns == INS_none) + { + return false; + } + + code_t code; + switch (compressedIns) + { + case INS_c_ldsp: + case INS_c_lwsp: + case INS_c_fldsp: + code = insEncodeCITypeInstr(compressedIns, reg1 & 0x1f, imm); + break; + case INS_c_swsp: + case INS_c_sdsp: + case INS_c_fsdsp: + code = insEncodeCSSTypeInstr(compressedIns, reg1 & 0x1f, imm); + break; + default: + return false; + }; + + instrDesc* id = emitNewInstr(attr); + + id->idIns(ins); + id->idReg1(reg1); + id->idReg2(reg2); + id->idAddr()->iiaSetInstrEncode(code); + id->idCodeSize(2); + + appendToCurIG(id); + + return true; +} + +instruction emitter::tryGetCompressedIns_R_R_I( + instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt) +{ + regNumber rd, rs1, rs2; + switch (ins) + { + case INS_lw: + case INS_ld: + case INS_fld: + rd = reg1; + rs1 = reg2; + break; + case INS_sw: + case INS_sd: + case INS_fsd: + rs1 = reg2; + rs2 = reg1; + break; + default: + return INS_none; + } + + switch (ins) + { + case INS_lw: + { + if ((rs1 == REG_SP) && (rd != REG_R0) && ((imm & 0b11) == 0) && ((imm >> 8) == 0)) + { + return INS_c_lwsp; + } + break; + } + case INS_ld: + if ((rs1 == REG_SP) && (rd != REG_R0) && ((imm & 0b111) == 0) && ((imm >> 9) == 0)) + { + return INS_c_ldsp; + } + break; + case INS_fld: + if ((rs1 == REG_SP) && ((rd & 0x1f) != REG_R0) && ((imm & 0b111) == 0) && ((imm >> 9) == 0)) + { + return INS_c_fldsp; + } + break; + case INS_sw: + if ((rs1 == REG_SP) && ((imm & 0b11) == 0) && ((imm >> 8) == 0)) + { + return INS_c_swsp; + } + break; + case INS_sd: + if ((rs1 == REG_SP) && ((imm & 0b111) == 0) && ((imm >> 9) == 0)) + { + return INS_c_sdsp; + } + break; + case INS_fsd: + if ((rs1 == REG_SP) && ((imm & 0b111) == 0) && ((imm >> 9) == 0)) + { + return INS_c_fsdsp; + } + break; + default: + break; + }; + return INS_none; +} + /***************************************************************************** * * Add an instruction referencing register and two constants. @@ -2785,6 +2897,85 @@ static inline void assertCodeLength(size_t code, uint8_t size) return insCode | (rs2Rvc << 2) | (rdRs1Rvc << 7); } +/***************************************************************************** + * + * Emit a 16-bit RISCV64C CI-Type instruction + * + * Note: Instruction types as per RISC-V Spec, Chapter "Compressed Instruction Formats" + * CI Format: + * 15---------13--12--11----------------7-6------------------2-1-----0 + * | funct3 |imm | rd | imm | op | + * ------------------------------------------------------------------- + */ + +/*static*/ emitter::code_t emitter::insEncodeCITypeInstr(instruction ins, unsigned rd, ssize_t imm) +{ + assert((INS_c_lwsp <= ins) && (ins <= INS_c_fldsp)); + code_t insCode = emitInsCode(ins); + + assertCodeLength(insCode, 16); + assertCodeLength(rd, 5); + + unsigned imm12 = (imm >> 5) & 0b1; + unsigned imm6To2; + switch (ins) + { + case INS_c_lwsp: + assertCodeLength(imm, 8); + imm6To2 = ((imm >> 6) & 0b11) | (((imm >> 2) & 0b111) << 2); + break; + case INS_c_ldsp: + case INS_c_fldsp: + assertCodeLength(imm, 9); + imm6To2 = ((imm >> 6) & 0b111) | (((imm >> 3) & 0b11) << 3); + break; + default: + unreached(); + }; + assertCodeLength(imm6To2, 5); + + return insCode | (imm6To2 << 2) | (rd << 7) | (imm12 << 12); +} + +/***************************************************************************** + * + * Emit a 16-bit RISCV64C CSS-Type instruction + * + * Note: Instruction types as per RISC-V Spec, Chapter "Compressed Instruction Formats" + * CSS Format: + * 15---------13-12---------------------7-6------------------2-1-----0 + * | funct3 | imm | rs2 | op | + * ------------------------------------------------------------------- + */ + +/*static*/ emitter::code_t emitter::insEncodeCSSTypeInstr(instruction ins, unsigned rs2, ssize_t imm) +{ + assert((INS_c_swsp <= ins) && (ins <= INS_c_fsdsp)); + code_t insCode = emitInsCode(ins); + + assertCodeLength(insCode, 16); + assertCodeLength(rs2, 5); + + unsigned imm12To7; + switch (ins) + { + case INS_c_swsp: + assertCodeLength(imm, 8); + imm12To7 = ((imm >> 6) & 0b11) | (((imm >> 2) & 0b1111) << 2); + break; + case INS_c_sdsp: + case INS_c_fsdsp: + assertCodeLength(imm, 9); + imm12To7 = ((imm >> 6) & 0b111) | (((imm >> 3) & 0b111) << 3); + break; + default: + unreached(); + }; + assertCodeLength(imm12To7, 6); + + return insCode | (rs2 << 2) | (imm12To7 << 7); +} + static constexpr unsigned kInstructionOpcodeMask = 0x7f; static constexpr unsigned kInstructionFunct3Mask = 0x7000; static constexpr unsigned kInstructionFunct5Mask = 0xf8000000; @@ -5010,6 +5201,81 @@ void emitter::emitDispInsName( } return; } + case MajorOpcode::LwSp: + { + unsigned rd = (code >> 7) & 0x1f; + ssize_t offset5 = (code >> 12) & 0b1; + ssize_t offset7To6 = (code >> 2) & 0b11; + ssize_t offset4To2 = (code >> 4) & 0b111; + ssize_t offset = (offset4To2 << 2) | (offset5 << 5) | (offset7To6 << 6); + // TODO-RISCV64-RVC: Introduce a switch in jitconfigvalues.h to show c.* prefix. + printf("lw %s, ", RegNames[rd]); + emitDispImmediate(offset, false, REG_SP); + printf("(%s)\n", RegNames[REG_SP]); + return; + } + case MajorOpcode::LdSp: + { + unsigned rd = (code >> 7) & 0x1f; + ssize_t offset5 = (code >> 12) & 0b1; + ssize_t offset8To6 = (code >> 2) & 0b111; + ssize_t offset4To3 = (code >> 5) & 0b11; + ssize_t offset = (offset4To3 << 3) | (offset5 << 5) | (offset8To6 << 6); + // TODO-RISCV64-RVC: Introduce a switch in jitconfigvalues.h to show c.* prefix. + printf("ld %s, ", RegNames[rd]); + emitDispImmediate(offset, false, REG_SP); + printf("(%s)\n", RegNames[REG_SP]); + return; + } + case MajorOpcode::FldSp: + { + unsigned rd = (code >> 7) & 0x1f; + ssize_t offset5 = (code >> 12) & 0b1; + ssize_t offset8To6 = (code >> 2) & 0b111; + ssize_t offset4To3 = (code >> 5) & 0b11; + ssize_t offset = (offset4To3 << 3) | (offset5 << 5) | (offset8To6 << 6); + // TODO-RISCV64-RVC: Introduce a switch in jitconfigvalues.h to show c.* prefix. + printf("fld %s, ", RegNames[rd]); + emitDispImmediate(offset, false, REG_SP); + printf("(%s)\n", RegNames[REG_SP]); + return; + } + case MajorOpcode::SwSp: + { + unsigned rs2 = (code >> 2) & 0x1f; + ssize_t offset7To6 = (code >> 7) & 0b11; + ssize_t offset5To2 = (code >> 9) & 0b1111; + ssize_t offset = (offset5To2 << 2) | (offset7To6 << 6); + // TODO-RISCV64-RVC: Introduce a switch in jitconfigvalues.h to show c.* prefix. + printf("sw %s, ", RegNames[rs2]); + emitDispImmediate(offset, false, REG_SP); + printf("(%s)\n", RegNames[REG_SP]); + return; + } + case MajorOpcode::SdSp: + { + unsigned rs2 = (code >> 2) & 0x1f; + ssize_t offset8To6 = (code >> 7) & 0b111; + ssize_t offset5To3 = (code >> 10) & 0b111; + ssize_t offset = (offset5To3 << 3) | (offset8To6 << 6); + // TODO-RISCV64-RVC: Introduce a switch in jitconfigvalues.h to show c.* prefix. + printf("sd %s, ", RegNames[rs2]); + emitDispImmediate(offset, false, REG_SP); + printf("(%s)\n", RegNames[REG_SP]); + return; + } + case MajorOpcode::FsdSp: + { + unsigned rs2 = (code >> 2) & 0x1f; + ssize_t offset8To6 = (code >> 7) & 0b111; + ssize_t offset5To3 = (code >> 10) & 0b111; + ssize_t offset = (offset5To3 << 3) | (offset8To6 << 6); + // TODO-RISCV64-RVC: Introduce a switch in jitconfigvalues.h to show c.* prefix. + printf("fsd %s, ", RegNames[rs2]); + emitDispImmediate(offset, false, REG_SP); + printf("(%s)\n", RegNames[REG_SP]); + return; + } default: NO_WAY("illegal ins within emitDisInsName!"); } @@ -5763,7 +6029,7 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins unsigned codeSize = id->idCodeSize(); assert((codeSize >= 2) && ((codeSize % 2) == 0)); - // Some instructions like jumps or loads may have not-yet-known simple auxilliary instructions (lui, addi, slli, + // jump instructions may have not-yet-known simple auxilliary instructions (lui, addi, slli, // etc) for building immediates, assume cost of one each. // instrDescLoadImm consists of OpImm, OpImm32, and Lui instructions. float immediateBuildingCost = ((codeSize / sizeof(code_t)) - 1) * PERFSCORE_LATENCY_1C; @@ -5902,11 +6168,19 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins case MajorOpcode::Store: case MajorOpcode::LoadFp: case MajorOpcode::StoreFp: + case MajorOpcode::LwSp: + case MajorOpcode::LdSp: + case MajorOpcode::FldSp: + case MajorOpcode::SwSp: + case MajorOpcode::SdSp: + case MajorOpcode::FsdSp: { - bool isLoad = (opcode == MajorOpcode::Load || opcode == MajorOpcode::LoadFp); + bool isRegularLoad = (opcode == MajorOpcode::Load || opcode == MajorOpcode::LoadFp); + bool isCompressedLoad = + (opcode == MajorOpcode::LwSp || opcode == MajorOpcode::LdSp || opcode == MajorOpcode::FldSp); - result.insLatency = isLoad ? PERFSCORE_LATENCY_2C : PERFSCORE_LATENCY_4C; - if (isLoad) + result.insLatency = isRegularLoad || isCompressedLoad ? PERFSCORE_LATENCY_2C : PERFSCORE_LATENCY_4C; + if (isRegularLoad) { code_t log2Size = (emitInsCode(ins) >> 12) & 0b11; if (log2Size < 2) // sub-word loads @@ -5917,8 +6191,7 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins if (baseReg != REG_SP || baseReg != REG_FP) result.insLatency += PERFSCORE_LATENCY_1C; // assume non-stack load/stores are more likely to cache-miss - result.insThroughput += immediateBuildingCost; - result.insMemoryAccessKind = isLoad ? PERFSCORE_MEMORY_READ : PERFSCORE_MEMORY_WRITE; + result.insMemoryAccessKind = isRegularLoad ? PERFSCORE_MEMORY_READ : PERFSCORE_MEMORY_WRITE; break; } diff --git a/src/coreclr/jit/emitriscv64.h b/src/coreclr/jit/emitriscv64.h index 9c6def497e30f7..4b30eb6fde07aa 100644 --- a/src/coreclr/jit/emitriscv64.h +++ b/src/coreclr/jit/emitriscv64.h @@ -65,10 +65,14 @@ bool emitInsIsLoadOrStore(instruction ins); // RVC emitters bool tryEmitCompressedIns_R_R_R( instruction ins, emitAttr attr, regNumber rd, regNumber rs1, regNumber rs2, insOpts opt); +bool tryEmitCompressedIns_R_R_I( + instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt); // RVC helpers instruction tryGetCompressedIns_R_R_R( instruction ins, emitAttr attr, regNumber rd, regNumber rs1, regNumber rs2, insOpts opt); +instruction tryGetCompressedIns_R_R_I( + instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, ssize_t imm, insOpts opt); unsigned tryGetRvcRegisterNumber(regNumber reg); instruction getCompressedArithmeticIns(instruction ins); regNumber getRegNumberFromRvcReg(unsigned rvcReg); @@ -113,6 +117,8 @@ static code_t insEncodeJTypeInstr(unsigned opcode, unsigned rd, unsigned imm21); static code_t insEncodeCRTypeInstr(instruction ins, unsigned rdRs1, unsigned rs2); static code_t insEncodeCATypeInstr(instruction ins, unsigned rdRs1Rvc, unsigned rs2Rvc); +static code_t insEncodeCITypeInstr(instruction ins, unsigned rd, ssize_t imm); +static code_t insEncodeCSSTypeInstr(instruction ins, unsigned rs2, ssize_t imm); #ifdef DEBUG static void emitOutput_RTypeInstr_SanityCheck(instruction ins, regNumber rd, regNumber rs1, regNumber rs2); @@ -169,7 +175,7 @@ enum class MajorOpcode /* inst[1:0] */ /* 00 */ Addi4Spn, Fld, Lw, Ld, Reserved2, Fsd, Sw, Sd, /* 01 */ Addi, Addiw, Li, LuiAddi16Sp, MiscAlu, J, Beqz, Bnez, - /* 10 */ Slli, FldSp, LwSp, Ldsp, JrJalrMvAdd, FsdSp, SwSp, SdSp, + /* 10 */ Slli, FldSp, LwSp, LdSp, JrJalrMvAdd, FsdSp, SwSp, SdSp, // clang-format on }; diff --git a/src/coreclr/jit/instrsriscv64.h b/src/coreclr/jit/instrsriscv64.h index 3ad89c3cda7d57..62fae18cd88c4f 100644 --- a/src/coreclr/jit/instrsriscv64.h +++ b/src/coreclr/jit/instrsriscv64.h @@ -316,6 +316,12 @@ INST(c_xor, "c.xor", 0, 0x00008c21) INST(c_sub, "c.sub", 0, 0x00008c01) INST(c_addw, "c.addw", 0, 0x00009c21) INST(c_subw, "c.subw", 0, 0x00009c01) +INST(c_lwsp, "c.lwsp", 0, 0x00004002) +INST(c_ldsp, "c.ldsp", 0, 0x00006002) +INST(c_fldsp, "c.fldsp", 0, 0x00002002) +INST(c_swsp, "c.swsp", 0, 0x0000c002) +INST(c_sdsp, "c.sdsp", 0, 0x0000e002) +INST(c_fsdsp, "c.fsdsp", 0, 0x0000a002) // clang-format on /*****************************************************************************/