}
else
{
-#ifdef _TARGET_AMD64_
- if (AddrShouldUsePCRel(imm))
- {
- getEmitter()->emitIns_R_AI(INS_lea, EA_PTR_DSP_RELOC, reg, imm);
- }
- else
-#endif // _TARGET_AMD64_
- {
- getEmitter()->emitIns_R_I(INS_mov, size, reg, imm);
- }
+ getEmitter()->emitIns_R_I(INS_mov, size, reg, imm);
}
regTracker.rsTrackRegIntCns(reg, imm);
}
#endif
case CORINFO_HELP_PROF_FCN_ENTER:
-#ifdef _TARGET_AMD64_
+#ifdef RBM_PROFILER_ENTER_TRASH
return RBM_PROFILER_ENTER_TRASH;
#else
- unreached();
+ NYI("Model kill set for CORINFO_HELP_PROF_FCN_ENTER on target arch");
#endif
+
case CORINFO_HELP_PROF_FCN_LEAVE:
- case CORINFO_HELP_PROF_FCN_TAILCALL:
-#ifdef _TARGET_AMD64_
+#ifdef RBM_PROFILER_LEAVE_TRASH
return RBM_PROFILER_LEAVE_TRASH;
#else
- unreached();
+ NYI("Model kill set for CORINFO_HELP_PROF_FCN_LEAVE on target arch");
+#endif
+
+ case CORINFO_HELP_PROF_FCN_TAILCALL:
+#ifdef RBM_PROFILER_TAILCALL_TRASH
+ return RBM_PROFILER_TAILCALL_TRASH;
+#else
+ NYI("Model kill set for CORINFO_HELP_PROF_FCN_TAILCALL on target arch");
#endif
case CORINFO_HELP_STOP_FOR_GC:
regMaskTP Compiler::compNoGCHelperCallKillSet(CorInfoHelpFunc helper)
{
assert(emitter::emitNoGChelper(helper));
-#ifdef _TARGET_AMD64_
+
switch (helper)
{
+#if defined(_TARGET_AMD64_) || defined(_TARGET_X86_)
case CORINFO_HELP_PROF_FCN_ENTER:
return RBM_PROFILER_ENTER_TRASH;
case CORINFO_HELP_PROF_FCN_LEAVE:
- case CORINFO_HELP_PROF_FCN_TAILCALL:
return RBM_PROFILER_LEAVE_TRASH;
+ case CORINFO_HELP_PROF_FCN_TAILCALL:
+ return RBM_PROFILER_TAILCALL_TRASH;
+#endif // defined(_TARGET_AMD64_) || defined(_TARGET_X86_)
+
+#if defined(_TARGET_AMD64_)
case CORINFO_HELP_ASSIGN_BYREF:
// this helper doesn't trash RSI and RDI
return RBM_CALLEE_TRASH_NOGC & ~(RBM_RSI | RBM_RDI);
+#endif // defined(_TARGET_AMD64_)
default:
return RBM_CALLEE_TRASH_NOGC;
}
-#else
- return RBM_CALLEE_TRASH_NOGC;
-#endif
}
// Update liveness (always var liveness, i.e., compCurLife, and also, if "ForCodeGen" is true, reg liveness, i.e.,
#ifdef PROFILING_SUPPORTED
-/*-----------------------------------------------------------------------------
- *
- * Generate the profiling function enter callback.
- */
-
+//-----------------------------------------------------------------------------------
+// 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
+//
+// Notes:
+// The x86 profile enter helper has the following requirements (see ProfileEnterNaked in
+// VM\i386\asmhelpers.asm for details):
+// 1. The calling sequence for calling the helper is:
+// push FunctionIDOrClientID
+// call ProfileEnterHelper
+// 2. The calling function has an EBP frame.
+// 3. EBP points to the saved ESP which is the first thing saved in the function. Thus,
+// the following prolog is assumed:
+// push ESP
+// mov EBP, ESP
+// 4. All registers are preserved.
+// 5. The helper pops the FunctionIDOrClientID argument from the stack.
+//
void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed)
{
assert(compiler->compGeneratingProlog);
return;
}
-#ifndef LEGACY_BACKEND
#if defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI) // No profiling for System V systems yet.
unsigned varNum;
LclVarDsc* varDsc;
else
{
// No need to record relocations, if we are generating ELT hooks under the influence
- // of complus_JitELtHookEnabled=1
+ // of COMPlus_JitELTHookEnabled=1
if (compiler->opts.compJitELTHookEnabled)
{
genSetRegToIcon(REG_ARG_0, (ssize_t)compiler->compProfilerMethHnd, TYP_I_IMPL);
*pInitRegZeroed = false;
}
-#else //!_TARGET_AMD64_
- NYI("RyuJIT: Emit Profiler Enter callback");
-#endif
-
-#else // LEGACY_BACKEND
+#elif defined(_TARGET_X86_) || (defined(_TARGET_ARM_) && defined(LEGACY_BACKEND))
unsigned saveStackLvl2 = genStackLevel;
/* Restore the stack level */
genStackLevel = saveStackLvl2;
-#endif // LEGACY_BACKEND
-}
-/*****************************************************************************
- *
- * Generates Leave profiler hook.
- * Technically, this is not part of the epilog; it is called when we are generating code for a GT_RETURN node.
- */
+#else // target
+ NYI("Emit Profiler Enter callback");
+#endif // target
+}
+//-----------------------------------------------------------------------------------
+// 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
+//
+// Notes:
+// The x86 profile leave/tailcall helper has the following requirements (see ProfileLeaveNaked and
+// ProfileTailcallNaked in VM\i386\asmhelpers.asm for details):
+// 1. The calling sequence for calling the helper is:
+// push FunctionIDOrClientID
+// call ProfileLeaveHelper or ProfileTailcallHelper
+// 2. The calling function has an EBP frame.
+// 3. EBP points to the saved ESP which is the first thing saved in the function. Thus,
+// the following prolog is assumed:
+// push ESP
+// mov EBP, ESP
+// 4. helper == CORINFO_HELP_PROF_FCN_LEAVE: All registers are preserved.
+// helper == CORINFO_HELP_PROF_FCN_TAILCALL: Only argument registers are preserved.
+// 5. The helper pops the FunctionIDOrClientID argument from the stack.
+//
void CodeGen::genProfilingLeaveCallback(unsigned helper /*= CORINFO_HELP_PROF_FCN_LEAVE*/)
{
+ assert((helper == CORINFO_HELP_PROF_FCN_LEAVE) || (helper == CORINFO_HELP_PROF_FCN_TAILCALL));
+
// Only hook if profiler says it's okay.
if (!compiler->compIsProfilerHookNeeded())
{
compiler->info.compProfilerCallback = true;
- // Need to save on to the stack level, since the callee will pop the argument
+ // Need to save on to the stack level, since the helper call will pop the argument
unsigned saveStackLvl2 = genStackLevel;
-#ifndef LEGACY_BACKEND
-
#if defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI) // No profiling for System V systems yet.
+
// Since the method needs to make a profiler callback, it should have out-going arg space allocated.
noway_assert(compiler->lvaOutgoingArgSpaceVar != BAD_VAR_NUM);
noway_assert(compiler->lvaOutgoingArgSpaceSize >= (4 * REGSIZE_BYTES));
else
{
// Don't record relocations, if we are generating ELT hooks under the influence
- // of complus_JitELtHookEnabled=1
+ // of COMPlus_JitELTHookEnabled=1
if (compiler->opts.compJitELTHookEnabled)
{
genSetRegToIcon(REG_ARG_0, (ssize_t)compiler->compProfilerMethHnd, TYP_I_IMPL);
// "mov r8, helper addr; call r8"
genEmitHelperCall(helper, 0, EA_UNKNOWN, REG_ARG_2);
-#else //!_TARGET_AMD64_
- NYI("RyuJIT: Emit Profiler Leave callback");
-#endif // _TARGET_*
-
-#else // LEGACY_BACKEND
+#elif defined(_TARGET_X86_)
-#if defined(_TARGET_X86_)
//
// Push the profilerHandle
//
}
genSinglePush();
- genEmitHelperCall(CORINFO_HELP_PROF_FCN_LEAVE,
+ genEmitHelperCall(helper,
sizeof(int) * 1, // argSize
EA_UNKNOWN); // retSize
{
compiler->fgPtrArgCntMax = 1;
}
-#elif defined(_TARGET_ARM_)
+
+#elif defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
+
//
// Push the profilerHandle
//
}
regSet.rsUnlockReg(RBM_PROFILER_RET_USED);
-#else // _TARGET_*
- NYI("Pushing the profilerHandle & caller's sp for the profiler callout and locking them");
-#endif // _TARGET_*
-#endif // LEGACY_BACKEND
+#else // target
+ NYI("Emit Profiler Leave callback");
+#endif // target
/* Restore the stack level */
genStackLevel = saveStackLvl2;
//
// Reason for not materializing Leave callback as a GT_PROF_HOOK node after GT_RETURN:
// In flowgraph and other places assert that the last node of a block marked as
- // GT_RETURN is either a GT_RETURN or GT_JMP or a tail call. It would be nice to
+ // BBJ_RETURN is either a GT_RETURN or GT_JMP or a tail call. It would be nice to
// maintain such an invariant irrespective of whether profiler hook needed or not.
// Also, there is not much to be gained by materializing it as an explicit node.
if (compiler->compCurBB == compiler->genReturnBB)
opts.compTailCallLoopOpt = true;
#endif
-#ifdef DEBUG
- opts.dspInstrs = false;
- opts.dspEmit = false;
- opts.dspLines = false;
- opts.varNames = false;
- opts.dmpHex = false;
- opts.disAsm = false;
- opts.disAsmSpilled = false;
- opts.disDiffable = false;
- opts.dspCode = false;
- opts.dspEHTable = false;
- opts.dspGCtbls = false;
- opts.disAsm2 = false;
- opts.dspUnwind = false;
- opts.compLongAddress = false;
+#ifdef PROFILING_SUPPORTED
opts.compJitELTHookEnabled = false;
+#endif // PROFILING_SUPPORTED
+
+#ifdef DEBUG
+ opts.dspInstrs = false;
+ opts.dspEmit = false;
+ opts.dspLines = false;
+ opts.varNames = false;
+ opts.dmpHex = false;
+ opts.disAsm = false;
+ opts.disAsmSpilled = false;
+ opts.disDiffable = false;
+ opts.dspCode = false;
+ opts.dspEHTable = false;
+ opts.dspGCtbls = false;
+ opts.disAsm2 = false;
+ opts.dspUnwind = false;
+ opts.compLongAddress = false;
#ifdef LATE_DISASM
opts.doLateDisasm = false;
compProfilerMethHndIndirected = false;
}
-#if defined(_TARGET_ARM_) || defined(_TARGET_AMD64_)
- // Right now this ELT hook option is enabled only for arm and amd64
-
- // Honour complus_JitELTHookEnabled only if VM has not asked us to generate profiler
- // hooks in the first place. That is, Override VM only if it hasn't asked for a
+ // Honour COMPlus_JitELTHookEnabled only if VM has not asked us to generate profiler
+ // hooks in the first place. That is, override VM only if it hasn't asked for a
// profiler callback for this method.
if (!compProfilerHookNeeded && (JitConfig.JitELTHookEnabled() != 0))
{
compProfilerMethHnd = (void*)DummyProfilerELTStub;
compProfilerMethHndIndirected = false;
}
-#endif // _TARGET_ARM_ || _TARGET_AMD64_
#endif // PROFILING_SUPPORTED
// for any call. We have a plan for not needing for stubs though
bool compNeedStackProbes;
- // Whether to emit Enter/Leave/TailCall hooks using a dummy stub (DummyProfilerELTStub())
- // This options helps one to make JIT behave as if it is under profiler.
+#ifdef PROFILING_SUPPORTED
+ // Whether to emit Enter/Leave/TailCall hooks using a dummy stub (DummyProfilerELTStub()).
+ // This option helps make the JIT behave as if it is running under a profiler.
bool compJitELTHookEnabled;
+#endif // PROFILING_SUPPORTED
#if FEATURE_TAILCALL_OPT
// Whether opportunistic or implicit tail call optimization is enabled.
#endif
void compCompile(void** methodCodePtr, ULONG* methodCodeSize, CORJIT_FLAGS* compileFlags);
+#ifdef PROFILING_SUPPORTED
// Data required for generating profiler Enter/Leave/TailCall hooks
- CLANG_FORMAT_COMMENT_ANCHOR;
-#ifdef PROFILING_SUPPORTED
bool compProfilerHookNeeded; // Whether profiler Enter/Leave/TailCall hook needs to be generated for the method
void* compProfilerMethHnd; // Profiler handle of the method being compiled. Passed as param to ELT callbacks
bool compProfilerMethHndIndirected; // Whether compProfilerHandle is pointer to the handle or is an actual handle
#endif
+
#ifdef _TARGET_AMD64_
bool compQuirkForPPP(); // Check if this method should be Quirked for the PPP issue
#endif
{
#ifdef PROFILING_SUPPORTED
return compProfilerHookNeeded
-
-#if defined(_TARGET_ARM_) || defined(_TARGET_AMD64_)
// IL stubs are excluded by VM and we need to do the same even running
// under a complus env hook to generate profiler hooks
- || (opts.compJitELTHookEnabled && !(opts.eeFlags & CORJIT_FLG_IL_STUB))
-#endif
- ;
-#else // PROFILING_SUPPORTED
+ || (opts.compJitELTHookEnabled && !(opts.eeFlags & CORJIT_FLG_IL_STUB));
+#else // !PROFILING_SUPPORTED
return false;
-#endif
+#endif // !PROFILING_SUPPORTED
}
/*****************************************************************************
case CORINFO_HELP_PROF_FCN_LEAVE:
case CORINFO_HELP_PROF_FCN_ENTER:
-#ifdef _TARGET_AMD64_
+#if defined(_TARGET_AMD64_) || (defined(_TARGET_X86_) && !defined(LEGACY_BACKEND))
case CORINFO_HELP_PROF_FCN_TAILCALL:
#endif
case CORINFO_HELP_LLSH:
#ifdef _MSC_VER
// These don't seem useful, so turning them off is no big deal
+#pragma warning(disable : 4065) // "switch statement contains 'default' but no 'case' labels" (happens due to #ifdefs)
#pragma warning(disable : 4510) // can't generate default constructor
#pragma warning(disable : 4511) // can't generate copy constructor
#pragma warning(disable : 4512) // can't generate assignment constructor
CONFIG_INTEGER(DisplayMemStats, W("JitMemStats"), 0) // Display JIT memory usage statistics
CONFIG_INTEGER(JitAggressiveInlining, W("JitAggressiveInlining"), 0) // Aggressive inlining of all methods
-CONFIG_INTEGER(JitELTHookEnabled, W("JitELTHookEnabled"), 0) // On ARM, setting this will emit Enter/Leave/TailCall
- // callbacks
+CONFIG_INTEGER(JitELTHookEnabled, W("JitELTHookEnabled"), 0) // If 1, emit Enter/Leave/TailCall callbacks
CONFIG_INTEGER(JitInlineSIMDMultiplier, W("JitInlineSIMDMultiplier"), 3)
#if defined(FEATURE_ENABLE_NO_RANGE_CHECKS)
// Inserts profiler hook, GT_PROF_HOOK for a tail call node.
//
+// AMD64:
// We need to insert this after all nested calls, but before all the arguments to this call have been set up.
// To do this, we look for the first GT_PUTARG_STK or GT_PUTARG_REG, and insert the hook immediately before
// that. If there are no args, then it should be inserted before the call node.
// In this case, the GT_PUTARG_REG src is a nested call. We need to put the instructions after that call
// (as shown). We assume that of all the GT_PUTARG_*, only the first one can have a nested call.
//
+// X86:
+// Insert the profiler hook immediately before the call. The profiler hook will preserve
+// all argument registers (ECX, EDX), but nothing else.
+//
// Params:
// callNode - tail call node
-// insertionPoint - if caller has an insertion point; If null
-// profiler hook is inserted before args are setup
+// insertionPoint - if non-null, insert the profiler hook before this point.
+// If null, insert the profiler hook before args are setup
// but after all arg side effects are computed.
+//
void Lowering::InsertProfTailCallHook(GenTreeCall* call, GenTree* insertionPoint)
{
assert(call->IsTailCall());
assert(comp->compIsProfilerHookNeeded());
+#if defined(_TARGET_X86_)
+
+ if (insertionPoint == nullptr)
+ {
+ insertionPoint = call;
+ }
+
+#else // !defined(_TARGET_X86_)
+
if (insertionPoint == nullptr)
{
GenTreePtr tmp = nullptr;
}
}
+#endif // !defined(_TARGET_X86_)
+
assert(insertionPoint != nullptr);
GenTreePtr profHookNode = new (comp, GT_PROF_HOOK) GenTree(GT_PROF_HOOK, TYP_VOID);
BlockRange().InsertBefore(insertionPoint, profHookNode);
// Now add back tail call flags for identifying this node as tail call dispatched via helper.
call->gtCallMoreFlags |= GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_HELPER;
+#ifdef PROFILING_SUPPORTED
// Insert profiler tail call hook if needed.
// Since we don't know the insertion point, pass null for second param.
if (comp->compIsProfilerHookNeeded())
{
InsertProfTailCallHook(call, nullptr);
}
+#endif // PROFILING_SUPPORTED
+
+ assert(call->IsTailCallViaHelper());
return result;
}
}
break;
-#if defined(PROFILING_SUPPORTED) && defined(_TARGET_AMD64_)
+#if defined(PROFILING_SUPPORTED)
// If this method requires profiler ELT hook then mark these nodes as killing
// callee trash registers (excluding RAX and XMM0). The reason for this is that
// profiler callback would trash these registers. See vm\amd64\asmhelpers.asm for
if (compiler->compIsProfilerHookNeeded())
{
killMask = compiler->compHelperCallKillSet(CORINFO_HELP_PROF_FCN_TAILCALL);
- ;
}
break;
-#endif // PROFILING_SUPPORTED && _TARGET_AMD64_
+#endif // PROFILING_SUPPORTED
default:
// for all other 'tree->OperGet()' kinds, leave 'killMask' = RBM_NONE
#define RBM_ARG_REGS (RBM_ARG_0|RBM_ARG_1)
+ // The registers trashed by profiler enter/leave/tailcall hook
+ // See vm\i386\asmhelpers.asm for more details.
+ #define RBM_PROFILER_ENTER_TRASH RBM_NONE
+ #define RBM_PROFILER_LEAVE_TRASH RBM_NONE
+ #define RBM_PROFILER_TAILCALL_TRASH (RBM_ALLINT & ~RBM_ARG_REGS)
+
// What sort of reloc do we use for [disp32] address mode
#define IMAGE_REL_BASED_DISP32 IMAGE_REL_BASED_HIGHLOW
#endif // !UNIX_AMD64_ABI
// The registers trashed by profiler enter/leave/tailcall hook
- // See vm\amd64\amshelpers.asm for more details.
- #define RBM_PROFILER_ENTER_TRASH RBM_CALLEE_TRASH
- #define RBM_PROFILER_LEAVE_TRASH (RBM_CALLEE_TRASH & ~(RBM_FLOATRET | RBM_INTRET))
+ // See vm\amd64\asmhelpers.asm for more details.
+ #define RBM_PROFILER_ENTER_TRASH RBM_CALLEE_TRASH
+ #define RBM_PROFILER_LEAVE_TRASH (RBM_CALLEE_TRASH & ~(RBM_FLOATRET | RBM_INTRET))
+ #define RBM_PROFILER_TAILCALL_TRASH RBM_PROFILER_LEAVE_TRASH
// The registers trashed by the CORINFO_HELP_STOP_FOR_GC helper.
#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING