mirror of https://github.com/dotnet/runtime
Merge 8d5e6123e4
into 02596ba8d9
This commit is contained in:
commit
5bc9996bd4
|
@ -3348,6 +3348,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
|
||||
//*****************************************************************************
|
||||
|
|
|
@ -6511,12 +6511,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
|
||||
|
|
|
@ -1696,28 +1696,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)
|
||||
|
@ -1750,16 +1737,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
|
||||
|
@ -1794,11 +1773,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());
|
||||
|
||||
|
@ -1837,131 +1815,30 @@ 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);
|
||||
}
|
||||
else if (id->idIsReloc())
|
||||
{
|
||||
// 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));
|
||||
}
|
||||
|
||||
assert((addr & 1) == 0);
|
||||
|
||||
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);
|
||||
|
||||
emitRecordRelocation(dst - 4, (BYTE*)addr, IMAGE_REL_RISCV64_PC);
|
||||
dst += emitOutput_ITypeInstr(dst, INS_jalr, id->idReg4(), id->idReg3(), TrimSignedToImm12(offset));
|
||||
}
|
||||
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
|
||||
size_t addr = (size_t)(id->idAddr()->iiaAddr); // get addr.
|
||||
|
||||
ssize_t imm = (ssize_t)(id->idAddr()->iiaAddr);
|
||||
assert((uint64_t)(imm >> 32) <= 0x7fff); // RISC-V Linux Kernel SV48
|
||||
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;
|
||||
|
||||
int reg2 = (int)(imm & 1);
|
||||
imm -= reg2;
|
||||
dst += emitOutput_UTypeInstr(dst, INS_auipc, tempReg, 0);
|
||||
emitGCregDeadUpd(tempReg, dst);
|
||||
dst += emitOutput_ITypeInstr(dst, INS_jalr, linkReg, tempReg, 0);
|
||||
|
||||
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);
|
||||
assert(id->idIsDspReloc());
|
||||
emitRecordRelocation(origDst, (BYTE*)addr, IMAGE_REL_RISCV64_PC);
|
||||
}
|
||||
|
||||
dst += 4;
|
||||
|
||||
// If the method returns a GC ref, mark INTRET (A0) appropriately.
|
||||
if (id->idGCref() == GCT_GCREF)
|
||||
{
|
||||
|
@ -2008,25 +1885,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()
|
||||
|
@ -3257,7 +3126,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -331,7 +331,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
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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])
|
||||
{
|
||||
|
|
|
@ -2332,6 +2332,55 @@ void PutLoongArch64JIR(UINT32 * pCode, INT64 imm38)
|
|||
_ASSERTE(GetLoongArch64JIR(pCode) == imm38);
|
||||
}
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
// 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);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// This function returns true, if it can determine that the instruction pointer
|
||||
// refers to a code address that belongs in the range of the given image.
|
||||
|
|
|
@ -11930,6 +11930,19 @@ void CEEJitInfo::recordRelocation(void * location,
|
|||
|
||||
#endif // TARGET_LOONGARCH64
|
||||
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
case IMAGE_REL_RISCV64_PC:
|
||||
{
|
||||
_ASSERTE(addlDelta == 0);
|
||||
|
||||
INT64 offset = (INT64)target - (INT64)location;
|
||||
PutRiscV64AuipcItype((UINT32 *)locationRW, offset);
|
||||
}
|
||||
break;
|
||||
|
||||
#endif // TARGET_RISCV64
|
||||
|
||||
default:
|
||||
_ASSERTE(!"Unknown reloc type");
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue