Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JIT: Add reasoning about loop trip counts and optimize counted loops into downwards counted loops #102261

Merged
merged 21 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 50 additions & 20 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,22 +72,21 @@ inline var_types genActualType(T value);
* Forward declarations
*/

struct InfoHdr; // defined in GCInfo.h
struct escapeMapping_t; // defined in fgdiagnostic.cpp
class emitter; // defined in emit.h
struct ShadowParamVarInfo; // defined in GSChecks.cpp
struct InitVarDscInfo; // defined in registerargconvention.h
class FgStack; // defined in fgbasic.cpp
class Instrumentor; // defined in fgprofile.cpp
class SpanningTreeVisitor; // defined in fgprofile.cpp
class CSE_DataFlow; // defined in optcse.cpp
struct CSEdsc; // defined in optcse.h
class CSE_HeuristicCommon; // defined in optcse.h
class OptBoolsDsc; // defined in optimizer.cpp
struct RelopImplicationInfo; // defined in redundantbranchopts.cpp
struct JumpThreadInfo; // defined in redundantbranchopts.cpp
class ProfileSynthesis; // defined in profilesynthesis.h
class LoopLocalOccurrences; // defined in inductionvariableopts.cpp
struct InfoHdr; // defined in GCInfo.h
struct escapeMapping_t; // defined in fgdiagnostic.cpp
class emitter; // defined in emit.h
struct ShadowParamVarInfo; // defined in GSChecks.cpp
struct InitVarDscInfo; // defined in registerargconvention.h
class FgStack; // defined in fgbasic.cpp
class Instrumentor; // defined in fgprofile.cpp
class SpanningTreeVisitor; // defined in fgprofile.cpp
class CSE_DataFlow; // defined in optcse.cpp
struct CSEdsc; // defined in optcse.h
class CSE_HeuristicCommon; // defined in optcse.h
class OptBoolsDsc; // defined in optimizer.cpp
struct JumpThreadInfo; // defined in redundantbranchopts.cpp
class ProfileSynthesis; // defined in profilesynthesis.h
class LoopLocalOccurrences; // defined in inductionvariableopts.cpp
#ifdef DEBUG
struct IndentStack;
#endif
Expand Down Expand Up @@ -2187,6 +2186,8 @@ class FlowGraphNaturalLoop
return m_exitEdges[index];
}

BasicBlock* GetPreheader() const;

unsigned GetDepth() const;

bool ContainsBlock(BasicBlock* block);
Expand Down Expand Up @@ -2495,6 +2496,30 @@ enum class NodeThreading
LIR, // Nodes are in LIR form (after rationalization)
};

//------------------------------------------------------------------------
// RelopImplicationInfo
//
// Describes information needed to check for and describe the
// inferences between two relops.
//
struct RelopImplicationInfo
{
// Dominating relop, whose value may be determined by control flow
ValueNum domCmpNormVN = ValueNumStore::NoVN;
// Dominated relop, whose value we would like to determine
ValueNum treeNormVN = ValueNumStore::NoVN;
// Relationship between the two relops, if any
ValueNumStore::VN_RELATION_KIND vnRelation = ValueNumStore::VN_RELATION_KIND::VRK_Same;
// Can we draw an inference?
bool canInfer = false;
// If canInfer and dominating relop is true, can we infer value of dominated relop?
bool canInferFromTrue = true;
// If canInfer and dominating relop is false, can we infer value of dominated relop?
bool canInferFromFalse = true;
// Reverse the sense of the inference
bool reverseSense = false;
};

/*
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Expand Down Expand Up @@ -7511,10 +7536,14 @@ class Compiler
#endif

PhaseStatus optInductionVariables();
bool optWidenPrimaryIV(FlowGraphNaturalLoop* loop,
unsigned lclNum,
ScevAddRec* addRec,
LoopLocalOccurrences* loopLocals);

bool optMakeLoopDownwardsCounted(ScalarEvolutionContext& scevContext,
FlowGraphNaturalLoop* loop,
LoopLocalOccurrences* loopLocals);
bool optWidenPrimaryIV(FlowGraphNaturalLoop* loop,
unsigned lclNum,
ScevAddRec* addRec,
LoopLocalOccurrences* loopLocals);

bool optCanSinkWidenedIV(unsigned lclNum, FlowGraphNaturalLoop* loop);
bool optIsIVWideningProfitable(unsigned lclNum,
Expand Down Expand Up @@ -10191,6 +10220,7 @@ class Compiler
STRESS_MODE(UNWIND) /* stress unwind info; e.g., create function fragments */ \
STRESS_MODE(OPT_REPEAT) /* stress JitOptRepeat */ \
STRESS_MODE(INITIAL_PARAM_REG) /* Stress initial register assigned to parameters */ \
STRESS_MODE(DOWNWARDS_COUNTED_LOOPS) /* Make more loops downwards counted */ \
\
/* After COUNT_VARN, stress level 2 does all of these all the time */ \
\
Expand Down
22 changes: 22 additions & 0 deletions src/coreclr/jit/flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4129,6 +4129,28 @@ FlowGraphNaturalLoop::FlowGraphNaturalLoop(const FlowGraphDfsTree* dfsTree, Basi
{
}

//------------------------------------------------------------------------
// GetPreheader: Get the preheader of this loop, if it has one.
//
// Returns:
// The preheader, or nullptr if there is no preheader.
//
BasicBlock* FlowGraphNaturalLoop::GetPreheader() const
{
if (m_entryEdges.size() != 1)
{
return nullptr;
}

BasicBlock* preheader = m_entryEdges[0]->getSourceBlock();
if (!preheader->KindIs(BBJ_ALWAYS))
{
return nullptr;
}

return preheader;
}

//------------------------------------------------------------------------
// GetDepth: Get the depth of the loop.
//
Expand Down
Loading
Loading