Skip to content

Commit 86efc10

Browse files
authored
JIT: enable cloning based on loop invariant type tests (#70377)
Such as those added by GDV. The JIT will now clone just for type tests, or just for array bounds, or for a mixture of the two. The JIT will still produce just one fast and one slow loop. If there are a mixture of array bounds and type test conditions, all conditions must pass for control to reach the fast loop. Unlike array bounds checks, type test failures are not intrinsically rare, so there is some profitability screening to ensure that a failed type test does not force execution to run the slow version "too often". The type test must execute frequently within the loop, and be heavily biased towards success. This is work towards resolving #65206.
1 parent 12a6db4 commit 86efc10

10 files changed

+847
-294
lines changed

src/coreclr/jit/compiler.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6815,11 +6815,6 @@ class Compiler
68156815
optMethodFlags |= OMF_HAS_GUARDEDDEVIRT;
68166816
}
68176817

6818-
void clearMethodHasGuardedDevirtualization()
6819-
{
6820-
optMethodFlags &= ~OMF_HAS_GUARDEDDEVIRT;
6821-
}
6822-
68236818
void considerGuardedDevirtualization(GenTreeCall* call,
68246819
IL_OFFSET ilOffset,
68256820
bool isInterface,
@@ -7314,10 +7309,20 @@ class Compiler
73147309
struct LoopCloneVisitorInfo
73157310
{
73167311
LoopCloneContext* context;
7317-
unsigned loopNum;
73187312
Statement* stmt;
7319-
LoopCloneVisitorInfo(LoopCloneContext* context, unsigned loopNum, Statement* stmt)
7320-
: context(context), loopNum(loopNum), stmt(nullptr)
7313+
const unsigned loopNum;
7314+
const bool cloneForArrayBounds;
7315+
const bool cloneForTypeTests;
7316+
LoopCloneVisitorInfo(LoopCloneContext* context,
7317+
unsigned loopNum,
7318+
Statement* stmt,
7319+
bool cloneForArrayBounds,
7320+
bool cloneForTypeTests)
7321+
: context(context)
7322+
, stmt(nullptr)
7323+
, loopNum(loopNum)
7324+
, cloneForArrayBounds(cloneForArrayBounds)
7325+
, cloneForTypeTests(cloneForTypeTests)
73217326
{
73227327
}
73237328
};

src/coreclr/jit/indirectcalltransformer.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,7 +1204,6 @@ Compiler::fgWalkResult Compiler::fgDebugCheckForTransformableIndirectCalls(GenTr
12041204
void Compiler::CheckNoTransformableIndirectCallsRemain()
12051205
{
12061206
assert(!doesMethodHaveFatPointer());
1207-
assert(!doesMethodHaveGuardedDevirtualization());
12081207
assert(!doesMethodHaveExpRuntimeLookup());
12091208

12101209
for (BasicBlock* const block : Blocks())
@@ -1244,7 +1243,6 @@ PhaseStatus Compiler::fgTransformIndirectCalls()
12441243
}
12451244

12461245
clearMethodHasFatPointer();
1247-
clearMethodHasGuardedDevirtualization();
12481246
clearMethodHasExpRuntimeLookup();
12491247
}
12501248
else

src/coreclr/jit/jitconfigvalues.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ CONFIG_INTEGER(JitBreakOnBadCode, W("JitBreakOnBadCode"), 0)
4242
CONFIG_INTEGER(JitBreakOnMinOpts, W("JITBreakOnMinOpts"), 0) // Halt if jit switches to MinOpts
4343
CONFIG_INTEGER(JitBreakOnUnsafeCode, W("JitBreakOnUnsafeCode"), 0)
4444
CONFIG_INTEGER(JitCloneLoops, W("JitCloneLoops"), 1) // If 0, don't clone. Otherwise clone loops for optimizations.
45+
CONFIG_INTEGER(JitCloneLoopsWithTypeTests, W("JitCloneLoopsWithTypeTests"), 1) // If 0, don't clone loops based on
46+
// invariant type tests
4547
CONFIG_INTEGER(JitDebugLogLoopCloning, W("JitDebugLogLoopCloning"), 0) // In debug builds log places where loop cloning
4648
// optimizations are performed on the fast path.
4749
CONFIG_INTEGER(JitDefaultFill, W("JitDefaultFill"), 0xdd) // In debug builds, initialize the memory allocated by the nra

0 commit comments

Comments
 (0)