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;