Skip to content

Check if loop body occured before loopTop and if so unmark alignment #91854

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

Merged
merged 1 commit into from
Sep 12, 2023
Merged
Changes from all 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
34 changes: 31 additions & 3 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5276,6 +5276,13 @@ PhaseStatus Compiler::placeLoopAlignInstructions()
weight_t minBlockSoFar = BB_MAX_WEIGHT;
BasicBlock* bbHavingAlign = nullptr;
BasicBlock::loopNumber currentAlignedLoopNum = BasicBlock::NOT_IN_LOOP;
bool visitedLoopNum[BasicBlock::MAX_LOOP_NUM];
memset(visitedLoopNum, false, sizeof(visitedLoopNum));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's weird to use memset to zero a bool array, but ok.


#ifdef DEBUG
int visitedBlockForLoopNum[BasicBlock::MAX_LOOP_NUM];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

block nums can't be negative; use unsigned?

memset(visitedBlockForLoopNum, false, sizeof(visitedBlockForLoopNum));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's weird to use false as a value to zero an int array.

#endif

if ((fgFirstBB != nullptr) && fgFirstBB->isLoopAlign())
{
Expand All @@ -5298,7 +5305,7 @@ PhaseStatus Compiler::placeLoopAlignInstructions()
}
}

// If there is a unconditional jump (which is not part of callf/always pair)
// If there is an unconditional jump (which is not part of callf/always pair)
if (opts.compJitHideAlignBehindJmp && (block->bbJumpKind == BBJ_ALWAYS) && !block->isBBCallAlwaysPairTail())
{
// Track the lower weight blocks
Expand Down Expand Up @@ -5352,12 +5359,19 @@ PhaseStatus Compiler::placeLoopAlignInstructions()
madeChanges = true;
unmarkedLoopAlign = true;
}
else if ((block->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) && (block->bbNatLoopNum == loopTop->bbNatLoopNum))
else if (visitedLoopNum[loopTop->bbNatLoopNum])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you need to check that block->bbNatLoopNum != BasicBlock::NOT_IN_LOOP?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really. block is the previous block before loopTop and we want to check here if we have seen a loop body related to loopTop->bbNatLoopNum.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sorry, I meant, don't you need to check loopTop->bbNatLoopNum != BasicBlock::NOT_IN_LOOP?

It appears that sometimes it does equal NOT_IN_LOOP, leading to reading beyond the array bounds.

{
#ifdef DEBUG
char buffer[50];
sprintf_s(buffer, 50, "loop block " FMT_BB " appears before top of loop",
visitedBlockForLoopNum[loopTop->bbNatLoopNum]);
#endif

// In some odd cases we may see blocks within the loop before we see the
// top block of the loop. Just bail on aligning such loops.
//
loopTop->unmarkLoopAlign(this DEBUG_ARG("loop block appears before top of loop"));

loopTop->unmarkLoopAlign(this DEBUG_ARG(buffer));
madeChanges = true;
unmarkedLoopAlign = true;
}
Expand Down Expand Up @@ -5392,6 +5406,20 @@ PhaseStatus Compiler::placeLoopAlignInstructions()
break;
}
}

if (block->bbNatLoopNum != BasicBlock::NOT_IN_LOOP)
{
#ifdef DEBUG
if (!visitedLoopNum[block->bbNatLoopNum])
{
// Record the first block for which bbNatLoopNum was seen for
// debugging purpose.
visitedBlockForLoopNum[block->bbNatLoopNum] = block->bbNum;
}
#endif
// If this block is part of loop, mark the loopNum as visited.
visitedLoopNum[block->bbNatLoopNum] = true;
}
}

assert(loopsToProcess == 0);
Expand Down