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

Commit

Permalink
Implement genProfilingEnterCallback genProfilingLeaveCallback on Arm64 (
Browse files Browse the repository at this point in the history
#26460)

* Split genProfilingEnterCallback and genProfilingLeaveCallback into architecture specific versions

* Remove redundant genStackLevel save/restore logic on Arm, Arm64, Amd64

* Implement JIT_ProfilerEnterLeaveTailcallStub in assembly

* Define RBM_PROFILER_{ENTER,LEAVE,TAILCALL}_TRASH for TARGET_ARM64

* Define REG_PROFILER_{ENTER,LEAVE}_ARG_FUNC_ID and RBM_PROFILER_{ENTER,LEAVE}_ARG_CALLER_SP

* Simplify r0Trashed logic in src/jit/codegenarm.cpp

* Remove wrong comment in src/jit/codegenarm.cpp

* On Arm genPrologPadForReJit does nothing so remove it in src/jit/codegenarm.cpp

* Implement LinearScan::BuildNode for GT_PROF_HOOK and GT_RETURN in src/jit/lsraarm64.cpp

* Shouldn't a call to CORINFO_HELP_PROF_FCN_TAILCALL be marked as a No-GC?

* Implement genProfilingEnterCallback genProfilingLeaveCallback in src/jit/codegenarm64.cpp

* Implement NYI profiler methods in src/vm/arm64/profiler.cpp

* Implement ProfileEnterNaked ProfileLeaveNaked ProfileTailcallNaked in src/vm/arm64/asmhelpers.S

* Implement profiler helpers on win-arm64

* Remove logic for !FINAL_FRAME_LAYOUT in codegenarm64.cpp

* Remove unused macro in src\jit\target.h

* genProfilingLeaveCallback ignores helper on arm in src\jit\codegenarm.cpp

* Refactor genProfilingLeaveCallback in src\jit\codegenarm.cpp
  • Loading branch information
echesakov authored Sep 20, 2019
1 parent 4da207d commit d88bc18
Show file tree
Hide file tree
Showing 16 changed files with 1,171 additions and 673 deletions.
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 @@ -1623,4 +1623,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

0 comments on commit d88bc18

Please sign in to comment.