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

Filter blocks to be used for hiding alignment instruction #62262

Merged
merged 9 commits into from
Dec 6, 2021

Conversation

kunalspathak
Copy link
Member

@kunalspathak kunalspathak commented Dec 2, 2021

  • Using bbNaturalLoopNum track which blocks are in a loop and do not use those blocks for hiding align instruction.
  • Also do not use blocks that are part of callf/finally pair for hiding align instruction.

Fixes: #62238 and #61899

@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 Dec 2, 2021
@ghost
Copy link

ghost commented Dec 2, 2021

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

Issue Details
  • Using bbNaturalLoopNum track which blocks are in a loop and do not use those blocks for hiding align instruction.
  • Also do not use blocks that are part of callf/finally pair for hiding align instruction.
Author: kunalspathak
Assignees: -
Labels:

area-CodeGen-coreclr

Milestone: -

@kunalspathak kunalspathak marked this pull request as ready for review December 2, 2021 16:48
@kunalspathak
Copy link
Member Author

@dotnet/jit-contrib

src/coreclr/jit/compiler.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/compiler.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/compiler.cpp Outdated Show resolved Hide resolved
bbHavingAlign = block;
JITDUMP(FMT_BB ", bbWeight=" FMT_WT " ends with unconditional 'jmp' \n", block->bbNum, block->bbWeight);
// Only if they are not part of the loop that will be aligned
if ((block->bbNatLoopNum == BasicBlock::NOT_IN_LOOP) || (block->bbNatLoopNum != currentLoopNum))
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->bbNatLoopNum == BasicBlock::NOT_IN_LOOP) || (block->bbNatLoopNum != currentLoopNum))
if (currentLoopNum != BasicBlock::NOT_IN_LOOP)

We only care whether we're in an aligned loop or not.

Copy link
Member Author

Choose a reason for hiding this comment

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

Assuming I will keep the reset of currentLoopNum = NOT_IN_LOOP inside bbJumpDest check (the way I have currently), this will not work. currentLoopNum is initialized with NOT_IN_LOOP and we will never select a block that ends with jmp until we come across a loop that sets a valid value of currentLoopNum.

Copy link
Member

Choose a reason for hiding this comment

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

Right, my logic is backwards. It should be:

if (currentLoopNum == BasicBlock::NOT_IN_LOOP)
 // ... ok to insert alignment insruction behind JMP

The idea being:

  1. If curLoopNum == NOT_IN_LOOP, then we aren't processing an aligned loop. In this case, we can put an align instruction behind a JMP.
  2. If curLoopNum != NOT_IN_LOOP, then block is within a loop that we are aligning. Don't put align after a JMP instruction; wait until we reach the end of the aligned loop (determined by comparing curLoopNum against bbNatLoopNum)

Comment on lines 5305 to 5311

if ((block->bbJumpDest != nullptr) && (block->bbJumpDest->isLoopAlign()))
{
// This is the last block of current loop. Reset the latestLoopNum so we can resume
// placing the align behind jmp for subsequent loops.
currentLoopNum = BasicBlock::NOT_IN_LOOP;
}
Copy link
Member

Choose a reason for hiding this comment

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

I suggest removing this code and adding the following at the top of the loop:

if (currentLoopNum != BasicBlock::NOT_IN_LOOP)
{
  // We've been processing blocks within an aligned loop. Are we out of that loop now?
  if (currentLoopNum != block->bbNatLoopNum)
  {
    currentLoopNum = BasicBlock::NOT_IN_LOOP;
  }
}

Note that this only works because we only align innermost loops, since the bbNatLoopNum has the innermost loop number for a block.

Then, if this block is a BBJ_ALWAYS, subsequent code will allow it to be used to add alignment. And, if the next block starts a loop, the code at the end will set up currentLoopNum for the next iteration.

Copy link
Member Author

Choose a reason for hiding this comment

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

The current implementation will make sure we reset the currentLoopNum for the earliest back-edge we see. With your suggestion, if we have multiple back-edges to the loop, and in between, one of the block ended with jmp, we won't be able to use that for hiding the alignment because the currentLoopNum will still match the block->bbNatLoopNum.

Copy link
Member

Choose a reason for hiding this comment

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

That's correct, but do you think that's a limitation? After all, if the bbNatLoopNum still matches, it's still part of the same inner loop. Is this concern because the first back-edge is considered the loop end in emitter::getLoopSize()? I would argue that is incorrect, even if it's not an unreasonable simplification. I don't think this situation arises often anyway, as most loops have a single back edge to the top.

Copy link
Member Author

@kunalspathak kunalspathak Dec 2, 2021

Choose a reason for hiding this comment

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

Is this concern because the first back-edge is considered the loop end in emitter::getLoopSize()?

Yes. My thinking behind the existing logic is that if getLoopSize() only considers the first back-edge, then we should open the opportunity to find jmp after that point and use them if needed instead of waiting to complete the loop.

Copy link
Member

Choose a reason for hiding this comment

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

I would argue, alternatively, that we should think of ways to fix getLoopSize() to respect the loop package's determination about what constitutes the inner loop.

Note that, even as is, there are a few other concerns: (1) bbJumpDest is part of a union and not valid for all jump types, (2) you don't check that the branch is to the beginning of the loop we care about; it could be a forward branch so a subsequent loop that is aligned.

Copy link
Member Author

@kunalspathak kunalspathak Dec 2, 2021

Choose a reason for hiding this comment

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

I would argue, alternatively, that we should think of ways to fix getLoopSize() to respect the loop package's determination about what constitutes the inner loop.

I think that needs separate discussion and should be not part of this PR. The initial decision was to just check the earliest back-edge to determine the loop size. If we want something smarter, we can definitely look at the weights of other blocks (the ones that follows after the earlier back-edge) to determine if those blocks are hot enough and do we need to include them as part of our loop size. It might further complicate things and we don't even have data to check if it will give us benefit.

(1) bbJumpDest is part of a union and not valid for all jump types,

That's true. We check that in codegenlinear.cpp and I should add similar check here as well.

(2) you don't check that the branch is to the beginning of the loop we care about; it could be a forward branch so a subsequent loop that is aligned

To make that work properly, we will need block renumbering, after which I can check it based on bbNum if it is forward or backward, right?

Copy link
Member

Choose a reason for hiding this comment

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

True, no need to change getLoopSize() here. I'm arguing that this code code be the "correct" general case, and getLoopSize can follow later, if necessary.

To make that work properly, we will need block renumbering, after which I can check it based on bbNum if it is forward or backward, right?

You could save away the block with the ALIGN bit and compare against that when looking for back edges.

However, I think my suggestion is simpler and doesn't require that.

@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 Dec 2, 2021
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

@kunalspathak
Copy link
Member Author

/azp run runtime-coreclr jitstress

@kunalspathak
Copy link
Member Author

/azp run runtime-coreclr libraries-jitstress

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

1 similar comment
@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@kunalspathak
Copy link
Member Author

Failures are #62285 and #62267

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.

microsoft.extensions.logging.generators.roslyn3.11.tests work item
2 participants