Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,7 @@ enum class CorInfoReloc
ARM64_BRANCH26, // Arm64: B, BL
ARM64_PAGEBASE_REL21, // ADRP
ARM64_PAGEOFFSET_12A, // ADD/ADDS (immediate) with zero shift, for page offset
ARM64_PAGEOFFSET_12L, // LDR (indexed, unsigned immediate), for page offset
Comment thread
tannergooding marked this conversation as resolved.
// Linux arm64
ARM64_LIN_TLSDESC_ADR_PAGE21,
ARM64_LIN_TLSDESC_LD64_LO12,
Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/inc/jiteeversionguid.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@

#include <minipal/guid.h>

constexpr GUID JITEEVersionIdentifier = { /* 2fa4c0dd-1b2b-4c3f-8a88-cc7b79c4667f */
0x2fa4c0dd,
0x1b2b,
0x4c3f,
{0x8a, 0x88, 0xcc, 0x7b, 0x79, 0xc4, 0x66, 0x7f}
constexpr GUID JITEEVersionIdentifier = { /* e1612019-5e77-477b-9148-506eb4179bac */
0xe1612019,
0x5e77,
0x477b,
{0x91, 0x48, 0x50, 0x6e, 0xb4, 0x17, 0x9b, 0xac}
};

#endif // JIT_EE_VERSIONING_GUID_H
10 changes: 10 additions & 0 deletions src/coreclr/inc/utilcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -3042,6 +3042,11 @@ INT32 GetArm64Rel21(UINT32 * pCode);
//*****************************************************************************
INT32 GetArm64Rel12(UINT32 * pCode);

//*****************************************************************************
// Extract the page offset from an ldr (unsigned immediate) instruction
//*****************************************************************************
INT32 GetArm64Rel12Ldr(UINT32 * pCode);

//*****************************************************************************
// Deposit the PC-Relative offset 'imm28' into a b or bl instruction
//*****************************************************************************
Expand All @@ -3057,6 +3062,11 @@ void PutArm64Rel21(UINT32 * pCode, INT32 imm21);
//*****************************************************************************
void PutArm64Rel12(UINT32 * pCode, INT32 imm12);

//*****************************************************************************
// Deposit the page offset 'imm12' into an ldr (unsigned immediate) instruction
//*****************************************************************************
void PutArm64Rel12Ldr(UINT32 * pCode, INT32 imm12);

//*****************************************************************************
// Extract the PC-Relative page address and page offset from pcalau12i+add/ld
//*****************************************************************************
Expand Down
115 changes: 111 additions & 4 deletions src/coreclr/jit/emitarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ void emitter::emitInsSanityCheck(instrDesc* id)
assert(isIntegerRegister(id->idReg1()) || // ZR
isVectorRegister(id->idReg1()));
assert(isIntegerRegister(id->idReg2())); // SP
assert((emitGetInsSC(id) == 0) || (id->idIsTlsGD()));
assert((emitGetInsSC(id) == 0) || id->idIsTlsGD() || id->idIsReloc());
assert(insOptsNone(id->idInsOpt()));
break;

Expand Down Expand Up @@ -5906,6 +5906,13 @@ void emitter::emitIns_R_R_I(instruction ins,
}
}

// Try to fold a preceding relocatable "adrp/add" page-offset into this load, turning
// "adrp Rd,sym; add Rd,Rd,#:lo12:sym; ldr Rd,[Rd]" into "adrp Rd,sym; ldr Rd,[Rd,#:lo12:sym]".
Comment thread
tannergooding marked this conversation as resolved.
if ((fmt == IF_LS_2A) && m_compiler->opts.compReloc && TryFoldPageOffsetIntoLdr(ins, attr, reg1, reg2))
{
return;
}

// Try to optimize a load/store with an alternative instruction.
if (isLdrStr && m_compiler->opts.OptimizationEnabled() &&
OptimizeLdrStr(ins, attr, reg1, reg2, imm, size, fmt, false, -1, -1 DEBUG_ARG(false)))
Expand Down Expand Up @@ -11423,6 +11430,11 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
{
emitRecordRelocation(odst, (void*)emitGetInsSC(id), CorInfoReloc::ARM64_LIN_TLSDESC_LD64_LO12);
}
else if (id->idIsReloc())
{
// "ldr Rt,[Rn,#:lo12:sym]" with the page offset folded in from a preceding adrp/add pair.
emitRecordRelocation(odst, (void*)emitGetInsSC(id), CorInfoReloc::ARM64_PAGEOFFSET_12L);
}
break;

case IF_LS_2B: // LS_2B .X.......Xiiiiii iiiiiinnnnnttttt Rt Rn imm(0-4095)
Expand Down Expand Up @@ -13856,9 +13868,21 @@ void emitter::emitDispInsHelp(

case IF_LS_2A: // LS_2A .X.......X...... ......nnnnnttttt Rt Rn
assert(insOptsNone(id->idInsOpt()));
assert((emitGetInsSC(id) == 0) || id->idIsTlsGD());
assert((emitGetInsSC(id) == 0) || id->idIsTlsGD() || id->idIsReloc());
emitDispReg(id->idReg1(), emitInsTargetRegSize(id), true);
emitDispAddrRI(id->idReg2(), id->idInsOpt(), 0);
if (id->idIsReloc() && !id->idIsTlsGD())
{
// "ldr Rt,[Rn,#:lo12:sym]" with the page offset folded in from a preceding adrp/add pair.
printf("[");
emitDispReg(id->idReg2(), EA_PTRSIZE, true);
printf("[LOW RELOC ");
emitDispImm((ssize_t)emitGetInsSC(id), false);
printf("]]");
Comment thread
EgorBo marked this conversation as resolved.
}
else
{
emitDispAddrRI(id->idReg2(), id->idInsOpt(), 0);
}
break;

case IF_LS_2B: // LS_2B .X.......Xiiiiii iiiiiinnnnnttttt Rt Rn imm(0-4095)
Expand Down Expand Up @@ -17891,7 +17915,7 @@ bool emitter::OptimizePostIndexed(instruction ins, regNumber reg, ssize_t imm, e
return false;
}

if ((emitLastIns->idInsFmt() != IF_LS_2A) || emitLastIns->idIsTlsGD())
if ((emitLastIns->idInsFmt() != IF_LS_2A) || emitLastIns->idIsTlsGD() || emitLastIns->idIsReloc())
{
return false;
}
Expand Down Expand Up @@ -17996,6 +18020,89 @@ bool emitter::OptimizePostIndexed(instruction ins, regNumber reg, ssize_t imm, e
return true;
}

//-----------------------------------------------------------------------------------
// TryFoldPageOffsetIntoLdr: Fold the page offset of an immediately preceding relocatable
// "add Rd, Rd, #:lo12:sym" (PAGEOFFSET_12A) into a "ldr Rd, [Rd]" so that the pair
// "adrp Rd, sym; add Rd, Rd, #:lo12:sym; ldr Rd, [Rd]" becomes the shorter
// "adrp Rd, sym; ldr Rd, [Rd, #:lo12:sym]" using a PAGEOFFSET_12L relocation.
//
// Arguments:
// ins - The load instruction being emitted (must be INS_ldr to fold).
// attr - The operand attributes of the load.
// reg1 - The destination register of the load.
// reg2 - The base (address) register of the load.
//
// Returns:
// True if the fold was performed and the (relocatable) load was emitted; false otherwise.
//
// Notes:
// The fold is only valid when the destination equals the base register (reg1 == reg2): the
// "add" produced the full cell address into that register, and having the load overwrite it
// proves the full address has no other use (only the page base from the "adrp" is still needed).
// This is the common pattern for loading a value through an R2R/relocatable indirection cell
// (string literals, static bases, helper-call targets, ...). It deliberately does not fire for
// call indirection cells, where the full address must stay live for the call's delay-load stub
// (there reg1 != reg2). Only 64-bit integer loads are folded, matching the PAGEOFFSET_12L
// encoding (a 64-bit LDR with an 8-byte-scaled immediate); cells are pointer-sized and aligned.
//
bool emitter::TryFoldPageOffsetIntoLdr(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2)
{
if (ins != INS_ldr)
{
return false;
}

// The load must overwrite its own base so the full cell address is provably dead.
if (reg1 != reg2)
{
return false;
}

// PAGEOFFSET_12L patches a 64-bit LDR (offset scaled by 8); restrict to 64-bit integer loads.
if ((EA_SIZE(attr) != EA_8BYTE) || !isGeneralRegister(reg1))
Comment thread
EgorBo marked this conversation as resolved.
Outdated
Comment thread
tannergooding marked this conversation as resolved.
{
return false;
}

if (!emitCanPeepholeLastIns())
{
return false;
}

if (m_compiler->compGeneratingUnwindProlog || m_compiler->compGeneratingUnwindEpilog)
{
// Don't remove instructions while generating the "unwind" part of prologs or epilogs.
return false;
}

// The previous instruction must be the "add Rd, Rd, #:lo12:sym" half of an adrp/add reloc pair.
instrDesc* prevId = emitLastIns;
if ((prevId->idIns() != INS_add) || (prevId->idInsFmt() != IF_DI_2A) || !prevId->idIsReloc() ||
prevId->idIsTlsGD() || (prevId->idReg1() != reg1) || (prevId->idReg2() != reg1))
{
return false;
}

void* sym = prevId->idAddr()->iiaAddr;

// Drop the "add"; the preceding "adrp" already put the page base of 'sym' into reg1.
emitRemoveLastInstruction();
Comment thread
EgorBo marked this conversation as resolved.

// Emit "ldr reg1, [reg1]" carrying a PAGEOFFSET_12L relocation against 'sym'. The instruction
// encodes a zero offset; the relocation deposits the scaled :lo12: page offset of 'sym'.
instrDesc* id = emitNewInstrSC(attr, (ssize_t)sym);
id->idIns(INS_ldr);
id->idInsFmt(IF_LS_2A);
id->idInsOpt(INS_OPTS_NONE);
id->idReg1(reg1);
id->idReg2(reg1);
id->idSetIsDspReloc();

dispIns(id);
appendToCurIG(id);
return true;
}

#if defined(FEATURE_SIMD)
//-----------------------------------------------------------------------------------
// emitStoreSimd12ToLclOffset: store SIMD12 value from dataReg to varNum+offset.
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/jit/emitarm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ FORCEINLINE bool OptimizeLdrStr(instruction ins,

bool OptimizePostIndexed(instruction ins, regNumber reg, ssize_t imm, emitAttr regAttr);

// Try to fold the page offset of a preceding relocatable "add Rd,Rd,#:lo12:sym" (PAGEOFFSET_12A)
// into a "ldr Rd,[Rd]" to form "ldr Rd,[Rd,#:lo12:sym]" (PAGEOFFSET_12L), removing the add.
bool TryFoldPageOffsetIntoLdr(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2);

emitLclVarAddr* emitGetLclVarPairLclVar2(instrDesc* id)
{
assert(id->idIsLclVarPair());
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4237,6 +4237,7 @@ private RelocType GetRelocType(CorInfoReloc reloc)
CorInfoReloc.ARM64_BRANCH26 => RelocType.IMAGE_REL_BASED_ARM64_BRANCH26,
CorInfoReloc.ARM64_PAGEBASE_REL21 => RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21,
CorInfoReloc.ARM64_PAGEOFFSET_12A => RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A,
CorInfoReloc.ARM64_PAGEOFFSET_12L => RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L,
CorInfoReloc.ARM64_LIN_TLSDESC_ADR_PAGE21 => RelocType.IMAGE_REL_AARCH64_TLSDESC_ADR_PAGE21,
CorInfoReloc.ARM64_LIN_TLSDESC_LD64_LO12 => RelocType.IMAGE_REL_AARCH64_TLSDESC_LD64_LO12,
CorInfoReloc.ARM64_LIN_TLSDESC_ADD_LO12 => RelocType.IMAGE_REL_AARCH64_TLSDESC_ADD_LO12,
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,7 @@ public enum CorInfoReloc
ARM64_BRANCH26, // Arm64: B, BL
ARM64_PAGEBASE_REL21, // ADRP
ARM64_PAGEOFFSET_12A, // ADD/ADDS (immediate) with zero shift, for page offset
ARM64_PAGEOFFSET_12L, // LDR (indexed, unsigned immediate), for page offset
// Linux arm64
ARM64_LIN_TLSDESC_ADR_PAGE21,
ARM64_LIN_TLSDESC_LD64_LO12,
Expand Down
14 changes: 13 additions & 1 deletion src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,7 @@ const char* relocationTypeToString(CorInfoReloc fRelocType)
ADD_CASE(ARM64_BRANCH26);
ADD_CASE(ARM64_PAGEBASE_REL21);
ADD_CASE(ARM64_PAGEOFFSET_12A);
ADD_CASE(ARM64_PAGEOFFSET_12L);
ADD_CASE(ARM64_LIN_TLSDESC_ADR_PAGE21);
ADD_CASE(ARM64_LIN_TLSDESC_LD64_LO12);
ADD_CASE(ARM64_LIN_TLSDESC_ADD_LO12);
Expand Down Expand Up @@ -846,7 +847,7 @@ void CompileResult::applyRelocs(RelocContext* rc, unsigned char* block1, ULONG b

DWORDLONG target = tmp.target + (int32_t)tmp.addlDelta;
if (relocType == CorInfoReloc::ARM64_PAGEBASE_REL21 || relocType == CorInfoReloc::ARM64_LIN_TLSDESC_ADR_PAGE21 ||
relocType == CorInfoReloc::ARM64_PAGEOFFSET_12A)
relocType == CorInfoReloc::ARM64_PAGEOFFSET_12A || relocType == CorInfoReloc::ARM64_PAGEOFFSET_12L)
{
if ((rc->originalRoDataAddress2 <= (size_t)target) &&
((size_t)target < rc->originalRoDataAddress2 + rc->roDataSize2))
Expand Down Expand Up @@ -913,6 +914,17 @@ void CompileResult::applyRelocs(RelocContext* rc, unsigned char* block1, ULONG b
}
break;

case CorInfoReloc::ARM64_PAGEOFFSET_12L: // LDR 12 bit page offset
{
Comment thread
EgorBo marked this conversation as resolved.
if ((section_begin <= address) && (address < section_end)) // A reloc for our section?
{
INT32 imm12 = (INT32)(SIZE_T)target & 0xFFFLL;
PutArm64Rel12Ldr((UINT32*)address, imm12);
}
wasRelocHandled = true;
}
break;

case CorInfoReloc::ARM64_WIN_TLS_SECREL_HIGH12A: // TLSDESC ADD for High-12 Add
case CorInfoReloc::ARM64_WIN_TLS_SECREL_LOW12A: // TLSDESC ADD for Low-12 Add
case CorInfoReloc::ARM64_LIN_TLSDESC_LD64_LO12:
Expand Down
10 changes: 10 additions & 0 deletions src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,16 @@ void PutArm64Rel12(UINT32* pCode, INT32 imm12)
*pCode = addInstr;
}

void PutArm64Rel12Ldr(UINT32* pCode, INT32 imm12)
{
// For a 64-bit LDR the encoded immediate is scaled by the access size (8).
INT32 scaledImm12 = imm12 >> 3;
UINT32 ldrInstr = *pCode;
ldrInstr &= 0xFFC003FF;
ldrInstr |= (scaledImm12 << 10);
*pCode = ldrInstr;
}

void PutThumb2Imm16(UINT16* p, UINT16 imm16)
{
USHORT Opcode0 = p[0];
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ inline size_t SpmiTargetPointerSize()
void PutArm64Rel28(UINT32* pCode, INT32 imm28);
void PutArm64Rel21(UINT32* pCode, INT32 imm21);
void PutArm64Rel12(UINT32* pCode, INT32 imm12);
void PutArm64Rel12Ldr(UINT32* pCode, INT32 imm12);

void PutThumb2Mov32(UINT16* p, UINT32 imm32);
void PutThumb2BlRel24(UINT16* p, INT32 imm24);
Expand Down
43 changes: 43 additions & 0 deletions src/coreclr/utilcode/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2109,6 +2109,49 @@ void PutArm64Rel12(UINT32 * pCode, INT32 imm12)
_ASSERTE(GetArm64Rel12(pCode) == imm12);
}

//*****************************************************************************
// Extract the 12-bit page offset from an LDR instruction (unsigned immediate).
// For a 64-bit LDR the encoded immediate is scaled by 8 bytes.
//*****************************************************************************
INT32 GetArm64Rel12Ldr(UINT32 * pCode)
{
LIMITED_METHOD_CONTRACT;

UINT32 ldrInstr = *pCode;

// 21-10 contains the scaled immediate. Mask 12 bits and shift by 10 bits.
INT32 scaledImm12 = (INT32)(ldrInstr & 0x003FFC00) >> 10;

// Scale back to a byte offset (multiply by 8).
return scaledImm12 << 3;
}

//*****************************************************************************
// Deposit the PC-Relative page offset 'imm12' into an LDR instruction (unsigned
// immediate). For a 64-bit LDR the immediate represents offset/8 (scaled by 8).
//*****************************************************************************
void PutArm64Rel12Ldr(UINT32 * pCode, INT32 imm12)
{
LIMITED_METHOD_CONTRACT;

// Verify that we got a valid offset that is aligned to 8 bytes.
_ASSERTE(FitsInRel12(imm12));
_ASSERTE((imm12 & 7) == 0);

UINT32 ldrInstr = *pCode;
// Check ldr opcode: 1111 1001 0100 .... (LDR 64-bit, unsigned immediate)
_ASSERTE((ldrInstr & 0xFFC00000) == 0xF9400000);

INT32 scaledImm12 = imm12 >> 3; // scale the offset by the access size (8)

ldrInstr &= 0xFFC003FF; // keep bits 31-22, 9-0
ldrInstr |= (scaledImm12 << 10); // Occupy 21-10.

*pCode = ldrInstr; // write the assembled instruction

_ASSERTE(GetArm64Rel12Ldr(pCode) == imm12);
}

//*****************************************************************************
// Extract the PC-Relative page address and page offset from pcalau12i+add/ld
//*****************************************************************************
Expand Down
10 changes: 10 additions & 0 deletions src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12182,6 +12182,16 @@ void CEEJitInfo::recordRelocation(void * location,
break;
}

case CorInfoReloc::ARM64_PAGEOFFSET_12L:
{
_ASSERTE(addlDelta == 0);

// Write the 12 bits page offset into the ldr instruction.
INT32 imm12 = (INT32)(SIZE_T)target & 0xFFFLL;
PutArm64Rel12Ldr((UINT32 *)locationRW, imm12);
break;
}

#endif // TARGET_ARM64

#ifdef TARGET_LOONGARCH64
Expand Down
Loading