mirror of https://github.com/dotnet/runtime
Merge 3aed89998f
into 02596ba8d9
This commit is contained in:
commit
03848046a8
|
@ -4354,7 +4354,7 @@ HRESULT CordbNativeCode::EnumerateVariableHomes(ICorDebugVariableHomeEnum **ppEn
|
|||
|
||||
int CordbNativeCode::GetCallInstructionLength(BYTE *ip, ULONG32 count)
|
||||
{
|
||||
#if defined(TARGET_ARM)
|
||||
#if defined(TARGET_ARM) || defined(TARGET_RISCV64)
|
||||
if (Is32BitInstruction(*(WORD*)ip))
|
||||
return 4;
|
||||
else
|
||||
|
@ -4726,8 +4726,6 @@ int CordbNativeCode::GetCallInstructionLength(BYTE *ip, ULONG32 count)
|
|||
|
||||
_ASSERTE(!"Invalid opcode!");
|
||||
return -1;
|
||||
#elif defined(TARGET_RISCV64)
|
||||
return MAX_INSTRUCTION_LENGTH;
|
||||
#else
|
||||
#error Platform not implemented
|
||||
#endif
|
||||
|
|
|
@ -70,7 +70,7 @@ void NativeWalker::Decode()
|
|||
|
||||
LOG((LF_CORDB, LL_INFO100000, "RiscV64Walker::Decode instruction at %p, opcode: %x\n", m_ip, opcode));
|
||||
|
||||
// TODO after "C" Standard Extension support implemented, add C.J, C.JAL, C.JR, C.JALR, C.BEQZ, C.BNEZ
|
||||
// TODO-RISCV64-RVC: after "C" Standard Extension support implemented, add C.J, C.JAL, C.JR, C.JALR, C.BEQZ, C.BNEZ
|
||||
|
||||
if ((opcode & 0x7f) == 0x6f) // JAL
|
||||
{
|
||||
|
|
|
@ -470,7 +470,7 @@ RtlpGetFunctionEndAddress (
|
|||
FunctionLength = *(PTR_ULONG64)(ImageBase + FunctionLength) & 0x3ffff;
|
||||
}
|
||||
|
||||
return FunctionEntry->BeginAddress + 4 * FunctionLength;
|
||||
return FunctionEntry->BeginAddress + 2 * FunctionLength;
|
||||
}
|
||||
|
||||
#define RUNTIME_FUNCTION__BeginAddress(FunctionEntry) ((FunctionEntry)->BeginAddress)
|
||||
|
|
|
@ -803,18 +803,18 @@ struct RISCV64GcInfoEncoding {
|
|||
// GC Pointers are 8-bytes aligned
|
||||
static inline constexpr int32_t NORMALIZE_STACK_SLOT (int32_t x) { return ((x)>>3); }
|
||||
static inline constexpr int32_t DENORMALIZE_STACK_SLOT (int32_t x) { return ((x)<<3); }
|
||||
// All Instructions are 4 bytes long
|
||||
static inline constexpr uint32_t NORMALIZE_CODE_LENGTH (uint32_t x) { return ((x)>>2); }
|
||||
static inline constexpr uint32_t DENORMALIZE_CODE_LENGTH (uint32_t x) { return ((x)<<2); }
|
||||
// All Instructions are 2/4 bytes long
|
||||
static inline constexpr uint32_t NORMALIZE_CODE_LENGTH (uint32_t x) { return ((x)>>1); }
|
||||
static inline constexpr uint32_t DENORMALIZE_CODE_LENGTH (uint32_t x) { return ((x)<<1); }
|
||||
// Encode Frame pointer X8 as zero, sp/x2 as 1
|
||||
static inline constexpr uint32_t NORMALIZE_STACK_BASE_REGISTER (uint32_t x) { return ((x) == 8 ? 0u : 1u); }
|
||||
static inline constexpr uint32_t DENORMALIZE_STACK_BASE_REGISTER (uint32_t x) { return ((x) == 0 ? 8u : 2u); }
|
||||
static inline constexpr uint32_t NORMALIZE_SIZE_OF_STACK_AREA (uint32_t x) { return ((x)>>3); }
|
||||
static inline constexpr uint32_t DENORMALIZE_SIZE_OF_STACK_AREA (uint32_t x) { return ((x)<<3); }
|
||||
static const bool CODE_OFFSETS_NEED_NORMALIZATION = true;
|
||||
// Instructions are 4 bytes long
|
||||
static inline constexpr uint32_t NORMALIZE_CODE_OFFSET (uint32_t x) { return ((x)>>2); }
|
||||
static inline constexpr uint32_t DENORMALIZE_CODE_OFFSET (uint32_t x) { return ((x)<<2); }
|
||||
// Instructions are 2/4 bytes long
|
||||
static inline constexpr uint32_t NORMALIZE_CODE_OFFSET (uint32_t x) { return ((x)>>1); }
|
||||
static inline constexpr uint32_t DENORMALIZE_CODE_OFFSET (uint32_t x) { return ((x)<<1); }
|
||||
|
||||
static const int PSP_SYM_STACK_SLOT_ENCBASE = 6;
|
||||
static const int GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE = 6;
|
||||
|
|
|
@ -101,6 +101,15 @@ inline ResultType ThumbCodeToDataPointer(SourceType pCode)
|
|||
|
||||
#endif // TARGET_ARM
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
|
||||
inline bool Is32BitInstruction(WORD opcode)
|
||||
{
|
||||
return (opcode & 0b11) == 0b11;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Convert from a PCODE to the corresponding PINSTR. On many architectures this will be the identity function;
|
||||
// on ARM, this will mask off the THUMB bit.
|
||||
inline TADDR PCODEToPINSTR(PCODE pc)
|
||||
|
|
|
@ -786,6 +786,7 @@ void CodeGen::genZeroInitFrameUsingBlockInit(int untrLclHi, int untrLclLo, regNu
|
|||
GetEmitter()->emitIns_R_R_R(INS_add, EA_PTRSIZE, rEndAddr, rEndAddr, rAddr);
|
||||
}
|
||||
|
||||
// TODO-RISCV64-RVC: Remove hardcoded branch offset here
|
||||
GetEmitter()->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_R0, rAddr, padding);
|
||||
GetEmitter()->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_R0, rAddr, padding + REGSIZE_BYTES);
|
||||
GetEmitter()->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_R0, rAddr, padding + 2 * REGSIZE_BYTES);
|
||||
|
@ -1006,10 +1007,11 @@ void CodeGen::genCodeForIncSaturate(GenTree* tree)
|
|||
regNumber operandReg = genConsumeReg(operand);
|
||||
emitAttr attr = emitActualTypeSize(tree);
|
||||
|
||||
BasicBlock* skip = genCreateTempLabel();
|
||||
GetEmitter()->emitIns_R_R_I(INS_addi, attr, targetReg, operandReg, 1);
|
||||
// bne targetReg, zero, 2 * 4
|
||||
GetEmitter()->emitIns_R_R_I(INS_bne, attr, targetReg, REG_R0, 8);
|
||||
GetEmitter()->emitIns_J_cond_la(INS_bne, skip, targetReg, REG_R0);
|
||||
GetEmitter()->emitIns_R_R_I(INS_xori, attr, targetReg, targetReg, -1);
|
||||
genDefineTempLabel(skip);
|
||||
|
||||
genProduceReg(tree);
|
||||
}
|
||||
|
@ -1533,6 +1535,8 @@ void CodeGen::genLclHeap(GenTree* tree)
|
|||
// and localloc size is a multiple of STACK_ALIGN.
|
||||
|
||||
// Loop:
|
||||
BasicBlock* loop = genCreateTempLabel();
|
||||
genDefineTempLabel(loop);
|
||||
emit->emitIns_R_R_I(INS_addi, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, -16);
|
||||
|
||||
emit->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_R0, REG_SPBASE, 8);
|
||||
|
@ -1546,7 +1550,7 @@ void CodeGen::genLclHeap(GenTree* tree)
|
|||
emit->emitIns_R_R_I(INS_addi, emitActualTypeSize(type), regCnt, regCnt, -16);
|
||||
|
||||
// goto Loop
|
||||
emit->emitIns_R_R_I(INS_bne, EA_PTRSIZE, regCnt, REG_R0, -4 << 2);
|
||||
emit->emitIns_J_cond_la(INS_bne, loop, regCnt, REG_R0);
|
||||
|
||||
lastTouchDelta = 0;
|
||||
}
|
||||
|
@ -1591,8 +1595,10 @@ void CodeGen::genLclHeap(GenTree* tree)
|
|||
emit->emitIns_R_R_R(INS_sub, EA_PTRSIZE, regCnt, REG_SPBASE, regCnt);
|
||||
|
||||
// Overflow, set regCnt to lowest possible value
|
||||
emit->emitIns_R_R_I(INS_beq, EA_PTRSIZE, tempReg, REG_R0, 2 << 2);
|
||||
BasicBlock* skip = genCreateTempLabel();
|
||||
emit->emitIns_J_cond_la(INS_beq, skip, tempReg, REG_R0);
|
||||
emit->emitIns_R_R(INS_mov, EA_PTRSIZE, regCnt, REG_R0);
|
||||
genDefineTempLabel(skip);
|
||||
|
||||
regNumber rPageSize = internalRegisters.GetSingle(tree);
|
||||
|
||||
|
@ -1603,10 +1609,12 @@ void CodeGen::genLclHeap(GenTree* tree)
|
|||
emit->emitIns_R_R(INS_mov, EA_PTRSIZE, tempReg, REG_SPBASE);
|
||||
|
||||
// tickle the page - this triggers a page fault when on the guard page
|
||||
BasicBlock* loop = genCreateTempLabel();
|
||||
genDefineTempLabel(loop);
|
||||
emit->emitIns_R_R_I(INS_lw, EA_4BYTE, REG_R0, tempReg, 0);
|
||||
emit->emitIns_R_R_R(INS_sub, EA_4BYTE, tempReg, tempReg, rPageSize);
|
||||
|
||||
emit->emitIns_R_R_I(INS_bgeu, EA_PTRSIZE, tempReg, regCnt, -2 << 2);
|
||||
emit->emitIns_J_cond_la(INS_bgeu, loop, tempReg, regCnt);
|
||||
|
||||
// lastTouchDelta is dynamic, and can be up to a page. So if we have outgoing arg space,
|
||||
// we're going to assume the worst and probe.
|
||||
|
@ -6517,6 +6525,7 @@ void CodeGen::genJumpToThrowHlpBlk_la(
|
|||
imm = 3 << 2;
|
||||
}
|
||||
|
||||
// TODO-RISCV64-RVC: Remove hardcoded branch offset here
|
||||
emit->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, reg2, imm);
|
||||
}
|
||||
else
|
||||
|
@ -6529,12 +6538,14 @@ void CodeGen::genJumpToThrowHlpBlk_la(
|
|||
params.ireg = REG_DEFAULT_HELPER_CALL_TARGET;
|
||||
if (compiler->opts.compReloc)
|
||||
{
|
||||
// TODO-RISCV64-RVC: Remove hardcoded branch offset here
|
||||
ssize_t imm = (3 + 1) << 2;
|
||||
emit->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, reg2, imm);
|
||||
emit->emitIns_R_AI(INS_jal, EA_PTR_DSP_RELOC, params.ireg, (ssize_t)pAddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO-RISCV64-RVC: Remove hardcoded branch offset here
|
||||
ssize_t imm = 9 << 2;
|
||||
emit->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, reg2, imm);
|
||||
// TODO-RISCV64-CQ: In the future we may consider using emitter::emitLoadImmediate instead,
|
||||
|
|
|
@ -141,10 +141,19 @@ bool emitter::emitInsWritesToLclVarStackLoc(instrDesc* id)
|
|||
|
||||
emitter::MajorOpcode emitter::GetMajorOpcode(code_t code)
|
||||
{
|
||||
assert((code & 0b11) == 0b11); // 16-bit instructions unsupported
|
||||
code_t opcode = (code >> 2) & 0b11111;
|
||||
assert((opcode & 0b111) != 0b111); // 48-bit and larger instructions unsupported
|
||||
return (MajorOpcode)opcode;
|
||||
if ((code & 0b11) == 0b11)
|
||||
{
|
||||
code_t opcode = (code >> 2) & 0b11111;
|
||||
assert((opcode & 0b111) != 0b111); // 48-bit and larger instructions unsupported
|
||||
return (MajorOpcode)opcode;
|
||||
}
|
||||
else
|
||||
{
|
||||
code_t op = code & 0b11;
|
||||
code_t funct3 = (code >> 13) & 0b111;
|
||||
code_t idx = 32 + (op << 3) + funct3;
|
||||
return (MajorOpcode)idx;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool emitter::emitInsMayWriteToGCReg(instruction ins)
|
||||
|
@ -755,6 +764,7 @@ void emitter::emitIns_R_R_I(
|
|||
code |= ((imm >> 5) & 0x3f) << 25;
|
||||
code |= ((imm >> 12) & 0x1) << 31;
|
||||
// TODO-RISCV64: Move jump logic to emitIns_J
|
||||
// TODO-RISC64-RVC: Remove this once all branches uses emitIns_J
|
||||
id->idAddr()->iiaSetInstrCount(static_cast<int>(imm / sizeof(code_t)));
|
||||
}
|
||||
else if (ins == INS_csrrs || ins == INS_csrrw || ins == INS_csrrc)
|
||||
|
@ -821,6 +831,11 @@ void emitter::emitIns_R_I_I(
|
|||
void emitter::emitIns_R_R_R(
|
||||
instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, insOpts opt) /* = INS_OPTS_NONE */
|
||||
{
|
||||
if (tryEmitCompressedIns_R_R_R(ins, attr, reg1, reg2, reg3, opt))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
code_t code = emitInsCode(ins);
|
||||
|
||||
if ((INS_add <= ins && ins <= INS_and) || (INS_mul <= ins && ins <= INS_remuw) ||
|
||||
|
@ -977,6 +992,173 @@ void emitter::emitIns_R_R_R(
|
|||
appendToCurIG(id);
|
||||
}
|
||||
|
||||
bool emitter::tryEmitCompressedIns_R_R_R(
|
||||
instruction ins, emitAttr attr, regNumber rd, regNumber rs1, regNumber rs2, insOpts opt)
|
||||
{
|
||||
// TODO-RISCV64-RVC: Disable this early return once compresed instructions are allowed in prolog / epilog
|
||||
if (emitComp->compGeneratingProlog || emitComp->compGeneratingEpilog)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
instruction compressedIns = tryGetCompressedIns_R_R_R(ins, attr, rd, rs1, rs2, opt);
|
||||
if (compressedIns == INS_none)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
code_t code;
|
||||
switch (compressedIns)
|
||||
{
|
||||
case INS_c_mv:
|
||||
code = insEncodeCRTypeInstr(compressedIns, rd, rs2);
|
||||
break;
|
||||
case INS_c_add:
|
||||
code = insEncodeCRTypeInstr(compressedIns, rd, rs2);
|
||||
break;
|
||||
case INS_c_and:
|
||||
case INS_c_or:
|
||||
case INS_c_xor:
|
||||
case INS_c_sub:
|
||||
case INS_c_addw:
|
||||
case INS_c_subw:
|
||||
{
|
||||
unsigned rdRvc = tryGetRvcRegisterNumber(rd);
|
||||
unsigned rs2Rvc = tryGetRvcRegisterNumber(rs2);
|
||||
assert((rdRvc != -1) && (rs2Rvc != -1));
|
||||
code = insEncodeCATypeInstr(compressedIns, rdRvc, rs2Rvc);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
|
||||
instrDesc* id = emitNewInstr(attr);
|
||||
|
||||
id->idIns(ins);
|
||||
id->idReg1(rd);
|
||||
id->idReg2(rs1);
|
||||
id->idReg3(rs2);
|
||||
id->idAddr()->iiaSetInstrEncode(code);
|
||||
id->idCodeSize(2);
|
||||
|
||||
appendToCurIG(id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
instruction emitter::tryGetCompressedIns_R_R_R(
|
||||
instruction ins, emitAttr attr, regNumber rd, regNumber rs1, regNumber rs2, insOpts opt)
|
||||
{
|
||||
switch (ins)
|
||||
{
|
||||
case INS_add:
|
||||
{
|
||||
if ((rs1 == REG_R0) && (rd != REG_R0) && (rs2 != REG_R0))
|
||||
{
|
||||
return INS_c_mv;
|
||||
}
|
||||
else if ((rd == rs1) && (rd != REG_R0) && (rs2 != REG_R0))
|
||||
{
|
||||
return INS_c_add;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INS_and:
|
||||
case INS_or:
|
||||
case INS_xor:
|
||||
case INS_sub:
|
||||
case INS_addw:
|
||||
case INS_subw:
|
||||
{
|
||||
unsigned rdRvc = tryGetRvcRegisterNumber(rd);
|
||||
unsigned rs2Rvc = tryGetRvcRegisterNumber(rs2);
|
||||
if ((rd == rs1) && (rdRvc != -1) && (rs2Rvc != -1))
|
||||
{
|
||||
return getCompressedArithmeticIns(ins);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
};
|
||||
return INS_none;
|
||||
}
|
||||
|
||||
unsigned emitter::tryGetRvcRegisterNumber(regNumber reg)
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case REG_FP:
|
||||
return 0;
|
||||
case REG_S1:
|
||||
return 1;
|
||||
case REG_A0:
|
||||
return 2;
|
||||
case REG_A1:
|
||||
return 3;
|
||||
case REG_A2:
|
||||
return 4;
|
||||
case REG_A3:
|
||||
return 5;
|
||||
case REG_A4:
|
||||
return 6;
|
||||
case REG_A5:
|
||||
return 7;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
regNumber emitter::getRegNumberFromRvcReg(unsigned rvcReg)
|
||||
{
|
||||
assert((rvcReg >> 3) == 0);
|
||||
switch (rvcReg)
|
||||
{
|
||||
case 0:
|
||||
return REG_FP;
|
||||
case 1:
|
||||
return REG_S1;
|
||||
case 2:
|
||||
return REG_A0;
|
||||
case 3:
|
||||
return REG_A1;
|
||||
case 4:
|
||||
return REG_A2;
|
||||
case 5:
|
||||
return REG_A3;
|
||||
case 6:
|
||||
return REG_A4;
|
||||
case 7:
|
||||
return REG_A5;
|
||||
default:
|
||||
unreached();
|
||||
}
|
||||
}
|
||||
|
||||
instruction emitter::getCompressedArithmeticIns(instruction ins)
|
||||
{
|
||||
assert((ins == INS_and) || (ins == INS_or) || (ins == INS_xor) || (ins == INS_sub) || (ins == INS_addw) ||
|
||||
(ins == INS_subw));
|
||||
switch (ins)
|
||||
{
|
||||
case INS_and:
|
||||
return INS_c_and;
|
||||
case INS_or:
|
||||
return INS_c_or;
|
||||
case INS_xor:
|
||||
return INS_c_xor;
|
||||
case INS_sub:
|
||||
return INS_c_sub;
|
||||
case INS_addw:
|
||||
return INS_c_addw;
|
||||
case INS_subw:
|
||||
return INS_c_subw;
|
||||
default:
|
||||
unreached();
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Add an instruction referencing three registers and a constant.
|
||||
|
@ -2284,7 +2466,7 @@ AGAIN:
|
|||
#endif // DEBUG_EMIT
|
||||
|
||||
assert(jmpDist >= 0);
|
||||
assert(!(jmpDist & 0x3));
|
||||
assert(!(jmpDist & 0x1));
|
||||
|
||||
if (!(isLinkingEnd & 0x2) && (extra > 0) &&
|
||||
(jmp->idInsOpt() == INS_OPTS_J || jmp->idInsOpt() == INS_OPTS_J_cond))
|
||||
|
@ -2371,15 +2553,17 @@ AGAIN:
|
|||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Emit a 32-bit RISCV64 instruction
|
||||
* Emit a 16/32-bit RISCV64 instruction
|
||||
*/
|
||||
|
||||
unsigned emitter::emitOutput_Instr(BYTE* dst, code_t code) const
|
||||
{
|
||||
assert(dst != nullptr);
|
||||
static_assert(sizeof(code_t) == 4, "code_t must be 4 bytes");
|
||||
memcpy(dst + writeableOffset, &code, sizeof(code));
|
||||
return sizeof(code_t);
|
||||
unsigned codeSize = ((code & 0b11) == 0b11) ? 4 : 2;
|
||||
assert((codeSize == 4) || ((code >> 16) == 0));
|
||||
memcpy(dst + writeableOffset, &code, codeSize);
|
||||
return codeSize;
|
||||
}
|
||||
|
||||
static inline void assertCodeLength(size_t code, uint8_t size)
|
||||
|
@ -2555,6 +2739,52 @@ static inline void assertCodeLength(size_t code, uint8_t size)
|
|||
(imm20HiBit << 31);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Emit a 16-bit RISCV64C CR-Type instruction
|
||||
*
|
||||
* Note: Instruction types as per RISC-V Spec, Chapter "Compressed Instruction Formats"
|
||||
* CR Format:
|
||||
* 15-------------12-11-----------------7-6------------------2-1-----0
|
||||
* | funct4 | rd/rs1 | rs2 | op |
|
||||
* -------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*static*/ emitter::code_t emitter::insEncodeCRTypeInstr(instruction ins, unsigned rdRs1, unsigned rs2)
|
||||
{
|
||||
assert((INS_c_mv <= ins) && (ins <= INS_c_add));
|
||||
code_t insCode = emitInsCode(ins);
|
||||
|
||||
assertCodeLength(insCode, 16);
|
||||
assertCodeLength(rdRs1, 5);
|
||||
assertCodeLength(rs2, 5);
|
||||
|
||||
return insCode | (rs2 << 2) | (rdRs1 << 7);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Emit a 16-bit RISCV64C CA-Type instruction
|
||||
*
|
||||
* Note: Instruction types as per RISC-V Spec, Chapter "Compressed Instruction Formats"
|
||||
* CA Format:
|
||||
* 15-----------------------10-9----------7-6------5-4---------2-1---0
|
||||
* | funct6 | rd'/rs1' | funct2 | rs2' | op |
|
||||
* -------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*static*/ emitter::code_t emitter::insEncodeCATypeInstr(instruction ins, unsigned rdRs1Rvc, unsigned rs2Rvc)
|
||||
{
|
||||
assert((INS_c_and <= ins) && (ins <= INS_c_subw));
|
||||
code_t insCode = emitInsCode(ins);
|
||||
|
||||
assertCodeLength(insCode, 16);
|
||||
assertCodeLength(rdRs1Rvc, 3);
|
||||
assertCodeLength(rs2Rvc, 3);
|
||||
|
||||
return insCode | (rs2Rvc << 2) | (rdRs1Rvc << 7);
|
||||
}
|
||||
|
||||
static constexpr unsigned kInstructionOpcodeMask = 0x7f;
|
||||
static constexpr unsigned kInstructionFunct3Mask = 0x7000;
|
||||
static constexpr unsigned kInstructionFunct5Mask = 0xf8000000;
|
||||
|
@ -3138,7 +3368,7 @@ BYTE* emitter::emitOutputInstr_OptsRc(BYTE* dst, const instrDesc* id, instructio
|
|||
assert(reg1 != REG_ZERO);
|
||||
assert(id->idCodeSize() == 2 * sizeof(code_t));
|
||||
const ssize_t immediate = (emitConsBlock - dst) + offset;
|
||||
assert((immediate > 0) && ((immediate & 0x03) == 0));
|
||||
assert((immediate > 0) && ((immediate & 0x01) == 0));
|
||||
assert(isValidSimm32(immediate));
|
||||
|
||||
const regNumber tempReg = isFloatReg(reg1) ? codeGen->rsGetRsvdReg() : reg1;
|
||||
|
@ -3158,7 +3388,7 @@ BYTE* emitter::emitOutputInstr_OptsRl(BYTE* dst, instrDesc* id, instruction* ins
|
|||
*ins = INS_auipc;
|
||||
|
||||
const ssize_t immediate = (emitCodeBlock - dst) + igOffs;
|
||||
assert((immediate & 0x03) == 0);
|
||||
assert((immediate & 0x01) == 0);
|
||||
assert(isValidSimm32(immediate));
|
||||
dst += emitOutput_UTypeInstr(dst, INS_auipc, reg1, UpperNBitsOfWordSignExtend<20>(immediate));
|
||||
dst += emitOutput_ITypeInstr(dst, INS_addi, reg1, reg1, LowerNBitsOfWord<12>(immediate));
|
||||
|
@ -3168,7 +3398,7 @@ BYTE* emitter::emitOutputInstr_OptsRl(BYTE* dst, instrDesc* id, instruction* ins
|
|||
BYTE* emitter::emitOutputInstr_OptsJalr(BYTE* dst, instrDescJmp* jmp, const insGroup* ig, instruction* ins)
|
||||
{
|
||||
const ssize_t immediate = emitOutputInstrJumpDistance(dst, ig, jmp) - 4;
|
||||
assert((immediate & 0x03) == 0);
|
||||
assert((immediate & 0x01) == 0);
|
||||
|
||||
*ins = jmp->idIns();
|
||||
if (jmp->idInsIs(INS_jal, INS_j)) // far jump
|
||||
|
@ -3211,7 +3441,7 @@ BYTE* emitter::emitOutputInstr_OptsJCond(BYTE* dst, instrDesc* id, const insGrou
|
|||
BYTE* emitter::emitOutputInstr_OptsJ(BYTE* dst, instrDesc* id, const insGroup* ig, instruction* ins)
|
||||
{
|
||||
const ssize_t immediate = emitOutputInstrJumpDistance(dst, ig, static_cast<instrDescJmp*>(id));
|
||||
assert((immediate & 0x03) == 0);
|
||||
assert((immediate & 0x01) == 0);
|
||||
|
||||
*ins = id->idIns();
|
||||
|
||||
|
@ -4723,6 +4953,63 @@ void emitter::emitDispInsName(
|
|||
}
|
||||
return;
|
||||
}
|
||||
case MajorOpcode::JrJalrMvAdd:
|
||||
{
|
||||
unsigned funct4 = (code >> 12) & 0xf;
|
||||
unsigned rdRs1 = (code >> 7) & 0x1f;
|
||||
unsigned rs2 = (code >> 2) & 0x1f;
|
||||
// TODO-RISCV64-RVC: Introduce a switch in jitconfigvalues.h to show c.* prefix.
|
||||
if (funct4 == 0b1001 && rdRs1 != REG_R0 && rs2 != REG_R0)
|
||||
{
|
||||
printf("add %s, %s, %s\n", RegNames[rdRs1], RegNames[rdRs1], RegNames[rs2]);
|
||||
}
|
||||
else if (funct4 == 0b1000 && rdRs1 != REG_R0 && rs2 != REG_R0)
|
||||
{
|
||||
printf("mv %s, %s\n", RegNames[rdRs1], RegNames[rs2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return emitDispIllegalInstruction(code);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case MajorOpcode::MiscAlu:
|
||||
{
|
||||
unsigned funct6 = (code >> 10) & 0x3f;
|
||||
unsigned funct2 = (code >> 5) & 0x3;
|
||||
unsigned rdRs1 = getRegNumberFromRvcReg(((code >> 7) & 0x7));
|
||||
unsigned rs2 = getRegNumberFromRvcReg(((code >> 2) & 0x7));
|
||||
// TODO-RISCV64-RVC: Introduce a switch in jitconfigvalues.h to show c.* prefix.
|
||||
if (funct6 == 0b100011 && funct2 == 0b00)
|
||||
{
|
||||
printf("sub %s, %s, %s\n", RegNames[rdRs1], RegNames[rdRs1], RegNames[rs2]);
|
||||
}
|
||||
else if (funct6 == 0b100011 && funct2 == 0b01)
|
||||
{
|
||||
printf("xor %s, %s, %s\n", RegNames[rdRs1], RegNames[rdRs1], RegNames[rs2]);
|
||||
}
|
||||
else if (funct6 == 0b100011 && funct2 == 0b10)
|
||||
{
|
||||
printf("or %s, %s, %s\n", RegNames[rdRs1], RegNames[rdRs1], RegNames[rs2]);
|
||||
}
|
||||
else if (funct6 == 0b100011 && funct2 == 0b11)
|
||||
{
|
||||
printf("and %s, %s, %s\n", RegNames[rdRs1], RegNames[rdRs1], RegNames[rs2]);
|
||||
}
|
||||
else if (funct6 == 0b100111 && funct2 == 0b00)
|
||||
{
|
||||
printf("subw %s, %s, %s\n", RegNames[rdRs1], RegNames[rdRs1], RegNames[rs2]);
|
||||
}
|
||||
else if (funct6 == 0b100111 && funct2 == 0b01)
|
||||
{
|
||||
printf("addw %s, %s, %s\n", RegNames[rdRs1], RegNames[rdRs1], RegNames[rs2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
emitDispIllegalInstruction(code);
|
||||
}
|
||||
return;
|
||||
}
|
||||
default:
|
||||
NO_WAY("illegal ins within emitDisInsName!");
|
||||
}
|
||||
|
@ -4754,10 +5041,14 @@ void emitter::emitDispIns(
|
|||
unsigned instrSize;
|
||||
for (size_t i = 0; i < sz; instr += instrSize, i += instrSize, offset += instrSize)
|
||||
{
|
||||
// TODO-RISCV64: support different size instructions
|
||||
instrSize = sizeof(code_t);
|
||||
code_t instruction;
|
||||
memcpy(&instruction, instr, instrSize);
|
||||
if ((instruction & 0b11) != 0b11)
|
||||
{
|
||||
instruction &= 0xffff;
|
||||
instrSize = 2;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (emitComp->verbose && i != 0)
|
||||
{
|
||||
|
@ -5470,7 +5761,7 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
|
|||
result.insMemoryAccessKind = PERFSCORE_MEMORY_NONE;
|
||||
|
||||
unsigned codeSize = id->idCodeSize();
|
||||
assert((codeSize >= 4) && (codeSize % sizeof(code_t) == 0));
|
||||
assert((codeSize >= 2) && ((codeSize % 2) == 0));
|
||||
|
||||
// Some instructions like jumps or loads may have not-yet-known simple auxilliary instructions (lui, addi, slli,
|
||||
// etc) for building immediates, assume cost of one each.
|
||||
|
@ -5499,6 +5790,8 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins
|
|||
|
||||
case MajorOpcode::Op:
|
||||
case MajorOpcode::Op32:
|
||||
case MajorOpcode::JrJalrMvAdd:
|
||||
case MajorOpcode::MiscAlu:
|
||||
if (id->idInsIs(INS_mul, INS_mulh, INS_mulhu, INS_mulhsu, INS_mulw))
|
||||
{
|
||||
result.insLatency = PERFSCORE_LATENCY_3C;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#if defined(TARGET_RISCV64)
|
||||
|
||||
// The RISCV64 instructions are all 32 bits in size.
|
||||
// The RISCV64 instructions are all 32 / 16 bits in size.
|
||||
// we use an unsigned int to hold the encoded instructions.
|
||||
// This typedef defines the type that we use to hold encoded instructions.
|
||||
//
|
||||
|
@ -62,6 +62,17 @@ bool emitInsIsLoad(instruction ins);
|
|||
bool emitInsIsStore(instruction ins);
|
||||
bool emitInsIsLoadOrStore(instruction ins);
|
||||
|
||||
// RVC emitters
|
||||
bool tryEmitCompressedIns_R_R_R(
|
||||
instruction ins, emitAttr attr, regNumber rd, regNumber rs1, regNumber rs2, insOpts opt);
|
||||
|
||||
// RVC helpers
|
||||
instruction tryGetCompressedIns_R_R_R(
|
||||
instruction ins, emitAttr attr, regNumber rd, regNumber rs1, regNumber rs2, insOpts opt);
|
||||
unsigned tryGetRvcRegisterNumber(regNumber reg);
|
||||
instruction getCompressedArithmeticIns(instruction ins);
|
||||
regNumber getRegNumberFromRvcReg(unsigned rvcReg);
|
||||
|
||||
void emitDispInsName(
|
||||
code_t code, const BYTE* addr, bool doffs, unsigned insOffset, const instrDesc* id, const insGroup* ig);
|
||||
void emitDispInsInstrNum(const instrDesc* id) const;
|
||||
|
@ -77,7 +88,7 @@ static emitter::code_t emitInsCode(instruction ins /*, insFormat fmt*/);
|
|||
// Generate code for a load or store operation and handle the case of contained GT_LEA op1 with [base + offset]
|
||||
void emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataReg, GenTreeIndir* indir);
|
||||
|
||||
// Emit the 32-bit RISCV64 instruction 'code' into the 'dst' buffer
|
||||
// Emit the 16/32-bit RISCV64 instruction 'code' into the 'dst' buffer
|
||||
unsigned emitOutput_Instr(BYTE* dst, code_t code) const;
|
||||
|
||||
ssize_t emitOutputInstrJumpDistance(const BYTE* src, const insGroup* ig, instrDescJmp* jmp);
|
||||
|
@ -100,6 +111,9 @@ static code_t insEncodeUTypeInstr(unsigned opcode, unsigned rd, unsigned imm20);
|
|||
static code_t insEncodeBTypeInstr(unsigned opcode, unsigned funct3, unsigned rs1, unsigned rs2, unsigned imm13);
|
||||
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);
|
||||
|
||||
#ifdef DEBUG
|
||||
static void emitOutput_RTypeInstr_SanityCheck(instruction ins, regNumber rd, regNumber rs1, regNumber rs2);
|
||||
static void emitOutput_ITypeInstr_SanityCheck(
|
||||
|
@ -135,11 +149,13 @@ static unsigned TrimSignedToImm13(ssize_t imm13);
|
|||
static unsigned TrimSignedToImm20(ssize_t imm20);
|
||||
static unsigned TrimSignedToImm21(ssize_t imm21);
|
||||
|
||||
// Major opcode of a 32-bit instruction as per "The RISC-V Instruction Set Manual", Chapter "RV32/64G Instruction Set
|
||||
// Listings", Table "RISC-V base opcode map"
|
||||
// Major opcode of 32-bit & 16-bit instructions as per "The RISC-V Instruction Set Manual", chapter "RV32/64G
|
||||
// Instruction Set Listings", table "RISC-V base opcode map" and chapter "RVC Instruction Set Listings", table "RVC
|
||||
// opcode map instructions"
|
||||
enum class MajorOpcode
|
||||
{
|
||||
// clang-format off
|
||||
// inst[1:0] = 11
|
||||
// inst[4:2] 000, 001, 010, 011, 100, 101, 110, 111 (>32Bit)
|
||||
/* inst[6:5] */
|
||||
/* 00 */ Load, LoadFp, Custom0, MiscMem, OpImm, Auipc, OpImm32, Encoding48Bit1,
|
||||
|
@ -147,6 +163,14 @@ enum class MajorOpcode
|
|||
/* 11 */ MAdd, MSub, NmSub, NmAdd, OpFp, OpV, Custom2Rv128, Encoding48Bit2,
|
||||
/* 11 */ Branch, Jalr, Reserved, Jal, System, OpVe, Custom3Rv128, Encoding80Bit,
|
||||
// clang-format on
|
||||
|
||||
// clang-format off
|
||||
// inst[15:13] 000, 001, 010, 011, 100, 101, 110, 111
|
||||
/* 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,
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
|
|
@ -307,6 +307,16 @@ INST(sh2add_uw, "sh2add_uw", 0, 0x2000403b)
|
|||
INST(sh3add_uw, "sh3add_uw", 0, 0x2000603b)
|
||||
INST(slli_uw, "slli_uw", 0, 0x0800101b)
|
||||
|
||||
// RVC
|
||||
INST(c_mv, "c.mv", 0, 0x00008002)
|
||||
INST(c_add, "c.add", 0, 0x00009002)
|
||||
INST(c_and, "c.and", 0, 0x00008c61)
|
||||
INST(c_or, "c.or", 0, 0x00008c41)
|
||||
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)
|
||||
|
||||
// clang-format on
|
||||
/*****************************************************************************/
|
||||
#undef INST
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
|
||||
#define MIN_ARG_AREA_FOR_CALL 0 // Minimum required outgoing argument space for a call.
|
||||
|
||||
#define CODE_ALIGN 4 // code alignment requirement
|
||||
#define CODE_ALIGN 2 // code alignment requirement
|
||||
#define STACK_ALIGN 16 // stack alignment requirement
|
||||
|
||||
#define FIRST_INT_CALLEE_SAVED REG_S1
|
||||
|
|
|
@ -48,7 +48,7 @@ const unsigned MAX_PROLOG_SIZE_BYTES = 200;
|
|||
const unsigned MAX_EPILOG_SIZE_BYTES = 200;
|
||||
#define UWC_END 0xE4 // "end" unwind code
|
||||
#define UWC_END_C 0xE5 // "end_c" unwind code
|
||||
#define UW_MAX_FRAGMENT_SIZE_BYTES (1U << 20)
|
||||
#define UW_MAX_FRAGMENT_SIZE_BYTES (1U << 19)
|
||||
#define UW_MAX_CODE_WORDS_COUNT 31
|
||||
#define UW_MAX_EPILOG_START_INDEX 0x3FFU
|
||||
|
||||
|
|
|
@ -347,9 +347,9 @@ void DumpUnwindInfo(Compiler* comp,
|
|||
printf(" X bit : %u\n", XBit);
|
||||
printf(" Vers : %u\n", Vers);
|
||||
printf(" Function Length : %u (0x%05x) Actual length = %u (0x%06x)\n", functionLength, functionLength,
|
||||
functionLength * 4, functionLength * 4);
|
||||
functionLength * 2, functionLength * 2);
|
||||
|
||||
assert(functionLength * 4 == endOffset - startOffset);
|
||||
assert(functionLength * 2 == endOffset - startOffset);
|
||||
|
||||
if (codeWords == 0 && epilogCount == 0)
|
||||
{
|
||||
|
@ -392,7 +392,7 @@ void DumpUnwindInfo(Compiler* comp,
|
|||
// of the current funclet, not the offset from the beginning of the main function.
|
||||
// To help find it when looking through JitDump output, also show the offset from
|
||||
// the beginning of the main function.
|
||||
DWORD epilogStartOffsetFromMainFunctionBegin = epilogStartOffset * 4 + startOffset;
|
||||
DWORD epilogStartOffsetFromMainFunctionBegin = epilogStartOffset * 2 + startOffset;
|
||||
|
||||
assert(res == 0);
|
||||
|
||||
|
@ -400,7 +400,7 @@ void DumpUnwindInfo(Compiler* comp,
|
|||
printf(" Epilog Start Offset : %u (0x%05x) Actual offset = %u (0x%06x) Offset from main "
|
||||
"function begin = %u (0x%06x)\n",
|
||||
comp->dspOffset(epilogStartOffset), comp->dspOffset(epilogStartOffset),
|
||||
comp->dspOffset(epilogStartOffset * 4), comp->dspOffset(epilogStartOffset * 4),
|
||||
comp->dspOffset(epilogStartOffset * 2), comp->dspOffset(epilogStartOffset * 2),
|
||||
comp->dspOffset(epilogStartOffsetFromMainFunctionBegin),
|
||||
comp->dspOffset(epilogStartOffsetFromMainFunctionBegin));
|
||||
printf(" Epilog Start Index : %u (0x%02x)\n", epilogStartIndex, epilogStartIndex);
|
||||
|
@ -1556,8 +1556,8 @@ void UnwindFragmentInfo::Finalize(UNATIVE_OFFSET functionLength)
|
|||
|
||||
// Compute the header
|
||||
|
||||
noway_assert((functionLength & 3) == 0);
|
||||
DWORD headerFunctionLength = functionLength / 4;
|
||||
noway_assert((functionLength & 1) == 0);
|
||||
DWORD headerFunctionLength = functionLength / 2;
|
||||
|
||||
DWORD headerVers = 0; // Version of the unwind info is zero. No other version number is currently defined.
|
||||
DWORD headerXBit = 0; // We never generate "exception data", but the VM might add some.
|
||||
|
@ -1644,9 +1644,9 @@ void UnwindFragmentInfo::Finalize(UNATIVE_OFFSET functionLength)
|
|||
// NOT the offset from the beginning of the main function.
|
||||
DWORD headerEpilogStartOffset = pEpi->GetStartOffset() - GetStartOffset();
|
||||
|
||||
noway_assert((headerEpilogStartOffset & 3) == 0);
|
||||
headerEpilogStartOffset /= 4; // The unwind data stores the actual offset divided by 4 (since the low 2 bits
|
||||
// of the actual offset is always zero)
|
||||
noway_assert((headerEpilogStartOffset & 1) == 0);
|
||||
headerEpilogStartOffset /= 2; // The unwind data stores the actual offset divided by 2 (since the low bit of
|
||||
// the actual offset is always zero)
|
||||
|
||||
DWORD headerEpilogStartIndex = pEpi->GetStartIndex();
|
||||
|
||||
|
|
|
@ -177,10 +177,10 @@ namespace Internal.TypeSystem
|
|||
switch (Architecture)
|
||||
{
|
||||
case TargetArchitecture.ARM:
|
||||
case TargetArchitecture.RiscV64:
|
||||
return 2;
|
||||
case TargetArchitecture.ARM64:
|
||||
case TargetArchitecture.LoongArch64:
|
||||
case TargetArchitecture.RiscV64:
|
||||
return 4;
|
||||
default:
|
||||
return 1;
|
||||
|
|
|
@ -847,9 +847,7 @@ namespace ILCompiler.ObjectWriter
|
|||
{
|
||||
EM_ARM => 0x05000000u, // For ARM32 claim conformance with the EABI specification
|
||||
EM_LOONGARCH => 0x43u, // For LoongArch ELF psABI specify the ABI version (1) and modifiers (64-bit GPRs, 64-bit FPRs)
|
||||
// TODO: update once RISC-V runtime supports "C" extension (compressed instructions)
|
||||
// it should be 0x0005u EF_RISCV_RVC (0x0001) | EF_RISCV_FLOAT_ABI_DOUBLE (0x0006)
|
||||
EM_RISCV => 0x0004u, // EF_RISCV_FLOAT_ABI_DOUBLE (double precision floating-point ABI).
|
||||
EM_RISCV => 0x0005u, // EF_RISCV_RVC (RVC ABI) | EF_RISCV_FLOAT_ABI_DOUBLE (double precision floating-point ABI).
|
||||
_ => 0u
|
||||
},
|
||||
};
|
||||
|
|
|
@ -180,10 +180,10 @@ namespace ILCompiler.Reflection.ReadyToRun
|
|||
switch (_target)
|
||||
{
|
||||
case Machine.ArmThumb2:
|
||||
case Machine.RiscV64:
|
||||
return (x << 1);
|
||||
case Machine.Arm64:
|
||||
case Machine.LoongArch64:
|
||||
case Machine.RiscV64:
|
||||
return (x << 2);
|
||||
}
|
||||
return x;
|
||||
|
@ -194,10 +194,10 @@ namespace ILCompiler.Reflection.ReadyToRun
|
|||
switch (_target)
|
||||
{
|
||||
case Machine.ArmThumb2:
|
||||
case Machine.RiscV64:
|
||||
return (x >> 1);
|
||||
case Machine.Arm64:
|
||||
case Machine.LoongArch64:
|
||||
case Machine.RiscV64:
|
||||
return (x >> 2);
|
||||
}
|
||||
return x;
|
||||
|
|
|
@ -30,13 +30,13 @@ namespace ILCompiler.Reflection.ReadyToRun.RiscV64
|
|||
// of the current funclet, not the offset from the beginning of the main function.
|
||||
// To help find it when looking through JitDump output, also show the offset from
|
||||
// the beginning of the main function.
|
||||
EpilogStartOffsetFromMainFunctionBegin = EpilogStartOffset * 4 + startOffset;
|
||||
EpilogStartOffsetFromMainFunctionBegin = EpilogStartOffset * 2 + startOffset;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine($" Epilog Start Offset: 0x{EpilogStartOffset:X5} Actual offset = 0x{EpilogStartOffset * 4:X5} Offset from main function begin = 0x{EpilogStartOffsetFromMainFunctionBegin:X6}");
|
||||
sb.AppendLine($" Epilog Start Offset: 0x{EpilogStartOffset:X5} Actual offset = 0x{EpilogStartOffset * 2:X5} Offset from main function begin = 0x{EpilogStartOffsetFromMainFunctionBegin:X6}");
|
||||
sb.AppendLine($" Condition: {Condition} (0x{Condition:X})" + ((Condition == 0xE) ? " (always)" : ""));
|
||||
sb.Append($" Epilog Start Index: {EpilogStartIndex} (0x{EpilogStartIndex:X})");
|
||||
return sb.ToString();
|
||||
|
@ -85,7 +85,7 @@ namespace ILCompiler.Reflection.ReadyToRun.RiscV64
|
|||
EBit = ExtractBits(dw, 21, 1);
|
||||
XBit = ExtractBits(dw, 20, 1);
|
||||
Vers = ExtractBits(dw, 18, 2);
|
||||
FunctionLength = ExtractBits(dw, 0, 18) * 4;
|
||||
FunctionLength = ExtractBits(dw, 0, 18) * 2;
|
||||
|
||||
if (CodeWords == 0 && EpilogCount == 0)
|
||||
{
|
||||
|
|
|
@ -192,9 +192,8 @@ namespace R2RDump
|
|||
// Instructions are dumped as 4-byte hexadecimal integers
|
||||
Machine.LoongArch64 => 4 * 2 + 1,
|
||||
|
||||
// Instructions are dumped as 4-byte hexadecimal integers
|
||||
// TODO: update once RISC-V runtime supports "C" extension (compressed instructions)
|
||||
Machine.RiscV64 => 4 * 2 + 1,
|
||||
// Instructions are either 2 or 4 bytes long
|
||||
Machine.RiscV64 => 4 * 3,
|
||||
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
|
@ -270,8 +269,7 @@ namespace R2RDump
|
|||
}
|
||||
else
|
||||
{
|
||||
// TODO: update once RISC-V runtime supports "C" extension (compressed instructions)
|
||||
if (_reader.Machine is Machine.Arm64 or Machine.LoongArch64 or Machine.RiscV64)
|
||||
if (_reader.Machine is Machine.Arm64 or Machine.LoongArch64)
|
||||
{
|
||||
// Replace " hh hh hh hh " byte dump with " hhhhhhhh ".
|
||||
// CoreDisTools should be fixed to dump bytes this way for ARM64.
|
||||
|
@ -360,7 +358,7 @@ namespace R2RDump
|
|||
break;
|
||||
|
||||
case Machine.RiscV64:
|
||||
ProbeRiscV64Quirks(rtf, imageOffset, rtfOffset, ref fixedTranslatedLine);
|
||||
// TODO-RISCV64-RVC: Add back ProbeRiscV64Quirks here once it's modified to support compressed instructions.
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1222,6 +1220,7 @@ namespace R2RDump
|
|||
/// <param name="instruction">Textual representation of the instruction</param>
|
||||
private void ProbeRiscV64Quirks(RuntimeFunction rtf, int imageOffset, int rtfOffset, ref string instruction)
|
||||
{
|
||||
// TODO-RISCV64-RVC: Modify this method to detect patterns in forward traversal. See ProbeArm64Quirks implementation.
|
||||
const int InstructionSize = 4;
|
||||
uint instr = BitConverter.ToUInt32(_reader.Image, imageOffset + rtfOffset);
|
||||
|
||||
|
@ -1233,11 +1232,11 @@ namespace R2RDump
|
|||
addi
|
||||
ld
|
||||
jalr
|
||||
|
||||
|
||||
auipc
|
||||
ld
|
||||
jalr
|
||||
|
||||
|
||||
auipc
|
||||
addi
|
||||
ld
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#define MEMORY_READ_DWORD(params, addr) (*dac_cast<PTR_DWORD>(addr))
|
||||
#define MEMORY_READ_QWORD(params, addr) (*dac_cast<PTR_UINT64>(addr))
|
||||
|
||||
#define WORDS_TO_HALFWORDS(value) ((value) << 1)
|
||||
|
||||
typedef struct _RISCV64_UNWIND_PARAMS
|
||||
{
|
||||
PT_KNONVOLATILE_CONTEXT_POINTERS ContextPointers;
|
||||
|
@ -127,7 +129,7 @@ Arguments:
|
|||
|
||||
Return Value:
|
||||
|
||||
The size of the scope described by the unwind codes, in halfword units.
|
||||
The size of the scope described by the unwind codes, in word units.
|
||||
|
||||
--*/
|
||||
|
||||
|
@ -148,6 +150,9 @@ Return Value:
|
|||
break;
|
||||
}
|
||||
|
||||
// TODO-RISCV64-RVC: Once we support RVC code in prolog / epilog,
|
||||
// need to create table for mapping CurCode to OpSize.
|
||||
// See arm/unwinder.cpp.
|
||||
UnwindCodePtr += UnwindCodeSizeTable[Opcode];
|
||||
ScopeSize++;
|
||||
}
|
||||
|
@ -386,7 +391,7 @@ Return Value:
|
|||
ULONG ScopeNum;
|
||||
ULONG ScopeSize;
|
||||
ULONG ScopeStart;
|
||||
DWORD64 SkipWords;
|
||||
DWORD64 SkipHalfWords;
|
||||
NTSTATUS Status;
|
||||
ULONG_PTR UnwindCodePtr;
|
||||
ULONG_PTR UnwindCodesEndPtr;
|
||||
|
@ -428,7 +433,7 @@ Return Value:
|
|||
}
|
||||
|
||||
FunctionLength = HeaderWord & 0x3ffff;
|
||||
OffsetInFunction = (ControlPcRva - FunctionEntry->BeginAddress) / 4;
|
||||
OffsetInFunction = (ControlPcRva - FunctionEntry->BeginAddress) / 2;
|
||||
|
||||
//
|
||||
// Determine the number of epilog scope records and the maximum number
|
||||
|
@ -467,7 +472,7 @@ Return Value:
|
|||
|
||||
UnwindCodePtr = UnwindDataPtr + 4 * EpilogScopeCount;
|
||||
UnwindCodesEndPtr = UnwindCodePtr + 4 * UnwindWords;
|
||||
SkipWords = 0;
|
||||
SkipHalfWords = 0;
|
||||
|
||||
//
|
||||
// If we're near the start of the function, and this function has a prolog,
|
||||
|
@ -483,11 +488,11 @@ Return Value:
|
|||
// in the body of the function.
|
||||
//
|
||||
|
||||
if (OffsetInFunction < 4 * UnwindWords) {
|
||||
ScopeSize = RtlpComputeScopeSize(UnwindCodePtr, UnwindCodesEndPtr, FALSE, UnwindParams);
|
||||
if (OffsetInFunction < WORDS_TO_HALFWORDS(4 * UnwindWords)) {
|
||||
ScopeSize = WORDS_TO_HALFWORDS(RtlpComputeScopeSize(UnwindCodePtr, UnwindCodesEndPtr, FALSE, UnwindParams));
|
||||
|
||||
if (OffsetInFunction < ScopeSize) {
|
||||
SkipWords = ScopeSize - OffsetInFunction;
|
||||
SkipHalfWords = ScopeSize - OffsetInFunction;
|
||||
ExceptionHandler = NULL;
|
||||
ExceptionHandlerData = NULL;
|
||||
goto ExecuteCodes;
|
||||
|
@ -511,13 +516,13 @@ Return Value:
|
|||
//
|
||||
|
||||
if ((HeaderWord & (1 << 21)) != 0) {
|
||||
if (OffsetInFunction + (4 * UnwindWords - UnwindIndex) >= FunctionLength) {
|
||||
ScopeSize = RtlpComputeScopeSize(UnwindCodePtr + UnwindIndex, UnwindCodesEndPtr, TRUE, UnwindParams);
|
||||
if (OffsetInFunction + WORDS_TO_HALFWORDS(4 * UnwindWords - UnwindIndex) >= FunctionLength) {
|
||||
ScopeSize = WORDS_TO_HALFWORDS(RtlpComputeScopeSize(UnwindCodePtr + UnwindIndex, UnwindCodesEndPtr, TRUE, UnwindParams));
|
||||
ScopeStart = FunctionLength - ScopeSize;
|
||||
|
||||
if (OffsetInFunction >= ScopeStart) {
|
||||
UnwindCodePtr += UnwindIndex;
|
||||
SkipWords = OffsetInFunction - ScopeStart;
|
||||
SkipHalfWords = OffsetInFunction - ScopeStart;
|
||||
ExceptionHandler = NULL;
|
||||
ExceptionHandlerData = NULL;
|
||||
}
|
||||
|
@ -547,13 +552,13 @@ Return Value:
|
|||
}
|
||||
|
||||
UnwindIndex = HeaderWord >> 22;
|
||||
if (OffsetInFunction < ScopeStart + (4 * UnwindWords - UnwindIndex)) {
|
||||
ScopeSize = RtlpComputeScopeSize(UnwindCodePtr + UnwindIndex, UnwindCodesEndPtr, TRUE, UnwindParams);
|
||||
if (OffsetInFunction < ScopeStart + WORDS_TO_HALFWORDS(4 * UnwindWords - UnwindIndex)) {
|
||||
ScopeSize = WORDS_TO_HALFWORDS(RtlpComputeScopeSize(UnwindCodePtr + UnwindIndex, UnwindCodesEndPtr, TRUE, UnwindParams));
|
||||
|
||||
if (OffsetInFunction < ScopeStart + ScopeSize) {
|
||||
|
||||
UnwindCodePtr += UnwindIndex;
|
||||
SkipWords = OffsetInFunction - ScopeStart;
|
||||
SkipHalfWords = OffsetInFunction - ScopeStart;
|
||||
ExceptionHandler = NULL;
|
||||
ExceptionHandlerData = NULL;
|
||||
break;
|
||||
|
@ -569,13 +574,16 @@ ExecuteCodes:
|
|||
// to skip.
|
||||
//
|
||||
|
||||
while (UnwindCodePtr < UnwindCodesEndPtr && SkipWords > 0) {
|
||||
while (UnwindCodePtr < UnwindCodesEndPtr && SkipHalfWords > 0) {
|
||||
CurCode = MEMORY_READ_BYTE(UnwindParams, UnwindCodePtr);
|
||||
if (OPCODE_IS_END(CurCode)) {
|
||||
break;
|
||||
}
|
||||
UnwindCodePtr += UnwindCodeSizeTable[CurCode];
|
||||
SkipWords--;
|
||||
// TODO-RISCV64-RVC: Once we support RVC code in prolog / epilog,
|
||||
// need to create table for mapping CurCode to OpSize.
|
||||
// See arm/unwinder.cpp.
|
||||
SkipHalfWords -= 2;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -159,6 +159,7 @@ void RiscV64SingleStepper::Apply(T_CONTEXT *pCtx)
|
|||
m_originalPc = pCtx->Pc;
|
||||
|
||||
// By default assume the next PC is right after the current instruction.
|
||||
// TODO-RISCV64-RVC: change this after "C" Standard Extension support implemented
|
||||
m_targetPc = m_originalPc + sizeof(uint32_t);
|
||||
m_fEmulate = false;
|
||||
|
||||
|
@ -263,7 +264,7 @@ bool RiscV64SingleStepper::Fixup(T_CONTEXT *pCtx, DWORD dwExceptionCode)
|
|||
LOG((LF_CORDB, LL_INFO100000, "RiscV64SingleStepper::Fixup emulated breakpoint\n"));
|
||||
pCtx->Pc = m_originalPc;
|
||||
|
||||
_ASSERTE((pCtx->Pc & 0x3) == 0); // TODO change this after "C" Standard Extension support implemented
|
||||
_ASSERTE((pCtx->Pc & 0x3) == 0); // TODO-RISCV64-RVC: change this after "C" Standard Extension support implemented
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -352,7 +353,7 @@ bool RiscV64SingleStepper::TryEmulate(T_CONTEXT *pCtx, uint32_t opcode, bool exe
|
|||
// instruction address).
|
||||
bool fEmulated = false;
|
||||
|
||||
// TODO after "C" Standard Extension support implemented, add C.J, C.JAL, C.JR, C.JALR, C.BEQZ, C.BNEZ
|
||||
// TODO-RISCV64-RVC: after "C" Standard Extension support implemented, add C.J, C.JAL, C.JR, C.JALR, C.BEQZ, C.BNEZ
|
||||
|
||||
if ((opcode & 0x7f) == 0x17) // AUIPC
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue