Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 6f69c6d

Browse files
committed
Merge pull request #5020 from kyulee1/imp
ARM64: Enable End-To-End ReadyToRun (R2R) Crossgen
2 parents f1d6f7a + 3165d8e commit 6f69c6d

File tree

8 files changed

+88
-47
lines changed

8 files changed

+88
-47
lines changed

src/jit/codegenarm64.cpp

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6842,39 +6842,31 @@ void CodeGen::genEmitHelperCall(unsigned helper,
68426842

68436843
if (addr == nullptr)
68446844
{
6845-
NYI("genEmitHelperCall indirect");
6846-
#if 0
6847-
assert(pAddr != nullptr);
6848-
if (genAddrCanBeEncodedAsPCRelOffset((size_t)pAddr))
6845+
// This is call to a runtime helper.
6846+
// adrp x, [reloc:rel page addr]
6847+
// add x, x, [reloc:page offset]
6848+
// ldr x, [x]
6849+
// br x
6850+
6851+
if (callTargetReg == REG_NA)
68496852
{
6850-
// generate call whose target is specified by PC-relative 32-bit offset.
6851-
callType = emitter::EC_FUNC_TOKEN_INDIR;
6852-
addr = pAddr;
6853+
// If a callTargetReg has not been explicitly provided, we will use REG_DEFAULT_HELPER_CALL_TARGET, but
6854+
// this is only a valid assumption if the helper call is known to kill REG_DEFAULT_HELPER_CALL_TARGET.
6855+
callTargetReg = REG_DEFAULT_HELPER_CALL_TARGET;
68536856
}
6854-
else
6855-
{
6856-
// If this address cannot be encoded as PC-relative 32-bit offset, load it into REG_HELPER_CALL_TARGET
6857-
// and use register indirect addressing mode to make the call.
6858-
// mov reg, addr
6859-
// call [reg]
6860-
if (callTargetReg == REG_NA)
6861-
{
6862-
// If a callTargetReg has not been explicitly provided, we will use REG_DEFAULT_HELPER_CALL_TARGET, but
6863-
// this is only a valid assumption if the helper call is known to kill REG_DEFAULT_HELPER_CALL_TARGET.
6864-
callTargetReg = REG_DEFAULT_HELPER_CALL_TARGET;
6865-
}
68666857

6867-
regMaskTP callTargetMask = genRegMask(callTargetReg);
6868-
regMaskTP callKillSet = compiler->compHelperCallKillSet((CorInfoHelpFunc)helper);
6858+
regMaskTP callTargetMask = genRegMask(callTargetReg);
6859+
regMaskTP callKillSet = compiler->compHelperCallKillSet((CorInfoHelpFunc)helper);
68696860

6870-
// assert that all registers in callTargetMask are in the callKillSet
6871-
noway_assert((callTargetMask & callKillSet) == callTargetMask);
6861+
// assert that all registers in callTargetMask are in the callKillSet
6862+
noway_assert((callTargetMask & callKillSet) == callTargetMask);
68726863

6873-
callTarget = callTargetReg;
6874-
CodeGen::genSetRegToIcon(callTarget, (ssize_t) pAddr, TYP_I_IMPL);
6875-
callType = emitter::EC_INDIR_ARD;
6876-
}
6877-
#endif // 0
6864+
callTarget = callTargetReg;
6865+
6866+
// adrp + add with relocations will be emitted
6867+
getEmitter()->emitIns_R_AI(INS_adrp, EA_PTR_DSP_RELOC, callTarget, (ssize_t)pAddr);
6868+
getEmitter()->emitIns_R_R(INS_ldr, EA_PTRSIZE, callTarget, callTarget);
6869+
callType = emitter::EC_INDIR_R;
68786870
}
68796871

68806872
getEmitter()->emitIns_Call(callType,

src/jit/flowgraph.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7047,6 +7047,8 @@ GenTreePtr Compiler::fgOptimizeDelegateConstructor(GenTreePtr call, CORINFO_C
70477047
info.compCompHnd->getReadyToRunHelper(targetMethod->gtFptrVal.gtLdftnResolvedToken,
70487048
CORINFO_HELP_READYTORUN_DELEGATE_CTOR, &call->gtCall.gtEntryPoint);
70497049
#endif
7050+
// This is the case from GetDynamicHelperCell.
7051+
call->gtCall.setR2RRelativeIndir();
70507052
}
70517053
}
70527054
else

src/jit/gentree.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4464,6 +4464,15 @@ unsigned Compiler::gtSetEvalOrder(GenTree * tree)
44644464
ftreg |= RBM_VIRTUAL_STUB_PARAM;
44654465
}
44664466

4467+
#ifdef FEATURE_READYTORUN_COMPILER
4468+
#ifdef _TARGET_ARM64_
4469+
if (tree->gtCall.IsR2RRelativeIndir())
4470+
{
4471+
ftreg |= RBM_R2R_INDIRECT_PARAM;
4472+
}
4473+
#endif
4474+
#endif
4475+
44674476
// Normally function calls don't preserve caller save registers
44684477
// and thus are much more expensive.
44694478
// However a few function calls do preserve these registers
@@ -7403,6 +7412,10 @@ Compiler::gtDispNodeName(GenTree *tree)
74037412
gtfType = " ind";
74047413
else if (tree->gtFlags & GTF_CALL_VIRT_STUB)
74057414
gtfType = " stub";
7415+
#ifdef FEATURE_READYTORUN_COMPILER
7416+
else if (tree->gtCall.IsR2RRelativeIndir())
7417+
gtfType = " r2r_ind";
7418+
#endif // FEATURE_READYTORUN_COMPILER
74067419
else if (tree->gtFlags & GTF_CALL_UNMANAGED)
74077420
{
74087421
char * gtfTypeBufWalk = gtfTypeBuf;

src/jit/gentree.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2762,6 +2762,8 @@ struct GenTreeCall final : public GenTree
27622762
// a Pinvoke but not as an unmanaged call. See impCheckForPInvokeCall() to
27632763
// know when these flags are set.
27642764

2765+
#define GTF_CALL_M_R2R_REL_INDIRECT 0x2000 // GT_CALL -- ready to run call is indirected through a relative address
2766+
27652767
bool IsUnmanaged() { return (gtFlags & GTF_CALL_UNMANAGED) != 0; }
27662768
bool NeedsNullCheck() { return (gtFlags & GTF_CALL_NULLCHECK) != 0; }
27672769
bool CallerPop() { return (gtFlags & GTF_CALL_POP_ARGS) != 0; }
@@ -2870,6 +2872,15 @@ struct GenTreeCall final : public GenTree
28702872
bool IsSameThis() { return (gtCallMoreFlags & GTF_CALL_M_NONVIRT_SAME_THIS) != 0; }
28712873
bool IsDelegateInvoke(){ return (gtCallMoreFlags & GTF_CALL_M_DELEGATE_INV) != 0; }
28722874
bool IsVirtualStubRelativeIndir() { return (gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT) != 0; }
2875+
#ifdef FEATURE_READYTORUN_COMPILER
2876+
bool IsR2RRelativeIndir() { return (gtCallMoreFlags & GTF_CALL_M_R2R_REL_INDIRECT) != 0; }
2877+
void setR2RRelativeIndir() {
2878+
if (gtEntryPoint.accessType == IAT_PVALUE)
2879+
{
2880+
gtCallMoreFlags |= GTF_CALL_M_R2R_REL_INDIRECT;
2881+
}
2882+
}
2883+
#endif // FEATURE_READYTORUN_COMPILER
28732884
bool IsVarargs() { return (gtCallMoreFlags & GTF_CALL_M_VARARGS) != 0; }
28742885

28752886
unsigned short gtCallMoreFlags; // in addition to gtFlags

src/jit/importer.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1647,6 +1647,9 @@ GenTreePtr Compiler::impReadyToRunHelperToTree(
16471647

16481648
op1->gtCall.gtEntryPoint = lookup;
16491649

1650+
// This is the case from GetDynamicHelperCell.
1651+
op1->gtCall.setR2RRelativeIndir();
1652+
16501653
return op1;
16511654
}
16521655
#endif
@@ -4519,6 +4522,8 @@ GenTreePtr Compiler::impImportLdvirtftn (GenTreePtr thisPtr,
45194522

45204523
call->gtEntryPoint = pCallInfo->codePointerLookup.constLookup;
45214524

4525+
// This is the case from GetDynamicHelperCell.
4526+
call->setR2RRelativeIndir();
45224527
return call;
45234528
}
45244529
#endif
@@ -5192,6 +5197,9 @@ GenTreePtr Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN * pResolv
51925197
op1 = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_STATIC_BASE, TYP_BYREF, callFlags);
51935198

51945199
op1->gtCall.gtEntryPoint = pFieldInfo->fieldLookup;
5200+
5201+
// This is the case from GetDynamicHelperCell.
5202+
op1->gtCall.setR2RRelativeIndir();
51955203
}
51965204
else
51975205
#endif
@@ -6028,6 +6036,9 @@ var_types Compiler::impImportCall (OPCODE opcode,
60286036
if (opts.IsReadyToRun())
60296037
{
60306038
call->gtCall.gtEntryPoint = callInfo->codePointerLookup.constLookup;
6039+
6040+
// This is the case from GetExternalMethodCell.
6041+
call->gtCall.setR2RRelativeIndir();
60316042
}
60326043
#endif
60336044
break;

src/jit/lower.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2389,10 +2389,26 @@ GenTree* Lowering::LowerDirectCall(GenTreeCall* call)
23892389
break;
23902390

23912391
case IAT_PVALUE:
2392+
{
23922393
// Non-virtual direct calls to addresses accessed by
23932394
// a single indirection.
2394-
result = Ind(AddrGen(addr));
2395+
GenTree* cellAddr = AddrGen(addr);
2396+
GenTree* indir = Ind(cellAddr);
2397+
2398+
#ifdef FEATURE_READYTORUN_COMPILER
2399+
#ifdef _TARGET_ARM64_
2400+
// For arm64, we dispatch code same as VSD using X11 for indirection cell address,
2401+
// which ZapIndirectHelperThunk expects.
2402+
if (call->IsR2RRelativeIndir())
2403+
{
2404+
cellAddr->gtRegNum = REG_R2R_INDIRECT_PARAM;
2405+
indir->gtRegNum = REG_JUMP_THUNK_PARAM;
2406+
}
2407+
#endif
2408+
#endif
2409+
result = indir;
23952410
break;
2411+
}
23962412

23972413
case IAT_PPVALUE:
23982414
// Non-virtual direct calls to addresses accessed by

src/jit/target.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,7 @@ typedef unsigned short regPairNoSmall; // arm: need 12 bits
15141514
#define RBM_CALLEE_SAVED (RBM_INT_CALLEE_SAVED | RBM_FLT_CALLEE_SAVED)
15151515
#define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
15161516
#define RBM_CALLEE_TRASH_NOGC (RBM_R12|RBM_R13|RBM_R14|RBM_R15)
1517+
#define REG_DEFAULT_HELPER_CALL_TARGET REG_R12
15171518

15181519
#define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
15191520
#define RBM_ALLFLOAT (RBM_FLT_CALLEE_SAVED | RBM_FLT_CALLEE_TRASH)
@@ -1606,6 +1607,11 @@ typedef unsigned short regPairNoSmall; // arm: need 12 bits
16061607
#define RBM_VIRTUAL_STUB_PARAM RBM_R11
16071608
#define PREDICT_REG_VIRTUAL_STUB_PARAM PREDICT_REG_R11
16081609

1610+
// R2R indirect call. Use the same registers as VSD
1611+
#define REG_R2R_INDIRECT_PARAM REG_R11
1612+
#define RBM_R2R_INDIRECT_PARAM RBM_R11
1613+
#define PREDICT_REG_RER_INDIRECT_PARAM PREDICT_REG_R11
1614+
16091615
// Registers used by PInvoke frame setup
16101616
#define REG_PINVOKE_FRAME REG_R8
16111617
#define RBM_PINVOKE_FRAME RBM_R8

src/zap/zapimport.cpp

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2146,17 +2146,8 @@ DWORD ZapIndirectHelperThunk::SaveWorker(ZapWriter * pZapWriter)
21462146
#elif defined(_TARGET_ARM64_)
21472147
if (IsDelayLoadHelper())
21482148
{
2149-
if (IsVSD())
2150-
{
2151-
// x11 contains indirection cell
2152-
// Do nothing x11 contains our first param
2153-
}
2154-
else
2155-
{
2156-
// mov x11, x12
2157-
*(DWORD*)p = 0xaa0c03eb;
2158-
p += 4;
2159-
}
2149+
// x11 contains indirection cell
2150+
// Do nothing x11 contains our first param
21602151

21612152
// movz x8, #index
21622153
DWORD index = GetSectionIndex();
@@ -2166,9 +2157,9 @@ DWORD ZapIndirectHelperThunk::SaveWorker(ZapWriter * pZapWriter)
21662157

21672158
// move Module* -> x9
21682159
// ldr x9, [PC+0x14]
2169-
*(DWORD*)p = 0x58000289;
2160+
*(DWORD*)p = 0x580000A9;
21702161
p += 4;
2171-
2162+
21722163
//ldr x9, [x9]
21732164
*(DWORD*)p = 0xf9400129;
21742165
p += 4;
@@ -2178,7 +2169,7 @@ DWORD ZapIndirectHelperThunk::SaveWorker(ZapWriter * pZapWriter)
21782169
{
21792170
// Move Module* -> x1
21802171
// ldr x1, [PC+0x14]
2181-
*(DWORD*)p = 0x58000289;
2172+
*(DWORD*)p = 0x580000A1;
21822173
p += 4;
21832174

21842175
// ldr x1, [x1]
@@ -2187,10 +2178,8 @@ DWORD ZapIndirectHelperThunk::SaveWorker(ZapWriter * pZapWriter)
21872178
}
21882179

21892180
// branch to helper
2190-
2191-
// mov x12, [helper]
21922181
// ldr x12, [PC+0x14]
2193-
*(DWORD*)p = 0x58000289;
2182+
*(DWORD*)p = 0x580000AC;
21942183
p += 4;
21952184

21962185
// ldr x12, [x12]
@@ -2199,12 +2188,13 @@ DWORD ZapIndirectHelperThunk::SaveWorker(ZapWriter * pZapWriter)
21992188

22002189
// br x12
22012190
*(DWORD *)p = 0xd61f0180;
2202-
p += 4;
2191+
p += 4;
22032192

22042193
// [Module*]
22052194
if (pImage != NULL)
22062195
pImage->WriteReloc(buffer, (int)(p - buffer), pImage->GetImportTable()->GetHelperImport(READYTORUN_HELPER_Module), 0, IMAGE_REL_BASED_PTR);
22072196
p += 8;
2197+
22082198
// [helper]
22092199
if (pImage != NULL)
22102200
pImage->WriteReloc(buffer, (int)(p - buffer), pImage->GetImportTable()->GetHelperImport(GetReadyToRunHelper()), 0, IMAGE_REL_BASED_PTR);

0 commit comments

Comments
 (0)