Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/coreclr/inc/utilcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -3315,6 +3315,16 @@ void PutLoongArch64PC12(UINT32 * pCode, INT64 imm);
//*****************************************************************************
void PutLoongArch64JIR(UINT32 * pCode, INT64 imm);

//*****************************************************************************
// Extract the PC-Relative offset from auipc + I-type adder (addi/ld/jalr)
//*****************************************************************************
INT64 GetRiscV64AuipcItype(UINT32 * pCode);

//*****************************************************************************
// Deposit the PC-Relative offset into auipc + I-type adder (addi/ld/jalr)
//*****************************************************************************
void PutRiscV64AuipcItype(UINT32 * pCode, INT64 offset);

//*****************************************************************************
// Returns whether the offset fits into bl instruction
//*****************************************************************************
Expand Down
7 changes: 1 addition & 6 deletions src/coreclr/jit/codegenriscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6538,12 +6538,7 @@ void CodeGen::genJumpToThrowHlpBlk_la(
params.addr = helperFunction.addr;
params.callType = EC_FUNC_TOKEN;

ssize_t imm = 9 << 2;
if (compiler->opts.compReloc)
{
imm = 3 << 2;
}

ssize_t imm = 3 * sizeof(emitter::code_t);
emit->emitIns_R_R_I(ins, EA_PTRSIZE, reg1, reg2, imm);
}
else
Expand Down
183 changes: 26 additions & 157 deletions src/coreclr/jit/emitriscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1725,28 +1725,15 @@ void emitter::emitIns_Call(const EmitCallParams& params)
id->idSetIsNoGC(params.isJump || params.noSafePoint || emitNoGChelper(params.methHnd));

/* Set the instruction - special case jumping a function */
instruction ins;

ins = INS_jalr; // jalr
id->idIns(ins);
id->idIns(INS_jalr);

id->idInsOpt(INS_OPTS_C);
// TODO-RISCV64: maybe optimize.

// INS_OPTS_C: placeholders. 1/2/4-ins:
// INS_OPTS_C: placeholders. 1/2-ins:
// if (callType == EC_INDIR_R)
// jalr REG_R0/REG_RA, ireg, offset <---- 1-ins
// jalr zero/ra, ireg, offset
// else if (callType == EC_FUNC_TOKEN || callType == EC_FUNC_ADDR)
// if reloc:
// //pc + offset_38bits # only when reloc.
// auipc t2, addr-hi20
// jalr r0/1, t2, addr-lo12
//
// else:
// lui t2, dst_offset_lo32-hi
// ori t2, t2, dst_offset_lo32-lo
// lui t2, dst_offset_hi32-lo
// jalr REG_R0/REG_RA, t2, 0
// auipc t2/ra, offset-hi20
// jalr zero/ra, t2/ra, offset-lo12

/* Record the address: method, indirection, or funcptr */
if (params.callType == EC_INDIR_R)
Expand Down Expand Up @@ -1779,16 +1766,8 @@ void emitter::emitIns_Call(const EmitCallParams& params)
void* addr =
(void*)(((size_t)params.addr) + (params.isJump ? 0 : 1)); // NOTE: low-bit0 is used for jalr ra/r0,rd,0
id->idAddr()->iiaAddr = (BYTE*)addr;

if (emitComp->opts.compReloc)
{
id->idSetIsDspReloc();
id->idCodeSize(8);
}
else
{
id->idCodeSize(32);
}
id->idCodeSize(2 * sizeof(code_t));
id->idSetIsDspReloc();
}

#ifdef DEBUG
Expand Down Expand Up @@ -1823,11 +1802,10 @@ void emitter::emitIns_Call(const EmitCallParams& params)
* Output a call instruction.
*/

unsigned emitter::emitOutputCall(const insGroup* ig, BYTE* dst, instrDesc* id, code_t code)
unsigned emitter::emitOutputCall(const insGroup* ig, BYTE* dst, instrDesc* id)
{
unsigned char callInstrSize = sizeof(code_t); // 4 bytes
regMaskTP gcrefRegs;
regMaskTP byrefRegs;
regMaskTP gcrefRegs;
regMaskTP byrefRegs;

VARSET_TP GCvars(VarSetOps::UninitVal());

Expand Down Expand Up @@ -1866,130 +1844,29 @@ unsigned emitter::emitOutputCall(const insGroup* ig, BYTE* dst, instrDesc* id, c
#endif // DEBUG

assert(id->idIns() == INS_jalr);
BYTE* origDst = dst;
if (id->idIsCallRegPtr())
{ // EC_INDIR_R
ssize_t offset = id->idSmallCns();
assert(isValidSimm12(offset));
code = emitInsCode(id->idIns());
code |= (code_t)id->idReg4() << 7;
code |= (code_t)id->idReg3() << 15;
code |= (code_t)offset << 20;
emitOutput_Instr(dst, code);
dst += emitOutput_ITypeInstr(dst, INS_jalr, id->idReg4(), id->idReg3(), TrimSignedToImm12(offset));
}
else if (id->idIsReloc())
else
{
// pc + offset_32bits
//
// auipc t2, addr-hi20
// jalr r0/1,t2,addr-lo12

emitOutput_Instr(dst, 0x00000397);

size_t addr = (size_t)(id->idAddr()->iiaAddr); // get addr.

int reg2 = (int)(addr & 1);
addr -= reg2;

if (!emitComp->opts.compReloc)
{
assert(isValidSimm32(addr - (ssize_t)dst));
}

regNumber linkReg = (regNumber)(addr & 1);
assert(linkReg == REG_ZERO || linkReg == REG_RA);
addr -= linkReg;
assert((addr & 1) == 0);
regNumber tempReg = (linkReg == REG_ZERO) ? REG_DEFAULT_HELPER_CALL_TARGET : REG_RA;

dst += 4;
emitGCregDeadUpd(REG_DEFAULT_HELPER_CALL_TARGET, dst);

#ifdef DEBUG
code = emitInsCode(INS_auipc);
assert((code | (REG_DEFAULT_HELPER_CALL_TARGET << 7)) == 0x00000397);
assert((int)REG_DEFAULT_HELPER_CALL_TARGET == 7);
code = emitInsCode(INS_jalr);
assert(code == 0x00000067);
#endif
emitOutput_Instr(dst, 0x00000067 | (REG_DEFAULT_HELPER_CALL_TARGET << 15) | reg2 << 7);
dst += emitOutput_UTypeInstr(dst, INS_auipc, tempReg, 0);
emitGCregDeadUpd(tempReg, dst);
dst += emitOutput_ITypeInstr(dst, INS_jalr, linkReg, tempReg, 0);

emitRecordRelocation(dst - 4, (BYTE*)addr, IMAGE_REL_RISCV64_PC);
assert(id->idIsDspReloc());
emitRecordRelocation(origDst, (BYTE*)addr, IMAGE_REL_RISCV64_PC);
}
else
{
// lui t2, dst_offset_hi32-hi
// addi t2, t2, dst_offset_hi32-lo
// slli t2, t2, 11
// addi t2, t2, dst_offset_low32-hi
// slli t2, t2, 11
// addi t2, t2, dst_offset_low32-md
// slli t2, t2, 10
// jalr t2

ssize_t imm = (ssize_t)(id->idAddr()->iiaAddr);
assert((uint64_t)(imm >> 32) <= 0x7fff); // RISC-V Linux Kernel SV48

int reg2 = (int)(imm & 1);
imm -= reg2;

UINT32 high = imm >> 32;
code = emitInsCode(INS_lui);
code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 7;
code |= ((code_t)((high + 0x800) >> 12) & 0xfffff) << 12;
emitOutput_Instr(dst, code);
dst += 4;

emitGCregDeadUpd(REG_DEFAULT_HELPER_CALL_TARGET, dst);

code = emitInsCode(INS_addi);
code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 7;
code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 15;
code |= (code_t)(high & 0xfff) << 20;
emitOutput_Instr(dst, code);
dst += 4;

code = emitInsCode(INS_slli);
code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 7;
code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 15;
code |= (code_t)(11 << 20);
emitOutput_Instr(dst, code);
dst += 4;

UINT32 low = imm & 0xffffffff;

code = emitInsCode(INS_addi);
code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 7;
code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 15;
code |= ((low >> 21) & 0x7ff) << 20;
emitOutput_Instr(dst, code);
dst += 4;

code = emitInsCode(INS_slli);
code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 7;
code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 15;
code |= (code_t)(11 << 20);
emitOutput_Instr(dst, code);
dst += 4;

code = emitInsCode(INS_addi);
code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 7;
code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 15;
code |= ((low >> 10) & 0x7ff) << 20;
emitOutput_Instr(dst, code);
dst += 4;

code = emitInsCode(INS_slli);
code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 7;
code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 15;
code |= (code_t)(10 << 20);
emitOutput_Instr(dst, code);
dst += 4;

code = emitInsCode(INS_jalr);
code |= (code_t)reg2 << 7;
code |= (code_t)REG_DEFAULT_HELPER_CALL_TARGET << 15;
code |= (low & 0x3ff) << 20;
// the offset default is 0;
emitOutput_Instr(dst, code);
}

dst += 4;

// If the method returns a GC ref, mark INTRET (A0) appropriately.
if (id->idGCref() == GCT_GCREF)
Expand Down Expand Up @@ -2037,25 +1914,17 @@ unsigned emitter::emitOutputCall(const insGroup* ig, BYTE* dst, instrDesc* id, c
// So we're not really doing a "stack pop" here (note that "args" is 0), but we use this mechanism
// to record the call for GC info purposes. (It might be best to use an alternate call,
// and protect "emitStackPop" under the EMIT_TRACK_STACK_DEPTH preprocessor variable.)
emitStackPop(dst, /*isCall*/ true, callInstrSize, /*args*/ 0);
emitStackPop(dst, /*isCall*/ true, sizeof(code_t), /*args*/ 0);

// Do we need to record a call location for GC purposes?
//
if (!emitFullGCinfo)
{
emitRecordGCcall(dst, callInstrSize);
emitRecordGCcall(dst, sizeof(code_t));
}
}
if (id->idIsCallRegPtr())
{
callInstrSize = 1 << 2;
}
else
{
callInstrSize = id->idIsReloc() ? (2 << 2) : (8 << 2); // INS_OPTS_C: 2/9-ins.
}

return callInstrSize;
return dst - origDst;
}

void emitter::emitJumpDistBind()
Expand Down Expand Up @@ -3453,7 +3322,7 @@ BYTE* emitter::emitOutputInstr_OptsC(BYTE* dst, instrDesc* id, const insGroup* i
assert(!id->idIsLargeCns());
*size = sizeof(instrDesc);
}
dst += emitOutputCall(ig, dst, id, 0);
dst += emitOutputCall(ig, dst, id);
return dst;
}

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/emitriscv64.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ void emitIns_R_AI(instruction ins,
regNumber reg,
ssize_t disp DEBUGARG(size_t targetHandle = 0) DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY));

unsigned emitOutputCall(const insGroup* ig, BYTE* dst, instrDesc* id, code_t code);
unsigned emitOutputCall(const insGroup* ig, BYTE* dst, instrDesc* id);

unsigned get_curTotalCodeSize(); // bytes of code

Expand Down
25 changes: 25 additions & 0 deletions src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,31 @@ void CompileResult::applyRelocs(RelocContext* rc, unsigned char* block1, ULONG b
}
}

if (targetArch == SPMI_TARGET_ARCHITECTURE_RISCV64)
{
DWORDLONG fixupLocation = tmp.location;
DWORDLONG address = section_begin + (size_t)fixupLocation - (size_t)originalAddr;

switch (relocType)
{
case IMAGE_REL_RISCV64_PC:
{
if ((section_begin <= address) && (address < section_end)) // A reloc for our section?
{
// Similar to x64's IMAGE_REL_BASED_REL32 handling we
// will handle this by also hardcoding the bottom bits
// of the target into the instruction.
PutRiscV64AuipcItype((UINT32*)address, (INT32)tmp.target);
}
wasRelocHandled = true;
}
break;

default:
break;
}
}

if (IsSpmiTarget64Bit())
{
if (!wasRelocHandled && (relocType == IMAGE_REL_BASED_DIR64))
Expand Down
48 changes: 48 additions & 0 deletions src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,54 @@ void PutArm32MovtConstant(UINT32* p, unsigned con)
*((UINT16*)p + 1) = (UINT16)instr;
}

//*****************************************************************************
// Extract the PC-Relative offset from auipc + I-type adder (addi/ld/jalr)
//*****************************************************************************
INT64 GetRiscV64AuipcItype(UINT32 * pCode)
{
enum
{
OpcodeAuipc = 0x00000017,
OpcodeAddi = 0x00000013,
OpcodeLd = 0x00003003,
OpcodeJalr = 0x00000067,
OpcodeUTypeMask = 0x0000007F,
OpcodeITypeMask = 0x0000307F,
};

UINT32 auipc = pCode[0];
_ASSERTE((auipc & OpcodeUTypeMask) == OpcodeAuipc);
int auipcRegDest = (auipc >> 7) & 0x1F;
_ASSERTE(auipcRegDest != 0);

INT64 hi20 = (INT32(auipc) >> 12) << 12;

UINT32 iType = pCode[1];
UINT32 opcode = iType & OpcodeITypeMask;
_ASSERTE(opcode == OpcodeAddi || opcode == OpcodeLd || opcode == OpcodeJalr);
int iTypeRegSrc = (iType >> 15) & 0x1F;
_ASSERTE(auipcRegDest == iTypeRegSrc);

INT64 lo12 = INT32(iType) >> 20;

return hi20 + lo12;
}

//*****************************************************************************
// Deposit the PC-Relative offset into auipc + I-type adder (addi/ld/jalr)
//*****************************************************************************
void PutRiscV64AuipcItype(UINT32 * pCode, INT64 offset)
{
INT32 lo12 = (offset << (64 - 12)) >> (64 - 12); // low 12 bits, sign-extended
INT32 hi20 = INT32(offset - lo12);
_ASSERTE(INT64(hi20) + INT64(lo12) == offset);

_ASSERTE(GetRiscV64AuipcItype(pCode) == 0);
pCode[0] |= hi20;
pCode[1] |= lo12 << 20;
_ASSERTE(GetRiscV64AuipcItype(pCode) == offset);
}

template<typename TPrint>
static std::string getFromPrinter(TPrint print)
{
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ bool Is32BitThumb2Instruction(UINT16* p);
UINT32 ExtractArm32MovImm(UINT32 instr);
void PutArm32MovtConstant(UINT32* p, unsigned con);

INT64 GetRiscV64AuipcItype(UINT32 * pCode);
void PutRiscV64AuipcItype(UINT32 * pCode, INT64 offset);

template <typename T, int size>
inline constexpr unsigned ArrLen(T (&)[size])
{
Expand Down
Loading
Loading