Skip to content

Commit 3f7c770

Browse files
committed
Do not continue to merge back cold path if guard2 block has been removed
`changeBranchDestination` tries to remove unreachable blocks after the removal of the old edge from guard2 to cold2. Rarely, a previous transformation in this pass could have made guard2Block unreachable without removing it, in which case it might have been removed just now. Normally, if all relevant blocks are removed, later `moveBlockAfterDest` will not cause any issue since it will be just moving around all unreachable blocks. However, in an even more rare case, if some of the blocks are removed and some of them are not (eg, guard2Block and the previous block of guard2Block are removed but the next block of guard2Block is still valid), `moveBlockAfterDest` could end up joining an invalid/removed block with a valid block. Therefore, if guard2Block is no longer valid, it should not proceed. Fixes: eclipse-openj9/openj9#18873 Signed-off-by: Annabelle Huo <[email protected]>
1 parent 6391cf4 commit 3f7c770

File tree

1 file changed

+32
-5
lines changed

1 file changed

+32
-5
lines changed

compiler/optimizer/VirtualGuardHeadMerger.cpp

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,20 +284,23 @@ static void moveBlockAfterDest(TR::CFG *cfg, TR::Block *toMove, TR::Block *dest)
284284
}
285285

286286
// This opt tries to reduce merge backs from cold code that are the result of inliner
287-
// gnerated nopable virtual guards
287+
// generated nopable virtual guards
288288
// It looks for one basic pattern
289289
//
290290
// guard1 -> cold1
291291
// BBEND
292292
// BBSTART
293293
// guard2 -> cold2
294-
// if guard1 is the guard for a method which calls the method guard2 protects or cold1 is
295-
// a predecessor of cold2 (a situation commonly greated by virtual guard tail splitter) we
296-
// can transform the guards as follows when guard1 and guard2 a
294+
//
295+
// If guard1 is the guard for a method which calls the method guard2 protects or cold1 is
296+
// a predecessor of cold2 (a situation commonly created by virtual guard tail splitter) we
297+
// can transform the guards as follows:
298+
//
297299
// guard1 -> cold1
298300
// BBEND
299301
// BBSTART
300302
// guard2 -> cold1
303+
//
301304
// This is safe because there are no trees between the guards and calling the caller will
302305
// result in the call to the callee if we need to patch guard2. cold2 and its mergebacks
303306
// can then be eliminated
@@ -383,6 +386,14 @@ int32_t TR_VirtualGuardHeadMerger::perform() {
383386
// scan for candidate guards to merge with guard1 identified above
384387
for (TR::Block *nextBlock = block->getNextBlock(); nextBlock; nextBlock = nextBlock->getNextBlock())
385388
{
389+
if (block->nodeIsRemoved() || nextBlock->nodeIsRemoved())
390+
{
391+
if (trace())
392+
traceMsg(comp(), "block block_%d %p (%d) or nextBlock block_%d %p (%d) has been removed\n",
393+
block->getNumber(), block, block->nodeIsRemoved(), nextBlock->getNumber(), nextBlock, nextBlock->nodeIsRemoved());
394+
break;
395+
}
396+
386397
if (!(nextBlock->getPredecessors().size() == 1) ||
387398
!nextBlock->hasPredecessor(block))
388399
{
@@ -467,6 +478,22 @@ int32_t TR_VirtualGuardHeadMerger::perform() {
467478
if (guard2->getBranchDestination() != guard1->getBranchDestination())
468479
guard2Block->changeBranchDestination(guard1->getBranchDestination(), cfg);
469480

481+
// changeBranchDestination tries to remove unreachable blocks after the removal of the old edge
482+
// from guard2 to cold2. Rarely, a previous transformation in this pass could have made
483+
// guard2Block unreachable without removing it, in which case it might have been removed just now.
484+
// Normally, if all relevant blocks are removed, later moveBlockAfterDest will not cause any issue
485+
// since it will be just moving around all unreachable blocks. However, in an even more rare case,
486+
// if some of the blocks are removed and some of them are not (eg, guard2Block and the previous block
487+
// of guard2Block are removed but the next block of guard2Block is still valid), moveBlockAfterDest
488+
// could end up joining an invalid/removed block with a valid block. Therefore, if guard2Block
489+
// is no longer valid, it should not proceed.
490+
if (guard2Block->nodeIsRemoved())
491+
{
492+
if (trace())
493+
traceMsg(comp(), "guard2Block block_%d %p has been removed after changeBranchDestination\n", guard2Block->getNumber(), guard2Block);
494+
break;
495+
}
496+
470497
if (guard2Tree != guard2Block->getFirstRealTreeTop())
471498
{
472499
cfg->setStructure(NULL);
@@ -477,7 +504,7 @@ int32_t TR_VirtualGuardHeadMerger::perform() {
477504
// 2, it might contain live monitor, moving it up above a guard can affect the monitor's live range
478505
if (!isStopTheWorldGuard(guard2))
479506
{
480-
// the block created above guard2 contains only privarg treetops or monitor stores if
507+
// the block created above guard2 contains only privarg treetops or monitor stores if
481508
// guard2 is a runtime-patchable guard and is safe to merge. We need to move the priv
482509
// args up to the runtime insert point and leave the monitor stores in place
483510
// It's safe to do so because there is no data dependency between the monitor store and

0 commit comments

Comments
 (0)