Skip to content

Commit

Permalink
Remove loop cloning var initialization condition
Browse files Browse the repository at this point in the history
Assume that any pre-existing initialization is ok. Check it against
zero if necessary. Const inits remain as before.

Lots of diffs due to more cloning for cases of `for (i = expression...`
where `expression` is not just a constant or local var.
  • Loading branch information
BruceForstall committed Mar 19, 2022
1 parent 1100930 commit f2ed920
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 150 deletions.
2 changes: 0 additions & 2 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,6 @@ unsigned totalLoopCount; // counts the total number of natural loops
unsigned totalUnnatLoopCount; // counts the total number of (not-necessarily natural) loops
unsigned totalUnnatLoopOverflows; // # of methods that identified more unnatural loops than we can represent
unsigned iterLoopCount; // counts the # of loops with an iterator (for like)
unsigned simpleTestLoopCount; // counts the # of loops with an iterator and a simple loop condition (iter < const)
unsigned constIterLoopCount; // counts the # of loops with a constant iterator (for like)
bool hasMethodLoops; // flag to keep track if we already counted a method as having loops
unsigned loopsThisMethod; // counts the number of loops in the current method
Expand Down Expand Up @@ -1556,7 +1555,6 @@ void Compiler::compShutdown()
fprintf(fout, "Total number of 'unnatural' loops is %5u\n", totalUnnatLoopCount);
fprintf(fout, "# of methods overflowing unnat loop limit is %5u\n", totalUnnatLoopOverflows);
fprintf(fout, "Total number of loops with an iterator is %5u\n", iterLoopCount);
fprintf(fout, "Total number of loops with a simple iterator is %5u\n", simpleTestLoopCount);
fprintf(fout, "Total number of loops with a constant iterator is %5u\n", constIterLoopCount);

fprintf(fout, "--------------------------------------------------\n");
Expand Down
45 changes: 19 additions & 26 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -2498,13 +2498,13 @@ enum LoopFlags : unsigned short

// LPFLG_UNUSED = 0x0001,
// LPFLG_UNUSED = 0x0002,
LPFLG_ITER = 0x0004, // loop of form: for (i = icon or lclVar; test_condition(); i++)
LPFLG_ITER = 0x0004, // loop of form: for (i = icon or expression; test_condition(); i++)
// LPFLG_UNUSED = 0x0008,

LPFLG_CONTAINS_CALL = 0x0010, // If executing the loop body *may* execute a call
LPFLG_VAR_INIT = 0x0020, // iterator is initialized with a local var (var # found in lpVarInit)
LPFLG_CONST_INIT = 0x0040, // iterator is initialized with a constant (found in lpConstInit)
LPFLG_SIMD_LIMIT = 0x0080, // iterator is compared with vector element count (found in lpConstLimit)
// LPFLG_UNUSED = 0x0020,
LPFLG_CONST_INIT = 0x0040, // iterator is initialized with a constant (found in lpConstInit)
LPFLG_SIMD_LIMIT = 0x0080, // iterator is compared with vector element count (found in lpConstLimit)

LPFLG_VAR_LIMIT = 0x0100, // iterator is compared with a local var (var # found in lpVarLimit)
LPFLG_CONST_LIMIT = 0x0200, // iterator is compared with a constant (found in lpConstLimit)
Expand Down Expand Up @@ -6929,16 +6929,11 @@ class Compiler

var_types lpIterOperType() const; // For overflow instructions

// Set to the block where we found the initialization for LPFLG_CONST_INIT or LPFLG_VAR_INIT loops.
// Set to the block where we found the initialization for LPFLG_CONST_INIT loops.
// Initially, this will be 'head', but 'head' might change if we insert a loop pre-header block.
BasicBlock* lpInitBlock;

union {
int lpConstInit; // initial constant value of iterator
// : Valid if LPFLG_CONST_INIT
unsigned lpVarInit; // initial local var number to which we initialize the iterator
// : Valid if LPFLG_VAR_INIT
};
int lpConstInit; // initial constant value of iterator : Valid if LPFLG_CONST_INIT

// The following is for LPFLG_ITER loops only (i.e. the loop condition is "i RELOP const or var")

Expand Down Expand Up @@ -12068,21 +12063,19 @@ extern Histogram bbOneBBSizeTable;

#if COUNT_LOOPS

extern unsigned totalLoopMethods; // counts the total number of methods that have natural loops
extern unsigned maxLoopsPerMethod; // counts the maximum number of loops a method has
extern unsigned totalLoopOverflows; // # of methods that identified more loops than we can represent
extern unsigned totalLoopCount; // counts the total number of natural loops
extern unsigned totalUnnatLoopCount; // counts the total number of (not-necessarily natural) loops
extern unsigned totalUnnatLoopOverflows; // # of methods that identified more unnatural loops than we can represent
extern unsigned iterLoopCount; // counts the # of loops with an iterator (for like)
extern unsigned simpleTestLoopCount; // counts the # of loops with an iterator and a simple loop condition (iter <
// const)
extern unsigned constIterLoopCount; // counts the # of loops with a constant iterator (for like)
extern bool hasMethodLoops; // flag to keep track if we already counted a method as having loops
extern unsigned loopsThisMethod; // counts the number of loops in the current method
extern bool loopOverflowThisMethod; // True if we exceeded the max # of loops in the method.
extern Histogram loopCountTable; // Histogram of loop counts
extern Histogram loopExitCountTable; // Histogram of loop exit counts
extern unsigned totalLoopMethods; // counts the total number of methods that have natural loops
extern unsigned maxLoopsPerMethod; // counts the maximum number of loops a method has
extern unsigned totalLoopOverflows; // # of methods that identified more loops than we can represent
extern unsigned totalLoopCount; // counts the total number of natural loops
extern unsigned totalUnnatLoopCount; // counts the total number of (not-necessarily natural) loops
extern unsigned totalUnnatLoopOverflows; // # of methods that identified more unnatural loops than we can represent
extern unsigned iterLoopCount; // counts the # of loops with an iterator (for like)
extern unsigned constIterLoopCount; // counts the # of loops with a constant iterator (for like)
extern bool hasMethodLoops; // flag to keep track if we already counted a method as having loops
extern unsigned loopsThisMethod; // counts the number of loops in the current method
extern bool loopOverflowThisMethod; // True if we exceeded the max # of loops in the method.
extern Histogram loopCountTable; // Histogram of loop counts
extern Histogram loopExitCountTable; // Histogram of loop exit counts

#endif // COUNT_LOOPS

Expand Down
12 changes: 2 additions & 10 deletions src/coreclr/jit/fgdiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3781,13 +3781,10 @@ void Compiler::fgDebugCheckLoopTable()
}

// Check the flags.
// Note that the various init/limit flags are only used when LPFLG_ITER is set, but they are set first,
// Note that the various limit flags are only used when LPFLG_ITER is set, but they are set first,
// separately, and only if everything works out is LPFLG_ITER set. If LPFLG_ITER is NOT set, the
// individual flags are not un-set (arguably, they should be).

// Only one of the `init` flags can be set.
assert(genCountBits((unsigned)(loop.lpFlags & (LPFLG_VAR_INIT | LPFLG_CONST_INIT))) <= 1);

// Only one of the `limit` flags can be set. (Note that LPFLG_SIMD_LIMIT is a "sub-flag" that can be
// set when LPFLG_CONST_LIMIT is set.)
assert(genCountBits((unsigned)(loop.lpFlags & (LPFLG_VAR_LIMIT | LPFLG_CONST_LIMIT | LPFLG_ARRLEN_LIMIT))) <=
Expand All @@ -3799,14 +3796,9 @@ void Compiler::fgDebugCheckLoopTable()
assert(loop.lpFlags & LPFLG_CONST_LIMIT);
}

if (loop.lpFlags & (LPFLG_CONST_INIT | LPFLG_VAR_INIT))
if (loop.lpFlags & LPFLG_CONST_INIT)
{
assert(loop.lpInitBlock != nullptr);

if (loop.lpFlags & LPFLG_VAR_INIT)
{
assert(loop.lpVarInit < lvaCount);
}
}

if (loop.lpFlags & LPFLG_ITER)
Expand Down
16 changes: 6 additions & 10 deletions src/coreclr/jit/loopcloning.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1038,17 +1038,18 @@ bool Compiler::optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext
if (loop->lpFlags & LPFLG_CONST_INIT)
{
// Only allowing non-negative const init at this time.
// REVIEW: why?
// This is because the variable initialized with this constant will be used as an array index,
// and array indices must be non-negative.
if (loop->lpConstInit < 0)
{
JITDUMP("> Init %d is invalid\n", loop->lpConstInit);
return false;
}
}
else if (loop->lpFlags & LPFLG_VAR_INIT)
else
{
// initVar >= 0
const unsigned initLcl = loop->lpVarInit;
// iterVar >= 0
const unsigned initLcl = loop->lpIterVar();
if (!genActualTypeIsInt(lvaGetDesc(initLcl)))
{
JITDUMP("> Init var V%02u not compatible with TYP_INT\n", initLcl);
Expand All @@ -1059,11 +1060,6 @@ bool Compiler::optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext
LC_Expr(LC_Ident(0, LC_Ident::Const)));
context->EnsureConditions(loopNum)->Push(geZero);
}
else
{
JITDUMP("> Not variable init\n");
return false;
}

// Limit Conditions
LC_Ident ident;
Expand Down Expand Up @@ -1096,7 +1092,7 @@ bool Compiler::optDeriveLoopCloningConditions(unsigned loopNum, LoopCloneContext
ArrIndex* index = new (getAllocator(CMK_LoopClone)) ArrIndex(getAllocator(CMK_LoopClone));
if (!loop->lpArrLenLimit(this, index))
{
JITDUMP("> ArrLen not matching");
JITDUMP("> ArrLen not matching\n");
return false;
}
ident = LC_Ident(LC_Array(LC_Array::Jagged, index, LC_Array::ArrLen));
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/loopcloning.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ exception occurs.
1. Loop detection has completed and the loop table is populated.
2. The loops that will be considered are the ones with the LPFLG_ITER flag:
"for (i = icon or lclVar; test_condition(); i++)"
"for ( ; test_condition(); i++)"
Limitations
Expand Down
Loading

0 comments on commit f2ed920

Please sign in to comment.