Skip to content

Commit

Permalink
JIT: Abandon loop search if we are about to walk off end of the bbNex…
Browse files Browse the repository at this point in the history
…t chain

In #69323 the 6.0.4 jit caused an AV because it walked off the end of the
bbNext chain during `optFindNaturalLoops`.

Analysis of a customer-provided dump showed that `MakeCompactAndFindExits`
might fail to find an expected loop block and so walk the entire bbNext chain
and then fall off the end. Details from the dump suggested that this happened
because a prior call to `MakeCompactAndFindExits` had moved most but not all of
a loop's blocks later in bbNext order, leaving that loop's bottom block earlier
in the bbNext chain then it's top. This ordering was unexpected.

I cannot repro this failure. The customer was using PGO and it's likely that
earlier PGO-driven block reordering contributed to this problem by interleaving
the blocks from two loops. We can recover the root method PGO schema from the
dump, but applying this is insufficient to cause the problem. This method does
quite a bit of inlining so it's likely that some inlinee PGO data must also be
a contributing factor.

At any rate, we can guard against this case easily enough, and simply abandon
recognition of any loop where we fail to find an expected loop block during
the bbNext chain walk.
  • Loading branch information
AndyAyersMS authored and github-actions committed May 18, 2022
1 parent f0a71f2 commit 7d46c1d
Showing 1 changed file with 15 additions and 2 deletions.
17 changes: 15 additions & 2 deletions src/coreclr/jit/optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1928,13 +1928,26 @@ class LoopSearch
// This blocks is lexically between TOP and BOTTOM, but it does not
// participate in the flow cycle. Check for a run of consecutive
// such blocks.
//
// If blocks have been reordered and bbNum no longer reflects bbNext ordering
// (say by a call to MakeCompactAndFindExits for an earlier loop or unsuccessful
// attempt to find a loop), the bottom block of this loop may now appear earlier
// in the bbNext chain than other loop blocks. So when the previous hasn't reached bottom
// and block is a non-loop block, and we walk the bbNext chain, we may reach the end.
// If so, give up on recognition of this loop.
//
BasicBlock* lastNonLoopBlock = block;
BasicBlock* nextLoopBlock = block->bbNext;
while (!loopBlocks.IsMember(nextLoopBlock->bbNum))
while ((nextLoopBlock != nullptr) && !loopBlocks.IsMember(nextLoopBlock->bbNum))
{
lastNonLoopBlock = nextLoopBlock;
nextLoopBlock = nextLoopBlock->bbNext;
// This loop must terminate because we know BOTTOM is in loopBlocks.
}

if (nextLoopBlock == nullptr)
{
JITDUMP("Did not find expected loop block when walking from " FMT_BB "\n", lastNonLoopBlock->bbNum);
return false;
}

// Choose an insertion point for non-loop blocks if we haven't yet done so.
Expand Down

0 comments on commit 7d46c1d

Please sign in to comment.