Skip to content

Commit 416cfd3

Browse files
authoredJun 24, 2024··
[LoongArch64] change pcaddu12i to pcalau12i & fix GT_CNS_INT generation in CodeGen::genCodeForJumpCompare (#103399)
1 parent bb63e36 commit 416cfd3

File tree

9 files changed

+193
-39
lines changed

9 files changed

+193
-39
lines changed
 

‎src/coreclr/inc/utilcode.h

+20
Original file line numberDiff line numberDiff line change
@@ -3311,6 +3311,26 @@ void PutArm64Rel21(UINT32 * pCode, INT32 imm21);
33113311
//*****************************************************************************
33123312
void PutArm64Rel12(UINT32 * pCode, INT32 imm12);
33133313

3314+
//*****************************************************************************
3315+
// Extract the PC-Relative page address and page offset from pcalau12i+add/ld
3316+
//*****************************************************************************
3317+
INT64 GetLoongArch64PC12(UINT32 * pCode);
3318+
3319+
//*****************************************************************************
3320+
// Extract the jump offset into pcaddu18i+jirl instructions
3321+
//*****************************************************************************
3322+
INT64 GetLoongArch64JIR(UINT32 * pCode);
3323+
3324+
//*****************************************************************************
3325+
// Deposit the PC-Relative page address and page offset into pcalau12i+add/ld
3326+
//*****************************************************************************
3327+
void PutLoongArch64PC12(UINT32 * pCode, INT64 imm);
3328+
3329+
//*****************************************************************************
3330+
// Deposit the jump offset into pcaddu18i+jirl instructions
3331+
//*****************************************************************************
3332+
void PutLoongArch64JIR(UINT32 * pCode, INT64 imm);
3333+
33143334
//*****************************************************************************
33153335
// Returns whether the offset fits into bl instruction
33163336
//*****************************************************************************

‎src/coreclr/jit/codegenloongarch64.cpp

+18-1
Original file line numberDiff line numberDiff line change
@@ -4007,7 +4007,24 @@ void CodeGen::genCodeForJumpCompare(GenTreeOpCC* tree)
40074007
unreached();
40084008
}
40094009

4010-
emit->emitIns_I_la(EA_PTRSIZE, REG_RA, imm);
4010+
GenTreeIntCon* con = op2->AsIntCon();
4011+
4012+
emitAttr attr = emitActualTypeSize(op2Type);
4013+
// TODO-CQ: Currently we cannot do this for all handles because of
4014+
// https://github.com/dotnet/runtime/issues/60712
4015+
if (con->ImmedValNeedsReloc(compiler))
4016+
{
4017+
attr = EA_SET_FLG(attr, EA_CNS_RELOC_FLG);
4018+
}
4019+
4020+
if (op2Type == TYP_BYREF)
4021+
{
4022+
attr = EA_SET_FLG(attr, EA_BYREF_FLG);
4023+
}
4024+
4025+
instGen_Set_Reg_To_Imm(attr, REG_RA, imm,
4026+
INS_FLAGS_DONT_CARE DEBUGARG(con->gtTargetHandle) DEBUGARG(con->gtFlags));
4027+
regSet.verifyRegUsed(REG_RA);
40114028
regs = (int)REG_RA << 5;
40124029
}
40134030
else

‎src/coreclr/jit/emitloongarch64.cpp

+7-7
Original file line numberDiff line numberDiff line change
@@ -2058,10 +2058,10 @@ void emitter::emitIns_R_AI(instruction ins,
20582058

20592059
// INS_OPTS_RELOC: placeholders. 2-ins:
20602060
// case:EA_HANDLE_CNS_RELOC
2061-
// pcaddu12i reg, off-hi-20bits
2061+
// pcalau12i reg, off-hi-20bits
20622062
// addi_d reg, reg, off-lo-12bits
20632063
// case:EA_PTR_DSP_RELOC
2064-
// pcaddu12i reg, off-hi-20bits
2064+
// pcalau12i reg, off-hi-20bits
20652065
// ld_d reg, reg, off-lo-12bits
20662066

20672067
instrDesc* id = emitNewInstr(attr);
@@ -3231,21 +3231,21 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
32313231
case INS_OPTS_RELOC:
32323232
{
32333233
// case:EA_HANDLE_CNS_RELOC
3234-
// pcaddu12i reg, off-hi-20bits
3234+
// pcalau12i reg, off-hi-20bits
32353235
// addi_d reg, reg, off-lo-12bits
32363236
// case:EA_PTR_DSP_RELOC
3237-
// pcaddu12i reg, off-hi-20bits
3237+
// pcalau12i reg, off-hi-20bits
32383238
// ld_d reg, reg, off-lo-12bits
32393239

32403240
regNumber reg1 = id->idReg1();
32413241

3242-
*(code_t*)dstRW = 0x1c000000 | (code_t)reg1;
3242+
*(code_t*)dstRW = 0x1a000000 | (code_t)reg1;
32433243

32443244
dstRW += 4;
32453245

32463246
#ifdef DEBUG
3247-
code = emitInsCode(INS_pcaddu12i);
3248-
assert(code == 0x1c000000);
3247+
code = emitInsCode(INS_pcalau12i);
3248+
assert(code == 0x1a000000);
32493249
code = emitInsCode(INS_addi_d);
32503250
assert(code == 0x02c00000);
32513251
code = emitInsCode(INS_ld_d);

‎src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs

+14-18
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public enum RelocType
1717
IMAGE_REL_BASED_THUMB_BRANCH24 = 0x13, // Thumb2: based B, BL
1818
IMAGE_REL_BASED_THUMB_MOV32_PCREL = 0x14, // Thumb2: based MOVW/MOVT
1919
IMAGE_REL_BASED_ARM64_BRANCH26 = 0x15, // Arm64: B, BL
20-
IMAGE_REL_BASED_LOONGARCH64_PC = 0x16, // LoongArch64: pcaddu12i+imm12
20+
IMAGE_REL_BASED_LOONGARCH64_PC = 0x16, // LoongArch64: pcalau12i+imm12
2121
IMAGE_REL_BASED_LOONGARCH64_JIR = 0x17, // LoongArch64: pcaddu18i+jirl
2222
IMAGE_REL_BASED_RISCV64_PC = 0x18, // RiscV64: auipc
2323
IMAGE_REL_BASED_RELPTR32 = 0x7C, // 32-bit relative address from byte starting reloc
@@ -334,43 +334,39 @@ private static unsafe int GetLoongArch64PC12(uint* pCode)
334334

335335
// then get the low 12 bits,
336336
pcInstr = *(pCode + 1);
337-
imm += ((int)(((pcInstr >> 10) & 0xFFF) << 20)) >> 20;
337+
imm |= (int)((pcInstr >> 10) & 0xFFF);
338338

339339
return imm;
340340
}
341341

342342
// case:EA_HANDLE_CNS_RELOC
343-
// pcaddu12i reg, off-hi-20bits
343+
// pcalau12i reg, off-hi-20bits
344344
// addi_d reg, reg, off-lo-12bits
345345
// case:EA_PTR_DSP_RELOC
346-
// pcaddu12i reg, off-hi-20bits
346+
// pcalau12i reg, off-hi-20bits
347347
// ld_d reg, reg, off-lo-12bits
348-
private static unsafe void PutLoongArch64PC12(uint* pCode, long imm32)
348+
private static unsafe void PutLoongArch64PC12(uint* pCode, long imm)
349349
{
350350
// Verify that we got a valid offset
351-
Debug.Assert((int)imm32 == imm32);
351+
Debug.Assert((int)imm == imm);
352352

353353
uint pcInstr = *pCode;
354354

355-
Debug.Assert((pcInstr & 0xFE000000) == 0x1c000000); // Must be pcaddu12i
356-
357-
int relOff = (int)imm32 & 0x800;
358-
int imm = (int)imm32 + relOff;
359-
relOff = ((imm & 0x7ff) - relOff) & 0xfff;
355+
Debug.Assert((pcInstr & 0xFE000000) == 0x1a000000); // Must be pcalau12i
360356

361-
// Assemble the pc-relative high 20 bits of 'imm32' into the pcaddu12i instruction
362-
pcInstr |= (uint)(((imm >> 12) & 0xFFFFF) << 5);
357+
// Assemble the pc-relative high 20 bits of 'imm' into the pcalau12i instruction
358+
pcInstr |= (uint)((imm >> 7) & 0x1FFFFE0);
363359

364360
*pCode = pcInstr; // write the assembled instruction
365361

366362
pcInstr = *(pCode + 1);
367363

368-
// Assemble the pc-relative low 12 bits of 'imm32' into the addid or ld instruction
369-
pcInstr |= (uint)(relOff << 10);
364+
// Assemble the pc-relative low 12 bits of 'imm' into the addid or ld instruction
365+
pcInstr |= (uint)((imm & 0xFFF) << 10);
370366

371367
*(pCode + 1) = pcInstr; // write the assembled instruction
372368

373-
Debug.Assert(GetLoongArch64PC12(pCode) == imm32);
369+
Debug.Assert(GetLoongArch64PC12(pCode) == imm);
374370
}
375371

376372
private static unsafe long GetLoongArch64JIR(uint* pCode)
@@ -402,14 +398,14 @@ private static unsafe void PutLoongArch64JIR(uint* pCode, long imm38)
402398
long imm = imm38 + relOff;
403399
relOff = (((imm & 0x1ffff) - relOff) >> 2) & 0xffff;
404400

405-
// Assemble the pc-relative high 20 bits of 'imm38' into the pcaddu12i instruction
401+
// Assemble the pc-relative high 20 bits of 'imm38' into the pcaddu18i instruction
406402
pcInstr |= (uint)(((imm >> 18) & 0xFFFFF) << 5);
407403

408404
*pCode = pcInstr; // write the assembled instruction
409405

410406
pcInstr = *(pCode + 1);
411407

412-
// Assemble the pc-relative low 18 bits of 'imm38' into the addid or ld instruction
408+
// Assemble the pc-relative low 18 bits of 'imm38' into the jirl instruction
413409
pcInstr |= (uint)(relOff << 10);
414410

415411
*(pCode + 1) = pcInstr; // write the assembled instruction

‎src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_LoongArch64/LoongArch64Emitter.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,18 @@ public void EmitMOV(Register regDst, Register regSrc)
4040
public void EmitMOV(Register regDst, ISymbolNode symbol)
4141
{
4242
Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_LOONGARCH64_PC);
43-
// pcaddu12i reg, off-hi-20bits
44-
Builder.EmitUInt(0x1c000000u | (uint)regDst);
43+
// pcalau12i reg, off-hi-20bits
44+
Builder.EmitUInt(0x1a000000u | (uint)regDst);
4545

4646
// addi_d reg, reg, off-lo-12bits
4747
Builder.EmitUInt(0x02c00000u | (uint)(((uint)regDst << 5) | (uint)regDst));
4848
}
4949

50-
// pcaddi regDst, 0
50+
// pcalau12i regDst, 0
5151
public void EmitPC(Register regDst)
5252
{
5353
Debug.Assert((uint)regDst > 0 && (uint)regDst < 32);
54-
Builder.EmitUInt(0x18000000 | (uint)regDst);
54+
Builder.EmitUInt(0x1a000000 | (uint)regDst);
5555
}
5656

5757
// addi.d regDst, regSrc, imm12
@@ -93,7 +93,7 @@ public void EmitJMP(ISymbolNode symbol)
9393
{
9494
if (symbol.RepresentsIndirectionCell)
9595
{
96-
// pcaddi R21, 0
96+
// pcalau12i R21, 0
9797
EmitPC(Register.R21);
9898

9999
EmitLD(Register.R21, Register.R21, 0x10);

‎src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/RelocationHelper.cs

+5
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targe
221221
}
222222

223223
case RelocType.IMAGE_REL_BASED_LOONGARCH64_PC:
224+
{
225+
relocationLength = 8;
226+
delta = (int)(targetRVA - (sourceRVA & ~0xfff) + ((targetRVA & 0x800) << 1));
227+
break;
228+
}
224229
case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR:
225230
{
226231
relocationLength = 8;

‎src/coreclr/tools/r2rdump/CoreDisTools.cs

+8-8
Original file line numberDiff line numberDiff line change
@@ -1416,15 +1416,15 @@ private void ProbeLoongArch64Quirks(RuntimeFunction rtf, int imageOffset, int rt
14161416
else if (IsLoongArch64JirlRAInstruction(instr, out uint rj, out int imm))
14171417
{
14181418
// Common Pattern:
1419-
// pcaddu12i
1419+
// pcalau12i
14201420
// ld.d
14211421
// jirl ra, rj, 0
14221422
//
1423-
// pcaddu12i
1423+
// pcalau12i
14241424
// addi.d
14251425
// ld.d
14261426
// jirl ra, rj, 0
1427-
// There may exist some irrelevant instructions between pcaddu12i and jirl.
1427+
// There may exist some irrelevant instructions between pcalau12i and jirl.
14281428
// We need to find relevant instructions based on rj to calculate the jump address.
14291429
uint register = rj;
14301430
int immediate = imm;
@@ -1444,11 +1444,11 @@ private void ProbeLoongArch64Quirks(RuntimeFunction rtf, int imageOffset, int rt
14441444
immediate += imm;
14451445
}
14461446
}
1447-
else if (IsLoongArch64Pcaddu12iInstruction(instr, out rd, out imm))
1447+
else if (IsLoongArch64Pcalau12iInstruction(instr, out rd, out imm))
14481448
{
14491449
if (rd == register)
14501450
{
1451-
immediate += currentPC + imm;
1451+
immediate += (currentPC & ~0xfff) + imm;
14521452
isFound = true;
14531453
break;
14541454
}
@@ -1549,14 +1549,14 @@ private bool IsLoongArch64JirlRAInstruction(uint ins, out uint rj, out int offs)
15491549
}
15501550

15511551
/// <summary>
1552-
/// Determine whether a given instruction is a PCADDU12I.
1552+
/// Determine whether a given instruction is a PCALAU12I.
15531553
/// </summary>
15541554
/// <param name="ins">Assembly code of instruction</param>
1555-
private bool IsLoongArch64Pcaddu12iInstruction(uint ins, out uint rd, out int imm)
1555+
private bool IsLoongArch64Pcalau12iInstruction(uint ins, out uint rd, out int imm)
15561556
{
15571557
rd = 0;
15581558
imm = 0;
1559-
if (((ins >> 25) & 0x3f) == 0xe)
1559+
if (((ins >> 25) & 0x3f) == 0xd)
15601560
{
15611561
rd = ins & 0x1f;
15621562
imm = (int)((ins >> 5) & 0xfffff) << 12;

‎src/coreclr/utilcode/util.cpp

+94
Original file line numberDiff line numberDiff line change
@@ -2286,6 +2286,100 @@ void PutArm64Rel12(UINT32 * pCode, INT32 imm12)
22862286
_ASSERTE(GetArm64Rel12(pCode) == imm12);
22872287
}
22882288

2289+
//*****************************************************************************
2290+
// Extract the PC-Relative page address and page offset from pcalau12i+add/ld
2291+
//*****************************************************************************
2292+
INT64 GetLoongArch64PC12(UINT32 * pCode)
2293+
{
2294+
UINT32 pcInstr = *pCode;
2295+
2296+
// first get the high 20 bits,
2297+
INT64 imm = (INT64)(((pcInstr >> 5) & 0xFFFFF) << 12);
2298+
2299+
// then get the low 12 bits,
2300+
pcInstr = *(pCode + 1);
2301+
imm |= (INT64)((pcInstr >> 10) & 0xFFF);
2302+
2303+
return imm;
2304+
}
2305+
2306+
//*****************************************************************************
2307+
// Extract the jump offset into pcaddu18i+jirl instructions
2308+
//*****************************************************************************
2309+
INT64 GetLoongArch64JIR(UINT32 * pCode)
2310+
{
2311+
UINT32 pcInstr = *pCode;
2312+
2313+
// first get the high 20 bits,
2314+
INT64 imm = ((INT64)((pcInstr >> 5) & 0xFFFFF) << 18);
2315+
2316+
// then get the low 18 bits
2317+
pcInstr = *(pCode + 1);
2318+
imm += ((INT64)((INT16)((pcInstr >> 10) & 0xFFFF))) << 2;
2319+
2320+
return imm;
2321+
}
2322+
2323+
//*****************************************************************************
2324+
// Deposit the PC-Relative page address and page offset into pcalau12i+add/ld
2325+
//*****************************************************************************
2326+
void PutLoongArch64PC12(UINT32 * pCode, INT64 imm)
2327+
{
2328+
// Verify that we got a valid offset
2329+
_ASSERTE((INT32)imm == imm);
2330+
2331+
UINT32 pcInstr = *pCode;
2332+
2333+
_ASSERTE((pcInstr & 0xFE000000) == 0x1a000000); // Must be pcalau12i
2334+
2335+
// Assemble the pc-relative high 20 bits of 'imm' into the pcalau12i instruction
2336+
pcInstr |= (UINT32)((imm >> 7) & 0x1FFFFE0);
2337+
2338+
*pCode = pcInstr; // write the assembled instruction
2339+
2340+
pcInstr = *(pCode + 1);
2341+
2342+
// Assemble the pc-relative low 12 bits of 'imm' into the addid or ld instruction
2343+
pcInstr |= (UINT32)((imm & 0xFFF) << 10);
2344+
2345+
*(pCode + 1) = pcInstr; // write the assembled instruction
2346+
2347+
_ASSERTE(GetLoongArch64PC12(pCode) == imm);
2348+
}
2349+
2350+
//*****************************************************************************
2351+
// Deposit the jump offset into pcaddu18i+jirl instructions
2352+
//*****************************************************************************
2353+
void PutLoongArch64JIR(UINT32 * pCode, INT64 imm38)
2354+
{
2355+
// Verify that we got a valid offset
2356+
_ASSERTE((imm38 >= -0x2000000000L) && (imm38 < 0x2000000000L));
2357+
2358+
_ASSERTE((imm38 & 0x3) == 0); // the low two bits must be zero
2359+
2360+
UINT32 pcInstr = *pCode;
2361+
2362+
_ASSERTE(pcInstr == 0x1e00000e); // Must be pcaddu18i R14, 0
2363+
2364+
INT64 relOff = imm38 & 0x20000;
2365+
INT64 imm = imm38 + relOff;
2366+
relOff = (((imm & 0x1ffff) - relOff) >> 2) & 0xffff;
2367+
2368+
// Assemble the pc-relative high 20 bits of 'imm38' into the pcaddu18i instruction
2369+
pcInstr |= (UINT32)(((imm >> 18) & 0xFFFFF) << 5);
2370+
2371+
*pCode = pcInstr; // write the assembled instruction
2372+
2373+
pcInstr = *(pCode + 1);
2374+
2375+
// Assemble the pc-relative low 18 bits of 'imm38' into the jirl instruction
2376+
pcInstr |= (UINT32)(relOff << 10);
2377+
2378+
*(pCode + 1) = pcInstr; // write the assembled instruction
2379+
2380+
_ASSERTE(GetLoongArch64JIR(pCode) == imm38);
2381+
}
2382+
22892383
//======================================================================
22902384
// This function returns true, if it can determine that the instruction pointer
22912385
// refers to a code address that belongs in the range of the given image.

‎src/coreclr/vm/jitinterface.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -11441,6 +11441,28 @@ void CEEJitInfo::recordRelocation(void * location,
1144111441

1144211442
#endif // TARGET_ARM64
1144311443

11444+
#ifdef TARGET_LOONGARCH64
11445+
case IMAGE_REL_LOONGARCH64_PC:
11446+
{
11447+
_ASSERTE(addlDelta == 0);
11448+
11449+
INT64 imm = (INT64)target - ((INT64)location & 0xFFFFFFFFFFFFF000LL);
11450+
imm += ((INT64)target & 0x800) << 1;
11451+
PutLoongArch64PC12((UINT32 *)locationRW, imm);
11452+
}
11453+
break;
11454+
11455+
case IMAGE_REL_LOONGARCH64_JIR:
11456+
{
11457+
_ASSERTE(addlDelta == 0);
11458+
11459+
INT64 imm = (INT64)target - (INT64)location;
11460+
PutLoongArch64JIR((UINT32 *)locationRW, imm);
11461+
}
11462+
break;
11463+
11464+
#endif // TARGET_LOONGARCH64
11465+
1144411466
default:
1144511467
_ASSERTE(!"Unknown reloc type");
1144611468
break;

0 commit comments

Comments
 (0)
Please sign in to comment.