Skip to content
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

JIT: Make BasicBlock::bbPrev and bbNext private #93032

Merged
merged 15 commits into from
Oct 6, 2023

Conversation

amanasifkhalid
Copy link
Member

Followup to #92908, and next step for #93020. CC @dotnet/jit-contrib.

@ghost ghost assigned amanasifkhalid Oct 4, 2023
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Oct 4, 2023
@ghost
Copy link

ghost commented Oct 4, 2023

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Issue Details

Followup to #92908, and next step for #93020. CC @dotnet/jit-contrib.

Author: amanasifkhalid
Assignees: amanasifkhalid
Labels:

area-CodeGen-coreclr

Milestone: -

@BruceForstall
Copy link
Member

BruceForstall commented Oct 5, 2023

No asm diffs but some TP diffs (maybe because SetBBPrev() does more than what it replaces?)

@BruceForstall
Copy link
Member

BruceForstall commented Oct 5, 2023

Seems like we should work to avoid too many GetBBNext() calls in the code (maybe as a follow-up?)

E.g., instead of (block->bbNext == nullptr) => a new function block->IsLast(), and block->bbPrev == nullptr => block->IsFirst().

block->GetBBNext() == compiler->fgFirstColdBlock => block->IsLastHotBlock(compiler) (true also for no cold section and block->IsEnd()?) Similarly, block->IsFirstColdBlock(compiler)?

This might be more controversial, but block->GetBBNext() == block2 => block->NextIs(block2)? Similarly, block->GetBBPrev() == block2 => block->PrevIs(block2).

Given the above, should we name GetBBNext() simply Next() and GetBBPrev() simply Prev()? The set functions could be SetNext() and SetPrev().

Looks like there are a few more places that can use the block iterators instead of manual for loops (though maybe not? the iterators don't tolerate block list modifications)

}
}

BasicBlock* GetBBNext() const
Copy link
Contributor

Choose a reason for hiding this comment

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

While we're renaming things, we could give these more "obvious" names, e. g. GetNextBlock.

@amanasifkhalid
Copy link
Member Author

No asm diffs but some TP diffs (maybe because SetBBPrev() does more than what it replaces?)

We previously had BasicBlock::setNext() that updated bbNext, and also null-checked the new next block to see if it could update its bbPrev; most of the time, we'd just directly update bbNext, and would sparingly call setNext() if we also intended to update the next block's bbPrev. Would it make sense to not have SetBBNext() do this additional work, and keep setNext() around to do it? I think this would reduce/eliminate the TP diffs, but we'd lose the guarantee that bbNext and bbNext->bbPrev are consistent within SetBBNext().

Seems like we should work to avoid too many GetBBNext() calls in the code (maybe as a follow-up?)

I'm happy to add helper methods for checking bbNext/bbPrev. This is for readability, since GetBBNext() should be getting inlined, right?

@amanasifkhalid
Copy link
Member Author

E.g., instead of (block->bbNext == nullptr) => a new function block->IsLast(), and block->bbPrev == nullptr => block->IsFirst().

Would it be preferable to check against fgFirstBB and fgLastBB instead of adding new methods? Ditto checking if block == fgFirstColdBlock instead of a new method (though for checking if a block is the last hot block, I agree we'd need a new method to avoid calling GetBBNext()).

@BruceForstall
Copy link
Member

Would it make sense to not have SetBBNext() do this additional work, and keep setNext() around to do it?

No, it's probably best to leave it as you have it now.

I'm happy to add helper methods for checking bbNext/bbPrev. This is for readability, since GetBBNext() should be getting inlined, right?

Yes.

Would it be preferable to check against fgFirstBB and fgLastBB instead of adding new methods? Ditto checking if block == fgFirstColdBlock instead of a new method (though for checking if a block is the last hot block, I agree we'd need a new method to avoid calling GetBBNext()).

We don't always have a Compiler* available that can be used to get fgFirstBB/fgLastBB.

For fgFirstColdBlock we have no other way to check except using that variable, which then requires a Compiler*.

@AndyAyersMS
Copy link
Member

I suspect over time we're going to see more and more cases where BB operations are contextual and need access to the compiler instance. At various times I've wondered if blocks should just point back to some parent object (either the compiler or some sort of "flow graph" object, but that seems wasteful. Given that blocks are all the same size we could perhaps play tricks to factor out common fields, if we say allocated them contiguously. For now, I think providing the context when needed via args is ok.

One issue with either a context arg or a parent object is that when we inline we do some funny things as there are two compiler objects around, and so it's possible to consult the wrong one....

@amanasifkhalid
Copy link
Member Author

@BruceForstall @AndyAyersMS PTAL. CI is clean, but small TP diffs. I'm planning on making the jump target members private next; if we can assert the jump kind is valid every time we try to read the jump destination, then maybe we can remove code that sets the jump destination to null when changing the jump kind. This might make up for the TP regression in Release builds.

Copy link
Member

@AndyAyersMS AndyAyersMS left a comment

Choose a reason for hiding this comment

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

This LGTM. Thanks!

Copy link
Member

@BruceForstall BruceForstall left a comment

Choose a reason for hiding this comment

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

Found a few nits that could be updated. Can't say I looked at every case.

@@ -186,6 +186,21 @@ FlowEdge* Compiler::BlockPredsWithEH(BasicBlock* blk)
return res;
}

//------------------------------------------------------------------------
// IsLastHotBlock: see if this is the last block before the cold section
Copy link
Member

Choose a reason for hiding this comment

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

Should we have a corresponding IsFirstColdBlock(Compiler*)?

Copy link
Member Author

Choose a reason for hiding this comment

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

I can add that in for consistency.

Comment on lines 1479 to 1480
assert((m_block->IsLast()) || m_block->Next()->PrevIs(m_block));
assert((m_block->IsFirst()) || m_block->Prev()->NextIs(m_block));
Copy link
Member

Choose a reason for hiding this comment

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

With the function, we can remove an unnecessary set of parens

Suggested change
assert((m_block->IsLast()) || m_block->Next()->PrevIs(m_block));
assert((m_block->IsFirst()) || m_block->Prev()->NextIs(m_block));
assert(m_block->IsLast() || m_block->Next()->PrevIs(m_block));
assert(m_block->IsFirst() || m_block->Prev()->NextIs(m_block));

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for catching all these nits (sorry, these kinds of PRs seem especially tedious to review).

@@ -5210,7 +5210,7 @@ void CodeGen::genReserveEpilog(BasicBlock* block)

assert(block != nullptr);
const VARSET_TP& gcrefVarsArg(GetEmitter()->emitThisGCrefVars);
bool last = (block->bbNext == nullptr);
bool last = (block->IsLast());
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
bool last = (block->IsLast());
bool last = block->IsLast();

or just substitute it in the call below and eliminate the last var

@@ -5257,7 +5257,7 @@ void CodeGen::genReserveFuncletEpilog(BasicBlock* block)

JITDUMP("Reserving funclet epilog IG for block " FMT_BB "\n", block->bbNum);

bool last = (block->bbNext == nullptr);
bool last = (block->IsLast());
Copy link
Member

Choose a reason for hiding this comment

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

ditto

@@ -547,10 +546,10 @@ void CodeGen::genCodeForBBlist()

/* Is this the last block, and are there any open scopes left ? */

bool isLastBlockProcessed = (block->bbNext == nullptr);
bool isLastBlockProcessed = (block->IsLast());
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
bool isLastBlockProcessed = (block->IsLast());
bool isLastBlockProcessed = block->IsLast();

if (block->isBBCallAlwaysPair())
{
isLastBlockProcessed = (block->bbNext->bbNext == nullptr);
isLastBlockProcessed = (block->Next()->IsLast());
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
isLastBlockProcessed = (block->Next()->IsLast());
isLastBlockProcessed = block->Next()->IsLast();

@@ -615,7 +614,7 @@ void CodeGen::genCodeForBBlist()
// Note: we may be generating a few too many NOPs for the case of call preceding an epilog. Technically,
// if the next block is a BBJ_RETURN, an epilog will be generated, but there may be some instructions
// generated before the OS epilog starts, such as a GS cookie check.
if ((block->bbNext == nullptr) || !BasicBlock::sameEHRegion(block, block->bbNext))
if ((block->IsLast()) || !BasicBlock::sameEHRegion(block, block->Next()))
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if ((block->IsLast()) || !BasicBlock::sameEHRegion(block, block->Next()))
if (block->IsLast() || !BasicBlock::sameEHRegion(block, block->Next()))

@@ -818,7 +817,7 @@ void CodeGen::genCodeForBBlist()
GetEmitter()->emitLoopAlignment(DEBUG_ARG1(block->KindIs(BBJ_ALWAYS)));
}

if ((block->bbNext != nullptr) && (block->bbNext->isLoopAlign()))
if (!block->IsLast() && (block->Next()->isLoopAlign()))
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (!block->IsLast() && (block->Next()->isLoopAlign()))
if (!block->IsLast() && block->Next()->isLoopAlign())

@@ -5291,11 +5291,11 @@ PhaseStatus Compiler::placeLoopAlignInstructions()
}
}

if ((block->bbNext != nullptr) && (block->bbNext->isLoopAlign()))
if (!block->IsLast() && (block->Next()->isLoopAlign()))
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (!block->IsLast() && (block->Next()->isLoopAlign()))
if (!block->IsLast() && block->Next()->isLoopAlign())

@@ -5641,24 +5635,20 @@ void Compiler::fgMoveBlocksAfter(BasicBlock* bStart, BasicBlock* bEnd, BasicBloc
{
printf("Relocated block%s [" FMT_BB ".." FMT_BB "] inserted after " FMT_BB "%s\n", (bStart == bEnd) ? "" : "s",
bStart->bbNum, bEnd->bbNum, insertAfterBlk->bbNum,
(insertAfterBlk->bbNext == nullptr) ? " at the end of method" : "");
(insertAfterBlk->IsLast()) ? " at the end of method" : "");
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
(insertAfterBlk->IsLast()) ? " at the end of method" : "");
insertAfterBlk->IsLast() ? " at the end of method" : "");

@amanasifkhalid
Copy link
Member Author

@BruceForstall I think I fixed all the style issues introduced (plus a couple extra I found along the way).

Copy link
Member

@BruceForstall BruceForstall left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks!

@amanasifkhalid amanasifkhalid merged commit 22d034f into dotnet:main Oct 6, 2023
139 checks passed
@ghost ghost locked as resolved and limited conversation to collaborators Nov 5, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants