diff --git a/src/coreclr/inc/utilcode.h b/src/coreclr/inc/utilcode.h index 192bdc5d0d5973..9d753da6912ac2 100644 --- a/src/coreclr/inc/utilcode.h +++ b/src/coreclr/inc/utilcode.h @@ -3311,6 +3311,26 @@ void PutArm64Rel21(UINT32 * pCode, INT32 imm21); //***************************************************************************** void PutArm64Rel12(UINT32 * pCode, INT32 imm12); +//***************************************************************************** +// Extract the PC-Relative page address and page offset from pcalau12i+add/ld +//***************************************************************************** +INT64 GetLoongArch64PC12(UINT32 * pCode); + +//***************************************************************************** +// Extract the jump offset into pcaddu18i+jirl instructions +//***************************************************************************** +INT64 GetLoongArch64JIR(UINT32 * pCode); + +//***************************************************************************** +// Deposit the PC-Relative page address and page offset into pcalau12i+add/ld +//***************************************************************************** +void PutLoongArch64PC12(UINT32 * pCode, INT64 imm); + +//***************************************************************************** +// Deposit the jump offset into pcaddu18i+jirl instructions +//***************************************************************************** +void PutLoongArch64JIR(UINT32 * pCode, INT64 imm); + //***************************************************************************** // Returns whether the offset fits into bl instruction //***************************************************************************** diff --git a/src/coreclr/jit/codegenloongarch64.cpp b/src/coreclr/jit/codegenloongarch64.cpp index f86f3b515863cd..4ecdc5b2c8414b 100644 --- a/src/coreclr/jit/codegenloongarch64.cpp +++ b/src/coreclr/jit/codegenloongarch64.cpp @@ -4007,7 +4007,24 @@ void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree) unreached(); } - emit->emitIns_I_la(EA_PTRSIZE, REG_RA, imm); + GenTreeIntCon* con = op2->AsIntCon(); + + emitAttr attr = emitActualTypeSize(op2Type); + // TODO-CQ: Currently we cannot do this for all handles because of + // https://github.com/dotnet/runtime/issues/60712 + if (con->ImmedValNeedsReloc(compiler)) + { + attr = EA_SET_FLG(attr, EA_CNS_RELOC_FLG); + } + + if (op2Type == TYP_BYREF) + { + attr = EA_SET_FLG(attr, EA_BYREF_FLG); + } + + instGen_Set_Reg_To_Imm(attr, REG_RA, imm, + INS_FLAGS_DONT_CARE DEBUGARG(con->gtTargetHandle) DEBUGARG(con->gtFlags)); + regSet.verifyRegUsed(REG_RA); regs = (int)REG_RA << 5; } else diff --git a/src/coreclr/jit/emitloongarch64.cpp b/src/coreclr/jit/emitloongarch64.cpp index 043f8ed88c260d..381e1b1f999c64 100644 --- a/src/coreclr/jit/emitloongarch64.cpp +++ b/src/coreclr/jit/emitloongarch64.cpp @@ -2058,10 +2058,10 @@ void emitter::emitIns_R_AI(instruction ins, // INS_OPTS_RELOC: placeholders. 2-ins: // case:EA_HANDLE_CNS_RELOC - // pcaddu12i reg, off-hi-20bits + // pcalau12i reg, off-hi-20bits // addi_d reg, reg, off-lo-12bits // case:EA_PTR_DSP_RELOC - // pcaddu12i reg, off-hi-20bits + // pcalau12i reg, off-hi-20bits // ld_d reg, reg, off-lo-12bits instrDesc* id = emitNewInstr(attr); @@ -3231,21 +3231,21 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) case INS_OPTS_RELOC: { // case:EA_HANDLE_CNS_RELOC - // pcaddu12i reg, off-hi-20bits + // pcalau12i reg, off-hi-20bits // addi_d reg, reg, off-lo-12bits // case:EA_PTR_DSP_RELOC - // pcaddu12i reg, off-hi-20bits + // pcalau12i reg, off-hi-20bits // ld_d reg, reg, off-lo-12bits regNumber reg1 = id->idReg1(); - *(code_t*)dstRW = 0x1c000000 | (code_t)reg1; + *(code_t*)dstRW = 0x1a000000 | (code_t)reg1; dstRW += 4; #ifdef DEBUG - code = emitInsCode(INS_pcaddu12i); - assert(code == 0x1c000000); + code = emitInsCode(INS_pcalau12i); + assert(code == 0x1a000000); code = emitInsCode(INS_addi_d); assert(code == 0x02c00000); code = emitInsCode(INS_ld_d); diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs index 7585ca75fa8b4a..0ad99e678c396c 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs @@ -17,7 +17,7 @@ public enum RelocType IMAGE_REL_BASED_THUMB_BRANCH24 = 0x13, // Thumb2: based B, BL IMAGE_REL_BASED_THUMB_MOV32_PCREL = 0x14, // Thumb2: based MOVW/MOVT IMAGE_REL_BASED_ARM64_BRANCH26 = 0x15, // Arm64: B, BL - IMAGE_REL_BASED_LOONGARCH64_PC = 0x16, // LoongArch64: pcaddu12i+imm12 + IMAGE_REL_BASED_LOONGARCH64_PC = 0x16, // LoongArch64: pcalau12i+imm12 IMAGE_REL_BASED_LOONGARCH64_JIR = 0x17, // LoongArch64: pcaddu18i+jirl IMAGE_REL_BASED_RISCV64_PC = 0x18, // RiscV64: auipc IMAGE_REL_BASED_RELPTR32 = 0x7C, // 32-bit relative address from byte starting reloc @@ -334,43 +334,39 @@ private static unsafe int GetLoongArch64PC12(uint* pCode) // then get the low 12 bits, pcInstr = *(pCode + 1); - imm += ((int)(((pcInstr >> 10) & 0xFFF) << 20)) >> 20; + imm |= (int)((pcInstr >> 10) & 0xFFF); return imm; } // case:EA_HANDLE_CNS_RELOC - // pcaddu12i reg, off-hi-20bits + // pcalau12i reg, off-hi-20bits // addi_d reg, reg, off-lo-12bits // case:EA_PTR_DSP_RELOC - // pcaddu12i reg, off-hi-20bits + // pcalau12i reg, off-hi-20bits // ld_d reg, reg, off-lo-12bits - private static unsafe void PutLoongArch64PC12(uint* pCode, long imm32) + private static unsafe void PutLoongArch64PC12(uint* pCode, long imm) { // Verify that we got a valid offset - Debug.Assert((int)imm32 == imm32); + Debug.Assert((int)imm == imm); uint pcInstr = *pCode; - Debug.Assert((pcInstr & 0xFE000000) == 0x1c000000); // Must be pcaddu12i - - int relOff = (int)imm32 & 0x800; - int imm = (int)imm32 + relOff; - relOff = ((imm & 0x7ff) - relOff) & 0xfff; + Debug.Assert((pcInstr & 0xFE000000) == 0x1a000000); // Must be pcalau12i - // Assemble the pc-relative high 20 bits of 'imm32' into the pcaddu12i instruction - pcInstr |= (uint)(((imm >> 12) & 0xFFFFF) << 5); + // Assemble the pc-relative high 20 bits of 'imm' into the pcalau12i instruction + pcInstr |= (uint)((imm >> 7) & 0x1FFFFE0); *pCode = pcInstr; // write the assembled instruction pcInstr = *(pCode + 1); - // Assemble the pc-relative low 12 bits of 'imm32' into the addid or ld instruction - pcInstr |= (uint)(relOff << 10); + // Assemble the pc-relative low 12 bits of 'imm' into the addid or ld instruction + pcInstr |= (uint)((imm & 0xFFF) << 10); *(pCode + 1) = pcInstr; // write the assembled instruction - Debug.Assert(GetLoongArch64PC12(pCode) == imm32); + Debug.Assert(GetLoongArch64PC12(pCode) == imm); } private static unsafe long GetLoongArch64JIR(uint* pCode) @@ -402,14 +398,14 @@ private static unsafe void PutLoongArch64JIR(uint* pCode, long imm38) long imm = imm38 + relOff; relOff = (((imm & 0x1ffff) - relOff) >> 2) & 0xffff; - // Assemble the pc-relative high 20 bits of 'imm38' into the pcaddu12i instruction + // Assemble the pc-relative high 20 bits of 'imm38' into the pcaddu18i instruction pcInstr |= (uint)(((imm >> 18) & 0xFFFFF) << 5); *pCode = pcInstr; // write the assembled instruction pcInstr = *(pCode + 1); - // Assemble the pc-relative low 18 bits of 'imm38' into the addid or ld instruction + // Assemble the pc-relative low 18 bits of 'imm38' into the jirl instruction pcInstr |= (uint)(relOff << 10); *(pCode + 1) = pcInstr; // write the assembled instruction diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_LoongArch64/LoongArch64Emitter.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_LoongArch64/LoongArch64Emitter.cs index db0fd17192a369..ada020f7ca93ba 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_LoongArch64/LoongArch64Emitter.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_LoongArch64/LoongArch64Emitter.cs @@ -40,18 +40,18 @@ public void EmitMOV(Register regDst, Register regSrc) public void EmitMOV(Register regDst, ISymbolNode symbol) { Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_LOONGARCH64_PC); - // pcaddu12i reg, off-hi-20bits - Builder.EmitUInt(0x1c000000u | (uint)regDst); + // pcalau12i reg, off-hi-20bits + Builder.EmitUInt(0x1a000000u | (uint)regDst); // addi_d reg, reg, off-lo-12bits Builder.EmitUInt(0x02c00000u | (uint)(((uint)regDst << 5) | (uint)regDst)); } - // pcaddi regDst, 0 + // pcalau12i regDst, 0 public void EmitPC(Register regDst) { Debug.Assert((uint)regDst > 0 && (uint)regDst < 32); - Builder.EmitUInt(0x18000000 | (uint)regDst); + Builder.EmitUInt(0x1a000000 | (uint)regDst); } // addi.d regDst, regSrc, imm12 @@ -93,7 +93,7 @@ public void EmitJMP(ISymbolNode symbol) { if (symbol.RepresentsIndirectionCell) { - // pcaddi R21, 0 + // pcalau12i R21, 0 EmitPC(Register.R21); EmitLD(Register.R21, Register.R21, 0x10); diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs index e68214579f79a1..6a2501482ab786 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs @@ -221,6 +221,11 @@ public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targe } case RelocType.IMAGE_REL_BASED_LOONGARCH64_PC: + { + relocationLength = 8; + delta = (int)(targetRVA - (sourceRVA & ~0xfff) + ((targetRVA & 0x800) << 1)); + break; + } case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR: { relocationLength = 8; diff --git a/src/coreclr/tools/r2rdump/CoreDisTools.cs b/src/coreclr/tools/r2rdump/CoreDisTools.cs index 2eefbdaa4ecd1b..dbceedeaf667c5 100644 --- a/src/coreclr/tools/r2rdump/CoreDisTools.cs +++ b/src/coreclr/tools/r2rdump/CoreDisTools.cs @@ -1416,15 +1416,15 @@ private void ProbeLoongArch64Quirks(RuntimeFunction rtf, int imageOffset, int rt else if (IsLoongArch64JirlRAInstruction(instr, out uint rj, out int imm)) { // Common Pattern: - // pcaddu12i + // pcalau12i // ld.d // jirl ra, rj, 0 // - // pcaddu12i + // pcalau12i // addi.d // ld.d // jirl ra, rj, 0 - // There may exist some irrelevant instructions between pcaddu12i and jirl. + // There may exist some irrelevant instructions between pcalau12i and jirl. // We need to find relevant instructions based on rj to calculate the jump address. uint register = rj; int immediate = imm; @@ -1444,11 +1444,11 @@ private void ProbeLoongArch64Quirks(RuntimeFunction rtf, int imageOffset, int rt immediate += imm; } } - else if (IsLoongArch64Pcaddu12iInstruction(instr, out rd, out imm)) + else if (IsLoongArch64Pcalau12iInstruction(instr, out rd, out imm)) { if (rd == register) { - immediate += currentPC + imm; + immediate += (currentPC & ~0xfff) + imm; isFound = true; break; } @@ -1549,14 +1549,14 @@ private bool IsLoongArch64JirlRAInstruction(uint ins, out uint rj, out int offs) } /// - /// Determine whether a given instruction is a PCADDU12I. + /// Determine whether a given instruction is a PCALAU12I. /// /// Assembly code of instruction - private bool IsLoongArch64Pcaddu12iInstruction(uint ins, out uint rd, out int imm) + private bool IsLoongArch64Pcalau12iInstruction(uint ins, out uint rd, out int imm) { rd = 0; imm = 0; - if (((ins >> 25) & 0x3f) == 0xe) + if (((ins >> 25) & 0x3f) == 0xd) { rd = ins & 0x1f; imm = (int)((ins >> 5) & 0xfffff) << 12; diff --git a/src/coreclr/utilcode/util.cpp b/src/coreclr/utilcode/util.cpp index 6dcae323ee1ec6..01d03df5da050d 100644 --- a/src/coreclr/utilcode/util.cpp +++ b/src/coreclr/utilcode/util.cpp @@ -2286,6 +2286,100 @@ void PutArm64Rel12(UINT32 * pCode, INT32 imm12) _ASSERTE(GetArm64Rel12(pCode) == imm12); } +//***************************************************************************** +// Extract the PC-Relative page address and page offset from pcalau12i+add/ld +//***************************************************************************** +INT64 GetLoongArch64PC12(UINT32 * pCode) +{ + UINT32 pcInstr = *pCode; + + // first get the high 20 bits, + INT64 imm = (INT64)(((pcInstr >> 5) & 0xFFFFF) << 12); + + // then get the low 12 bits, + pcInstr = *(pCode + 1); + imm |= (INT64)((pcInstr >> 10) & 0xFFF); + + return imm; +} + +//***************************************************************************** +// Extract the jump offset into pcaddu18i+jirl instructions +//***************************************************************************** +INT64 GetLoongArch64JIR(UINT32 * pCode) +{ + UINT32 pcInstr = *pCode; + + // first get the high 20 bits, + INT64 imm = ((INT64)((pcInstr >> 5) & 0xFFFFF) << 18); + + // then get the low 18 bits + pcInstr = *(pCode + 1); + imm += ((INT64)((INT16)((pcInstr >> 10) & 0xFFFF))) << 2; + + return imm; +} + +//***************************************************************************** +// Deposit the PC-Relative page address and page offset into pcalau12i+add/ld +//***************************************************************************** +void PutLoongArch64PC12(UINT32 * pCode, INT64 imm) +{ + // Verify that we got a valid offset + _ASSERTE((INT32)imm == imm); + + UINT32 pcInstr = *pCode; + + _ASSERTE((pcInstr & 0xFE000000) == 0x1a000000); // Must be pcalau12i + + // Assemble the pc-relative high 20 bits of 'imm' into the pcalau12i instruction + pcInstr |= (UINT32)((imm >> 7) & 0x1FFFFE0); + + *pCode = pcInstr; // write the assembled instruction + + pcInstr = *(pCode + 1); + + // Assemble the pc-relative low 12 bits of 'imm' into the addid or ld instruction + pcInstr |= (UINT32)((imm & 0xFFF) << 10); + + *(pCode + 1) = pcInstr; // write the assembled instruction + + _ASSERTE(GetLoongArch64PC12(pCode) == imm); +} + +//***************************************************************************** +// Deposit the jump offset into pcaddu18i+jirl instructions +//***************************************************************************** +void PutLoongArch64JIR(UINT32 * pCode, INT64 imm38) +{ + // Verify that we got a valid offset + _ASSERTE((imm38 >= -0x2000000000L) && (imm38 < 0x2000000000L)); + + _ASSERTE((imm38 & 0x3) == 0); // the low two bits must be zero + + UINT32 pcInstr = *pCode; + + _ASSERTE(pcInstr == 0x1e00000e); // Must be pcaddu18i R14, 0 + + INT64 relOff = imm38 & 0x20000; + INT64 imm = imm38 + relOff; + relOff = (((imm & 0x1ffff) - relOff) >> 2) & 0xffff; + + // Assemble the pc-relative high 20 bits of 'imm38' into the pcaddu18i instruction + pcInstr |= (UINT32)(((imm >> 18) & 0xFFFFF) << 5); + + *pCode = pcInstr; // write the assembled instruction + + pcInstr = *(pCode + 1); + + // Assemble the pc-relative low 18 bits of 'imm38' into the jirl instruction + pcInstr |= (UINT32)(relOff << 10); + + *(pCode + 1) = pcInstr; // write the assembled instruction + + _ASSERTE(GetLoongArch64JIR(pCode) == imm38); +} + //====================================================================== // 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 2631fb927d5d8f..180b04e2de0359 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -11421,6 +11421,28 @@ void CEEJitInfo::recordRelocation(void * location, #endif // TARGET_ARM64 +#ifdef TARGET_LOONGARCH64 + case IMAGE_REL_LOONGARCH64_PC: + { + _ASSERTE(addlDelta == 0); + + INT64 imm = (INT64)target - ((INT64)location & 0xFFFFFFFFFFFFF000LL); + imm += ((INT64)target & 0x800) << 1; + PutLoongArch64PC12((UINT32 *)locationRW, imm); + } + break; + + case IMAGE_REL_LOONGARCH64_JIR: + { + _ASSERTE(addlDelta == 0); + + INT64 imm = (INT64)target - (INT64)location; + PutLoongArch64JIR((UINT32 *)locationRW, imm); + } + break; + +#endif // TARGET_LOONGARCH64 + default: _ASSERTE(!"Unknown reloc type"); break;