Skip to content

Commit

Permalink
JIT: enable cloning based on loop invariant type tests
Browse files Browse the repository at this point in the history
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 dotnet#65206.
  • Loading branch information
AndyAyersMS committed Jun 7, 2022
1 parent deb4044 commit 3da009f
Show file tree
Hide file tree
Showing 10 changed files with 785 additions and 285 deletions.
21 changes: 13 additions & 8 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6801,11 +6801,6 @@ class Compiler
optMethodFlags |= OMF_HAS_GUARDEDDEVIRT;
}

void clearMethodHasGuardedDevirtualization()
{
optMethodFlags &= ~OMF_HAS_GUARDEDDEVIRT;
}

void considerGuardedDevirtualization(GenTreeCall* call,
IL_OFFSET ilOffset,
bool isInterface,
Expand Down Expand Up @@ -7300,10 +7295,20 @@ class Compiler
struct LoopCloneVisitorInfo
{
LoopCloneContext* context;
unsigned loopNum;
Statement* stmt;
LoopCloneVisitorInfo(LoopCloneContext* context, unsigned loopNum, Statement* stmt)
: context(context), loopNum(loopNum), stmt(nullptr)
const unsigned loopNum;
const bool cloneForArrayBounds;
const bool cloneForTypeTests;
LoopCloneVisitorInfo(LoopCloneContext* context,
unsigned loopNum,
Statement* stmt,
bool cloneForArrayBounds,
bool cloneForTypeTests)
: context(context)
, stmt(nullptr)
, loopNum(loopNum)
, cloneForArrayBounds(cloneForArrayBounds)
, cloneForTypeTests(cloneForTypeTests)
{
}
};
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/jit/indirectcalltransformer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1204,7 +1204,6 @@ Compiler::fgWalkResult Compiler::fgDebugCheckForTransformableIndirectCalls(GenTr
void Compiler::CheckNoTransformableIndirectCallsRemain()
{
assert(!doesMethodHaveFatPointer());
assert(!doesMethodHaveGuardedDevirtualization());
assert(!doesMethodHaveExpRuntimeLookup());

for (BasicBlock* const block : Blocks())
Expand Down Expand Up @@ -1244,7 +1243,6 @@ PhaseStatus Compiler::fgTransformIndirectCalls()
}

clearMethodHasFatPointer();
clearMethodHasGuardedDevirtualization();
clearMethodHasExpRuntimeLookup();
}
else
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ CONFIG_INTEGER(JitBreakOnBadCode, W("JitBreakOnBadCode"), 0)
CONFIG_INTEGER(JitBreakOnMinOpts, W("JITBreakOnMinOpts"), 0) // Halt if jit switches to MinOpts
CONFIG_INTEGER(JitBreakOnUnsafeCode, W("JitBreakOnUnsafeCode"), 0)
CONFIG_INTEGER(JitCloneLoops, W("JitCloneLoops"), 1) // If 0, don't clone. Otherwise clone loops for optimizations.
CONFIG_INTEGER(JitCloneLoopsWithTypeTests, W("JitCloneLoopsWithTypeTests"), 1) // If 0, don't clone loops based on
// invariant type tests
CONFIG_INTEGER(JitDebugLogLoopCloning, W("JitDebugLogLoopCloning"), 0) // In debug builds log places where loop cloning
// optimizations are performed on the fast path.
CONFIG_INTEGER(JitDefaultFill, W("JitDefaultFill"), 0xdd) // In debug builds, initialize the memory allocated by the nra
Expand Down
Loading

0 comments on commit 3da009f

Please sign in to comment.