Importer was a bit too liberal marking recursive calls as loop-inducing, at
least from the standpoint of enforcing backward-branch constraints. This would
sometimes lead us to inline into cold paths like throws. Only tail-recursive
calls will turn into loops.
Also, future-proof the propagation of simple loopness the root compiler, in
case we ever decide to enable inlining at Tier0.
Commit migrated from https://github.com/dotnet/coreclr/commit/
6b13065e7ac88671795a01577e017ff7cdc26f35
info.compTotalHotCodeSize = 0;
info.compTotalColdCodeSize = 0;
- fgHasBackwardJump = false;
+ compHasBackwardJump = false;
#ifdef DEBUG
compCurBB = nullptr;
}
#ifdef FEATURE_CORECLR
- if (fgHasBackwardJump && (info.compFlags & CORINFO_FLG_DISABLE_TIER0_FOR_LOOPS) != 0 && fgCanSwitchToOptimized())
+ if (compHasBackwardJump && (info.compFlags & CORINFO_FLG_DISABLE_TIER0_FOR_LOOPS) != 0 && fgCanSwitchToOptimized())
#else // !FEATURE_CORECLR
// We may want to use JitConfig value here to support DISABLE_TIER0_FOR_LOOPS
- if (fgHasBackwardJump && fgCanSwitchToOptimized())
+ if (compHasBackwardJump && fgCanSwitchToOptimized())
#endif
{
// Method likely has a loop, switch to the OptimizedTier to avoid spending too much time running slower code
void fgInitBBLookup();
BasicBlock* fgLookupBB(unsigned addr);
- bool fgHasBackwardJump;
-
bool fgCanSwitchToOptimized();
void fgSwitchToOptimized();
bool compQmarkUsed; // Does the method use GT_QMARK/GT_COLON
bool compQmarkRationalized; // Is it allowed to use a GT_QMARK/GT_COLON node.
bool compUnsafeCastUsed; // Does the method use LDIND/STIND to cast between scalar/refernce types
+ bool compHasBackwardJump; // Does the method (or some inlinee) have a lexically backwards jump?
// NOTE: These values are only reliable after
// the importing is completely finished.
bool compLSRADone;
bool compRationalIRForm;
- bool compUsesThrowHelper; // There is a call to a THOROW_HELPER for the compiled method.
+ bool compUsesThrowHelper; // There is a call to a THROW_HELPER for the compiled method.
bool compGeneratingProlog;
bool compGeneratingEpilog;
assert(fgCanSwitchToOptimized());
// Switch to optimized and re-init options
+ JITDUMP("****\n**** JIT Tier0 jit request switching to Tier1 because of loop\n****\n");
assert(opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER0));
opts.jitFlags->Clear(JitFlags::JIT_FLAG_TIER0);
compInitOptions(opts.jitFlags);
if ((block->bbFlags & BBF_BACKWARD_JUMP) == 0)
{
block->bbFlags |= BBF_BACKWARD_JUMP;
- fgHasBackwardJump = true;
+ compHasBackwardJump = true;
}
}
}
compUnsafeCastUsed |= InlineeCompiler->compUnsafeCastUsed;
compNeedsGSSecurityCookie |= InlineeCompiler->compNeedsGSSecurityCookie;
compGSReorderStackLayout |= InlineeCompiler->compGSReorderStackLayout;
+ compHasBackwardJump |= InlineeCompiler->compHasBackwardJump;
#ifdef FEATURE_SIMD
if (InlineeCompiler->usesSIMDTypes())
exactContextHnd = callInfo->contextHandle;
exactContextNeedsRuntimeLookup = callInfo->exactContextNeedsRuntimeLookup == TRUE;
- // Recursive call is treated as a loop to the begining of the method.
- if (gtIsRecursiveCall(methHnd))
- {
-#ifdef DEBUG
- if (verbose)
- {
- JITDUMP("\nFound recursive call in the method. Mark " FMT_BB " to " FMT_BB
- " as having a backward branch.\n",
- fgFirstBB->bbNum, compCurBB->bbNum);
- }
-#endif
- fgMarkBackwardJump(fgFirstBB, compCurBB);
- }
-
switch (callInfo->kind)
{
}
}
+ // A tail recursive call is a potential loop from the current block to the start of the method.
+ if (canTailCall && gtIsRecursiveCall(methHnd))
+ {
+ JITDUMP("\nFound tail recursive call in the method. Mark " FMT_BB " to " FMT_BB
+ " as having a backward branch.\n",
+ fgFirstBB->bbNum, compCurBB->bbNum);
+ fgMarkBackwardJump(fgFirstBB, compCurBB);
+ }
+
// Note: we assume that small return types are already normalized by the managed callee
// or by the pinvoke stub for calls to unmanaged code.