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

Perform reachability analysis before codegen #66967

Merged
merged 9 commits into from
Mar 29, 2022

Conversation

kunalspathak
Copy link
Member

@kunalspathak kunalspathak commented Mar 22, 2022

Perform reachability analysis one last time before doing code gen to eliminate unreachable blocks.

While investigating, #66578, I noticed that there was lot of dead blocks that were kept around and that keeps variables alive longer and creating unnecessary refpositions. Having extra refpositions is not problematic, but the liveness of variables was not tracked correctly because of unreachable blocks. The liveness of variables decides if an interval should be spilled or not. As seen in my analysis in #66578 (comment), there were 3 refpositions (def, use, use) created for the problematic variable, but because of missing liveness, both the uses were marked as lastUse leading to making the interval as inactive instead of spilled.

In this PR, I have added the computeReachability() phase after all the optimizations are done so it can remove any unreachable blocks. It performs the block renumbering, but since LSRA is sensitive to block renumbering (see #66994), I didn't want to see its impact as part of this change. Hence, I have added an option to skip the block renumbering in the final phase.

PIN numbers on windows/x64 SPMI

Collection Base Diff % diff
libraries 1392303237458 1393889260100 0.11%
benchmarks 328547820836 328920196300 0.11%

Also emit the block size after every block in order to spot the code size diff at block level.

Fixes: #66578

@ghost ghost assigned kunalspathak Mar 22, 2022
@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 Mar 22, 2022
@ghost
Copy link

ghost commented Mar 22, 2022

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

Issue Details

Perform reachability analysis one last time before doing code gen to eliminate unreachable blocks.

Author: kunalspathak
Assignees: kunalspathak
Labels:

area-CodeGen-coreclr

Milestone: -

@kunalspathak kunalspathak marked this pull request as ready for review March 22, 2022 20:55
@kunalspathak
Copy link
Member Author

@dotnet/jit-contrib

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.

Are you actually removing the blocks anywhere?

fgComputeReachability is not particularly efficient (it blindly unions all preds instead of just the ones with updates).

It is overkill for what I think you are looking for here -- you only want to know if a block A is reachable from method entry, not whether block A is reachable from block B.

fgComputeReachability also updates the gc safe block flags, which, while likely harmless is probably not something we want to be doing.

So I think you can get this information more cheaply and with less collateral impact.

EnsureBasicBlockEpoch();
fgComputeReachability(/* computeDoms */ false, /* doRenumbering */ false);
};
DoPhase(this, PHASE_COMPUTE_REACHABILITY, computeReachability);
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 use a different local name and a different phase name (reusing a phase name likely messes up some stats computations).

@@ -4769,7 +4769,8 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl

// Compute reachability sets and dominators.
//
DoPhase(this, PHASE_COMPUTE_REACHABILITY, &Compiler::fgComputeReachability);
Copy link
Member

Choose a reason for hiding this comment

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

Why does this need to change?

@@ -6556,7 +6556,8 @@ unsigned emitter::emitEndCodeGen(Compiler* comp,
#ifdef DEBUG
if (emitComp->opts.disAsm || emitComp->verbose)
{
printf("\t\t\t\t\t\t;; bbWeight=%s PerfScore %.2f", refCntWtd2str(ig->igWeight), ig->igPerfScore);
printf("\t\t\t\t\t\t;; size=%d bbWeight=%s PerfScore %.2f", ig->igSize, refCntWtd2str(ig->igWeight),
Copy link
Member

Choose a reason for hiding this comment

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

nit: why so much whitespace?

// Arguments:
// renumberingDone -- `true` if block renumbering was done.
//
void Compiler::fgComputeEnterBlocksSet(DEBUG_ARG1(const bool renumberingDone))
Copy link
Member

Choose a reason for hiding this comment

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

This is kind of annoying (adding an arg just for this). Why not just remove the offending assert instead? Doesn't seem like it has much value anyway.

@@ -543,10 +546,14 @@ bool Compiler::fgRemoveUnreachableBlocks()
// Also, compute the list of return blocks `fgReturnBlocks` and set of enter blocks `fgEnterBlks`.
// Delete unreachable blocks.
//
// Arguments:
// computeDoms - Whether to compute doms or not.
Copy link
Member

Choose a reason for hiding this comment

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

It would be useful to understand (and add to this comment block) when renumbering is required, and why. And when it is not. Same for creating doms.

@ghost ghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Mar 22, 2022
@kunalspathak
Copy link
Member Author

Are you actually removing the blocks anywhere?

Yes, after it tracks the bbReach it uses it to determine (by referring the fgEnterBlks) whether to remove it or not, but I agree with you. I can do bbReach or equivalent calculation cheaper. Let me work on it.

if (!BlockSetOps::IsEmptyIntersection(this, fgEnterBlks, block->bbReach))
{
continue;
}
#if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)
if (!BlockSetOps::IsEmptyIntersection(this, fgAlwaysBlks, block->bbReach))
{
continue;
}

@ghost ghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Mar 22, 2022
@kunalspathak
Copy link
Member Author

@AndyAyersMS - Just to answer your original question, yes it does remove block in that method as seen in asmdiffs.

@kunalspathak
Copy link
Member Author

I have verified the diffs between the new implementation and previous (exhaustive) implementation and there is no diff.

@kunalspathak
Copy link
Member Author

Ping.

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.

I think the approach is good.

I have one question and also wondered if you had new TP measurements.

src/coreclr/jit/fgopt.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/fgopt.cpp Show resolved Hide resolved
src/coreclr/jit/fgopt.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/fgopt.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/fgopt.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/fgopt.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/fgopt.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/fgopt.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/fgopt.cpp Outdated Show resolved Hide resolved
@kunalspathak
Copy link
Member Author

Latest pin numbers on superpmi libraries_pmi collection:

Before: 327744184719
After: 328136546105
Diff: 0.12%

src/coreclr/jit/fgopt.cpp Outdated Show resolved Hide resolved
@kunalspathak
Copy link
Member Author

failure related to #59542

@EgorBo
Copy link
Member

EgorBo commented Apr 7, 2022

Improvements in System.Text.Json.Tests.Perf_Booleans dotnet/perf-autofiling-issues#4364 on x64
dotnet/perf-autofiling-issues#4284

@ghost ghost locked as resolved and limited conversation to collaborators May 7, 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 'interval->isSpilled' during 'LSRA allocate'
4 participants