Skip to content

Commit a526847

Browse files
EgorBoCopilotjakobbotsch
authored
Arm64: don't fold ldr page offset (PAGEOFFSET_12L) for NativeAOT (#129966)
Fixes #129936. PR #129589 added an Arm64 fold of `adrp+add+ldr` into `adrp+ldr[#:lo12:]` via a 64-bit `PAGEOFFSET_12L` reloc (`R_AARCH64_LDST64_ABS_LO12_NC`). That reloc encodes the offset scaled by 8, so the target must be 8-byte aligned. In R2R the relocatable loads always go through pointer-aligned indirection cells, but NativeAOT can fold a direct 64-bit load of byte-packed frozen data (4-byte aligned), which `ld.lld` rejects: ``` ld.lld : error : improper alignment for relocation R_AARCH64_LDST64_ABS_LO12_NC: 0x74A52C is not aligned to 8 bytes ``` The fold is purely a size optimization, so this restricts it to non-NativeAOT and falls back to the always-safe `adrp+add+ldr`. Validation (SPMI, linux-arm64): - `benchmarks.run` (R2R, ~427K contexts): **0 asm diffs** — the win is preserved. - `smoke_tests.nativeaot` (18891 ctx): clean replay, no diffs. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>
1 parent 553b3b7 commit a526847

29 files changed

Lines changed: 304 additions & 49 deletions

src/coreclr/inc/corinfo.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3190,6 +3190,15 @@ class ICorStaticInfo
31903190
// Returns the primitive type for passing/returning a Wasm struct by value,
31913191
// or CORINFO_WASM_TYPE_VOID if passing/returning must be by reference.
31923192
virtual CorInfoWasmType getWasmLowering(CORINFO_CLASS_HANDLE structHnd) = 0;
3193+
3194+
// Returns the guaranteed alignment, in bytes, of the data referenced by 'address'.
3195+
// 'address' is a relocation target such as a static, RVA, or frozen-data blob. The JIT
3196+
// uses this to decide whether it can emit an alignment-sensitive relocation against the
3197+
// target (e.g. the Arm64 LDST64 ':lo12:' page-offset fold, which requires the target to
3198+
// be 8-byte aligned).
3199+
virtual uint32_t getAddressAlignment(
3200+
void* address
3201+
) = 0;
31933202
};
31943203

31953204
/*****************************************************************************

src/coreclr/inc/icorjitinfoimpl_generated.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,9 @@ void getFpStructLowering(
536536
CorInfoWasmType getWasmLowering(
537537
CORINFO_CLASS_HANDLE structHnd) override;
538538

539+
uint32_t getAddressAlignment(
540+
void* address) override;
541+
539542
uint32_t getThreadTLSIndex(
540543
void** ppIndirection) override;
541544

src/coreclr/inc/jiteeversionguid.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@
3737

3838
#include <minipal/guid.h>
3939

40-
constexpr GUID JITEEVersionIdentifier = { /* 5fe1ab78-3c99-4866-8771-5596c7a0e181 */
41-
0x5fe1ab78,
42-
0x3c99,
43-
0x4866,
44-
{0x87, 0x71, 0x55, 0x96, 0xc7, 0xa0, 0xe1, 0x81}
40+
constexpr GUID JITEEVersionIdentifier = { /* 58dd28fc-38f0-4782-989a-25e2d721a98b */
41+
0x58dd28fc,
42+
0x38f0,
43+
0x4782,
44+
{0x98, 0x9a, 0x25, 0xe2, 0xd7, 0x21, 0xa9, 0x8b}
4545
};
4646

4747
#endif // JIT_EE_VERSIONING_GUID_H

src/coreclr/jit/ICorJitInfo_names_generated.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ DEF_CLR_API(getSystemVAmd64PassStructInRegisterDescriptor)
133133
DEF_CLR_API(getSwiftLowering)
134134
DEF_CLR_API(getFpStructLowering)
135135
DEF_CLR_API(getWasmLowering)
136+
DEF_CLR_API(getAddressAlignment)
136137
DEF_CLR_API(getThreadTLSIndex)
137138
DEF_CLR_API(getAddrOfCaptureThreadGlobal)
138139
DEF_CLR_API(getHelperFtn)

src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,15 @@ CorInfoWasmType WrapICorJitInfo::getWasmLowering(
12691269
return temp;
12701270
}
12711271

1272+
uint32_t WrapICorJitInfo::getAddressAlignment(
1273+
void* address)
1274+
{
1275+
API_ENTER(getAddressAlignment);
1276+
uint32_t temp = wrapHnd->getAddressAlignment(address);
1277+
API_LEAVE(getAddressAlignment);
1278+
return temp;
1279+
}
1280+
12721281
uint32_t WrapICorJitInfo::getThreadTLSIndex(
12731282
void** ppIndirection)
12741283
{

src/coreclr/jit/compiler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9688,6 +9688,8 @@ class Compiler
96889688

96899689
CorInfoReloc eeGetRelocTypeHint(void* target);
96909690

9691+
uint32_t eeGetAddressAlignment(void* address);
9692+
96919693
// ICorStaticInfo wrapper functions
96929694

96939695
#if defined(UNIX_AMD64_ABI)

src/coreclr/jit/ee_il_dll.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,30 @@ CorInfoReloc Compiler::eeGetRelocTypeHint(void* target)
13991399
}
14001400
}
14011401

1402+
//------------------------------------------------------------------------
1403+
// eeGetAddressAlignment: Get the guaranteed alignment, in bytes, of the data referenced by
1404+
// 'address' (a relocation target such as a static, RVA, or frozen-data blob).
1405+
//
1406+
// Arguments:
1407+
// address - the relocation target to query
1408+
//
1409+
// Return Value:
1410+
// The guaranteed alignment in bytes, or 1 when it cannot be determined (e.g. when the JIT's
1411+
// target does not match the VM). The JIT uses this to gate alignment-sensitive relocations.
1412+
//
1413+
uint32_t Compiler::eeGetAddressAlignment(void* address)
1414+
{
1415+
if (info.compMatchedVM)
1416+
{
1417+
return info.compCompHnd->getAddressAlignment(address);
1418+
}
1419+
else
1420+
{
1421+
// The VM does not match the JIT target, so we cannot assume any alignment.
1422+
return 1;
1423+
}
1424+
}
1425+
14021426
CORINFO_FIELD_HANDLE Compiler::eeFindJitDataOffs(unsigned dataOffs)
14031427
{
14041428
// Data offsets are marked by the fact that the low two bits are 0b01 0x1

src/coreclr/jit/emitarm64.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18094,6 +18094,15 @@ bool emitter::TryFoldPageOffsetIntoLdr(instruction ins, emitAttr attr, regNumber
1809418094

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

18097+
// PAGEOFFSET_12L encodes the :lo12: page offset scaled by 8, so the reloc target must be at
18098+
// least 8-byte aligned. Only fold when the VM guarantees that alignment for 'sym' (e.g. in
18099+
// NativeAOT a byte-packed non-GC static region may be only 4-byte aligned, which the linker
18100+
// rejects for R_AARCH64_LDST64_ABS_LO12_NC).
18101+
if (m_compiler->eeGetAddressAlignment(sym) < 8)
18102+
{
18103+
return false;
18104+
}
18105+
1809718106
// Drop the "add"; the preceding "adrp" already put the page base of 'sym' into reg1.
1809818107
emitRemoveLastInstruction();
1809918108

src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4525,6 +4525,17 @@ private CorInfoReloc getRelocTypeHint(void* target)
45254525
}
45264526
}
45274527

4528+
private uint getAddressAlignment(void* address)
4529+
{
4530+
if (address != null && HandleToObject(address) is IObjectNodeWithAlignment node)
4531+
{
4532+
return (uint)node.GetAlignment(_compilation.NodeFactory);
4533+
}
4534+
4535+
// Null or unknown target: report unaligned so the JIT avoids alignment-sensitive relocations.
4536+
return 1;
4537+
}
4538+
45284539
private uint getExpectedTargetArchitecture()
45294540
{
45304541
TargetArchitecture arch = _compilation.TypeSystemContext.Target.Architecture;

src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ static ICorJitInfoCallbacks()
149149
s_callbacks.getSwiftLowering = &_getSwiftLowering;
150150
s_callbacks.getFpStructLowering = &_getFpStructLowering;
151151
s_callbacks.getWasmLowering = &_getWasmLowering;
152+
s_callbacks.getAddressAlignment = &_getAddressAlignment;
152153
s_callbacks.getThreadTLSIndex = &_getThreadTLSIndex;
153154
s_callbacks.getAddrOfCaptureThreadGlobal = &_getAddrOfCaptureThreadGlobal;
154155
s_callbacks.getHelperFtn = &_getHelperFtn;
@@ -331,6 +332,7 @@ static ICorJitInfoCallbacks()
331332
public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_SWIFT_LOWERING*, void> getSwiftLowering;
332333
public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_FPSTRUCT_LOWERING*, void> getFpStructLowering;
333334
public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoWasmType> getWasmLowering;
335+
public delegate* unmanaged<IntPtr, IntPtr*, void*, uint> getAddressAlignment;
334336
public delegate* unmanaged<IntPtr, IntPtr*, void**, uint> getThreadTLSIndex;
335337
public delegate* unmanaged<IntPtr, IntPtr*, void**, int*> getAddrOfCaptureThreadGlobal;
336338
public delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, CORINFO_CONST_LOOKUP*, CORINFO_METHOD_STRUCT_**, void> getHelperFtn;
@@ -2292,6 +2294,21 @@ private static CorInfoWasmType _getWasmLowering(IntPtr thisHandle, IntPtr* ppExc
22922294
}
22932295
}
22942296

2297+
[UnmanagedCallersOnly]
2298+
private static uint _getAddressAlignment(IntPtr thisHandle, IntPtr* ppException, void* address)
2299+
{
2300+
var _this = GetThis(thisHandle);
2301+
try
2302+
{
2303+
return _this.getAddressAlignment(address);
2304+
}
2305+
catch (Exception ex)
2306+
{
2307+
*ppException = _this.AllocException(ex);
2308+
return default;
2309+
}
2310+
}
2311+
22952312
[UnmanagedCallersOnly]
22962313
private static uint _getThreadTLSIndex(IntPtr thisHandle, IntPtr* ppException, void** ppIndirection)
22972314
{

0 commit comments

Comments
 (0)