From 3fc6ef44c5af3916ac5336b021a80080c750f633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Mon, 23 Jun 2025 17:43:41 +0200 Subject: [PATCH 1/7] auipc in EmitOutputCall also non-reloc --- src/coreclr/jit/codegenriscv64.cpp | 7 +- src/coreclr/jit/emitriscv64.cpp | 181 ++++++----------------------- src/coreclr/jit/emitriscv64.h | 2 +- 3 files changed, 37 insertions(+), 153 deletions(-) diff --git a/src/coreclr/jit/codegenriscv64.cpp b/src/coreclr/jit/codegenriscv64.cpp index 640cb5ec6bf330..68c82f6b8a9f33 100644 --- a/src/coreclr/jit/codegenriscv64.cpp +++ b/src/coreclr/jit/codegenriscv64.cpp @@ -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 diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp index 6f772120f480e8..bd3112473b2eca 100644 --- a/src/coreclr/jit/emitriscv64.cpp +++ b/src/coreclr/jit/emitriscv64.cpp @@ -1733,20 +1733,12 @@ void emitter::emitIns_Call(const EmitCallParams& params) 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 // 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, offset-hi20 + // jalr r0/1, t2, offset-lo12 /* Record the address: method, indirection, or funcptr */ if (params.callType == EC_INDIR_R) @@ -1779,16 +1771,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(emitComp->opts.compReloc); } #ifdef DEBUG @@ -1823,11 +1807,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()); @@ -1866,130 +1849,44 @@ 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); + // auipc t2, offset-hi20 + // jalr r0/1, t2, offset-lo12 size_t addr = (size_t)(id->idAddr()->iiaAddr); // get addr. - int reg2 = (int)(addr & 1); - addr -= reg2; + regNumber regLink = (regNumber)(addr & 1); + assert(regLink == REG_ZERO || regLink == REG_RA); + addr -= regLink; + assert((addr & 1) == 0); - if (!emitComp->opts.compReloc) + unsigned offsetHi = 0; + unsigned offsetLo = 0; + if (!id->idIsReloc() || !emitComp->opts.compReloc) { - assert(isValidSimm32(addr - (ssize_t)dst)); + ssize_t offset = addr - (ssize_t)dst; + assert(isValidSimm32(offset)); + if (!id->idIsReloc()) + { + offsetLo = offset & 0xFFF; + offsetHi = TrimSignedToImm20((offset + 0x800) >> 12); + } } - assert((addr & 1) == 0); - - dst += 4; + dst += emitOutput_UTypeInstr(dst, INS_auipc, REG_DEFAULT_HELPER_CALL_TARGET, offsetHi); emitGCregDeadUpd(REG_DEFAULT_HELPER_CALL_TARGET, dst); + dst += emitOutput_ITypeInstr(dst, INS_jalr, regLink, REG_DEFAULT_HELPER_CALL_TARGET, offsetLo); -#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); + if (id->idIsReloc()) + 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) @@ -2037,25 +1934,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() @@ -3453,7 +3342,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; } diff --git a/src/coreclr/jit/emitriscv64.h b/src/coreclr/jit/emitriscv64.h index cbb2b11ec96747..4fa54b756bc54d 100644 --- a/src/coreclr/jit/emitriscv64.h +++ b/src/coreclr/jit/emitriscv64.h @@ -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 From 198e111c7dee2fbeba8e296d8336a73cee6d05cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 1 Jul 2025 10:04:37 +0200 Subject: [PATCH 2/7] Always record relocation for auipc+jalr like on arm64 --- src/coreclr/inc/utilcode.h | 10 +++++++ src/coreclr/jit/emitriscv64.cpp | 24 +++++----------- src/coreclr/utilcode/util.cpp | 49 +++++++++++++++++++++++++++++++++ src/coreclr/vm/jitinterface.cpp | 13 +++++++++ 4 files changed, 79 insertions(+), 17 deletions(-) diff --git a/src/coreclr/inc/utilcode.h b/src/coreclr/inc/utilcode.h index a65140ea80331a..306be0b10ce86a 100644 --- a/src/coreclr/inc/utilcode.h +++ b/src/coreclr/inc/utilcode.h @@ -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 //***************************************************************************** diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp index bd3112473b2eca..9a910063179ce9 100644 --- a/src/coreclr/jit/emitriscv64.cpp +++ b/src/coreclr/jit/emitriscv64.cpp @@ -1866,26 +1866,16 @@ unsigned emitter::emitOutputCall(const insGroup* ig, BYTE* dst, instrDesc* id) assert(regLink == REG_ZERO || regLink == REG_RA); addr -= regLink; assert((addr & 1) == 0); + regNumber addrReg = (regLink == REG_ZERO) ? REG_DEFAULT_HELPER_CALL_TARGET : REG_RA; - unsigned offsetHi = 0; - unsigned offsetLo = 0; - if (!id->idIsReloc() || !emitComp->opts.compReloc) - { - ssize_t offset = addr - (ssize_t)dst; - assert(isValidSimm32(offset)); - if (!id->idIsReloc()) - { - offsetLo = offset & 0xFFF; - offsetHi = TrimSignedToImm20((offset + 0x800) >> 12); - } - } + dst += emitOutput_UTypeInstr(dst, INS_auipc, addrReg, 0); + emitGCregDeadUpd(addrReg, dst); - dst += emitOutput_UTypeInstr(dst, INS_auipc, REG_DEFAULT_HELPER_CALL_TARGET, offsetHi); - emitGCregDeadUpd(REG_DEFAULT_HELPER_CALL_TARGET, dst); - dst += emitOutput_ITypeInstr(dst, INS_jalr, regLink, REG_DEFAULT_HELPER_CALL_TARGET, offsetLo); + dst += emitOutput_ITypeInstr(dst, INS_jalr, regLink, addrReg, 0); + if (regLink != addrReg) + emitGCregDeadUpd(regLink, dst); - if (id->idIsReloc()) - emitRecordRelocation(origDst, (BYTE*)addr, IMAGE_REL_RISCV64_PC); + emitRecordRelocation(origDst, (BYTE*)addr, IMAGE_REL_RISCV64_PC); } // If the method returns a GC ref, mark INTRET (A0) appropriately. diff --git a/src/coreclr/utilcode/util.cpp b/src/coreclr/utilcode/util.cpp index dac90c2ad97925..aa676a2681983f 100644 --- a/src/coreclr/utilcode/util.cpp +++ b/src/coreclr/utilcode/util.cpp @@ -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) +{ + INT64 lo12 = (offset << (64 - 12)) >> (64 - 12); + INT64 hi20 = INT32(offset - lo12); + _ASSERTE((hi20 + 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. diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index e6dbcde9e8b53a..e9106f17e576b4 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -11876,6 +11876,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; From db5c2d9918592d85cc1b08a3b06d59340aa20204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 1 Jul 2025 14:11:58 +0200 Subject: [PATCH 3/7] Stop squirelling link register in lowest bit of the call address --- src/coreclr/jit/emitriscv64.cpp | 44 ++++++++++++--------------------- src/coreclr/utilcode/util.cpp | 6 ++--- 2 files changed, 19 insertions(+), 31 deletions(-) diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp index 9a910063179ce9..090b015b19c72b 100644 --- a/src/coreclr/jit/emitriscv64.cpp +++ b/src/coreclr/jit/emitriscv64.cpp @@ -1725,20 +1725,17 @@ 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-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) - // auipc t2, offset-hi20 - // jalr r0/1, t2, offset-lo12 + // 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) @@ -1768,11 +1765,10 @@ void emitter::emitIns_Call(const EmitCallParams& params) assert(params.callType == EC_FUNC_TOKEN); assert(params.addr != NULL); - 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; + id->idReg1(params.isJump ? REG_ZERO : REG_RA); + id->idAddr()->iiaAddr = (BYTE*)params.addr; id->idCodeSize(2 * sizeof(code_t)); - id->idSetIsDspReloc(emitComp->opts.compReloc); + id->idSetIsDspReloc(); } #ifdef DEBUG @@ -1857,25 +1853,17 @@ unsigned emitter::emitOutputCall(const insGroup* ig, BYTE* dst, instrDesc* id) } else { - // auipc t2, offset-hi20 - // jalr r0/1, t2, offset-lo12 - - size_t addr = (size_t)(id->idAddr()->iiaAddr); // get addr. + regNumber linkReg = id->idReg1(); + regNumber tempReg = (linkReg == REG_ZERO) ? REG_DEFAULT_HELPER_CALL_TARGET : REG_RA; + assert(linkReg == REG_ZERO || linkReg == REG_RA); - regNumber regLink = (regNumber)(addr & 1); - assert(regLink == REG_ZERO || regLink == REG_RA); - addr -= regLink; - assert((addr & 1) == 0); - regNumber addrReg = (regLink == REG_ZERO) ? REG_DEFAULT_HELPER_CALL_TARGET : REG_RA; + dst += emitOutput_UTypeInstr(dst, INS_auipc, tempReg, 0); + emitGCregDeadUpd(tempReg, dst); + dst += emitOutput_ITypeInstr(dst, INS_jalr, linkReg, tempReg, 0); - dst += emitOutput_UTypeInstr(dst, INS_auipc, addrReg, 0); - emitGCregDeadUpd(addrReg, dst); - - dst += emitOutput_ITypeInstr(dst, INS_jalr, regLink, addrReg, 0); - if (regLink != addrReg) - emitGCregDeadUpd(regLink, dst); - - emitRecordRelocation(origDst, (BYTE*)addr, IMAGE_REL_RISCV64_PC); + assert(id->idIsDspReloc()); + assert(((size_t)id->idAddr()->iiaAddr & 1) == 0); + emitRecordRelocation(origDst, (BYTE*)id->idAddr()->iiaAddr, IMAGE_REL_RISCV64_PC); } // If the method returns a GC ref, mark INTRET (A0) appropriately. diff --git a/src/coreclr/utilcode/util.cpp b/src/coreclr/utilcode/util.cpp index aa676a2681983f..8a239c4e5d3c32 100644 --- a/src/coreclr/utilcode/util.cpp +++ b/src/coreclr/utilcode/util.cpp @@ -2371,9 +2371,9 @@ INT64 GetRiscv64AuipcItype(UINT32 * pCode) //***************************************************************************** void PutRiscv64AuipcItype(UINT32 * pCode, INT64 offset) { - INT64 lo12 = (offset << (64 - 12)) >> (64 - 12); - INT64 hi20 = INT32(offset - lo12); - _ASSERTE((hi20 + lo12) == offset); + INT32 lo12 = (offset << (64 - 12)) >> (64 - 12); // low 12 bits, sign-extended + INT32 hi20 = offset - lo12; + _ASSERTE(INT64(hi20) + INT64(lo12) == offset); _ASSERTE(GetRiscv64AuipcItype(pCode) == 0); pCode[0] |= hi20; From 749141b8da05b45c00e71cdc610878a735a55e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 1 Jul 2025 15:20:12 +0200 Subject: [PATCH 4/7] Handle auipc+I-type reloc in superpmi --- .../superpmi-shared/compileresult.cpp | 25 ++++++++++ .../superpmi/superpmi-shared/spmiutil.cpp | 48 +++++++++++++++++++ .../tools/superpmi/superpmi-shared/spmiutil.h | 3 ++ 3 files changed, 76 insertions(+) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp index 8c9252869fe243..485aad030dea57 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp @@ -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)) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp b/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp index 9bba21b1bfd8e5..cd0e4b20fc2b47 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp @@ -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 = offset - lo12; + _ASSERTE(INT64(hi20) + INT64(lo12) == offset); + + _ASSERTE(GetRiscv64AuipcItype(pCode) == 0); + pCode[0] |= hi20; + pCode[1] |= lo12 << 20; + _ASSERTE(GetRiscv64AuipcItype(pCode) == offset); +} + template static std::string getFromPrinter(TPrint print) { diff --git a/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h b/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h index 9ff49500321217..26f727aa6ff93b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h @@ -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 inline constexpr unsigned ArrLen(T (&)[size]) { From 74139927a9cecba242d897b4518a0db2523c6b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 1 Jul 2025 15:37:16 +0200 Subject: [PATCH 5/7] Fix RiscV casing --- src/coreclr/inc/utilcode.h | 4 ++-- .../tools/superpmi/superpmi-shared/compileresult.cpp | 2 +- src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp | 8 ++++---- src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h | 4 ++-- src/coreclr/utilcode/util.cpp | 8 ++++---- src/coreclr/vm/jitinterface.cpp | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/coreclr/inc/utilcode.h b/src/coreclr/inc/utilcode.h index 306be0b10ce86a..a3097b59da3e73 100644 --- a/src/coreclr/inc/utilcode.h +++ b/src/coreclr/inc/utilcode.h @@ -3318,12 +3318,12 @@ void PutLoongArch64JIR(UINT32 * pCode, INT64 imm); //***************************************************************************** // Extract the PC-Relative offset from auipc + I-type adder (addi/ld/jalr) //***************************************************************************** -INT64 GetRiscv64AuipcItype(UINT32 * pCode); +INT64 GetRiscV64AuipcItype(UINT32 * pCode); //***************************************************************************** // Deposit the PC-Relative offset into auipc + I-type adder (addi/ld/jalr) //***************************************************************************** -void PutRiscv64AuipcItype(UINT32 * pCode, INT64 offset); +void PutRiscV64AuipcItype(UINT32 * pCode, INT64 offset); //***************************************************************************** // Returns whether the offset fits into bl instruction diff --git a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp index 485aad030dea57..e878cd59d82ff3 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp @@ -920,7 +920,7 @@ void CompileResult::applyRelocs(RelocContext* rc, unsigned char* block1, ULONG b // 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); + PutRiscV64AuipcItype((UINT32*)address, (INT32)tmp.target); } wasRelocHandled = true; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp b/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp index cd0e4b20fc2b47..cdc7585fa1b4f2 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp @@ -480,7 +480,7 @@ void PutArm32MovtConstant(UINT32* p, unsigned con) //***************************************************************************** // Extract the PC-Relative offset from auipc + I-type adder (addi/ld/jalr) //***************************************************************************** -INT64 GetRiscv64AuipcItype(UINT32 * pCode) +INT64 GetRiscV64AuipcItype(UINT32 * pCode) { enum { @@ -513,16 +513,16 @@ INT64 GetRiscv64AuipcItype(UINT32 * pCode) //***************************************************************************** // Deposit the PC-Relative offset into auipc + I-type adder (addi/ld/jalr) //***************************************************************************** -void PutRiscv64AuipcItype(UINT32 * pCode, INT64 offset) +void PutRiscV64AuipcItype(UINT32 * pCode, INT64 offset) { INT32 lo12 = (offset << (64 - 12)) >> (64 - 12); // low 12 bits, sign-extended INT32 hi20 = offset - lo12; _ASSERTE(INT64(hi20) + INT64(lo12) == offset); - _ASSERTE(GetRiscv64AuipcItype(pCode) == 0); + _ASSERTE(GetRiscV64AuipcItype(pCode) == 0); pCode[0] |= hi20; pCode[1] |= lo12 << 20; - _ASSERTE(GetRiscv64AuipcItype(pCode) == offset); + _ASSERTE(GetRiscV64AuipcItype(pCode) == offset); } template diff --git a/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h b/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h index 26f727aa6ff93b..72e3b2b0f93a50 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h @@ -97,8 +97,8 @@ bool Is32BitThumb2Instruction(UINT16* p); UINT32 ExtractArm32MovImm(UINT32 instr); void PutArm32MovtConstant(UINT32* p, unsigned con); -INT64 GetRiscv64AuipcItype(UINT32 * pCode); -void PutRiscv64AuipcItype(UINT32 * pCode, INT64 offset); +INT64 GetRiscV64AuipcItype(UINT32 * pCode); +void PutRiscV64AuipcItype(UINT32 * pCode, INT64 offset); template inline constexpr unsigned ArrLen(T (&)[size]) diff --git a/src/coreclr/utilcode/util.cpp b/src/coreclr/utilcode/util.cpp index 8a239c4e5d3c32..4b2d7f4c4807bc 100644 --- a/src/coreclr/utilcode/util.cpp +++ b/src/coreclr/utilcode/util.cpp @@ -2336,7 +2336,7 @@ void PutLoongArch64JIR(UINT32 * pCode, INT64 imm38) //***************************************************************************** // Extract the PC-Relative offset from auipc + I-type adder (addi/ld/jalr) //***************************************************************************** -INT64 GetRiscv64AuipcItype(UINT32 * pCode) +INT64 GetRiscV64AuipcItype(UINT32 * pCode) { enum { @@ -2369,16 +2369,16 @@ INT64 GetRiscv64AuipcItype(UINT32 * pCode) //***************************************************************************** // Deposit the PC-Relative offset into auipc + I-type adder (addi/ld/jalr) //***************************************************************************** -void PutRiscv64AuipcItype(UINT32 * pCode, INT64 offset) +void PutRiscV64AuipcItype(UINT32 * pCode, INT64 offset) { INT32 lo12 = (offset << (64 - 12)) >> (64 - 12); // low 12 bits, sign-extended INT32 hi20 = offset - lo12; _ASSERTE(INT64(hi20) + INT64(lo12) == offset); - _ASSERTE(GetRiscv64AuipcItype(pCode) == 0); + _ASSERTE(GetRiscV64AuipcItype(pCode) == 0); pCode[0] |= hi20; pCode[1] |= lo12 << 20; - _ASSERTE(GetRiscv64AuipcItype(pCode) == offset); + _ASSERTE(GetRiscV64AuipcItype(pCode) == offset); } //====================================================================== diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index e9106f17e576b4..3ba5b8a3c13e96 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -11883,7 +11883,7 @@ void CEEJitInfo::recordRelocation(void * location, _ASSERTE(addlDelta == 0); INT64 offset = (INT64)target - (INT64)location; - PutRiscv64AuipcItype((UINT32 *)locationRW, offset); + PutRiscV64AuipcItype((UINT32 *)locationRW, offset); } break; From 3b5fdf1b92b366dac2077f8b7fa4ad7701a62ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Wed, 2 Jul 2025 11:15:31 +0200 Subject: [PATCH 6/7] Revert link reg encoding in call address --- src/coreclr/jit/emitriscv64.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp index 090b015b19c72b..8256f6b5dbaf36 100644 --- a/src/coreclr/jit/emitriscv64.cpp +++ b/src/coreclr/jit/emitriscv64.cpp @@ -1728,8 +1728,6 @@ void emitter::emitIns_Call(const EmitCallParams& params) id->idIns(INS_jalr); id->idInsOpt(INS_OPTS_C); - // TODO-RISCV64: maybe optimize. - // INS_OPTS_C: placeholders. 1/2-ins: // if (callType == EC_INDIR_R) // jalr zero/ra, ireg, offset @@ -1765,8 +1763,9 @@ void emitter::emitIns_Call(const EmitCallParams& params) assert(params.callType == EC_FUNC_TOKEN); assert(params.addr != NULL); - id->idReg1(params.isJump ? REG_ZERO : REG_RA); - id->idAddr()->iiaAddr = (BYTE*)params.addr; + 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; id->idCodeSize(2 * sizeof(code_t)); id->idSetIsDspReloc(); } @@ -1853,17 +1852,20 @@ unsigned emitter::emitOutputCall(const insGroup* ig, BYTE* dst, instrDesc* id) } else { - regNumber linkReg = id->idReg1(); - regNumber tempReg = (linkReg == REG_ZERO) ? REG_DEFAULT_HELPER_CALL_TARGET : REG_RA; + size_t addr = (size_t)(id->idAddr()->iiaAddr); // get addr. + + 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 += emitOutput_UTypeInstr(dst, INS_auipc, tempReg, 0); emitGCregDeadUpd(tempReg, dst); dst += emitOutput_ITypeInstr(dst, INS_jalr, linkReg, tempReg, 0); assert(id->idIsDspReloc()); - assert(((size_t)id->idAddr()->iiaAddr & 1) == 0); - emitRecordRelocation(origDst, (BYTE*)id->idAddr()->iiaAddr, IMAGE_REL_RISCV64_PC); + emitRecordRelocation(origDst, (BYTE*)addr, IMAGE_REL_RISCV64_PC); } // If the method returns a GC ref, mark INTRET (A0) appropriately. From 8d5e6123e442a88b34837e6c3a70fa96d50c0070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Wed, 2 Jul 2025 11:27:14 +0200 Subject: [PATCH 7/7] Fix windows build --- src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp | 2 +- src/coreclr/utilcode/util.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp b/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp index cdc7585fa1b4f2..2b17d0ac8352ad 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp @@ -516,7 +516,7 @@ INT64 GetRiscV64AuipcItype(UINT32 * pCode) void PutRiscV64AuipcItype(UINT32 * pCode, INT64 offset) { INT32 lo12 = (offset << (64 - 12)) >> (64 - 12); // low 12 bits, sign-extended - INT32 hi20 = offset - lo12; + INT32 hi20 = INT32(offset - lo12); _ASSERTE(INT64(hi20) + INT64(lo12) == offset); _ASSERTE(GetRiscV64AuipcItype(pCode) == 0); diff --git a/src/coreclr/utilcode/util.cpp b/src/coreclr/utilcode/util.cpp index 4b2d7f4c4807bc..e6c2bf271f46c3 100644 --- a/src/coreclr/utilcode/util.cpp +++ b/src/coreclr/utilcode/util.cpp @@ -2372,7 +2372,7 @@ INT64 GetRiscV64AuipcItype(UINT32 * pCode) void PutRiscV64AuipcItype(UINT32 * pCode, INT64 offset) { INT32 lo12 = (offset << (64 - 12)) >> (64 - 12); // low 12 bits, sign-extended - INT32 hi20 = offset - lo12; + INT32 hi20 = INT32(offset - lo12); _ASSERTE(INT64(hi20) + INT64(lo12) == offset); _ASSERTE(GetRiscV64AuipcItype(pCode) == 0);