diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 89d0ca29b11e3d..3f8675f87107f4 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -5573,14 +5573,7 @@ bool Compiler::optLoopComplexityExceeds(FlowGraphNaturalLoop* loop, unsigned lim : BasicBlockVisit::Continue; }); - if (result == BasicBlockVisit::Abort) - { - JITDUMP("Loop " FMT_LP ": exceeds complexity limit %u\n", loop->GetIndex(), limit); - return true; - } - - JITDUMP("Loop " FMT_LP ": complexity %u does not exceed limit %u\n", loop->GetIndex(), loopComplexity, limit); - return false; + return (result == BasicBlockVisit::Abort); } /*****************************************************************************/ diff --git a/src/coreclr/jit/loopcloning.cpp b/src/coreclr/jit/loopcloning.cpp index 6ef535a4cd8e27..a204a82618be9b 100644 --- a/src/coreclr/jit/loopcloning.cpp +++ b/src/coreclr/jit/loopcloning.cpp @@ -3108,6 +3108,7 @@ PhaseStatus Compiler::optCloneLoops() // then the method returns false. else if ((sizeLimit >= 0) && optLoopComplexityExceeds(loop, (unsigned)sizeLimit, countNode)) { + JITDUMP(FMT_LP " exceeds cloning size limit %d\n", loop->GetIndex(), sizeLimit); context.CancelLoopOptInfo(loop->GetIndex()); } } diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index b13a80d6a022ef..cead5e4da1c180 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -1903,14 +1903,45 @@ bool Compiler::optTryInvertWhileLoop(FlowGraphNaturalLoop* loop) // Check if loop is small enough to consider for inversion. // Large loops are less likely to benefit from inversion. - const int sizeLimit = JitConfig.JitLoopInversionSizeLimit(); - auto countNode = [](GenTree* tree) -> unsigned { - return 1; - }; + const int invertSizeLimit = JitConfig.JitLoopInversionSizeLimit(); + if (invertSizeLimit >= 0) + { + const int cloneSizeLimit = JitConfig.JitCloneLoopsSizeLimit(); + bool mightBenefitFromCloning = false; + unsigned loopSize = 0; + + // Loops with bounds checks can benefit from cloning, which depends on inversion running. + // Thus, we will try to proceed with inversion for slightly oversize loops if they show potential for cloning. + auto countNode = [&mightBenefitFromCloning, &loopSize](GenTree* tree) -> unsigned { + mightBenefitFromCloning |= tree->OperIs(GT_BOUNDS_CHECK); + loopSize++; + return 1; + }; - if ((sizeLimit >= 0) && optLoopComplexityExceeds(loop, (unsigned)sizeLimit, countNode)) - { - return false; + optLoopComplexityExceeds(loop, (unsigned)max(invertSizeLimit, cloneSizeLimit), countNode); + if (loopSize > (unsigned)invertSizeLimit) + { + // Don't try to invert oversize loops if they don't show cloning potential, + // or if they're too big to be cloned anyway. + JITDUMP(FMT_LP " exceeds inversion size limit of %d\n", loop->GetIndex(), invertSizeLimit); + const bool tooBigToClone = (cloneSizeLimit >= 0) && (loopSize > (unsigned)cloneSizeLimit); + if (!mightBenefitFromCloning || tooBigToClone) + { + JITDUMP("No inversion for " FMT_LP ": %s\n", loop->GetIndex(), + tooBigToClone ? "too big to clone" : "unlikely to benefit from cloning"); + return false; + } + + // If the loop shows cloning potential, tolerate some excess size. + const unsigned liberalInvertSizeLimit = (unsigned)(invertSizeLimit * 1.25); + if (loopSize > liberalInvertSizeLimit) + { + JITDUMP(FMT_LP " might benefit from cloning, but is too large to invert.\n", loop->GetIndex()); + return false; + } + + JITDUMP(FMT_LP " might benefit from cloning. Continuing.\n", loop->GetIndex()); + } } unsigned estDupCostSz = 0;