Skip to content

Commit

Permalink
Loop alignment: Handle blocks added in loop as part of split edges of…
Browse files Browse the repository at this point in the history
… LSRA (#55047)

* Handle blocks added in loop as part of split edges of LSRA

If there are new blocks added by LSRA and modifies the flow of
blocks that are in loop, then make sure that we do not align such
loops if they intersect with last aligned loop.

* Retain LOOP_ALIGN flag of loops whose start are same

* jit format

* review feedback
  • Loading branch information
kunalspathak committed Jul 8, 2021
1 parent 9dd6d2e commit b2a5499
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 36 deletions.
114 changes: 84 additions & 30 deletions src/coreclr/jit/emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1023,9 +1023,9 @@ void emitter::emitBegFN(bool hasFramePtr
emitIGbuffSize = 0;

#if FEATURE_LOOP_ALIGN
emitLastAlignedIgNum = 0;
emitLastInnerLoopStartIgNum = 0;
emitLastInnerLoopEndIgNum = 0;
emitLastAlignedIgNum = 0;
emitLastLoopStart = 0;
emitLastLoopEnd = 0;
#endif

/* Record stack frame info (the temp size is just an estimate) */
Expand Down Expand Up @@ -4820,58 +4820,112 @@ unsigned emitter::getLoopSize(insGroup* igLoopHeader, unsigned maxLoopSize DEBUG
// if currIG has back-edge to dstIG.
//
// Notes:
// If the current loop encloses a loop that is already marked as align, then remove
// the alignment flag present on IG before dstIG.
// Despite we align only inner most loop, we might see intersected loops because of control flow
// re-arrangement like adding a split edge in LSRA.
//
// If there is an intersection of current loop with last loop that is already marked as align,
// then *do not align* one of the loop that completely encloses the other one. Or if they both intersect,
// then *do not align* either of them because since the flow is complicated enough that aligning one of them
// will not improve the performance.
//
void emitter::emitSetLoopBackEdge(BasicBlock* loopTopBlock)
{
insGroup* dstIG = (insGroup*)loopTopBlock->bbEmitCookie;
insGroup* dstIG = (insGroup*)loopTopBlock->bbEmitCookie;
bool alignCurrentLoop = true;
bool alignLastLoop = true;

// With (dstIG != nullptr), ensure that only back edges are tracked.
// If there is forward jump, dstIG is not yet generated.
//
// We don't rely on (block->bbJumpDest->bbNum <= block->bbNum) because the basic
// block numbering is not guaranteed to be sequential.

if ((dstIG != nullptr) && (dstIG->igNum <= emitCurIG->igNum))
{
unsigned currLoopStart = dstIG->igNum;
unsigned currLoopEnd = emitCurIG->igNum;

// Only mark back-edge if current loop starts after the last inner loop ended.
if (emitLastInnerLoopEndIgNum < currLoopStart)
if (emitLastLoopEnd < currLoopStart)
{
emitCurIG->igLoopBackEdge = dstIG;

JITDUMP("** IG%02u jumps back to IG%02u forming a loop.\n", currLoopEnd, currLoopStart);

emitLastInnerLoopStartIgNum = currLoopStart;
emitLastInnerLoopEndIgNum = currLoopEnd;
emitLastLoopStart = currLoopStart;
emitLastLoopEnd = currLoopEnd;
}
else if (currLoopStart == emitLastLoopStart)
{
// Note: If current and last loop starts at same point,
// retain the alignment flag of the smaller loop.
// |
// .---->|<----.
// last | | |
// loop | | | current
// .---->| | loop
// | |
// |-----.
//
}
else if ((currLoopStart < emitLastLoopStart) && (emitLastLoopEnd < currLoopEnd))
{
// if current loop completely encloses last loop,
// then current loop should not be aligned.
alignCurrentLoop = false;
}
else if ((emitLastLoopStart < currLoopStart) && (currLoopEnd < emitLastLoopEnd))
{
// if last loop completely encloses current loop,
// then last loop should not be aligned.
alignLastLoop = false;
}
else
{
// The loops intersect and should not align either of the loops
alignLastLoop = false;
alignCurrentLoop = false;
}
// Otherwise, mark the dstIG->prevIG as no alignment needed.
//
// Note: If current loop's back-edge target is same as emitLastInnerLoopStartIgNum,
// retain the alignment flag of dstIG->prevIG so the loop
// (emitLastInnerLoopStartIgNum ~ emitLastInnerLoopEndIgNum) is still aligned.
else if (emitLastInnerLoopStartIgNum != currLoopStart)
{
// Find the IG before dstIG...
instrDescAlign* alignInstr = emitAlignList;
while ((alignInstr != nullptr) && (alignInstr->idaIG->igNext != dstIG))
{
alignInstr = alignInstr->idaNext;
}

// ...and clear the IGF_LOOP_ALIGN flag
if (alignInstr != nullptr)
if (!alignLastLoop || !alignCurrentLoop)
{
instrDescAlign* alignInstr = emitAlignList;
bool markedLastLoop = alignLastLoop;
bool markedCurrLoop = alignCurrentLoop;
while ((alignInstr != nullptr))
{
assert(alignInstr->idaIG->igNext == dstIG);
alignInstr->idaIG->igFlags &= ~IGF_LOOP_ALIGN;
// Find the IG before current loop and clear the IGF_LOOP_ALIGN flag
if (!alignCurrentLoop && (alignInstr->idaIG->igNext == dstIG))
{
assert(!markedCurrLoop);
alignInstr->idaIG->igFlags &= ~IGF_LOOP_ALIGN;
markedCurrLoop = true;
JITDUMP("** Skip alignment for current loop IG%02u ~ IG%02u because it encloses an aligned loop "
"IG%02u ~ IG%02u.\n",
currLoopStart, currLoopEnd, emitLastLoopStart, emitLastLoopEnd);
}

// Find the IG before the last loop and clear the IGF_LOOP_ALIGN flag
if (!alignLastLoop && (alignInstr->idaIG->igNext != nullptr) &&
(alignInstr->idaIG->igNext->igNum == emitLastLoopStart))
{
assert(!markedLastLoop);
assert(alignInstr->idaIG->isLoopAlign());
alignInstr->idaIG->igFlags &= ~IGF_LOOP_ALIGN;
markedLastLoop = true;
JITDUMP("** Skip alignment for aligned loop IG%02u ~ IG%02u because it encloses the current loop "
"IG%02u ~ IG%02u.\n",
emitLastLoopStart, emitLastLoopEnd, currLoopStart, currLoopEnd);
}

if (markedLastLoop && markedCurrLoop)
{
break;
}

alignInstr = alignInstr->idaNext;
}

JITDUMP(
"** Skip alignment for loop IG%02u ~ IG%02u, because it encloses an aligned loop IG%02u ~ IG%02u.\n",
currLoopStart, currLoopEnd, emitLastInnerLoopStartIgNum, emitLastInnerLoopEndIgNum);
assert(markedLastLoop && markedCurrLoop);
}
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/coreclr/jit/emit.h
Original file line number Diff line number Diff line change
Expand Up @@ -1762,12 +1762,12 @@ class emitter
void emitJumpDistBind(); // Bind all the local jumps in method

#if FEATURE_LOOP_ALIGN
instrDescAlign* emitCurIGAlignList; // list of align instructions in current IG
unsigned emitLastInnerLoopStartIgNum; // Start IG of last inner loop
unsigned emitLastInnerLoopEndIgNum; // End IG of last inner loop
unsigned emitLastAlignedIgNum; // last IG that has align instruction
instrDescAlign* emitAlignList; // list of local align instructions in method
instrDescAlign* emitAlignLast; // last align instruction in method
instrDescAlign* emitCurIGAlignList; // list of align instructions in current IG
unsigned emitLastLoopStart; // Start IG of last inner loop
unsigned emitLastLoopEnd; // End IG of last inner loop
unsigned emitLastAlignedIgNum; // last IG that has align instruction
instrDescAlign* emitAlignList; // list of local align instructions in method
instrDescAlign* emitAlignLast; // last align instruction in method
unsigned getLoopSize(insGroup* igLoopHeader,
unsigned maxLoopSize DEBUG_ARG(bool isAlignAdjusted)); // Get the smallest loop size
void emitLoopAlignment();
Expand Down

0 comments on commit b2a5499

Please sign in to comment.