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

Implement genProfilingEnterCallback genProfilingLeaveCallback on Arm64 #26460

Merged
merged 19 commits into from
Sep 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
3b20ac2
Split genProfilingEnterCallback and genProfilingLeaveCallback into ar…
echesakov Aug 21, 2019
97031ef
Remove redundant genStackLevel save/restore logic on Arm, Arm64, Amd64
echesakov Aug 22, 2019
017a8be
Implement JIT_ProfilerEnterLeaveTailcallStub in assembly
echesakov Aug 28, 2019
bb6ebed
Simplify r0Trashed logic in src/jit/codegenarm.cpp
echesakov Aug 28, 2019
1f94b0a
Implement NYI profiler methods in src/vm/arm64/profiler.cpp
echesakov Sep 13, 2019
ed0f5ae
Remove wrong comment in src/jit/codegenarm.cpp
echesakov Aug 28, 2019
217cc26
On Arm genPrologPadForReJit does nothing so remove it in src/jit/code…
echesakov Aug 29, 2019
10818e7
Define RBM_PROFILER_{ENTER,LEAVE,TAILCALL}_TRASH for TARGET_ARM64
echesakov Aug 28, 2019
6bf02a6
Implement genProfilingEnterCallback genProfilingLeaveCallback in src/…
echesakov Sep 12, 2019
5e7950a
Implement LinearScan::BuildNode for GT_PROF_HOOK and GT_RETURN in src…
echesakov Aug 30, 2019
a379517
Shouldn't a call to CORINFO_HELP_PROF_FCN_TAILCALL be marked as a No-GC?
echesakov Sep 12, 2019
1566546
Implement ProfileEnterNaked ProfileLeaveNaked ProfileTailcallNaked in…
echesakov Sep 14, 2019
49616e6
Implement profiler helpers on win-arm64
echesakov Sep 17, 2019
ceac8ae
Fix formatting
echesakov Sep 17, 2019
75a78f6
Fix Release build break
echesakov Sep 17, 2019
1b4ca93
Remove logic for !FINAL_FRAME_LAYOUT in codegenarm64.cpp
echesakov Sep 18, 2019
0234933
Remove unused macro in src\jit\target.h
echesakov Sep 19, 2019
358437d
genProfilingLeaveCallback ignores helper on arm in src\jit\codegenarm…
echesakov Sep 19, 2019
2f55942
Refactor genProfilingLeaveCallback in src\jit\codegenarm.cpp
echesakov Sep 19, 2019
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
2 changes: 1 addition & 1 deletion src/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ class CodeGen : public CodeGenInterface

#ifdef PROFILING_SUPPORTED
void genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed);
void genProfilingLeaveCallback(unsigned helper = CORINFO_HELP_PROF_FCN_LEAVE);
void genProfilingLeaveCallback(unsigned helper);
#endif // PROFILING_SUPPORTED

void genPrologPadForReJit();
Expand Down
149 changes: 149 additions & 0 deletions src/jit/codegenarm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1621,4 +1621,153 @@ void CodeGen::genCodeForMulLong(GenTreeMultiRegOp* node)
genProduceReg(node);
}

#ifdef PROFILING_SUPPORTED

//-----------------------------------------------------------------------------------
// genProfilingEnterCallback: Generate the profiling function enter callback.
//
// Arguments:
// initReg - register to use as scratch register
// pInitRegZeroed - OUT parameter. *pInitRegZeroed set to 'false' if 'initReg' is
// not zero after this call.
//
// Return Value:
// None
//
void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed)
{
assert(compiler->compGeneratingProlog);

// Give profiler a chance to back out of hooking this method
if (!compiler->compIsProfilerHookNeeded())
{
return;
}

// On Arm arguments are prespilled on stack, which frees r0-r3.
// For generating Enter callout we would need two registers and one of them has to be r0 to pass profiler handle.
// The call target register could be any free register.
regNumber argReg = REG_PROFILER_ENTER_ARG;
regMaskTP argRegMask = genRegMask(argReg);
assert((regSet.rsMaskPreSpillRegArg & argRegMask) != 0);

if (compiler->compProfilerMethHndIndirected)
{
getEmitter()->emitIns_R_AI(INS_ldr, EA_PTR_DSP_RELOC, argReg, (ssize_t)compiler->compProfilerMethHnd);
regSet.verifyRegUsed(argReg);
}
else
{
instGen_Set_Reg_To_Imm(EA_4BYTE, argReg, (ssize_t)compiler->compProfilerMethHnd);
}

genEmitHelperCall(CORINFO_HELP_PROF_FCN_ENTER,
0, // argSize. Again, we have to lie about it
EA_UNKNOWN); // retSize

if (initReg == argReg)
{
*pInitRegZeroed = false;
}
}

//-----------------------------------------------------------------------------------
// genProfilingLeaveCallback: Generate the profiling function leave or tailcall callback.
// Technically, this is not part of the epilog; it is called when we are generating code for a GT_RETURN node.
//
// Arguments:
// helper - which helper to call. Either CORINFO_HELP_PROF_FCN_LEAVE or CORINFO_HELP_PROF_FCN_TAILCALL
//
// Return Value:
// None
//
void CodeGen::genProfilingLeaveCallback(unsigned helper)
{
assert((helper == CORINFO_HELP_PROF_FCN_LEAVE) || (helper == CORINFO_HELP_PROF_FCN_TAILCALL));

// Only hook if profiler says it's okay.
if (!compiler->compIsProfilerHookNeeded())
{
return;
}

compiler->info.compProfilerCallback = true;

//
// Push the profilerHandle
//

// Contract between JIT and Profiler Leave callout on arm:
// Return size <= 4 bytes: REG_PROFILER_RET_SCRATCH will contain return value
// Return size > 4 and <= 8: <REG_PROFILER_RET_SCRATCH,r1> will contain return value.
// Floating point or double or HFA return values will be in s0-s15 in case of non-vararg methods.
// It is assumed that profiler Leave callback doesn't trash registers r1,REG_PROFILER_RET_SCRATCH and s0-s15.
//
// In the following cases r0 doesn't contain a return value and hence need not be preserved before emitting Leave
// callback.
bool r0InUse;
emitAttr attr = EA_UNKNOWN;

if (compiler->info.compRetType == TYP_VOID)
{
r0InUse = false;
}
else if (varTypeIsFloating(compiler->info.compRetType) ||
compiler->IsHfa(compiler->info.compMethodInfo->args.retTypeClass))
{
r0InUse = !compiler->info.compIsVarArgs && !compiler->opts.compUseSoftFP;
}
else
{
r0InUse = true;
}

if (r0InUse)
{
if (varTypeIsGC(compiler->info.compRetType))
{
attr = emitActualTypeSize(compiler->info.compRetType);
}
else
{
attr = EA_PTRSIZE;
}
}

if (r0InUse)
{
// Has a return value and r0 is in use. For emitting Leave profiler callout we would need r0 for passing
// profiler handle. Therefore, r0 is moved to REG_PROFILER_RETURN_SCRATCH as per contract.
getEmitter()->emitIns_R_R(INS_mov, attr, REG_PROFILER_RET_SCRATCH, REG_R0);
genTransferRegGCState(REG_PROFILER_RET_SCRATCH, REG_R0);
regSet.verifyRegUsed(REG_PROFILER_RET_SCRATCH);
}

if (compiler->compProfilerMethHndIndirected)
{
getEmitter()->emitIns_R_AI(INS_ldr, EA_PTR_DSP_RELOC, REG_R0, (ssize_t)compiler->compProfilerMethHnd);
}
else
{
instGen_Set_Reg_To_Imm(EA_PTRSIZE, REG_R0, (ssize_t)compiler->compProfilerMethHnd);
}

gcInfo.gcMarkRegSetNpt(RBM_R0);
regSet.verifyRegUsed(REG_R0);

genEmitHelperCall(helper,
0, // argSize
EA_UNKNOWN); // retSize

// Restore state that existed before profiler callback
if (r0InUse)
{
getEmitter()->emitIns_R_R(INS_mov, attr, REG_R0, REG_PROFILER_RET_SCRATCH);
genTransferRegGCState(REG_R0, REG_PROFILER_RET_SCRATCH);
gcInfo.gcMarkRegSetNpt(RBM_PROFILER_RET_SCRATCH);
}
}

#endif // PROFILING_SUPPORTED

#endif // _TARGET_ARM_
90 changes: 90 additions & 0 deletions src/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5883,6 +5883,96 @@ void CodeGen::genHWIntrinsicShaRotateOp(GenTreeHWIntrinsic* node)

#endif // FEATURE_HW_INTRINSICS

#ifdef PROFILING_SUPPORTED

//-----------------------------------------------------------------------------------
// genProfilingEnterCallback: Generate the profiling function enter callback.
//
// Arguments:
// initReg - register to use as scratch register
// pInitRegZeroed - OUT parameter. *pInitRegZeroed set to 'false' if 'initReg' is
// not zero after this call.
//
// Return Value:
// None
//
void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed)
{
assert(compiler->compGeneratingProlog);

if (!compiler->compIsProfilerHookNeeded())
{
return;
}

if (compiler->compProfilerMethHndIndirected)
{
instGen_Set_Reg_To_Imm(EA_PTR_DSP_RELOC, REG_PROFILER_ENTER_ARG_FUNC_ID,
(ssize_t)compiler->compProfilerMethHnd);
getEmitter()->emitIns_R_R(INS_ldr, EA_PTRSIZE, REG_PROFILER_ENTER_ARG_FUNC_ID, REG_PROFILER_ENTER_ARG_FUNC_ID);
}
else
{
genSetRegToIcon(REG_PROFILER_ENTER_ARG_FUNC_ID, (ssize_t)compiler->compProfilerMethHnd, TYP_I_IMPL);
}

int callerSPOffset = compiler->lvaToCallerSPRelativeOffset(0, isFramePointerUsed());
genInstrWithConstant(INS_add, EA_PTRSIZE, REG_PROFILER_ENTER_ARG_CALLER_SP, genFramePointerReg(),
(ssize_t)(-callerSPOffset), REG_PROFILER_ENTER_ARG_CALLER_SP);

genEmitHelperCall(CORINFO_HELP_PROF_FCN_ENTER, 0, EA_UNKNOWN);

if ((genRegMask(initReg) & RBM_PROFILER_ENTER_TRASH) != RBM_NONE)
{
*pInitRegZeroed = false;
}
}

//-----------------------------------------------------------------------------------
// genProfilingLeaveCallback: Generate the profiling function leave or tailcall callback.
// Technically, this is not part of the epilog; it is called when we are generating code for a GT_RETURN node.
//
// Arguments:
// helper - which helper to call. Either CORINFO_HELP_PROF_FCN_LEAVE or CORINFO_HELP_PROF_FCN_TAILCALL
//
// Return Value:
// None
//
void CodeGen::genProfilingLeaveCallback(unsigned helper)
{
assert((helper == CORINFO_HELP_PROF_FCN_LEAVE) || (helper == CORINFO_HELP_PROF_FCN_TAILCALL));

if (!compiler->compIsProfilerHookNeeded())
{
return;
}

compiler->info.compProfilerCallback = true;

if (compiler->compProfilerMethHndIndirected)
{
instGen_Set_Reg_To_Imm(EA_PTR_DSP_RELOC, REG_PROFILER_LEAVE_ARG_FUNC_ID,
(ssize_t)compiler->compProfilerMethHnd);
getEmitter()->emitIns_R_R(INS_ldr, EA_PTRSIZE, REG_PROFILER_LEAVE_ARG_FUNC_ID, REG_PROFILER_LEAVE_ARG_FUNC_ID);
}
else
{
genSetRegToIcon(REG_PROFILER_LEAVE_ARG_FUNC_ID, (ssize_t)compiler->compProfilerMethHnd, TYP_I_IMPL);
}

gcInfo.gcMarkRegSetNpt(RBM_PROFILER_LEAVE_ARG_FUNC_ID);

int callerSPOffset = compiler->lvaToCallerSPRelativeOffset(0, isFramePointerUsed());
genInstrWithConstant(INS_add, EA_PTRSIZE, REG_PROFILER_LEAVE_ARG_CALLER_SP, genFramePointerReg(),
(ssize_t)(-callerSPOffset), REG_PROFILER_LEAVE_ARG_CALLER_SP);

gcInfo.gcMarkRegSetNpt(RBM_PROFILER_LEAVE_ARG_CALLER_SP);

genEmitHelperCall(helper, 0, EA_UNKNOWN);
}

#endif // PROFILING_SUPPORTED

/*****************************************************************************
* Unit testing of the ARM64 emitter: generate a bunch of instructions into the prolog
* (it's as good a place as any), then use COMPlus_JitLateDisasm=* to see if the late
Expand Down
Loading