未验证 提交 fe043561 编写于 作者: A Andy Ayers 提交者: GitHub

JIT: merge fgMorph into compCompile (#2110)

This gives us a single method that controls most of the jit's phase behavior.
Largely a manual inline, though I updated some comments and changed one assert.

Follow up from #1309; also see #2109.
上级 8bd94d1a
...@@ -4129,16 +4129,24 @@ void Compiler::compFunctionTraceEnd(void* methodCodePtr, ULONG methodCodeSize, b ...@@ -4129,16 +4129,24 @@ void Compiler::compFunctionTraceEnd(void* methodCodePtr, ULONG methodCodeSize, b
#endif // DEBUG #endif // DEBUG
} }
//********************************************************************************************* //------------------------------------------------------------------------
// #Phases // compCompile: run phases needed for compilation
//
// Arguments:
// methodCodePtr [OUT] - address of generated code
// methodCodeSize [OUT] - size of the generated code (hot + cold setions)
// compileFlags [IN] - flags controlling jit behavior
// //
// This is the most interesting 'toplevel' function in the JIT. It goes through the operations of // Notes:
// importing, morphing, optimizations and code generation. This is called from the EE through the // This is the most interesting 'toplevel' function in the JIT. It goes through the operations of
// code:CILJit::compileMethod function. // importing, morphing, optimizations and code generation. This is called from the EE through the
// code:CILJit::compileMethod function.
// //
// For an overview of the structure of the JIT, see: // For an overview of the structure of the JIT, see:
// https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/ryujit-overview.md // https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/ryujit-overview.md
// //
// Also called for inlinees, though they will only be run through the first few phases.
//
void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags* compileFlags) void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags* compileFlags)
{ {
if (compIsForInlining()) if (compIsForInlining())
...@@ -4151,8 +4159,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4151,8 +4159,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
VarSetOps::AssignAllowUninitRhs(this, compCurLife, VarSetOps::UninitVal()); VarSetOps::AssignAllowUninitRhs(this, compCurLife, VarSetOps::UninitVal());
/* The temp holding the secret stub argument is used by fgImport() when importing the intrinsic. */ // The temp holding the secret stub argument is used by fgImport() when importing the intrinsic.
if (info.compPublishStubParam) if (info.compPublishStubParam)
{ {
assert(lvaStubArgumentVar == BAD_VAR_NUM); assert(lvaStubArgumentVar == BAD_VAR_NUM);
...@@ -4164,8 +4171,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4164,8 +4171,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
compFunctionTraceStart(); compFunctionTraceStart();
/* Convert the instrs in each basic block to a tree based intermediate representation */ // Convert the instrs in each basic block to a tree based intermediate representation
fgImport(); fgImport();
assert(!fgComputePredsDone); assert(!fgComputePredsDone);
...@@ -4184,12 +4190,10 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4184,12 +4190,10 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
if (compIsForInlining()) if (compIsForInlining())
{ {
/* Quit inlining if fgImport() failed for any reason. */ // Abandon inlining if fgImport() failed for any reason
if (!compDonotInline()) if (!compDonotInline())
{ {
/* Filter out unimported BBs */ // Filter out unimported BBs
fgRemoveEmptyBlocks(); fgRemoveEmptyBlocks();
// Update type of return spill temp if we have gathered // Update type of return spill temp if we have gathered
...@@ -4226,7 +4230,10 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4226,7 +4230,10 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
return; return;
} }
assert(!compDonotInline()); // At this point in the phase list, all the inlinee phases have
// been run, and inlinee compiles have exited, so we should only
// get this far if we are jitting the root method.
noway_assert(!compIsForInlining());
// Maybe the caller was not interested in generating code // Maybe the caller was not interested in generating code
if (compIsForImportOnly()) if (compIsForImportOnly())
...@@ -4269,16 +4276,212 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4269,16 +4276,212 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
EndPhase(PHASE_POST_IMPORT); EndPhase(PHASE_POST_IMPORT);
/* Initialize the BlockSet epoch */ // Initialize the BlockSet epoch
NewBasicBlockEpoch(); NewBasicBlockEpoch();
/* Massage the trees so that we can generate code out of them */ // Start phases that are broadly called morphing, and includes
// global morph, as well as other phases that massage the trees so
// that we can generate code out of them.
fgOutgoingArgTemps = nullptr;
#ifdef DEBUG
if (verbose)
{
printf("*************** In fgMorph()\n");
}
if (verboseTrees)
{
fgDispBasicBlocks(true);
}
#endif // DEBUG
// Insert call to class constructor as the first basic block if
// we were asked to do so.
if (info.compCompHnd->initClass(nullptr /* field */, info.compMethodHnd /* method */,
impTokenLookupContextHandle /* context */) &
CORINFO_INITCLASS_USE_HELPER)
{
fgEnsureFirstBBisScratch();
fgNewStmtAtBeg(fgFirstBB, fgInitThisClass());
}
#ifdef DEBUG
if (opts.compGcChecks)
{
for (unsigned i = 0; i < info.compArgsCount; i++)
{
if (lvaTable[i].TypeGet() == TYP_REF)
{
// confirm that the argument is a GC pointer (for debugging (GC stress))
GenTree* op = gtNewLclvNode(i, TYP_REF);
GenTreeCall::Use* args = gtNewCallArgs(op);
op = gtNewHelperCallNode(CORINFO_HELP_CHECK_OBJ, TYP_VOID, args);
fgEnsureFirstBBisScratch();
fgNewStmtAtEnd(fgFirstBB, op);
if (verbose)
{
printf("\ncompGcChecks tree:\n");
gtDispTree(op);
}
}
}
}
#endif // DEBUG
#if defined(DEBUG) && defined(_TARGET_XARCH_)
if (opts.compStackCheckOnRet)
{
lvaReturnSpCheck = lvaGrabTempWithImplicitUse(false DEBUGARG("ReturnSpCheck"));
lvaTable[lvaReturnSpCheck].lvType = TYP_I_IMPL;
}
#endif // defined(DEBUG) && defined(_TARGET_XARCH_)
#if defined(DEBUG) && defined(_TARGET_X86_)
if (opts.compStackCheckOnCall)
{
lvaCallSpCheck = lvaGrabTempWithImplicitUse(false DEBUGARG("CallSpCheck"));
lvaTable[lvaCallSpCheck].lvType = TYP_I_IMPL;
}
#endif // defined(DEBUG) && defined(_TARGET_X86_)
// Filter out unimported BBs
fgRemoveEmptyBlocks();
#ifdef DEBUG
// Inliner could add basic blocks. Check that the flowgraph data is up-to-date
fgDebugCheckBBlist(false, false);
#endif // DEBUG
EndPhase(PHASE_MORPH_INIT);
// Inline callee methods into this root method
fgInline();
RecordStateAtEndOfInlining(); // Record "start" values for post-inlining cycles and elapsed time.
EndPhase(PHASE_MORPH_INLINE);
// Transform each GT_ALLOCOBJ node into either an allocation helper call or
// local variable allocation on the stack.
ObjectAllocator objectAllocator(this); // PHASE_ALLOCATE_OBJECTS
if (JitConfig.JitObjectStackAllocation() && opts.OptimizationEnabled())
{
objectAllocator.EnableObjectStackAllocation();
}
objectAllocator.Run();
fgMorph(); // Add any internal blocks/trees we may need
fgAddInternal();
#ifdef DEBUG
// Inliner could add basic blocks. Check that the flowgraph data is up-to-date
fgDebugCheckBBlist(false, false);
// Inliner could clone some trees.
fgDebugCheckNodesUniqueness();
#endif // DEBUG
fgRemoveEmptyTry();
EndPhase(PHASE_EMPTY_TRY);
fgRemoveEmptyFinally();
EndPhase(PHASE_EMPTY_FINALLY);
fgMergeFinallyChains();
EndPhase(PHASE_MERGE_FINALLY_CHAINS);
fgCloneFinally();
fgUpdateFinallyTargetFlags();
EndPhase(PHASE_CLONE_FINALLY);
// Compute bbNum, bbRefs and bbPreds
//
JITDUMP("\nRenumbering the basic blocks for fgComputePreds\n");
fgRenumberBlocks();
// This is the first time full (not cheap) preds will be computed
//
noway_assert(!fgComputePredsDone);
fgComputePreds();
// Run an early flow graph simplification pass
if (opts.OptimizationEnabled())
{
fgUpdateFlowGraph();
}
EndPhase(PHASE_COMPUTE_PREDS);
// From this point on the flowgraph information such as bbNum,
// bbRefs or bbPreds has to be kept updated
// For x64 and ARM64 we need to mark irregular parameters
lvaRefCountState = RCS_EARLY;
fgResetImplicitByRefRefCount();
// Promote struct locals if necessary
fgPromoteStructs();
// Figure out what locals are address exposed
fgMarkAddressExposedLocals();
EndPhase(PHASE_STR_ADRLCL);
// Apply type updates to implicit byref parameters; also choose (based on address-exposed
// analysis) which implicit byref promotions to keep (requires copy to initialize) or discard.
fgRetypeImplicitByRefArgs();
#ifdef DEBUG
// Now that locals have address-taken and implicit byref marked, we can safely apply stress.
lvaStressLclFld();
fgStress64RsltMul();
#endif // DEBUG
EndPhase(PHASE_MORPH_IMPBYREF);
// Morph the trees in all the blocks of the method
fgMorphBlocks();
// Fix any LclVar annotations on discarded struct promotion temps for implicit by-ref args
fgMarkDemotedImplicitByRefArgs();
lvaRefCountState = RCS_INVALID;
EndPhase(PHASE_MORPH_GLOBAL);
#if 0
JITDUMP("trees after fgMorphBlocks\n");
DBEXEC(VERBOSE, fgDispBasicBlocks(true));
#endif
#if defined(FEATURE_EH_FUNCLETS) && defined(_TARGET_ARM_)
if (fgNeedToAddFinallyTargetBits)
{
// We previously wiped out the BBF_FINALLY_TARGET bits due to some morphing; add them back.
fgAddFinallyTargetFlags();
fgNeedToAddFinallyTargetBits = false;
}
#endif // defined(FEATURE_EH_FUNCLETS) && defined(_TARGET_ARM_)
// Decide the kind of code we want to generate
fgSetOptions();
fgExpandQmarkNodes();
#ifdef DEBUG
compCurBB = nullptr;
#endif // DEBUG
// End of the morphing phases
EndPhase(PHASE_MORPH_END); EndPhase(PHASE_MORPH_END);
/* GS security checks for unsafe buffers */ // GS security checks for unsafe buffers
if (getNeedsGSSecurityCookie()) if (getNeedsGSSecurityCookie())
{ {
#ifdef DEBUG #ifdef DEBUG
...@@ -4309,9 +4512,8 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4309,9 +4512,8 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
// so make sure this is the case. // so make sure this is the case.
fgRenumberBlocks(); fgRenumberBlocks();
/* If we need to emit GC Poll calls, mark the blocks that need them now. This is conservative and can // If we need to emit GC Poll calls, mark the blocks that need them now.
* be optimized later. */ // This is conservative and can be optimized later.
fgMarkGCPollBlocks(); fgMarkGCPollBlocks();
EndPhase(PHASE_MARK_GC_POLL_BLOCKS); EndPhase(PHASE_MARK_GC_POLL_BLOCKS);
...@@ -4321,8 +4523,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4321,8 +4523,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
#if defined(FEATURE_EH_FUNCLETS) #if defined(FEATURE_EH_FUNCLETS)
/* Create funclets from the EH handlers. */ // Create funclets from the EH handlers.
fgCreateFunclets(); fgCreateFunclets();
EndPhase(PHASE_CREATE_FUNCLETS); EndPhase(PHASE_CREATE_FUNCLETS);
...@@ -4343,12 +4544,10 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4343,12 +4544,10 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
if (opts.OptimizationEnabled()) if (opts.OptimizationEnabled())
{ {
/* Perform loop inversion (i.e. transform "while" loops into // Perform loop inversion (i.e. transform "while" loops into
"repeat" loops) and discover and classify natural loops // "repeat" loops) and discover and classify natural loops
(e.g. mark iterative loops as such). Also marks loop blocks // (e.g. mark iterative loops as such). Also marks loop blocks
and sets bbWeight to the loop nesting levels // and sets bbWeight to the loop nesting levels
*/
optOptimizeLoops(); optOptimizeLoops();
EndPhase(PHASE_OPTIMIZE_LOOPS); EndPhase(PHASE_OPTIMIZE_LOOPS);
...@@ -4357,7 +4556,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4357,7 +4556,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
optCloneLoops(); optCloneLoops();
EndPhase(PHASE_CLONE_LOOPS); EndPhase(PHASE_CLONE_LOOPS);
/* Unroll loops */ // Unroll loops
optUnrollLoops(); optUnrollLoops();
EndPhase(PHASE_UNROLL_LOOPS); EndPhase(PHASE_UNROLL_LOOPS);
} }
...@@ -4366,29 +4565,24 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4366,29 +4565,24 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
fgDebugCheckLinks(); fgDebugCheckLinks();
#endif #endif
/* Create the variable table (and compute variable ref counts) */ // Create the variable table (and compute variable ref counts)
lvaMarkLocalVars(); lvaMarkLocalVars();
EndPhase(PHASE_MARK_LOCAL_VARS); EndPhase(PHASE_MARK_LOCAL_VARS);
// IMPORTANT, after this point, every place where trees are modified or cloned // IMPORTANT, after this point, locals are ref counted.
// the local variable reference counts must be updated // However, ref counts are not kept incrementally up to date.
// You can test the value of the following variable to see if
// the local variable ref counts must be updated
//
assert(lvaLocalVarRefCounted()); assert(lvaLocalVarRefCounted());
if (opts.OptimizationEnabled()) if (opts.OptimizationEnabled())
{ {
/* Optimize boolean conditions */ // Optimize boolean conditions
optOptimizeBools(); optOptimizeBools();
EndPhase(PHASE_OPTIMIZE_BOOLS); EndPhase(PHASE_OPTIMIZE_BOOLS);
// optOptimizeBools() might have changed the number of blocks; the dominators/reachability might be bad. // optOptimizeBools() might have changed the number of blocks; the dominators/reachability might be bad.
} }
/* Figure out the order in which operators are to be evaluated */ // Figure out the order in which operators are to be evaluated
fgFindOperOrder(); fgFindOperOrder();
EndPhase(PHASE_FIND_OPER_ORDER); EndPhase(PHASE_FIND_OPER_ORDER);
...@@ -4451,7 +4645,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4451,7 +4645,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
if (doEarlyProp) if (doEarlyProp)
{ {
/* Propagate array length and rewrite getType() method call */ // Propagate array length and rewrite getType() method call
optEarlyProp(); optEarlyProp();
EndPhase(PHASE_EARLY_PROP); EndPhase(PHASE_EARLY_PROP);
} }
...@@ -4464,41 +4658,41 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4464,41 +4658,41 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
if (doLoopHoisting) if (doLoopHoisting)
{ {
/* Hoist invariant code out of loops */ // Hoist invariant code out of loops
optHoistLoopCode(); optHoistLoopCode();
EndPhase(PHASE_HOIST_LOOP_CODE); EndPhase(PHASE_HOIST_LOOP_CODE);
} }
if (doCopyProp) if (doCopyProp)
{ {
/* Perform VN based copy propagation */ // Perform VN based copy propagation
optVnCopyProp(); optVnCopyProp();
EndPhase(PHASE_VN_COPY_PROP); EndPhase(PHASE_VN_COPY_PROP);
} }
#if FEATURE_ANYCSE #if FEATURE_ANYCSE
/* Remove common sub-expressions */ // Remove common sub-expressions
optOptimizeCSEs(); optOptimizeCSEs();
#endif // FEATURE_ANYCSE #endif // FEATURE_ANYCSE
#if ASSERTION_PROP #if ASSERTION_PROP
if (doAssertionProp) if (doAssertionProp)
{ {
/* Assertion propagation */ // Assertion propagation
optAssertionPropMain(); optAssertionPropMain();
EndPhase(PHASE_ASSERTION_PROP_MAIN); EndPhase(PHASE_ASSERTION_PROP_MAIN);
} }
if (doRangeAnalysis) if (doRangeAnalysis)
{ {
/* Optimize array index range checks */ // Optimize array index range checks
RangeCheck rc(this); RangeCheck rc(this);
rc.OptimizeRangeChecks(); rc.OptimizeRangeChecks();
EndPhase(PHASE_OPTIMIZE_INDEX_CHECKS); EndPhase(PHASE_OPTIMIZE_INDEX_CHECKS);
} }
#endif // ASSERTION_PROP #endif // ASSERTION_PROP
/* update the flowgraph if we modified it during the optimization phase*/ // update the flowgraph if we modified it during the optimization phase
if (fgModified) if (fgModified)
{ {
fgUpdateFlowGraph(); fgUpdateFlowGraph();
...@@ -4562,9 +4756,8 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4562,9 +4756,8 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
fgDebugCheckLinks(); fgDebugCheckLinks();
#endif #endif
/* Enable this to gather statistical data such as // Enable this to gather statistical data such as
* call and register argument info, flowgraph and loop info, etc. */ // call and register argument info, flowgraph and loop info, etc.
compJitStats(); compJitStats();
#ifdef _TARGET_ARM_ #ifdef _TARGET_ARM_
...@@ -4575,7 +4768,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4575,7 +4768,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
} }
#endif // _TARGET_ARM_ #endif // _TARGET_ARM_
/* Assign registers to variables, etc. */ // Assign registers to variables, etc.
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Dominator and reachability sets are no longer valid. They haven't been // Dominator and reachability sets are no longer valid. They haven't been
...@@ -4583,19 +4776,22 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4583,19 +4776,22 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
fgDomsComputed = false; fgDomsComputed = false;
/* Create LSRA before Lowering, this way Lowering can initialize the TreeNode Map */ // Create LinearScan before Lowering, so that Lowering can call LinearScan methods
// for determining whether locals are register candidates and (for xarch) whether
// a node is a containable memory op.
m_pLinearScan = getLinearScanAllocator(this); m_pLinearScan = getLinearScanAllocator(this);
/* Lower */ // Lower
m_pLowering = new (this, CMK_LSRA) Lowering(this, m_pLinearScan); // PHASE_LOWERING m_pLowering = new (this, CMK_LSRA) Lowering(this, m_pLinearScan); // PHASE_LOWERING
m_pLowering->Run(); m_pLowering->Run();
StackLevelSetter stackLevelSetter(this); // PHASE_STACK_LEVEL_SETTER StackLevelSetter stackLevelSetter(this); // PHASE_STACK_LEVEL_SETTER
stackLevelSetter.Run(); stackLevelSetter.Run();
lvaTrackedFixed = true; // We can not add any new tracked variables after this point. // We can not add any new tracked variables after this point.
lvaTrackedFixed = true;
/* Now that lowering is completed we can proceed to perform register allocation */ // Now that lowering is completed we can proceed to perform register allocation
m_pLinearScan->doLinearScan(); m_pLinearScan->doLinearScan();
EndPhase(PHASE_LINEAR_SCAN); EndPhase(PHASE_LINEAR_SCAN);
...@@ -4606,8 +4802,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags ...@@ -4606,8 +4802,7 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
fgDebugCheckLinks(); fgDebugCheckLinks();
#endif #endif
/* Generate code */ // Generate code
codeGen->genGenerateCode(methodCodePtr, methodCodeSize); codeGen->genGenerateCode(methodCodePtr, methodCodeSize);
#ifdef FEATURE_JIT_METHOD_PERF #ifdef FEATURE_JIT_METHOD_PERF
......
...@@ -4443,8 +4443,6 @@ public: ...@@ -4443,8 +4443,6 @@ public:
void fgExpandQmarkStmt(BasicBlock* block, Statement* stmt); void fgExpandQmarkStmt(BasicBlock* block, Statement* stmt);
void fgExpandQmarkNodes(); void fgExpandQmarkNodes();
void fgMorph();
// Do "simple lowering." This functionality is (conceptually) part of "general" // Do "simple lowering." This functionality is (conceptually) part of "general"
// lowering that is distributed between fgMorph and the lowering phase of LSRA. // lowering that is distributed between fgMorph and the lowering phase of LSRA.
void fgSimpleLowering(); void fgSimpleLowering();
......
...@@ -16523,220 +16523,6 @@ void Compiler::fgPostExpandQmarkChecks() ...@@ -16523,220 +16523,6 @@ void Compiler::fgPostExpandQmarkChecks()
} }
#endif #endif
/*****************************************************************************
*
* Transform all basic blocks for codegen.
*/
void Compiler::fgMorph()
{
noway_assert(!compIsForInlining()); // Inlinee's compiler should never reach here.
fgOutgoingArgTemps = nullptr;
#ifdef DEBUG
if (verbose)
{
printf("*************** In fgMorph()\n");
}
if (verboseTrees)
{
fgDispBasicBlocks(true);
}
#endif // DEBUG
// Insert call to class constructor as the first basic block if
// we were asked to do so.
if (info.compCompHnd->initClass(nullptr /* field */, info.compMethodHnd /* method */,
impTokenLookupContextHandle /* context */) &
CORINFO_INITCLASS_USE_HELPER)
{
fgEnsureFirstBBisScratch();
fgNewStmtAtBeg(fgFirstBB, fgInitThisClass());
}
#ifdef DEBUG
if (opts.compGcChecks)
{
for (unsigned i = 0; i < info.compArgsCount; i++)
{
if (lvaTable[i].TypeGet() == TYP_REF)
{
// confirm that the argument is a GC pointer (for debugging (GC stress))
GenTree* op = gtNewLclvNode(i, TYP_REF);
GenTreeCall::Use* args = gtNewCallArgs(op);
op = gtNewHelperCallNode(CORINFO_HELP_CHECK_OBJ, TYP_VOID, args);
fgEnsureFirstBBisScratch();
fgNewStmtAtEnd(fgFirstBB, op);
if (verbose)
{
printf("\ncompGcChecks tree:\n");
gtDispTree(op);
}
}
}
}
#endif // DEBUG
#if defined(DEBUG) && defined(_TARGET_XARCH_)
if (opts.compStackCheckOnRet)
{
lvaReturnSpCheck = lvaGrabTempWithImplicitUse(false DEBUGARG("ReturnSpCheck"));
lvaTable[lvaReturnSpCheck].lvType = TYP_I_IMPL;
}
#endif // defined(DEBUG) && defined(_TARGET_XARCH_)
#if defined(DEBUG) && defined(_TARGET_X86_)
if (opts.compStackCheckOnCall)
{
lvaCallSpCheck = lvaGrabTempWithImplicitUse(false DEBUGARG("CallSpCheck"));
lvaTable[lvaCallSpCheck].lvType = TYP_I_IMPL;
}
#endif // defined(DEBUG) && defined(_TARGET_X86_)
/* Filter out unimported BBs */
fgRemoveEmptyBlocks();
#ifdef DEBUG
/* Inliner could add basic blocks. Check that the flowgraph data is up-to-date */
fgDebugCheckBBlist(false, false);
#endif // DEBUG
EndPhase(PHASE_MORPH_INIT);
/* Inline */
fgInline();
#if 0
JITDUMP("trees after inlining\n");
DBEXEC(VERBOSE, fgDispBasicBlocks(true));
#endif
RecordStateAtEndOfInlining(); // Record "start" values for post-inlining cycles and elapsed time.
EndPhase(PHASE_MORPH_INLINE);
// Transform each GT_ALLOCOBJ node into either an allocation helper call or
// local variable allocation on the stack.
ObjectAllocator objectAllocator(this); // PHASE_ALLOCATE_OBJECTS
if (JitConfig.JitObjectStackAllocation() && opts.OptimizationEnabled())
{
objectAllocator.EnableObjectStackAllocation();
}
objectAllocator.Run();
/* Add any internal blocks/trees we may need */
fgAddInternal();
#ifdef DEBUG
/* Inliner could add basic blocks. Check that the flowgraph data is up-to-date */
fgDebugCheckBBlist(false, false);
/* Inliner could clone some trees. */
fgDebugCheckNodesUniqueness();
#endif // DEBUG
fgRemoveEmptyTry();
EndPhase(PHASE_EMPTY_TRY);
fgRemoveEmptyFinally();
EndPhase(PHASE_EMPTY_FINALLY);
fgMergeFinallyChains();
EndPhase(PHASE_MERGE_FINALLY_CHAINS);
fgCloneFinally();
fgUpdateFinallyTargetFlags();
EndPhase(PHASE_CLONE_FINALLY);
// Compute bbNum, bbRefs and bbPreds
//
JITDUMP("\nRenumbering the basic blocks for fgComputePreds\n");
fgRenumberBlocks();
// This is the first time full (not cheap) preds will be computed
//
noway_assert(!fgComputePredsDone);
fgComputePreds();
// Run an early flow graph simplification pass
if (opts.OptimizationEnabled())
{
fgUpdateFlowGraph();
}
EndPhase(PHASE_COMPUTE_PREDS);
// From this point on the flowgraph information such as bbNum,
// bbRefs or bbPreds has to be kept updated
/* For x64 and ARM64 we need to mark irregular parameters */
lvaRefCountState = RCS_EARLY;
fgResetImplicitByRefRefCount();
/* Promote struct locals if necessary */
fgPromoteStructs();
/* Now it is the time to figure out what locals have address-taken. */
fgMarkAddressExposedLocals();
EndPhase(PHASE_STR_ADRLCL);
/* Apply the type update to implicit byref parameters; also choose (based on address-exposed
analysis) which implicit byref promotions to keep (requires copy to initialize) or discard. */
fgRetypeImplicitByRefArgs();
#ifdef DEBUG
/* Now that locals have address-taken and implicit byref marked, we can safely apply stress. */
lvaStressLclFld();
fgStress64RsltMul();
#endif // DEBUG
EndPhase(PHASE_MORPH_IMPBYREF);
/* Morph the trees in all the blocks of the method */
fgMorphBlocks();
/* Fix any LclVar annotations on discarded struct promotion temps for implicit by-ref args */
fgMarkDemotedImplicitByRefArgs();
lvaRefCountState = RCS_INVALID;
EndPhase(PHASE_MORPH_GLOBAL);
#if 0
JITDUMP("trees after fgMorphBlocks\n");
DBEXEC(VERBOSE, fgDispBasicBlocks(true));
#endif
#if defined(FEATURE_EH_FUNCLETS) && defined(_TARGET_ARM_)
if (fgNeedToAddFinallyTargetBits)
{
// We previously wiped out the BBF_FINALLY_TARGET bits due to some morphing; add them back.
fgAddFinallyTargetFlags();
fgNeedToAddFinallyTargetBits = false;
}
#endif // defined(FEATURE_EH_FUNCLETS) && defined(_TARGET_ARM_)
/* Decide the kind of code we want to generate */
fgSetOptions();
fgExpandQmarkNodes();
#ifdef DEBUG
compCurBB = nullptr;
#endif // DEBUG
}
/***************************************************************************** /*****************************************************************************
* *
* Promoting struct locals * Promoting struct locals
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册