Skip to content

Conversation

@kunalspathak
Copy link
Contributor

Currently, we save and restore vectors for BBJ_THROW blocks as well, which is not really needed. In #62662, we avoiding doing save/restore for calls that do not return. This PR extends the logic to also skip save/restore if the block ends with throw.

This also reverts #66062.

Fixes: #65332

@ghost ghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Mar 2, 2022
@ghost ghost assigned kunalspathak Mar 2, 2022
@ghost
Copy link

ghost commented Mar 2, 2022

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

Issue Details

Currently, we save and restore vectors for BBJ_THROW blocks as well, which is not really needed. In #62662, we avoiding doing save/restore for calls that do not return. This PR extends the logic to also skip save/restore if the block ends with throw.

This also reverts #66062.

Fixes: #65332

Author: kunalspathak
Assignees: kunalspathak
Labels:

area-CodeGen-coreclr

Milestone: -

@kunalspathak
Copy link
Contributor Author

/azp run runtime-coreclr superpmi-replay, runtime-coreclr jitstressregs

@kunalspathak
Copy link
Contributor Author

@dotnet/jit-contrib , @BruceForstall

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

{
if ((tree != nullptr) && tree->IsCall())
{
if (tree->AsCall()->IsNoReturn())
Copy link
Member

Choose a reason for hiding this comment

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

You might also want to check fgIsThrow here but I assume both IsNoreReturn and fgIsThrow should always be inside a BBJ_THROW block

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I looked around and seems that the only non-throw case where calls are marked as NoReturn is here:

impInlineInfo->iciCall->gtCallMoreFlags |= GTF_CALL_M_DOES_NOT_RETURN;

I am not familiar with how that translates to during LSRA.

}
}

if ((compiler->compCurBB != nullptr) && (compiler->compCurBB->KindIs(BBJ_THROW)))
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps, block should a parameter, or method renamed to something stating it checks current block?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought about passing block as a parameter but there are lot of call chain where I would have to pass block. We use compCurBB in earlier phases as well as curBBNum in LSRA to avoid doing that. As far method name, I think I have stated in the comments that it inspects the block.

{
if (tree->AsCall()->IsNoReturn())
{
// No point in having vector save/restore if the call will not return.
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 not clear to me why this would be safe. Couldn't you have computation after a call that requires restoring the registers, and before a throw?

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like it's only safe if there are not uses of the (restored) register between this point and the throw, in which case the restore is "dead code".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Vector restore happens at two places:

  • At the end of every block, whenever any largeVectorVars was partially spilled
  • At the locations where we see the use

While it should be safe to eliminate the restores (and hence the saves) that happen for #1 above if the block is a THROW block, but there can be a scenario (as you pointed out) where eliminating save/restore will be wrong:

save(Vx)  ; <- shouldn't be eliminated because of the use
CALL ...
Vx = restore() ;  <- shouldn't be eliminated because of the use
 = use(Vx)
...
THROW

Since UpperVectorSave refpositions are created when we build kills, it is hard to look ahead to see which ones of them will be used (and hence restored) and thus can be eliminated. For e.g. in following case, we can (should) eliminate the unnecessary save/restore.

save(Vx)  ; <- safe to eliminate
CALL ...
Vx = restore() ;  <- safe to eliminate
...
THROW

To summarize, I was trying to eliminate vector saves, but it might not be safe (as Bruce pointed), so I will just try to at least eliminate the restore that happens at the end of the THROW block.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hhm, looks like our model is not built such that it can withstand to see only saves and not (optimally removed) restores.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Pushed an attempt to track for a block that throws, if a spill done before the call will ever be used. If not, skip save/restore for them. While I am at it, I will check what it takes to fix the problem @sandreenko pointed out in #59315.

@ghost ghost added needs-author-action An issue or pull request that requires more info or actions from the author. and removed needs-author-action An issue or pull request that requires more info or actions from the author. labels Mar 2, 2022
@kunalspathak
Copy link
Contributor Author

/azp run runtime-coreclr superpmi-replay, runtime-coreclr jitstressregs

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@kunalspathak
Copy link
Contributor Author

/azp run runtime-coreclr jitstressregs

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@kunalspathak
Copy link
Contributor Author

The failures seems to be infrastructure issue. superpmi-replay is green which used to fail earlier.
@BruceForstall - can you take a look at the fresh updates?

Copy link
Contributor

@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

@kunalspathak
Copy link
Contributor Author

Failure is #65455.

@kunalspathak kunalspathak merged commit d832bef into dotnet:main Mar 4, 2022
@kunalspathak kunalspathak deleted the vector-save-restore branch March 4, 2022 07:00
@ghost ghost locked as resolved and limited conversation to collaborators Apr 3, 2022
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.

Assertion failed 'block->KindIs(BBJ_NONE, BBJ_ALWAYS)'

3 participants