Skip to content

JIT: Add a head merging transformation alongside the tail merging transformation - #90468

Merged
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging
Aug 18, 2023
Merged

JIT: Add a head merging transformation alongside the tail merging transformation#90468
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Aug 12, 2023

Copy link
Copy Markdown
Member

Add a pass that does head merging to complement the existing tail merging pass. Unlike tail merging this either requires spilling or reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix#90017

Add a pass that does head merging to compliment the existing tail
merging pass. Unlike tail merging this requires reordering the first
statement with the terminator node of the predecessor, which requires
some interference checking.
Fixdotnet#90017
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Aug 12, 2023
@ghost

Copy link
Copy Markdown

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

Issue Details

Add a pass that does head merging to compliment the existing tail merging pass. Unlike tail merging this requires reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix #90017

Author:jakobbotsch
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotschjakobbotsch added this to the 9.0.0 milestone Aug 14, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 10:17
@jakobbotsch
jakobbotsch marked this pull request as draft August 16, 2023 10:25
@jakobbotschjakobbotsch changed the title JIT: Add a head merging passJIT: Add a head merging transformation alongside the tail merging transformationAug 16, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 13:08
@jakobbotsch

jakobbotsch commented Aug 16, 2023

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Diffs. Quite skewed because of one particular test, but still a fair amount of improvements, in a lot of cases creating new conditional selects (which both bring size-wise improvements and regressions). The reordering also can bring regressions with it, in the same way that we see from forward sub sometimes.

There's also a consideration that tail merging and head merging can create new opportunities for each other, but this change doesn't try to rerun either of them when that potentially happens.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn, runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
{
if (gtHasRef(tree1, dsc->lvFieldLclStart + i))
{
JITDUMP(" cannot reorder with interferring use of struct field\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
JITDUMP(" cannot reorder with interferring use of struct field\n");
JITDUMP(" cannot reorder with interfering use of struct field\n");

similar elsehwere

@AndyAyersMS

Copy link
Copy Markdown
Member

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Seems like a pretty natural fit.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

@jakobbotsch

jakobbotsch commented Aug 17, 2023

Copy link
Copy Markdown
MemberAuthor

The Fuzzlyn failures are #7539 (hitting this a lot after adding Unsafe.As support -- need to figure out what to do about it). Runtime and jitstress failures are #90593.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

For libraries.pmi the histogram of how many statements we head merge in each block (where we head merge any) looks like:

1 .. 1===>4173 count ( 56% of total)
2 .. 2===>972 count ( 70% of total)
3 .. 3===>919 count ( 82% of total)
4 .. 4===>366 count ( 87% of total)
5 .. 5===>487 count ( 94% of total)
6 .. 10===>360 count ( 99% of total)
11 .. 15===>40 count ( 99% of total)
16 .. 20===>5 count (100% of total)

I can try to see if I can improve TP a bit -- for one we shouldn't need to iterate over all BBs twice if we just call both head and tail merging from one loop.
I'm not sure that the interference checks are that costly, but certainly we could do fewer tree walks as part of it.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

The detailed TP breakdown is, after moving the head merging into fgHeadMerge:

Base:115595112161, Diff:115766296686, +0.1481%?fgHeadMerge@Compiler@@QEAA_NPEAUBasicBlock@@AEAV?$ArrayStack@UPredSuccInfo@@@@_N@Z:159867209:NA:20.48%:+0.1383%
`Compiler::fgHeadTailMerge'::`2'::<lambda_1>::operator() :128143167:NA:16.42%:+0.1109%?NumSucc@BasicBlock@@QEAAIPEAVCompiler@@@Z:55787892:+32.82%:7.15%:+0.0483%?fgHeadTailMerge@Compiler@@QEAA?AW4PhaseStatus@@_N@Z:53696551:NA:6.88%:+0.0465%?GetSucc@BasicBlock@@QEAAPEAU1@IPEAVCompiler@@@Z:30154807:+13.41%:3.86%:+0.0261%?Compare@GenTree@@SA_NPEAU1@0_N@Z:15846220:+21.62%:2.03%:+0.0137%
`Compiler::compCompile'::`2'::<lambda_3>::operator() :12277667:NA:1.57%:+0.0106%??$Emplace@AEAUPredSuccInfo@@@?$ArrayStack@UPredSuccInfo@@@@QEAAXAEAUPredSuccInfo@@@Z:5529537:NA:0.71%:+0.0048%?compCompile@Compiler@@IEAAXPEAPEAXPEAIPEAVJitFlags@@@Z:1684987:+1.37%:0.22%:+0.0015%GenTreeVisitor<`Compiler::gtHasLocalsWithAddrOp'::`2'::LocalsWithAddrOpVisitor>::WalkTree:1252917:+1.84%:0.16%:+0.0011%?fgUpdateFlowGraph@Compiler@@QEAA_N_N0@Z:1130065:+0.08%:0.14%:+0.0010%BasicBlock::VisitAllSuccs<`Compiler::optReachable'::`12'::<lambda_1>>:879816:+0.47%:0.11%:+0.0008%?fgReorderBlocks@Compiler@@QEAA_N_N@Z:-790057:-0.21%:0.10%:-0.0007%?newRefPosition@LinearScan@@AEAAPEAVRefPosition@@PEAVInterval@@IW4RefType@@PEAUGenTree@@_KI@Z:-801471:-0.09%:0.10%:-0.0007%?RenameDef@SsaBuilder@@AEAAXPEAUGenTree@@PEAUBasicBlock@@@Z:-812236:-0.86%:0.10%:-0.0007%?incRefCnts@LclVarDsc@@QEAAXNPEAVCompiler@@W4RefCountState@@_N@Z:-814351:-0.27%:0.10%:-0.0007%?OptimizeRangeCheck@RangeCheck@@QEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTree@@@Z:-825515:-0.37%:0.11%:-0.0007%?genCodeForTreeNode@CodeGen@@IEAAXPEAUGenTree@@@Z:-825588:-0.12%:0.11%:-0.0007%?MakeCopy@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAPEA_KPEAVCompiler@@PEA_K@Z:-835566:-0.32%:0.11%:-0.0007%?fgValueNumberBlock@Compiler@@QEAAXPEAUBasicBlock@@@Z:-846018:-0.31%:0.11%:-0.0007%?AddPhiArg@SsaBuilder@@AEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTreePhi@@II0@Z:-862799:-1.49%:0.11%:-0.0007%?getWeight@LinearScan@@AEAANPEAVRefPosition@@@Z:-866614:-0.29%:0.11%:-0.0007%?UnionD@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAXPEAVCompiler@@AEAPEA_KPEA_K@Z:-871931:-0.20%:0.11%:-0.0008%?fgMorphTree@Compiler@@QEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@@Z:-883522:-0.10%:0.11%:-0.0008%?RenamePushDef@SsaBuilder@@AEAAIPEAUGenTree@@PEAUBasicBlock@@I_N@Z:-886870:-1.13%:0.11%:-0.0008%?EnsureCoversInd@?$JitExpandArray@PEAUChunk@ValueNumStore@@@@IEAAXI@Z:-892604:-0.31%:0.11%:-0.0008%?gtSetEvalOrder@Compiler@@QEAAIPEAUGenTree@@@Z:-905597:-0.05%:0.12%:-0.0008%??$resolveRegisters@$00@LinearScan@@QEAAXXZ:-934671:-0.15%:0.12%:-0.0008%?fgInterBlockLocalVarLiveness@Compiler@@QEAAXXZ:-998691:-0.17%:0.13%:-0.0009%?optVnCopyProp@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1013931:-0.51%:0.13%:-0.0009%?RewriteNode@Rationalizer@@AEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@AEAV?$ArrayStack@PEAUGenTree@@@@@Z:-1016909:-0.13%:0.13%:-0.0009%?fgValueNumberStore@Compiler@@QEAAXPEAUGenTree@@@Z:-1027387:-0.72%:0.13%:-0.0009%?fgComputeLifeLIR@Compiler@@QEAAXAEAPEA_KPEAUBasicBlock@@AEBQEA_K@Z:-1032432:-0.25%:0.13%:-0.0009%?BuildNode@LinearScan@@AEAAHPEAUGenTree@@@Z:-1036010:-0.15%:0.13%:-0.0009%?fgPerBlockLocalVarLiveness@Compiler@@QEAAXXZ:-1052193:-0.16%:0.13%:-0.0009%?InsertPhiFunctions@SsaBuilder@@AEAAXPEAPEAUBasicBlock@@H@Z:-1106749:-0.58%:0.14%:-0.0010%?optBlockCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-1144389:-0.32%:0.15%:-0.0010%?fgValueNumberTree@Compiler@@QEAAXPEAUGenTree@@@Z:-1149567:-0.17%:0.15%:-0.0010%
`Compiler::optCopyPropPushDef'::`2'::<lambda_1>::operator() :-1166866:-1.11%:0.15%:-0.0010%?optAssertionProp@Compiler@@QEAAPEAUGenTree@@AEBQEA_KPEAU2@PEAUStatement@@PEAUBasicBlock@@@Z:-1194100:-0.26%:0.15%:-0.0010%?fgMorphSmpOp@Compiler@@AEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@PEA_N@Z:-1206778:-0.07%:0.15%:-0.0010%?fgComputeLifeTrackedLocalDef@Compiler@@QEAA_NAEAPEA_KAEBQEA_KAEAVLclVarDsc@@PEAUGenTreeLclVarCommon@@@Z:-1229223:-0.67%:0.16%:-0.0011%?optAssertionPropMain@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1373368:-0.34%:0.18%:-0.0012%?PerBlockAnalysis@LiveVarAnalysis@@AEAA_NPEAUBasicBlock@@_N1@Z:-1390878:-0.10%:0.18%:-0.0012%??$buildIntervals@$00@LinearScan@@QEAAXXZ:-1420236:-0.28%:0.18%:-0.0012%?doLinearScan@LinearScan@@UEAA?AW4PhaseStatus@@XZ:-1472138:-0.40%:0.19%:-0.0013%?WalkTree@?$GenTreeVisitor@V?$GenericTreeWalker@$0A@$00$0A@$00@@@@QEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@PEAU4@@Z:-1480816:-0.34%:0.19%:-0.0013%?UpdateLifeVar@?$TreeLifeUpdater@$00@@AEAAXPEAUGenTree@@PEAUGenTreeLclVarCommon@@@Z:-1492533:-0.53%:0.19%:-0.0013%?resolveLocalRef@LinearScan@@AEAAXPEAUBasicBlock@@PEAUGenTreeLclVar@@PEAVRefPosition@@@Z:-1708209:-0.47%:0.22%:-0.0015%?optVNAssertionPropCurStmtVisitor@Compiler@@KA?AW4fgWalkResult@1@PEAPEAUGenTree@@PEAUfgWalkData@1@@Z:-1787018:-0.34%:0.23%:-0.0015%?genCodeForBBlist@CodeGen@@IEAAXXZ:-1863492:-0.20%:0.24%:-0.0016%?optAssertionGen@Compiler@@QEAAXPEAUGenTree@@@Z:-1953068:-0.28%:0.25%:-0.0017%?lvaComputeRefCounts@Compiler@@QEAAX_N0@Z:-1990712:-0.26%:0.26%:-0.0017%
jitstd::`anonymous namespace'::quick_sort<unsigned int *,LclVarDsc_BlendedCode_Less> :-2055001:-0.47%:0.26%:-0.0018%?allocateMemory@ArenaAllocator@@QEAAPEAX_K@Z:-2058385:-0.08%:0.26%:-0.0018%?fgMarkUseDef@Compiler@@AEAAXPEAUGenTreeLclVarCommon@@@Z:-2423637:-0.39%:0.31%:-0.0021%?allocateRegisters@LinearScan@@QEAAXXZ:-2501343:-0.08%:0.32%:-0.0022%??$select@$0A@@RegisterSelection@LinearScan@@QEAA_KPEAVInterval@@PEAVRefPosition@@@Z:-3296353:-0.12%:0.42%:-0.0029%?DoPhase@@YAXPEAVCompiler@@W4Phases@@P81@EAA?AW4PhaseStatus@@XZ@Z:-3654638:-1.32%:0.47%:-0.0032%?processBlockStartLocations@LinearScan@@AEAAXPEAUBasicBlock@@@Z:-3668164:-0.25%:0.47%:-0.0032%ArrayStack<`Compiler::fgTailMerge'::`2'::PredInfo>::Emplace<`Compiler::fgTailMerge'::`2'::PredInfo&>:-5529385:-100.00%:0.71%:-0.0048%?optCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAUStatement@@PEAUGenTreeLclVarCommon@@IPEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-10813657:-0.93%:1.39%:-0.0094%
`Compiler::compCompile'::`2'::<lambda_2>::operator() :-12285906:-100.00%:1.57%:-0.0106%?fgTailMerge@Compiler@@QEAA?AW4PhaseStatus@@XZ:-28273557:-100.00%:3.62%:-0.0245%
`Compiler::fgTailMerge'::`2'::<lambda_1>::operator() :-128142453:-100.00%:16.42%:-0.1109%

(Note that fgTailMerge() was changed to fgHeadTailMerge(bool), so the tail merging lambda shows up both as appearing with the new name and disappearing with the old). So it seems like it is pretty close to the same TP cost as the tail merging.

fgCanMoveFirstStatementIntoPred is not costly enough to show up in the trace. gtHasLocalsWithAddrOp barely shows up.

I collected stats on the checks, and over libraries.pmi fgCanMoveFirstStatementIntoPred is called 18110 times and returns true 15688 times and false 2422 times.

@AndyAyersMS

Copy link
Copy Markdown
Member

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

It over halves the TP impact with only a couple non-test regressions -- I will switch to that. I wonder how much it is about visiting switches compared to the Succs enumerator being expensive -- I am introducing a visitor based regular successor enumerator in #89328 that could probably also have helped.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Failures are known according to build analysis.

@jakobbotsch
jakobbotsch merged commit e9ce3aa into dotnet:mainAug 18, 2023
@jakobbotsch
jakobbotsch deleted the head-merging branch August 18, 2023 09:39
@ghostghost locked as resolved and limited conversation to collaborators Sep 17, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

cmove is not emitted for a simple expression

2 participants

@jakobbotsch@AndyAyersMS
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
JIT: Add a head merging transformation alongside the tail merging transformation by jakobbotsch · Pull Request #90468 · dotnet/runtime · GitHub
Skip to content

JIT: Add a head merging transformation alongside the tail merging transformation - #90468

Merged
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging
Aug 18, 2023
Merged

JIT: Add a head merging transformation alongside the tail merging transformation#90468
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Aug 12, 2023

Copy link
Copy Markdown
Member

Add a pass that does head merging to complement the existing tail merging pass. Unlike tail merging this either requires spilling or reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix#90017

Add a pass that does head merging to compliment the existing tail
merging pass. Unlike tail merging this requires reordering the first
statement with the terminator node of the predecessor, which requires
some interference checking.
Fixdotnet#90017
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Aug 12, 2023
@ghost

Copy link
Copy Markdown

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

Issue Details

Add a pass that does head merging to compliment the existing tail merging pass. Unlike tail merging this requires reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix #90017

Author:jakobbotsch
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotschjakobbotsch added this to the 9.0.0 milestone Aug 14, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 10:17
@jakobbotsch
jakobbotsch marked this pull request as draft August 16, 2023 10:25
@jakobbotschjakobbotsch changed the title JIT: Add a head merging passJIT: Add a head merging transformation alongside the tail merging transformationAug 16, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 13:08
@jakobbotsch

jakobbotsch commented Aug 16, 2023

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Diffs. Quite skewed because of one particular test, but still a fair amount of improvements, in a lot of cases creating new conditional selects (which both bring size-wise improvements and regressions). The reordering also can bring regressions with it, in the same way that we see from forward sub sometimes.

There's also a consideration that tail merging and head merging can create new opportunities for each other, but this change doesn't try to rerun either of them when that potentially happens.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn, runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
{
if (gtHasRef(tree1, dsc->lvFieldLclStart + i))
{
JITDUMP(" cannot reorder with interferring use of struct field\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
JITDUMP(" cannot reorder with interferring use of struct field\n");
JITDUMP(" cannot reorder with interfering use of struct field\n");

similar elsehwere

@AndyAyersMS

Copy link
Copy Markdown
Member

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Seems like a pretty natural fit.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

@jakobbotsch

jakobbotsch commented Aug 17, 2023

Copy link
Copy Markdown
MemberAuthor

The Fuzzlyn failures are #7539 (hitting this a lot after adding Unsafe.As support -- need to figure out what to do about it). Runtime and jitstress failures are #90593.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

For libraries.pmi the histogram of how many statements we head merge in each block (where we head merge any) looks like:

1 .. 1===>4173 count ( 56% of total)
2 .. 2===>972 count ( 70% of total)
3 .. 3===>919 count ( 82% of total)
4 .. 4===>366 count ( 87% of total)
5 .. 5===>487 count ( 94% of total)
6 .. 10===>360 count ( 99% of total)
11 .. 15===>40 count ( 99% of total)
16 .. 20===>5 count (100% of total)

I can try to see if I can improve TP a bit -- for one we shouldn't need to iterate over all BBs twice if we just call both head and tail merging from one loop.
I'm not sure that the interference checks are that costly, but certainly we could do fewer tree walks as part of it.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

The detailed TP breakdown is, after moving the head merging into fgHeadMerge:

Base:115595112161, Diff:115766296686, +0.1481%?fgHeadMerge@Compiler@@QEAA_NPEAUBasicBlock@@AEAV?$ArrayStack@UPredSuccInfo@@@@_N@Z:159867209:NA:20.48%:+0.1383%
`Compiler::fgHeadTailMerge'::`2'::<lambda_1>::operator() :128143167:NA:16.42%:+0.1109%?NumSucc@BasicBlock@@QEAAIPEAVCompiler@@@Z:55787892:+32.82%:7.15%:+0.0483%?fgHeadTailMerge@Compiler@@QEAA?AW4PhaseStatus@@_N@Z:53696551:NA:6.88%:+0.0465%?GetSucc@BasicBlock@@QEAAPEAU1@IPEAVCompiler@@@Z:30154807:+13.41%:3.86%:+0.0261%?Compare@GenTree@@SA_NPEAU1@0_N@Z:15846220:+21.62%:2.03%:+0.0137%
`Compiler::compCompile'::`2'::<lambda_3>::operator() :12277667:NA:1.57%:+0.0106%??$Emplace@AEAUPredSuccInfo@@@?$ArrayStack@UPredSuccInfo@@@@QEAAXAEAUPredSuccInfo@@@Z:5529537:NA:0.71%:+0.0048%?compCompile@Compiler@@IEAAXPEAPEAXPEAIPEAVJitFlags@@@Z:1684987:+1.37%:0.22%:+0.0015%GenTreeVisitor<`Compiler::gtHasLocalsWithAddrOp'::`2'::LocalsWithAddrOpVisitor>::WalkTree:1252917:+1.84%:0.16%:+0.0011%?fgUpdateFlowGraph@Compiler@@QEAA_N_N0@Z:1130065:+0.08%:0.14%:+0.0010%BasicBlock::VisitAllSuccs<`Compiler::optReachable'::`12'::<lambda_1>>:879816:+0.47%:0.11%:+0.0008%?fgReorderBlocks@Compiler@@QEAA_N_N@Z:-790057:-0.21%:0.10%:-0.0007%?newRefPosition@LinearScan@@AEAAPEAVRefPosition@@PEAVInterval@@IW4RefType@@PEAUGenTree@@_KI@Z:-801471:-0.09%:0.10%:-0.0007%?RenameDef@SsaBuilder@@AEAAXPEAUGenTree@@PEAUBasicBlock@@@Z:-812236:-0.86%:0.10%:-0.0007%?incRefCnts@LclVarDsc@@QEAAXNPEAVCompiler@@W4RefCountState@@_N@Z:-814351:-0.27%:0.10%:-0.0007%?OptimizeRangeCheck@RangeCheck@@QEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTree@@@Z:-825515:-0.37%:0.11%:-0.0007%?genCodeForTreeNode@CodeGen@@IEAAXPEAUGenTree@@@Z:-825588:-0.12%:0.11%:-0.0007%?MakeCopy@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAPEA_KPEAVCompiler@@PEA_K@Z:-835566:-0.32%:0.11%:-0.0007%?fgValueNumberBlock@Compiler@@QEAAXPEAUBasicBlock@@@Z:-846018:-0.31%:0.11%:-0.0007%?AddPhiArg@SsaBuilder@@AEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTreePhi@@II0@Z:-862799:-1.49%:0.11%:-0.0007%?getWeight@LinearScan@@AEAANPEAVRefPosition@@@Z:-866614:-0.29%:0.11%:-0.0007%?UnionD@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAXPEAVCompiler@@AEAPEA_KPEA_K@Z:-871931:-0.20%:0.11%:-0.0008%?fgMorphTree@Compiler@@QEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@@Z:-883522:-0.10%:0.11%:-0.0008%?RenamePushDef@SsaBuilder@@AEAAIPEAUGenTree@@PEAUBasicBlock@@I_N@Z:-886870:-1.13%:0.11%:-0.0008%?EnsureCoversInd@?$JitExpandArray@PEAUChunk@ValueNumStore@@@@IEAAXI@Z:-892604:-0.31%:0.11%:-0.0008%?gtSetEvalOrder@Compiler@@QEAAIPEAUGenTree@@@Z:-905597:-0.05%:0.12%:-0.0008%??$resolveRegisters@$00@LinearScan@@QEAAXXZ:-934671:-0.15%:0.12%:-0.0008%?fgInterBlockLocalVarLiveness@Compiler@@QEAAXXZ:-998691:-0.17%:0.13%:-0.0009%?optVnCopyProp@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1013931:-0.51%:0.13%:-0.0009%?RewriteNode@Rationalizer@@AEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@AEAV?$ArrayStack@PEAUGenTree@@@@@Z:-1016909:-0.13%:0.13%:-0.0009%?fgValueNumberStore@Compiler@@QEAAXPEAUGenTree@@@Z:-1027387:-0.72%:0.13%:-0.0009%?fgComputeLifeLIR@Compiler@@QEAAXAEAPEA_KPEAUBasicBlock@@AEBQEA_K@Z:-1032432:-0.25%:0.13%:-0.0009%?BuildNode@LinearScan@@AEAAHPEAUGenTree@@@Z:-1036010:-0.15%:0.13%:-0.0009%?fgPerBlockLocalVarLiveness@Compiler@@QEAAXXZ:-1052193:-0.16%:0.13%:-0.0009%?InsertPhiFunctions@SsaBuilder@@AEAAXPEAPEAUBasicBlock@@H@Z:-1106749:-0.58%:0.14%:-0.0010%?optBlockCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-1144389:-0.32%:0.15%:-0.0010%?fgValueNumberTree@Compiler@@QEAAXPEAUGenTree@@@Z:-1149567:-0.17%:0.15%:-0.0010%
`Compiler::optCopyPropPushDef'::`2'::<lambda_1>::operator() :-1166866:-1.11%:0.15%:-0.0010%?optAssertionProp@Compiler@@QEAAPEAUGenTree@@AEBQEA_KPEAU2@PEAUStatement@@PEAUBasicBlock@@@Z:-1194100:-0.26%:0.15%:-0.0010%?fgMorphSmpOp@Compiler@@AEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@PEA_N@Z:-1206778:-0.07%:0.15%:-0.0010%?fgComputeLifeTrackedLocalDef@Compiler@@QEAA_NAEAPEA_KAEBQEA_KAEAVLclVarDsc@@PEAUGenTreeLclVarCommon@@@Z:-1229223:-0.67%:0.16%:-0.0011%?optAssertionPropMain@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1373368:-0.34%:0.18%:-0.0012%?PerBlockAnalysis@LiveVarAnalysis@@AEAA_NPEAUBasicBlock@@_N1@Z:-1390878:-0.10%:0.18%:-0.0012%??$buildIntervals@$00@LinearScan@@QEAAXXZ:-1420236:-0.28%:0.18%:-0.0012%?doLinearScan@LinearScan@@UEAA?AW4PhaseStatus@@XZ:-1472138:-0.40%:0.19%:-0.0013%?WalkTree@?$GenTreeVisitor@V?$GenericTreeWalker@$0A@$00$0A@$00@@@@QEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@PEAU4@@Z:-1480816:-0.34%:0.19%:-0.0013%?UpdateLifeVar@?$TreeLifeUpdater@$00@@AEAAXPEAUGenTree@@PEAUGenTreeLclVarCommon@@@Z:-1492533:-0.53%:0.19%:-0.0013%?resolveLocalRef@LinearScan@@AEAAXPEAUBasicBlock@@PEAUGenTreeLclVar@@PEAVRefPosition@@@Z:-1708209:-0.47%:0.22%:-0.0015%?optVNAssertionPropCurStmtVisitor@Compiler@@KA?AW4fgWalkResult@1@PEAPEAUGenTree@@PEAUfgWalkData@1@@Z:-1787018:-0.34%:0.23%:-0.0015%?genCodeForBBlist@CodeGen@@IEAAXXZ:-1863492:-0.20%:0.24%:-0.0016%?optAssertionGen@Compiler@@QEAAXPEAUGenTree@@@Z:-1953068:-0.28%:0.25%:-0.0017%?lvaComputeRefCounts@Compiler@@QEAAX_N0@Z:-1990712:-0.26%:0.26%:-0.0017%
jitstd::`anonymous namespace'::quick_sort<unsigned int *,LclVarDsc_BlendedCode_Less> :-2055001:-0.47%:0.26%:-0.0018%?allocateMemory@ArenaAllocator@@QEAAPEAX_K@Z:-2058385:-0.08%:0.26%:-0.0018%?fgMarkUseDef@Compiler@@AEAAXPEAUGenTreeLclVarCommon@@@Z:-2423637:-0.39%:0.31%:-0.0021%?allocateRegisters@LinearScan@@QEAAXXZ:-2501343:-0.08%:0.32%:-0.0022%??$select@$0A@@RegisterSelection@LinearScan@@QEAA_KPEAVInterval@@PEAVRefPosition@@@Z:-3296353:-0.12%:0.42%:-0.0029%?DoPhase@@YAXPEAVCompiler@@W4Phases@@P81@EAA?AW4PhaseStatus@@XZ@Z:-3654638:-1.32%:0.47%:-0.0032%?processBlockStartLocations@LinearScan@@AEAAXPEAUBasicBlock@@@Z:-3668164:-0.25%:0.47%:-0.0032%ArrayStack<`Compiler::fgTailMerge'::`2'::PredInfo>::Emplace<`Compiler::fgTailMerge'::`2'::PredInfo&>:-5529385:-100.00%:0.71%:-0.0048%?optCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAUStatement@@PEAUGenTreeLclVarCommon@@IPEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-10813657:-0.93%:1.39%:-0.0094%
`Compiler::compCompile'::`2'::<lambda_2>::operator() :-12285906:-100.00%:1.57%:-0.0106%?fgTailMerge@Compiler@@QEAA?AW4PhaseStatus@@XZ:-28273557:-100.00%:3.62%:-0.0245%
`Compiler::fgTailMerge'::`2'::<lambda_1>::operator() :-128142453:-100.00%:16.42%:-0.1109%

(Note that fgTailMerge() was changed to fgHeadTailMerge(bool), so the tail merging lambda shows up both as appearing with the new name and disappearing with the old). So it seems like it is pretty close to the same TP cost as the tail merging.

fgCanMoveFirstStatementIntoPred is not costly enough to show up in the trace. gtHasLocalsWithAddrOp barely shows up.

I collected stats on the checks, and over libraries.pmi fgCanMoveFirstStatementIntoPred is called 18110 times and returns true 15688 times and false 2422 times.

@AndyAyersMS

Copy link
Copy Markdown
Member

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

It over halves the TP impact with only a couple non-test regressions -- I will switch to that. I wonder how much it is about visiting switches compared to the Succs enumerator being expensive -- I am introducing a visitor based regular successor enumerator in #89328 that could probably also have helped.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Failures are known according to build analysis.

@jakobbotsch
jakobbotsch merged commit e9ce3aa into dotnet:mainAug 18, 2023
@jakobbotsch
jakobbotsch deleted the head-merging branch August 18, 2023 09:39
@ghostghost locked as resolved and limited conversation to collaborators Sep 17, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

cmove is not emitted for a simple expression

2 participants

@jakobbotsch@AndyAyersMS
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' JIT: Add a head merging transformation alongside the tail merging transformation by jakobbotsch · Pull Request #90468 · dotnet/runtime · GitHub
Skip to content

JIT: Add a head merging transformation alongside the tail merging transformation - #90468

Merged
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging
Aug 18, 2023
Merged

JIT: Add a head merging transformation alongside the tail merging transformation#90468
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Aug 12, 2023

Copy link
Copy Markdown
Member

Add a pass that does head merging to complement the existing tail merging pass. Unlike tail merging this either requires spilling or reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix#90017

Add a pass that does head merging to compliment the existing tail
merging pass. Unlike tail merging this requires reordering the first
statement with the terminator node of the predecessor, which requires
some interference checking.
Fixdotnet#90017
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Aug 12, 2023
@ghost

Copy link
Copy Markdown

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

Issue Details

Add a pass that does head merging to compliment the existing tail merging pass. Unlike tail merging this requires reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix #90017

Author:jakobbotsch
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotschjakobbotsch added this to the 9.0.0 milestone Aug 14, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 10:17
@jakobbotsch
jakobbotsch marked this pull request as draft August 16, 2023 10:25
@jakobbotschjakobbotsch changed the title JIT: Add a head merging passJIT: Add a head merging transformation alongside the tail merging transformationAug 16, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 13:08
@jakobbotsch

jakobbotsch commented Aug 16, 2023

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Diffs. Quite skewed because of one particular test, but still a fair amount of improvements, in a lot of cases creating new conditional selects (which both bring size-wise improvements and regressions). The reordering also can bring regressions with it, in the same way that we see from forward sub sometimes.

There's also a consideration that tail merging and head merging can create new opportunities for each other, but this change doesn't try to rerun either of them when that potentially happens.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn, runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
{
if (gtHasRef(tree1, dsc->lvFieldLclStart + i))
{
JITDUMP(" cannot reorder with interferring use of struct field\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
JITDUMP(" cannot reorder with interferring use of struct field\n");
JITDUMP(" cannot reorder with interfering use of struct field\n");

similar elsehwere

@AndyAyersMS

Copy link
Copy Markdown
Member

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Seems like a pretty natural fit.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

@jakobbotsch

jakobbotsch commented Aug 17, 2023

Copy link
Copy Markdown
MemberAuthor

The Fuzzlyn failures are #7539 (hitting this a lot after adding Unsafe.As support -- need to figure out what to do about it). Runtime and jitstress failures are #90593.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

For libraries.pmi the histogram of how many statements we head merge in each block (where we head merge any) looks like:

1 .. 1===>4173 count ( 56% of total)
2 .. 2===>972 count ( 70% of total)
3 .. 3===>919 count ( 82% of total)
4 .. 4===>366 count ( 87% of total)
5 .. 5===>487 count ( 94% of total)
6 .. 10===>360 count ( 99% of total)
11 .. 15===>40 count ( 99% of total)
16 .. 20===>5 count (100% of total)

I can try to see if I can improve TP a bit -- for one we shouldn't need to iterate over all BBs twice if we just call both head and tail merging from one loop.
I'm not sure that the interference checks are that costly, but certainly we could do fewer tree walks as part of it.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

The detailed TP breakdown is, after moving the head merging into fgHeadMerge:

Base:115595112161, Diff:115766296686, +0.1481%?fgHeadMerge@Compiler@@QEAA_NPEAUBasicBlock@@AEAV?$ArrayStack@UPredSuccInfo@@@@_N@Z:159867209:NA:20.48%:+0.1383%
`Compiler::fgHeadTailMerge'::`2'::<lambda_1>::operator() :128143167:NA:16.42%:+0.1109%?NumSucc@BasicBlock@@QEAAIPEAVCompiler@@@Z:55787892:+32.82%:7.15%:+0.0483%?fgHeadTailMerge@Compiler@@QEAA?AW4PhaseStatus@@_N@Z:53696551:NA:6.88%:+0.0465%?GetSucc@BasicBlock@@QEAAPEAU1@IPEAVCompiler@@@Z:30154807:+13.41%:3.86%:+0.0261%?Compare@GenTree@@SA_NPEAU1@0_N@Z:15846220:+21.62%:2.03%:+0.0137%
`Compiler::compCompile'::`2'::<lambda_3>::operator() :12277667:NA:1.57%:+0.0106%??$Emplace@AEAUPredSuccInfo@@@?$ArrayStack@UPredSuccInfo@@@@QEAAXAEAUPredSuccInfo@@@Z:5529537:NA:0.71%:+0.0048%?compCompile@Compiler@@IEAAXPEAPEAXPEAIPEAVJitFlags@@@Z:1684987:+1.37%:0.22%:+0.0015%GenTreeVisitor<`Compiler::gtHasLocalsWithAddrOp'::`2'::LocalsWithAddrOpVisitor>::WalkTree:1252917:+1.84%:0.16%:+0.0011%?fgUpdateFlowGraph@Compiler@@QEAA_N_N0@Z:1130065:+0.08%:0.14%:+0.0010%BasicBlock::VisitAllSuccs<`Compiler::optReachable'::`12'::<lambda_1>>:879816:+0.47%:0.11%:+0.0008%?fgReorderBlocks@Compiler@@QEAA_N_N@Z:-790057:-0.21%:0.10%:-0.0007%?newRefPosition@LinearScan@@AEAAPEAVRefPosition@@PEAVInterval@@IW4RefType@@PEAUGenTree@@_KI@Z:-801471:-0.09%:0.10%:-0.0007%?RenameDef@SsaBuilder@@AEAAXPEAUGenTree@@PEAUBasicBlock@@@Z:-812236:-0.86%:0.10%:-0.0007%?incRefCnts@LclVarDsc@@QEAAXNPEAVCompiler@@W4RefCountState@@_N@Z:-814351:-0.27%:0.10%:-0.0007%?OptimizeRangeCheck@RangeCheck@@QEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTree@@@Z:-825515:-0.37%:0.11%:-0.0007%?genCodeForTreeNode@CodeGen@@IEAAXPEAUGenTree@@@Z:-825588:-0.12%:0.11%:-0.0007%?MakeCopy@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAPEA_KPEAVCompiler@@PEA_K@Z:-835566:-0.32%:0.11%:-0.0007%?fgValueNumberBlock@Compiler@@QEAAXPEAUBasicBlock@@@Z:-846018:-0.31%:0.11%:-0.0007%?AddPhiArg@SsaBuilder@@AEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTreePhi@@II0@Z:-862799:-1.49%:0.11%:-0.0007%?getWeight@LinearScan@@AEAANPEAVRefPosition@@@Z:-866614:-0.29%:0.11%:-0.0007%?UnionD@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAXPEAVCompiler@@AEAPEA_KPEA_K@Z:-871931:-0.20%:0.11%:-0.0008%?fgMorphTree@Compiler@@QEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@@Z:-883522:-0.10%:0.11%:-0.0008%?RenamePushDef@SsaBuilder@@AEAAIPEAUGenTree@@PEAUBasicBlock@@I_N@Z:-886870:-1.13%:0.11%:-0.0008%?EnsureCoversInd@?$JitExpandArray@PEAUChunk@ValueNumStore@@@@IEAAXI@Z:-892604:-0.31%:0.11%:-0.0008%?gtSetEvalOrder@Compiler@@QEAAIPEAUGenTree@@@Z:-905597:-0.05%:0.12%:-0.0008%??$resolveRegisters@$00@LinearScan@@QEAAXXZ:-934671:-0.15%:0.12%:-0.0008%?fgInterBlockLocalVarLiveness@Compiler@@QEAAXXZ:-998691:-0.17%:0.13%:-0.0009%?optVnCopyProp@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1013931:-0.51%:0.13%:-0.0009%?RewriteNode@Rationalizer@@AEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@AEAV?$ArrayStack@PEAUGenTree@@@@@Z:-1016909:-0.13%:0.13%:-0.0009%?fgValueNumberStore@Compiler@@QEAAXPEAUGenTree@@@Z:-1027387:-0.72%:0.13%:-0.0009%?fgComputeLifeLIR@Compiler@@QEAAXAEAPEA_KPEAUBasicBlock@@AEBQEA_K@Z:-1032432:-0.25%:0.13%:-0.0009%?BuildNode@LinearScan@@AEAAHPEAUGenTree@@@Z:-1036010:-0.15%:0.13%:-0.0009%?fgPerBlockLocalVarLiveness@Compiler@@QEAAXXZ:-1052193:-0.16%:0.13%:-0.0009%?InsertPhiFunctions@SsaBuilder@@AEAAXPEAPEAUBasicBlock@@H@Z:-1106749:-0.58%:0.14%:-0.0010%?optBlockCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-1144389:-0.32%:0.15%:-0.0010%?fgValueNumberTree@Compiler@@QEAAXPEAUGenTree@@@Z:-1149567:-0.17%:0.15%:-0.0010%
`Compiler::optCopyPropPushDef'::`2'::<lambda_1>::operator() :-1166866:-1.11%:0.15%:-0.0010%?optAssertionProp@Compiler@@QEAAPEAUGenTree@@AEBQEA_KPEAU2@PEAUStatement@@PEAUBasicBlock@@@Z:-1194100:-0.26%:0.15%:-0.0010%?fgMorphSmpOp@Compiler@@AEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@PEA_N@Z:-1206778:-0.07%:0.15%:-0.0010%?fgComputeLifeTrackedLocalDef@Compiler@@QEAA_NAEAPEA_KAEBQEA_KAEAVLclVarDsc@@PEAUGenTreeLclVarCommon@@@Z:-1229223:-0.67%:0.16%:-0.0011%?optAssertionPropMain@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1373368:-0.34%:0.18%:-0.0012%?PerBlockAnalysis@LiveVarAnalysis@@AEAA_NPEAUBasicBlock@@_N1@Z:-1390878:-0.10%:0.18%:-0.0012%??$buildIntervals@$00@LinearScan@@QEAAXXZ:-1420236:-0.28%:0.18%:-0.0012%?doLinearScan@LinearScan@@UEAA?AW4PhaseStatus@@XZ:-1472138:-0.40%:0.19%:-0.0013%?WalkTree@?$GenTreeVisitor@V?$GenericTreeWalker@$0A@$00$0A@$00@@@@QEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@PEAU4@@Z:-1480816:-0.34%:0.19%:-0.0013%?UpdateLifeVar@?$TreeLifeUpdater@$00@@AEAAXPEAUGenTree@@PEAUGenTreeLclVarCommon@@@Z:-1492533:-0.53%:0.19%:-0.0013%?resolveLocalRef@LinearScan@@AEAAXPEAUBasicBlock@@PEAUGenTreeLclVar@@PEAVRefPosition@@@Z:-1708209:-0.47%:0.22%:-0.0015%?optVNAssertionPropCurStmtVisitor@Compiler@@KA?AW4fgWalkResult@1@PEAPEAUGenTree@@PEAUfgWalkData@1@@Z:-1787018:-0.34%:0.23%:-0.0015%?genCodeForBBlist@CodeGen@@IEAAXXZ:-1863492:-0.20%:0.24%:-0.0016%?optAssertionGen@Compiler@@QEAAXPEAUGenTree@@@Z:-1953068:-0.28%:0.25%:-0.0017%?lvaComputeRefCounts@Compiler@@QEAAX_N0@Z:-1990712:-0.26%:0.26%:-0.0017%
jitstd::`anonymous namespace'::quick_sort<unsigned int *,LclVarDsc_BlendedCode_Less> :-2055001:-0.47%:0.26%:-0.0018%?allocateMemory@ArenaAllocator@@QEAAPEAX_K@Z:-2058385:-0.08%:0.26%:-0.0018%?fgMarkUseDef@Compiler@@AEAAXPEAUGenTreeLclVarCommon@@@Z:-2423637:-0.39%:0.31%:-0.0021%?allocateRegisters@LinearScan@@QEAAXXZ:-2501343:-0.08%:0.32%:-0.0022%??$select@$0A@@RegisterSelection@LinearScan@@QEAA_KPEAVInterval@@PEAVRefPosition@@@Z:-3296353:-0.12%:0.42%:-0.0029%?DoPhase@@YAXPEAVCompiler@@W4Phases@@P81@EAA?AW4PhaseStatus@@XZ@Z:-3654638:-1.32%:0.47%:-0.0032%?processBlockStartLocations@LinearScan@@AEAAXPEAUBasicBlock@@@Z:-3668164:-0.25%:0.47%:-0.0032%ArrayStack<`Compiler::fgTailMerge'::`2'::PredInfo>::Emplace<`Compiler::fgTailMerge'::`2'::PredInfo&>:-5529385:-100.00%:0.71%:-0.0048%?optCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAUStatement@@PEAUGenTreeLclVarCommon@@IPEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-10813657:-0.93%:1.39%:-0.0094%
`Compiler::compCompile'::`2'::<lambda_2>::operator() :-12285906:-100.00%:1.57%:-0.0106%?fgTailMerge@Compiler@@QEAA?AW4PhaseStatus@@XZ:-28273557:-100.00%:3.62%:-0.0245%
`Compiler::fgTailMerge'::`2'::<lambda_1>::operator() :-128142453:-100.00%:16.42%:-0.1109%

(Note that fgTailMerge() was changed to fgHeadTailMerge(bool), so the tail merging lambda shows up both as appearing with the new name and disappearing with the old). So it seems like it is pretty close to the same TP cost as the tail merging.

fgCanMoveFirstStatementIntoPred is not costly enough to show up in the trace. gtHasLocalsWithAddrOp barely shows up.

I collected stats on the checks, and over libraries.pmi fgCanMoveFirstStatementIntoPred is called 18110 times and returns true 15688 times and false 2422 times.

@AndyAyersMS

Copy link
Copy Markdown
Member

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

It over halves the TP impact with only a couple non-test regressions -- I will switch to that. I wonder how much it is about visiting switches compared to the Succs enumerator being expensive -- I am introducing a visitor based regular successor enumerator in #89328 that could probably also have helped.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Failures are known according to build analysis.

@jakobbotsch
jakobbotsch merged commit e9ce3aa into dotnet:mainAug 18, 2023
@jakobbotsch
jakobbotsch deleted the head-merging branch August 18, 2023 09:39
@ghostghost locked as resolved and limited conversation to collaborators Sep 17, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

cmove is not emitted for a simple expression

2 participants

@jakobbotsch@AndyAyersMS
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' JIT: Add a head merging transformation alongside the tail merging transformation by jakobbotsch · Pull Request #90468 · dotnet/runtime · GitHub
Skip to content

JIT: Add a head merging transformation alongside the tail merging transformation - #90468

Merged
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging
Aug 18, 2023
Merged

JIT: Add a head merging transformation alongside the tail merging transformation#90468
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Aug 12, 2023

Copy link
Copy Markdown
Member

Add a pass that does head merging to complement the existing tail merging pass. Unlike tail merging this either requires spilling or reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix#90017

Add a pass that does head merging to compliment the existing tail
merging pass. Unlike tail merging this requires reordering the first
statement with the terminator node of the predecessor, which requires
some interference checking.
Fixdotnet#90017
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Aug 12, 2023
@ghost

Copy link
Copy Markdown

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

Issue Details

Add a pass that does head merging to compliment the existing tail merging pass. Unlike tail merging this requires reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix #90017

Author:jakobbotsch
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotschjakobbotsch added this to the 9.0.0 milestone Aug 14, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 10:17
@jakobbotsch
jakobbotsch marked this pull request as draft August 16, 2023 10:25
@jakobbotschjakobbotsch changed the title JIT: Add a head merging passJIT: Add a head merging transformation alongside the tail merging transformationAug 16, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 13:08
@jakobbotsch

jakobbotsch commented Aug 16, 2023

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Diffs. Quite skewed because of one particular test, but still a fair amount of improvements, in a lot of cases creating new conditional selects (which both bring size-wise improvements and regressions). The reordering also can bring regressions with it, in the same way that we see from forward sub sometimes.

There's also a consideration that tail merging and head merging can create new opportunities for each other, but this change doesn't try to rerun either of them when that potentially happens.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn, runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
{
if (gtHasRef(tree1, dsc->lvFieldLclStart + i))
{
JITDUMP(" cannot reorder with interferring use of struct field\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
JITDUMP(" cannot reorder with interferring use of struct field\n");
JITDUMP(" cannot reorder with interfering use of struct field\n");

similar elsehwere

@AndyAyersMS

Copy link
Copy Markdown
Member

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Seems like a pretty natural fit.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

@jakobbotsch

jakobbotsch commented Aug 17, 2023

Copy link
Copy Markdown
MemberAuthor

The Fuzzlyn failures are #7539 (hitting this a lot after adding Unsafe.As support -- need to figure out what to do about it). Runtime and jitstress failures are #90593.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

For libraries.pmi the histogram of how many statements we head merge in each block (where we head merge any) looks like:

1 .. 1===>4173 count ( 56% of total)
2 .. 2===>972 count ( 70% of total)
3 .. 3===>919 count ( 82% of total)
4 .. 4===>366 count ( 87% of total)
5 .. 5===>487 count ( 94% of total)
6 .. 10===>360 count ( 99% of total)
11 .. 15===>40 count ( 99% of total)
16 .. 20===>5 count (100% of total)

I can try to see if I can improve TP a bit -- for one we shouldn't need to iterate over all BBs twice if we just call both head and tail merging from one loop.
I'm not sure that the interference checks are that costly, but certainly we could do fewer tree walks as part of it.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

The detailed TP breakdown is, after moving the head merging into fgHeadMerge:

Base:115595112161, Diff:115766296686, +0.1481%?fgHeadMerge@Compiler@@QEAA_NPEAUBasicBlock@@AEAV?$ArrayStack@UPredSuccInfo@@@@_N@Z:159867209:NA:20.48%:+0.1383%
`Compiler::fgHeadTailMerge'::`2'::<lambda_1>::operator() :128143167:NA:16.42%:+0.1109%?NumSucc@BasicBlock@@QEAAIPEAVCompiler@@@Z:55787892:+32.82%:7.15%:+0.0483%?fgHeadTailMerge@Compiler@@QEAA?AW4PhaseStatus@@_N@Z:53696551:NA:6.88%:+0.0465%?GetSucc@BasicBlock@@QEAAPEAU1@IPEAVCompiler@@@Z:30154807:+13.41%:3.86%:+0.0261%?Compare@GenTree@@SA_NPEAU1@0_N@Z:15846220:+21.62%:2.03%:+0.0137%
`Compiler::compCompile'::`2'::<lambda_3>::operator() :12277667:NA:1.57%:+0.0106%??$Emplace@AEAUPredSuccInfo@@@?$ArrayStack@UPredSuccInfo@@@@QEAAXAEAUPredSuccInfo@@@Z:5529537:NA:0.71%:+0.0048%?compCompile@Compiler@@IEAAXPEAPEAXPEAIPEAVJitFlags@@@Z:1684987:+1.37%:0.22%:+0.0015%GenTreeVisitor<`Compiler::gtHasLocalsWithAddrOp'::`2'::LocalsWithAddrOpVisitor>::WalkTree:1252917:+1.84%:0.16%:+0.0011%?fgUpdateFlowGraph@Compiler@@QEAA_N_N0@Z:1130065:+0.08%:0.14%:+0.0010%BasicBlock::VisitAllSuccs<`Compiler::optReachable'::`12'::<lambda_1>>:879816:+0.47%:0.11%:+0.0008%?fgReorderBlocks@Compiler@@QEAA_N_N@Z:-790057:-0.21%:0.10%:-0.0007%?newRefPosition@LinearScan@@AEAAPEAVRefPosition@@PEAVInterval@@IW4RefType@@PEAUGenTree@@_KI@Z:-801471:-0.09%:0.10%:-0.0007%?RenameDef@SsaBuilder@@AEAAXPEAUGenTree@@PEAUBasicBlock@@@Z:-812236:-0.86%:0.10%:-0.0007%?incRefCnts@LclVarDsc@@QEAAXNPEAVCompiler@@W4RefCountState@@_N@Z:-814351:-0.27%:0.10%:-0.0007%?OptimizeRangeCheck@RangeCheck@@QEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTree@@@Z:-825515:-0.37%:0.11%:-0.0007%?genCodeForTreeNode@CodeGen@@IEAAXPEAUGenTree@@@Z:-825588:-0.12%:0.11%:-0.0007%?MakeCopy@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAPEA_KPEAVCompiler@@PEA_K@Z:-835566:-0.32%:0.11%:-0.0007%?fgValueNumberBlock@Compiler@@QEAAXPEAUBasicBlock@@@Z:-846018:-0.31%:0.11%:-0.0007%?AddPhiArg@SsaBuilder@@AEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTreePhi@@II0@Z:-862799:-1.49%:0.11%:-0.0007%?getWeight@LinearScan@@AEAANPEAVRefPosition@@@Z:-866614:-0.29%:0.11%:-0.0007%?UnionD@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAXPEAVCompiler@@AEAPEA_KPEA_K@Z:-871931:-0.20%:0.11%:-0.0008%?fgMorphTree@Compiler@@QEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@@Z:-883522:-0.10%:0.11%:-0.0008%?RenamePushDef@SsaBuilder@@AEAAIPEAUGenTree@@PEAUBasicBlock@@I_N@Z:-886870:-1.13%:0.11%:-0.0008%?EnsureCoversInd@?$JitExpandArray@PEAUChunk@ValueNumStore@@@@IEAAXI@Z:-892604:-0.31%:0.11%:-0.0008%?gtSetEvalOrder@Compiler@@QEAAIPEAUGenTree@@@Z:-905597:-0.05%:0.12%:-0.0008%??$resolveRegisters@$00@LinearScan@@QEAAXXZ:-934671:-0.15%:0.12%:-0.0008%?fgInterBlockLocalVarLiveness@Compiler@@QEAAXXZ:-998691:-0.17%:0.13%:-0.0009%?optVnCopyProp@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1013931:-0.51%:0.13%:-0.0009%?RewriteNode@Rationalizer@@AEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@AEAV?$ArrayStack@PEAUGenTree@@@@@Z:-1016909:-0.13%:0.13%:-0.0009%?fgValueNumberStore@Compiler@@QEAAXPEAUGenTree@@@Z:-1027387:-0.72%:0.13%:-0.0009%?fgComputeLifeLIR@Compiler@@QEAAXAEAPEA_KPEAUBasicBlock@@AEBQEA_K@Z:-1032432:-0.25%:0.13%:-0.0009%?BuildNode@LinearScan@@AEAAHPEAUGenTree@@@Z:-1036010:-0.15%:0.13%:-0.0009%?fgPerBlockLocalVarLiveness@Compiler@@QEAAXXZ:-1052193:-0.16%:0.13%:-0.0009%?InsertPhiFunctions@SsaBuilder@@AEAAXPEAPEAUBasicBlock@@H@Z:-1106749:-0.58%:0.14%:-0.0010%?optBlockCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-1144389:-0.32%:0.15%:-0.0010%?fgValueNumberTree@Compiler@@QEAAXPEAUGenTree@@@Z:-1149567:-0.17%:0.15%:-0.0010%
`Compiler::optCopyPropPushDef'::`2'::<lambda_1>::operator() :-1166866:-1.11%:0.15%:-0.0010%?optAssertionProp@Compiler@@QEAAPEAUGenTree@@AEBQEA_KPEAU2@PEAUStatement@@PEAUBasicBlock@@@Z:-1194100:-0.26%:0.15%:-0.0010%?fgMorphSmpOp@Compiler@@AEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@PEA_N@Z:-1206778:-0.07%:0.15%:-0.0010%?fgComputeLifeTrackedLocalDef@Compiler@@QEAA_NAEAPEA_KAEBQEA_KAEAVLclVarDsc@@PEAUGenTreeLclVarCommon@@@Z:-1229223:-0.67%:0.16%:-0.0011%?optAssertionPropMain@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1373368:-0.34%:0.18%:-0.0012%?PerBlockAnalysis@LiveVarAnalysis@@AEAA_NPEAUBasicBlock@@_N1@Z:-1390878:-0.10%:0.18%:-0.0012%??$buildIntervals@$00@LinearScan@@QEAAXXZ:-1420236:-0.28%:0.18%:-0.0012%?doLinearScan@LinearScan@@UEAA?AW4PhaseStatus@@XZ:-1472138:-0.40%:0.19%:-0.0013%?WalkTree@?$GenTreeVisitor@V?$GenericTreeWalker@$0A@$00$0A@$00@@@@QEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@PEAU4@@Z:-1480816:-0.34%:0.19%:-0.0013%?UpdateLifeVar@?$TreeLifeUpdater@$00@@AEAAXPEAUGenTree@@PEAUGenTreeLclVarCommon@@@Z:-1492533:-0.53%:0.19%:-0.0013%?resolveLocalRef@LinearScan@@AEAAXPEAUBasicBlock@@PEAUGenTreeLclVar@@PEAVRefPosition@@@Z:-1708209:-0.47%:0.22%:-0.0015%?optVNAssertionPropCurStmtVisitor@Compiler@@KA?AW4fgWalkResult@1@PEAPEAUGenTree@@PEAUfgWalkData@1@@Z:-1787018:-0.34%:0.23%:-0.0015%?genCodeForBBlist@CodeGen@@IEAAXXZ:-1863492:-0.20%:0.24%:-0.0016%?optAssertionGen@Compiler@@QEAAXPEAUGenTree@@@Z:-1953068:-0.28%:0.25%:-0.0017%?lvaComputeRefCounts@Compiler@@QEAAX_N0@Z:-1990712:-0.26%:0.26%:-0.0017%
jitstd::`anonymous namespace'::quick_sort<unsigned int *,LclVarDsc_BlendedCode_Less> :-2055001:-0.47%:0.26%:-0.0018%?allocateMemory@ArenaAllocator@@QEAAPEAX_K@Z:-2058385:-0.08%:0.26%:-0.0018%?fgMarkUseDef@Compiler@@AEAAXPEAUGenTreeLclVarCommon@@@Z:-2423637:-0.39%:0.31%:-0.0021%?allocateRegisters@LinearScan@@QEAAXXZ:-2501343:-0.08%:0.32%:-0.0022%??$select@$0A@@RegisterSelection@LinearScan@@QEAA_KPEAVInterval@@PEAVRefPosition@@@Z:-3296353:-0.12%:0.42%:-0.0029%?DoPhase@@YAXPEAVCompiler@@W4Phases@@P81@EAA?AW4PhaseStatus@@XZ@Z:-3654638:-1.32%:0.47%:-0.0032%?processBlockStartLocations@LinearScan@@AEAAXPEAUBasicBlock@@@Z:-3668164:-0.25%:0.47%:-0.0032%ArrayStack<`Compiler::fgTailMerge'::`2'::PredInfo>::Emplace<`Compiler::fgTailMerge'::`2'::PredInfo&>:-5529385:-100.00%:0.71%:-0.0048%?optCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAUStatement@@PEAUGenTreeLclVarCommon@@IPEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-10813657:-0.93%:1.39%:-0.0094%
`Compiler::compCompile'::`2'::<lambda_2>::operator() :-12285906:-100.00%:1.57%:-0.0106%?fgTailMerge@Compiler@@QEAA?AW4PhaseStatus@@XZ:-28273557:-100.00%:3.62%:-0.0245%
`Compiler::fgTailMerge'::`2'::<lambda_1>::operator() :-128142453:-100.00%:16.42%:-0.1109%

(Note that fgTailMerge() was changed to fgHeadTailMerge(bool), so the tail merging lambda shows up both as appearing with the new name and disappearing with the old). So it seems like it is pretty close to the same TP cost as the tail merging.

fgCanMoveFirstStatementIntoPred is not costly enough to show up in the trace. gtHasLocalsWithAddrOp barely shows up.

I collected stats on the checks, and over libraries.pmi fgCanMoveFirstStatementIntoPred is called 18110 times and returns true 15688 times and false 2422 times.

@AndyAyersMS

Copy link
Copy Markdown
Member

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

It over halves the TP impact with only a couple non-test regressions -- I will switch to that. I wonder how much it is about visiting switches compared to the Succs enumerator being expensive -- I am introducing a visitor based regular successor enumerator in #89328 that could probably also have helped.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Failures are known according to build analysis.

@jakobbotsch
jakobbotsch merged commit e9ce3aa into dotnet:mainAug 18, 2023
@jakobbotsch
jakobbotsch deleted the head-merging branch August 18, 2023 09:39
@ghostghost locked as resolved and limited conversation to collaborators Sep 17, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

cmove is not emitted for a simple expression

2 participants

@jakobbotsch@AndyAyersMS
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' JIT: Add a head merging transformation alongside the tail merging transformation by jakobbotsch · Pull Request #90468 · dotnet/runtime · GitHub
Skip to content

JIT: Add a head merging transformation alongside the tail merging transformation - #90468

Merged
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging
Aug 18, 2023
Merged

JIT: Add a head merging transformation alongside the tail merging transformation#90468
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Aug 12, 2023

Copy link
Copy Markdown
Member

Add a pass that does head merging to complement the existing tail merging pass. Unlike tail merging this either requires spilling or reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix#90017

Add a pass that does head merging to compliment the existing tail
merging pass. Unlike tail merging this requires reordering the first
statement with the terminator node of the predecessor, which requires
some interference checking.
Fixdotnet#90017
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Aug 12, 2023
@ghost

Copy link
Copy Markdown

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

Issue Details

Add a pass that does head merging to compliment the existing tail merging pass. Unlike tail merging this requires reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix #90017

Author:jakobbotsch
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotschjakobbotsch added this to the 9.0.0 milestone Aug 14, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 10:17
@jakobbotsch
jakobbotsch marked this pull request as draft August 16, 2023 10:25
@jakobbotschjakobbotsch changed the title JIT: Add a head merging passJIT: Add a head merging transformation alongside the tail merging transformationAug 16, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 13:08
@jakobbotsch

jakobbotsch commented Aug 16, 2023

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Diffs. Quite skewed because of one particular test, but still a fair amount of improvements, in a lot of cases creating new conditional selects (which both bring size-wise improvements and regressions). The reordering also can bring regressions with it, in the same way that we see from forward sub sometimes.

There's also a consideration that tail merging and head merging can create new opportunities for each other, but this change doesn't try to rerun either of them when that potentially happens.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn, runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
{
if (gtHasRef(tree1, dsc->lvFieldLclStart + i))
{
JITDUMP(" cannot reorder with interferring use of struct field\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
JITDUMP(" cannot reorder with interferring use of struct field\n");
JITDUMP(" cannot reorder with interfering use of struct field\n");

similar elsehwere

@AndyAyersMS

Copy link
Copy Markdown
Member

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Seems like a pretty natural fit.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

@jakobbotsch

jakobbotsch commented Aug 17, 2023

Copy link
Copy Markdown
MemberAuthor

The Fuzzlyn failures are #7539 (hitting this a lot after adding Unsafe.As support -- need to figure out what to do about it). Runtime and jitstress failures are #90593.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

For libraries.pmi the histogram of how many statements we head merge in each block (where we head merge any) looks like:

1 .. 1===>4173 count ( 56% of total)
2 .. 2===>972 count ( 70% of total)
3 .. 3===>919 count ( 82% of total)
4 .. 4===>366 count ( 87% of total)
5 .. 5===>487 count ( 94% of total)
6 .. 10===>360 count ( 99% of total)
11 .. 15===>40 count ( 99% of total)
16 .. 20===>5 count (100% of total)

I can try to see if I can improve TP a bit -- for one we shouldn't need to iterate over all BBs twice if we just call both head and tail merging from one loop.
I'm not sure that the interference checks are that costly, but certainly we could do fewer tree walks as part of it.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

The detailed TP breakdown is, after moving the head merging into fgHeadMerge:

Base:115595112161, Diff:115766296686, +0.1481%?fgHeadMerge@Compiler@@QEAA_NPEAUBasicBlock@@AEAV?$ArrayStack@UPredSuccInfo@@@@_N@Z:159867209:NA:20.48%:+0.1383%
`Compiler::fgHeadTailMerge'::`2'::<lambda_1>::operator() :128143167:NA:16.42%:+0.1109%?NumSucc@BasicBlock@@QEAAIPEAVCompiler@@@Z:55787892:+32.82%:7.15%:+0.0483%?fgHeadTailMerge@Compiler@@QEAA?AW4PhaseStatus@@_N@Z:53696551:NA:6.88%:+0.0465%?GetSucc@BasicBlock@@QEAAPEAU1@IPEAVCompiler@@@Z:30154807:+13.41%:3.86%:+0.0261%?Compare@GenTree@@SA_NPEAU1@0_N@Z:15846220:+21.62%:2.03%:+0.0137%
`Compiler::compCompile'::`2'::<lambda_3>::operator() :12277667:NA:1.57%:+0.0106%??$Emplace@AEAUPredSuccInfo@@@?$ArrayStack@UPredSuccInfo@@@@QEAAXAEAUPredSuccInfo@@@Z:5529537:NA:0.71%:+0.0048%?compCompile@Compiler@@IEAAXPEAPEAXPEAIPEAVJitFlags@@@Z:1684987:+1.37%:0.22%:+0.0015%GenTreeVisitor<`Compiler::gtHasLocalsWithAddrOp'::`2'::LocalsWithAddrOpVisitor>::WalkTree:1252917:+1.84%:0.16%:+0.0011%?fgUpdateFlowGraph@Compiler@@QEAA_N_N0@Z:1130065:+0.08%:0.14%:+0.0010%BasicBlock::VisitAllSuccs<`Compiler::optReachable'::`12'::<lambda_1>>:879816:+0.47%:0.11%:+0.0008%?fgReorderBlocks@Compiler@@QEAA_N_N@Z:-790057:-0.21%:0.10%:-0.0007%?newRefPosition@LinearScan@@AEAAPEAVRefPosition@@PEAVInterval@@IW4RefType@@PEAUGenTree@@_KI@Z:-801471:-0.09%:0.10%:-0.0007%?RenameDef@SsaBuilder@@AEAAXPEAUGenTree@@PEAUBasicBlock@@@Z:-812236:-0.86%:0.10%:-0.0007%?incRefCnts@LclVarDsc@@QEAAXNPEAVCompiler@@W4RefCountState@@_N@Z:-814351:-0.27%:0.10%:-0.0007%?OptimizeRangeCheck@RangeCheck@@QEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTree@@@Z:-825515:-0.37%:0.11%:-0.0007%?genCodeForTreeNode@CodeGen@@IEAAXPEAUGenTree@@@Z:-825588:-0.12%:0.11%:-0.0007%?MakeCopy@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAPEA_KPEAVCompiler@@PEA_K@Z:-835566:-0.32%:0.11%:-0.0007%?fgValueNumberBlock@Compiler@@QEAAXPEAUBasicBlock@@@Z:-846018:-0.31%:0.11%:-0.0007%?AddPhiArg@SsaBuilder@@AEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTreePhi@@II0@Z:-862799:-1.49%:0.11%:-0.0007%?getWeight@LinearScan@@AEAANPEAVRefPosition@@@Z:-866614:-0.29%:0.11%:-0.0007%?UnionD@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAXPEAVCompiler@@AEAPEA_KPEA_K@Z:-871931:-0.20%:0.11%:-0.0008%?fgMorphTree@Compiler@@QEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@@Z:-883522:-0.10%:0.11%:-0.0008%?RenamePushDef@SsaBuilder@@AEAAIPEAUGenTree@@PEAUBasicBlock@@I_N@Z:-886870:-1.13%:0.11%:-0.0008%?EnsureCoversInd@?$JitExpandArray@PEAUChunk@ValueNumStore@@@@IEAAXI@Z:-892604:-0.31%:0.11%:-0.0008%?gtSetEvalOrder@Compiler@@QEAAIPEAUGenTree@@@Z:-905597:-0.05%:0.12%:-0.0008%??$resolveRegisters@$00@LinearScan@@QEAAXXZ:-934671:-0.15%:0.12%:-0.0008%?fgInterBlockLocalVarLiveness@Compiler@@QEAAXXZ:-998691:-0.17%:0.13%:-0.0009%?optVnCopyProp@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1013931:-0.51%:0.13%:-0.0009%?RewriteNode@Rationalizer@@AEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@AEAV?$ArrayStack@PEAUGenTree@@@@@Z:-1016909:-0.13%:0.13%:-0.0009%?fgValueNumberStore@Compiler@@QEAAXPEAUGenTree@@@Z:-1027387:-0.72%:0.13%:-0.0009%?fgComputeLifeLIR@Compiler@@QEAAXAEAPEA_KPEAUBasicBlock@@AEBQEA_K@Z:-1032432:-0.25%:0.13%:-0.0009%?BuildNode@LinearScan@@AEAAHPEAUGenTree@@@Z:-1036010:-0.15%:0.13%:-0.0009%?fgPerBlockLocalVarLiveness@Compiler@@QEAAXXZ:-1052193:-0.16%:0.13%:-0.0009%?InsertPhiFunctions@SsaBuilder@@AEAAXPEAPEAUBasicBlock@@H@Z:-1106749:-0.58%:0.14%:-0.0010%?optBlockCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-1144389:-0.32%:0.15%:-0.0010%?fgValueNumberTree@Compiler@@QEAAXPEAUGenTree@@@Z:-1149567:-0.17%:0.15%:-0.0010%
`Compiler::optCopyPropPushDef'::`2'::<lambda_1>::operator() :-1166866:-1.11%:0.15%:-0.0010%?optAssertionProp@Compiler@@QEAAPEAUGenTree@@AEBQEA_KPEAU2@PEAUStatement@@PEAUBasicBlock@@@Z:-1194100:-0.26%:0.15%:-0.0010%?fgMorphSmpOp@Compiler@@AEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@PEA_N@Z:-1206778:-0.07%:0.15%:-0.0010%?fgComputeLifeTrackedLocalDef@Compiler@@QEAA_NAEAPEA_KAEBQEA_KAEAVLclVarDsc@@PEAUGenTreeLclVarCommon@@@Z:-1229223:-0.67%:0.16%:-0.0011%?optAssertionPropMain@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1373368:-0.34%:0.18%:-0.0012%?PerBlockAnalysis@LiveVarAnalysis@@AEAA_NPEAUBasicBlock@@_N1@Z:-1390878:-0.10%:0.18%:-0.0012%??$buildIntervals@$00@LinearScan@@QEAAXXZ:-1420236:-0.28%:0.18%:-0.0012%?doLinearScan@LinearScan@@UEAA?AW4PhaseStatus@@XZ:-1472138:-0.40%:0.19%:-0.0013%?WalkTree@?$GenTreeVisitor@V?$GenericTreeWalker@$0A@$00$0A@$00@@@@QEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@PEAU4@@Z:-1480816:-0.34%:0.19%:-0.0013%?UpdateLifeVar@?$TreeLifeUpdater@$00@@AEAAXPEAUGenTree@@PEAUGenTreeLclVarCommon@@@Z:-1492533:-0.53%:0.19%:-0.0013%?resolveLocalRef@LinearScan@@AEAAXPEAUBasicBlock@@PEAUGenTreeLclVar@@PEAVRefPosition@@@Z:-1708209:-0.47%:0.22%:-0.0015%?optVNAssertionPropCurStmtVisitor@Compiler@@KA?AW4fgWalkResult@1@PEAPEAUGenTree@@PEAUfgWalkData@1@@Z:-1787018:-0.34%:0.23%:-0.0015%?genCodeForBBlist@CodeGen@@IEAAXXZ:-1863492:-0.20%:0.24%:-0.0016%?optAssertionGen@Compiler@@QEAAXPEAUGenTree@@@Z:-1953068:-0.28%:0.25%:-0.0017%?lvaComputeRefCounts@Compiler@@QEAAX_N0@Z:-1990712:-0.26%:0.26%:-0.0017%
jitstd::`anonymous namespace'::quick_sort<unsigned int *,LclVarDsc_BlendedCode_Less> :-2055001:-0.47%:0.26%:-0.0018%?allocateMemory@ArenaAllocator@@QEAAPEAX_K@Z:-2058385:-0.08%:0.26%:-0.0018%?fgMarkUseDef@Compiler@@AEAAXPEAUGenTreeLclVarCommon@@@Z:-2423637:-0.39%:0.31%:-0.0021%?allocateRegisters@LinearScan@@QEAAXXZ:-2501343:-0.08%:0.32%:-0.0022%??$select@$0A@@RegisterSelection@LinearScan@@QEAA_KPEAVInterval@@PEAVRefPosition@@@Z:-3296353:-0.12%:0.42%:-0.0029%?DoPhase@@YAXPEAVCompiler@@W4Phases@@P81@EAA?AW4PhaseStatus@@XZ@Z:-3654638:-1.32%:0.47%:-0.0032%?processBlockStartLocations@LinearScan@@AEAAXPEAUBasicBlock@@@Z:-3668164:-0.25%:0.47%:-0.0032%ArrayStack<`Compiler::fgTailMerge'::`2'::PredInfo>::Emplace<`Compiler::fgTailMerge'::`2'::PredInfo&>:-5529385:-100.00%:0.71%:-0.0048%?optCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAUStatement@@PEAUGenTreeLclVarCommon@@IPEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-10813657:-0.93%:1.39%:-0.0094%
`Compiler::compCompile'::`2'::<lambda_2>::operator() :-12285906:-100.00%:1.57%:-0.0106%?fgTailMerge@Compiler@@QEAA?AW4PhaseStatus@@XZ:-28273557:-100.00%:3.62%:-0.0245%
`Compiler::fgTailMerge'::`2'::<lambda_1>::operator() :-128142453:-100.00%:16.42%:-0.1109%

(Note that fgTailMerge() was changed to fgHeadTailMerge(bool), so the tail merging lambda shows up both as appearing with the new name and disappearing with the old). So it seems like it is pretty close to the same TP cost as the tail merging.

fgCanMoveFirstStatementIntoPred is not costly enough to show up in the trace. gtHasLocalsWithAddrOp barely shows up.

I collected stats on the checks, and over libraries.pmi fgCanMoveFirstStatementIntoPred is called 18110 times and returns true 15688 times and false 2422 times.

@AndyAyersMS

Copy link
Copy Markdown
Member

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

It over halves the TP impact with only a couple non-test regressions -- I will switch to that. I wonder how much it is about visiting switches compared to the Succs enumerator being expensive -- I am introducing a visitor based regular successor enumerator in #89328 that could probably also have helped.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Failures are known according to build analysis.

@jakobbotsch
jakobbotsch merged commit e9ce3aa into dotnet:mainAug 18, 2023
@jakobbotsch
jakobbotsch deleted the head-merging branch August 18, 2023 09:39
@ghostghost locked as resolved and limited conversation to collaborators Sep 17, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

cmove is not emitted for a simple expression

2 participants

@jakobbotsch@AndyAyersMS
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' JIT: Add a head merging transformation alongside the tail merging transformation by jakobbotsch · Pull Request #90468 · dotnet/runtime · GitHub
Skip to content

JIT: Add a head merging transformation alongside the tail merging transformation - #90468

Merged
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging
Aug 18, 2023
Merged

JIT: Add a head merging transformation alongside the tail merging transformation#90468
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Aug 12, 2023

Copy link
Copy Markdown
Member

Add a pass that does head merging to complement the existing tail merging pass. Unlike tail merging this either requires spilling or reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix#90017

Add a pass that does head merging to compliment the existing tail
merging pass. Unlike tail merging this requires reordering the first
statement with the terminator node of the predecessor, which requires
some interference checking.
Fixdotnet#90017
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Aug 12, 2023
@ghost

Copy link
Copy Markdown

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

Issue Details

Add a pass that does head merging to compliment the existing tail merging pass. Unlike tail merging this requires reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix #90017

Author:jakobbotsch
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotschjakobbotsch added this to the 9.0.0 milestone Aug 14, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 10:17
@jakobbotsch
jakobbotsch marked this pull request as draft August 16, 2023 10:25
@jakobbotschjakobbotsch changed the title JIT: Add a head merging passJIT: Add a head merging transformation alongside the tail merging transformationAug 16, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 13:08
@jakobbotsch

jakobbotsch commented Aug 16, 2023

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Diffs. Quite skewed because of one particular test, but still a fair amount of improvements, in a lot of cases creating new conditional selects (which both bring size-wise improvements and regressions). The reordering also can bring regressions with it, in the same way that we see from forward sub sometimes.

There's also a consideration that tail merging and head merging can create new opportunities for each other, but this change doesn't try to rerun either of them when that potentially happens.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn, runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
{
if (gtHasRef(tree1, dsc->lvFieldLclStart + i))
{
JITDUMP(" cannot reorder with interferring use of struct field\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
JITDUMP(" cannot reorder with interferring use of struct field\n");
JITDUMP(" cannot reorder with interfering use of struct field\n");

similar elsehwere

@AndyAyersMS

Copy link
Copy Markdown
Member

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Seems like a pretty natural fit.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

@jakobbotsch

jakobbotsch commented Aug 17, 2023

Copy link
Copy Markdown
MemberAuthor

The Fuzzlyn failures are #7539 (hitting this a lot after adding Unsafe.As support -- need to figure out what to do about it). Runtime and jitstress failures are #90593.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

For libraries.pmi the histogram of how many statements we head merge in each block (where we head merge any) looks like:

1 .. 1===>4173 count ( 56% of total)
2 .. 2===>972 count ( 70% of total)
3 .. 3===>919 count ( 82% of total)
4 .. 4===>366 count ( 87% of total)
5 .. 5===>487 count ( 94% of total)
6 .. 10===>360 count ( 99% of total)
11 .. 15===>40 count ( 99% of total)
16 .. 20===>5 count (100% of total)

I can try to see if I can improve TP a bit -- for one we shouldn't need to iterate over all BBs twice if we just call both head and tail merging from one loop.
I'm not sure that the interference checks are that costly, but certainly we could do fewer tree walks as part of it.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

The detailed TP breakdown is, after moving the head merging into fgHeadMerge:

Base:115595112161, Diff:115766296686, +0.1481%?fgHeadMerge@Compiler@@QEAA_NPEAUBasicBlock@@AEAV?$ArrayStack@UPredSuccInfo@@@@_N@Z:159867209:NA:20.48%:+0.1383%
`Compiler::fgHeadTailMerge'::`2'::<lambda_1>::operator() :128143167:NA:16.42%:+0.1109%?NumSucc@BasicBlock@@QEAAIPEAVCompiler@@@Z:55787892:+32.82%:7.15%:+0.0483%?fgHeadTailMerge@Compiler@@QEAA?AW4PhaseStatus@@_N@Z:53696551:NA:6.88%:+0.0465%?GetSucc@BasicBlock@@QEAAPEAU1@IPEAVCompiler@@@Z:30154807:+13.41%:3.86%:+0.0261%?Compare@GenTree@@SA_NPEAU1@0_N@Z:15846220:+21.62%:2.03%:+0.0137%
`Compiler::compCompile'::`2'::<lambda_3>::operator() :12277667:NA:1.57%:+0.0106%??$Emplace@AEAUPredSuccInfo@@@?$ArrayStack@UPredSuccInfo@@@@QEAAXAEAUPredSuccInfo@@@Z:5529537:NA:0.71%:+0.0048%?compCompile@Compiler@@IEAAXPEAPEAXPEAIPEAVJitFlags@@@Z:1684987:+1.37%:0.22%:+0.0015%GenTreeVisitor<`Compiler::gtHasLocalsWithAddrOp'::`2'::LocalsWithAddrOpVisitor>::WalkTree:1252917:+1.84%:0.16%:+0.0011%?fgUpdateFlowGraph@Compiler@@QEAA_N_N0@Z:1130065:+0.08%:0.14%:+0.0010%BasicBlock::VisitAllSuccs<`Compiler::optReachable'::`12'::<lambda_1>>:879816:+0.47%:0.11%:+0.0008%?fgReorderBlocks@Compiler@@QEAA_N_N@Z:-790057:-0.21%:0.10%:-0.0007%?newRefPosition@LinearScan@@AEAAPEAVRefPosition@@PEAVInterval@@IW4RefType@@PEAUGenTree@@_KI@Z:-801471:-0.09%:0.10%:-0.0007%?RenameDef@SsaBuilder@@AEAAXPEAUGenTree@@PEAUBasicBlock@@@Z:-812236:-0.86%:0.10%:-0.0007%?incRefCnts@LclVarDsc@@QEAAXNPEAVCompiler@@W4RefCountState@@_N@Z:-814351:-0.27%:0.10%:-0.0007%?OptimizeRangeCheck@RangeCheck@@QEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTree@@@Z:-825515:-0.37%:0.11%:-0.0007%?genCodeForTreeNode@CodeGen@@IEAAXPEAUGenTree@@@Z:-825588:-0.12%:0.11%:-0.0007%?MakeCopy@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAPEA_KPEAVCompiler@@PEA_K@Z:-835566:-0.32%:0.11%:-0.0007%?fgValueNumberBlock@Compiler@@QEAAXPEAUBasicBlock@@@Z:-846018:-0.31%:0.11%:-0.0007%?AddPhiArg@SsaBuilder@@AEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTreePhi@@II0@Z:-862799:-1.49%:0.11%:-0.0007%?getWeight@LinearScan@@AEAANPEAVRefPosition@@@Z:-866614:-0.29%:0.11%:-0.0007%?UnionD@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAXPEAVCompiler@@AEAPEA_KPEA_K@Z:-871931:-0.20%:0.11%:-0.0008%?fgMorphTree@Compiler@@QEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@@Z:-883522:-0.10%:0.11%:-0.0008%?RenamePushDef@SsaBuilder@@AEAAIPEAUGenTree@@PEAUBasicBlock@@I_N@Z:-886870:-1.13%:0.11%:-0.0008%?EnsureCoversInd@?$JitExpandArray@PEAUChunk@ValueNumStore@@@@IEAAXI@Z:-892604:-0.31%:0.11%:-0.0008%?gtSetEvalOrder@Compiler@@QEAAIPEAUGenTree@@@Z:-905597:-0.05%:0.12%:-0.0008%??$resolveRegisters@$00@LinearScan@@QEAAXXZ:-934671:-0.15%:0.12%:-0.0008%?fgInterBlockLocalVarLiveness@Compiler@@QEAAXXZ:-998691:-0.17%:0.13%:-0.0009%?optVnCopyProp@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1013931:-0.51%:0.13%:-0.0009%?RewriteNode@Rationalizer@@AEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@AEAV?$ArrayStack@PEAUGenTree@@@@@Z:-1016909:-0.13%:0.13%:-0.0009%?fgValueNumberStore@Compiler@@QEAAXPEAUGenTree@@@Z:-1027387:-0.72%:0.13%:-0.0009%?fgComputeLifeLIR@Compiler@@QEAAXAEAPEA_KPEAUBasicBlock@@AEBQEA_K@Z:-1032432:-0.25%:0.13%:-0.0009%?BuildNode@LinearScan@@AEAAHPEAUGenTree@@@Z:-1036010:-0.15%:0.13%:-0.0009%?fgPerBlockLocalVarLiveness@Compiler@@QEAAXXZ:-1052193:-0.16%:0.13%:-0.0009%?InsertPhiFunctions@SsaBuilder@@AEAAXPEAPEAUBasicBlock@@H@Z:-1106749:-0.58%:0.14%:-0.0010%?optBlockCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-1144389:-0.32%:0.15%:-0.0010%?fgValueNumberTree@Compiler@@QEAAXPEAUGenTree@@@Z:-1149567:-0.17%:0.15%:-0.0010%
`Compiler::optCopyPropPushDef'::`2'::<lambda_1>::operator() :-1166866:-1.11%:0.15%:-0.0010%?optAssertionProp@Compiler@@QEAAPEAUGenTree@@AEBQEA_KPEAU2@PEAUStatement@@PEAUBasicBlock@@@Z:-1194100:-0.26%:0.15%:-0.0010%?fgMorphSmpOp@Compiler@@AEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@PEA_N@Z:-1206778:-0.07%:0.15%:-0.0010%?fgComputeLifeTrackedLocalDef@Compiler@@QEAA_NAEAPEA_KAEBQEA_KAEAVLclVarDsc@@PEAUGenTreeLclVarCommon@@@Z:-1229223:-0.67%:0.16%:-0.0011%?optAssertionPropMain@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1373368:-0.34%:0.18%:-0.0012%?PerBlockAnalysis@LiveVarAnalysis@@AEAA_NPEAUBasicBlock@@_N1@Z:-1390878:-0.10%:0.18%:-0.0012%??$buildIntervals@$00@LinearScan@@QEAAXXZ:-1420236:-0.28%:0.18%:-0.0012%?doLinearScan@LinearScan@@UEAA?AW4PhaseStatus@@XZ:-1472138:-0.40%:0.19%:-0.0013%?WalkTree@?$GenTreeVisitor@V?$GenericTreeWalker@$0A@$00$0A@$00@@@@QEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@PEAU4@@Z:-1480816:-0.34%:0.19%:-0.0013%?UpdateLifeVar@?$TreeLifeUpdater@$00@@AEAAXPEAUGenTree@@PEAUGenTreeLclVarCommon@@@Z:-1492533:-0.53%:0.19%:-0.0013%?resolveLocalRef@LinearScan@@AEAAXPEAUBasicBlock@@PEAUGenTreeLclVar@@PEAVRefPosition@@@Z:-1708209:-0.47%:0.22%:-0.0015%?optVNAssertionPropCurStmtVisitor@Compiler@@KA?AW4fgWalkResult@1@PEAPEAUGenTree@@PEAUfgWalkData@1@@Z:-1787018:-0.34%:0.23%:-0.0015%?genCodeForBBlist@CodeGen@@IEAAXXZ:-1863492:-0.20%:0.24%:-0.0016%?optAssertionGen@Compiler@@QEAAXPEAUGenTree@@@Z:-1953068:-0.28%:0.25%:-0.0017%?lvaComputeRefCounts@Compiler@@QEAAX_N0@Z:-1990712:-0.26%:0.26%:-0.0017%
jitstd::`anonymous namespace'::quick_sort<unsigned int *,LclVarDsc_BlendedCode_Less> :-2055001:-0.47%:0.26%:-0.0018%?allocateMemory@ArenaAllocator@@QEAAPEAX_K@Z:-2058385:-0.08%:0.26%:-0.0018%?fgMarkUseDef@Compiler@@AEAAXPEAUGenTreeLclVarCommon@@@Z:-2423637:-0.39%:0.31%:-0.0021%?allocateRegisters@LinearScan@@QEAAXXZ:-2501343:-0.08%:0.32%:-0.0022%??$select@$0A@@RegisterSelection@LinearScan@@QEAA_KPEAVInterval@@PEAVRefPosition@@@Z:-3296353:-0.12%:0.42%:-0.0029%?DoPhase@@YAXPEAVCompiler@@W4Phases@@P81@EAA?AW4PhaseStatus@@XZ@Z:-3654638:-1.32%:0.47%:-0.0032%?processBlockStartLocations@LinearScan@@AEAAXPEAUBasicBlock@@@Z:-3668164:-0.25%:0.47%:-0.0032%ArrayStack<`Compiler::fgTailMerge'::`2'::PredInfo>::Emplace<`Compiler::fgTailMerge'::`2'::PredInfo&>:-5529385:-100.00%:0.71%:-0.0048%?optCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAUStatement@@PEAUGenTreeLclVarCommon@@IPEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-10813657:-0.93%:1.39%:-0.0094%
`Compiler::compCompile'::`2'::<lambda_2>::operator() :-12285906:-100.00%:1.57%:-0.0106%?fgTailMerge@Compiler@@QEAA?AW4PhaseStatus@@XZ:-28273557:-100.00%:3.62%:-0.0245%
`Compiler::fgTailMerge'::`2'::<lambda_1>::operator() :-128142453:-100.00%:16.42%:-0.1109%

(Note that fgTailMerge() was changed to fgHeadTailMerge(bool), so the tail merging lambda shows up both as appearing with the new name and disappearing with the old). So it seems like it is pretty close to the same TP cost as the tail merging.

fgCanMoveFirstStatementIntoPred is not costly enough to show up in the trace. gtHasLocalsWithAddrOp barely shows up.

I collected stats on the checks, and over libraries.pmi fgCanMoveFirstStatementIntoPred is called 18110 times and returns true 15688 times and false 2422 times.

@AndyAyersMS

Copy link
Copy Markdown
Member

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

It over halves the TP impact with only a couple non-test regressions -- I will switch to that. I wonder how much it is about visiting switches compared to the Succs enumerator being expensive -- I am introducing a visitor based regular successor enumerator in #89328 that could probably also have helped.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Failures are known according to build analysis.

@jakobbotsch
jakobbotsch merged commit e9ce3aa into dotnet:mainAug 18, 2023
@jakobbotsch
jakobbotsch deleted the head-merging branch August 18, 2023 09:39
@ghostghost locked as resolved and limited conversation to collaborators Sep 17, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

cmove is not emitted for a simple expression

2 participants

@jakobbotsch@AndyAyersMS
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' JIT: Add a head merging transformation alongside the tail merging transformation by jakobbotsch · Pull Request #90468 · dotnet/runtime · GitHub
Skip to content

JIT: Add a head merging transformation alongside the tail merging transformation - #90468

Merged
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging
Aug 18, 2023
Merged

JIT: Add a head merging transformation alongside the tail merging transformation#90468
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Aug 12, 2023

Copy link
Copy Markdown
Member

Add a pass that does head merging to complement the existing tail merging pass. Unlike tail merging this either requires spilling or reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix#90017

Add a pass that does head merging to compliment the existing tail
merging pass. Unlike tail merging this requires reordering the first
statement with the terminator node of the predecessor, which requires
some interference checking.
Fixdotnet#90017
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Aug 12, 2023
@ghost

Copy link
Copy Markdown

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

Issue Details

Add a pass that does head merging to compliment the existing tail merging pass. Unlike tail merging this requires reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix #90017

Author:jakobbotsch
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotschjakobbotsch added this to the 9.0.0 milestone Aug 14, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 10:17
@jakobbotsch
jakobbotsch marked this pull request as draft August 16, 2023 10:25
@jakobbotschjakobbotsch changed the title JIT: Add a head merging passJIT: Add a head merging transformation alongside the tail merging transformationAug 16, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 13:08
@jakobbotsch

jakobbotsch commented Aug 16, 2023

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Diffs. Quite skewed because of one particular test, but still a fair amount of improvements, in a lot of cases creating new conditional selects (which both bring size-wise improvements and regressions). The reordering also can bring regressions with it, in the same way that we see from forward sub sometimes.

There's also a consideration that tail merging and head merging can create new opportunities for each other, but this change doesn't try to rerun either of them when that potentially happens.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn, runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
{
if (gtHasRef(tree1, dsc->lvFieldLclStart + i))
{
JITDUMP(" cannot reorder with interferring use of struct field\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
JITDUMP(" cannot reorder with interferring use of struct field\n");
JITDUMP(" cannot reorder with interfering use of struct field\n");

similar elsehwere

@AndyAyersMS

Copy link
Copy Markdown
Member

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Seems like a pretty natural fit.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

@jakobbotsch

jakobbotsch commented Aug 17, 2023

Copy link
Copy Markdown
MemberAuthor

The Fuzzlyn failures are #7539 (hitting this a lot after adding Unsafe.As support -- need to figure out what to do about it). Runtime and jitstress failures are #90593.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

For libraries.pmi the histogram of how many statements we head merge in each block (where we head merge any) looks like:

1 .. 1===>4173 count ( 56% of total)
2 .. 2===>972 count ( 70% of total)
3 .. 3===>919 count ( 82% of total)
4 .. 4===>366 count ( 87% of total)
5 .. 5===>487 count ( 94% of total)
6 .. 10===>360 count ( 99% of total)
11 .. 15===>40 count ( 99% of total)
16 .. 20===>5 count (100% of total)

I can try to see if I can improve TP a bit -- for one we shouldn't need to iterate over all BBs twice if we just call both head and tail merging from one loop.
I'm not sure that the interference checks are that costly, but certainly we could do fewer tree walks as part of it.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

The detailed TP breakdown is, after moving the head merging into fgHeadMerge:

Base:115595112161, Diff:115766296686, +0.1481%?fgHeadMerge@Compiler@@QEAA_NPEAUBasicBlock@@AEAV?$ArrayStack@UPredSuccInfo@@@@_N@Z:159867209:NA:20.48%:+0.1383%
`Compiler::fgHeadTailMerge'::`2'::<lambda_1>::operator() :128143167:NA:16.42%:+0.1109%?NumSucc@BasicBlock@@QEAAIPEAVCompiler@@@Z:55787892:+32.82%:7.15%:+0.0483%?fgHeadTailMerge@Compiler@@QEAA?AW4PhaseStatus@@_N@Z:53696551:NA:6.88%:+0.0465%?GetSucc@BasicBlock@@QEAAPEAU1@IPEAVCompiler@@@Z:30154807:+13.41%:3.86%:+0.0261%?Compare@GenTree@@SA_NPEAU1@0_N@Z:15846220:+21.62%:2.03%:+0.0137%
`Compiler::compCompile'::`2'::<lambda_3>::operator() :12277667:NA:1.57%:+0.0106%??$Emplace@AEAUPredSuccInfo@@@?$ArrayStack@UPredSuccInfo@@@@QEAAXAEAUPredSuccInfo@@@Z:5529537:NA:0.71%:+0.0048%?compCompile@Compiler@@IEAAXPEAPEAXPEAIPEAVJitFlags@@@Z:1684987:+1.37%:0.22%:+0.0015%GenTreeVisitor<`Compiler::gtHasLocalsWithAddrOp'::`2'::LocalsWithAddrOpVisitor>::WalkTree:1252917:+1.84%:0.16%:+0.0011%?fgUpdateFlowGraph@Compiler@@QEAA_N_N0@Z:1130065:+0.08%:0.14%:+0.0010%BasicBlock::VisitAllSuccs<`Compiler::optReachable'::`12'::<lambda_1>>:879816:+0.47%:0.11%:+0.0008%?fgReorderBlocks@Compiler@@QEAA_N_N@Z:-790057:-0.21%:0.10%:-0.0007%?newRefPosition@LinearScan@@AEAAPEAVRefPosition@@PEAVInterval@@IW4RefType@@PEAUGenTree@@_KI@Z:-801471:-0.09%:0.10%:-0.0007%?RenameDef@SsaBuilder@@AEAAXPEAUGenTree@@PEAUBasicBlock@@@Z:-812236:-0.86%:0.10%:-0.0007%?incRefCnts@LclVarDsc@@QEAAXNPEAVCompiler@@W4RefCountState@@_N@Z:-814351:-0.27%:0.10%:-0.0007%?OptimizeRangeCheck@RangeCheck@@QEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTree@@@Z:-825515:-0.37%:0.11%:-0.0007%?genCodeForTreeNode@CodeGen@@IEAAXPEAUGenTree@@@Z:-825588:-0.12%:0.11%:-0.0007%?MakeCopy@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAPEA_KPEAVCompiler@@PEA_K@Z:-835566:-0.32%:0.11%:-0.0007%?fgValueNumberBlock@Compiler@@QEAAXPEAUBasicBlock@@@Z:-846018:-0.31%:0.11%:-0.0007%?AddPhiArg@SsaBuilder@@AEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTreePhi@@II0@Z:-862799:-1.49%:0.11%:-0.0007%?getWeight@LinearScan@@AEAANPEAVRefPosition@@@Z:-866614:-0.29%:0.11%:-0.0007%?UnionD@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAXPEAVCompiler@@AEAPEA_KPEA_K@Z:-871931:-0.20%:0.11%:-0.0008%?fgMorphTree@Compiler@@QEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@@Z:-883522:-0.10%:0.11%:-0.0008%?RenamePushDef@SsaBuilder@@AEAAIPEAUGenTree@@PEAUBasicBlock@@I_N@Z:-886870:-1.13%:0.11%:-0.0008%?EnsureCoversInd@?$JitExpandArray@PEAUChunk@ValueNumStore@@@@IEAAXI@Z:-892604:-0.31%:0.11%:-0.0008%?gtSetEvalOrder@Compiler@@QEAAIPEAUGenTree@@@Z:-905597:-0.05%:0.12%:-0.0008%??$resolveRegisters@$00@LinearScan@@QEAAXXZ:-934671:-0.15%:0.12%:-0.0008%?fgInterBlockLocalVarLiveness@Compiler@@QEAAXXZ:-998691:-0.17%:0.13%:-0.0009%?optVnCopyProp@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1013931:-0.51%:0.13%:-0.0009%?RewriteNode@Rationalizer@@AEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@AEAV?$ArrayStack@PEAUGenTree@@@@@Z:-1016909:-0.13%:0.13%:-0.0009%?fgValueNumberStore@Compiler@@QEAAXPEAUGenTree@@@Z:-1027387:-0.72%:0.13%:-0.0009%?fgComputeLifeLIR@Compiler@@QEAAXAEAPEA_KPEAUBasicBlock@@AEBQEA_K@Z:-1032432:-0.25%:0.13%:-0.0009%?BuildNode@LinearScan@@AEAAHPEAUGenTree@@@Z:-1036010:-0.15%:0.13%:-0.0009%?fgPerBlockLocalVarLiveness@Compiler@@QEAAXXZ:-1052193:-0.16%:0.13%:-0.0009%?InsertPhiFunctions@SsaBuilder@@AEAAXPEAPEAUBasicBlock@@H@Z:-1106749:-0.58%:0.14%:-0.0010%?optBlockCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-1144389:-0.32%:0.15%:-0.0010%?fgValueNumberTree@Compiler@@QEAAXPEAUGenTree@@@Z:-1149567:-0.17%:0.15%:-0.0010%
`Compiler::optCopyPropPushDef'::`2'::<lambda_1>::operator() :-1166866:-1.11%:0.15%:-0.0010%?optAssertionProp@Compiler@@QEAAPEAUGenTree@@AEBQEA_KPEAU2@PEAUStatement@@PEAUBasicBlock@@@Z:-1194100:-0.26%:0.15%:-0.0010%?fgMorphSmpOp@Compiler@@AEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@PEA_N@Z:-1206778:-0.07%:0.15%:-0.0010%?fgComputeLifeTrackedLocalDef@Compiler@@QEAA_NAEAPEA_KAEBQEA_KAEAVLclVarDsc@@PEAUGenTreeLclVarCommon@@@Z:-1229223:-0.67%:0.16%:-0.0011%?optAssertionPropMain@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1373368:-0.34%:0.18%:-0.0012%?PerBlockAnalysis@LiveVarAnalysis@@AEAA_NPEAUBasicBlock@@_N1@Z:-1390878:-0.10%:0.18%:-0.0012%??$buildIntervals@$00@LinearScan@@QEAAXXZ:-1420236:-0.28%:0.18%:-0.0012%?doLinearScan@LinearScan@@UEAA?AW4PhaseStatus@@XZ:-1472138:-0.40%:0.19%:-0.0013%?WalkTree@?$GenTreeVisitor@V?$GenericTreeWalker@$0A@$00$0A@$00@@@@QEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@PEAU4@@Z:-1480816:-0.34%:0.19%:-0.0013%?UpdateLifeVar@?$TreeLifeUpdater@$00@@AEAAXPEAUGenTree@@PEAUGenTreeLclVarCommon@@@Z:-1492533:-0.53%:0.19%:-0.0013%?resolveLocalRef@LinearScan@@AEAAXPEAUBasicBlock@@PEAUGenTreeLclVar@@PEAVRefPosition@@@Z:-1708209:-0.47%:0.22%:-0.0015%?optVNAssertionPropCurStmtVisitor@Compiler@@KA?AW4fgWalkResult@1@PEAPEAUGenTree@@PEAUfgWalkData@1@@Z:-1787018:-0.34%:0.23%:-0.0015%?genCodeForBBlist@CodeGen@@IEAAXXZ:-1863492:-0.20%:0.24%:-0.0016%?optAssertionGen@Compiler@@QEAAXPEAUGenTree@@@Z:-1953068:-0.28%:0.25%:-0.0017%?lvaComputeRefCounts@Compiler@@QEAAX_N0@Z:-1990712:-0.26%:0.26%:-0.0017%
jitstd::`anonymous namespace'::quick_sort<unsigned int *,LclVarDsc_BlendedCode_Less> :-2055001:-0.47%:0.26%:-0.0018%?allocateMemory@ArenaAllocator@@QEAAPEAX_K@Z:-2058385:-0.08%:0.26%:-0.0018%?fgMarkUseDef@Compiler@@AEAAXPEAUGenTreeLclVarCommon@@@Z:-2423637:-0.39%:0.31%:-0.0021%?allocateRegisters@LinearScan@@QEAAXXZ:-2501343:-0.08%:0.32%:-0.0022%??$select@$0A@@RegisterSelection@LinearScan@@QEAA_KPEAVInterval@@PEAVRefPosition@@@Z:-3296353:-0.12%:0.42%:-0.0029%?DoPhase@@YAXPEAVCompiler@@W4Phases@@P81@EAA?AW4PhaseStatus@@XZ@Z:-3654638:-1.32%:0.47%:-0.0032%?processBlockStartLocations@LinearScan@@AEAAXPEAUBasicBlock@@@Z:-3668164:-0.25%:0.47%:-0.0032%ArrayStack<`Compiler::fgTailMerge'::`2'::PredInfo>::Emplace<`Compiler::fgTailMerge'::`2'::PredInfo&>:-5529385:-100.00%:0.71%:-0.0048%?optCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAUStatement@@PEAUGenTreeLclVarCommon@@IPEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-10813657:-0.93%:1.39%:-0.0094%
`Compiler::compCompile'::`2'::<lambda_2>::operator() :-12285906:-100.00%:1.57%:-0.0106%?fgTailMerge@Compiler@@QEAA?AW4PhaseStatus@@XZ:-28273557:-100.00%:3.62%:-0.0245%
`Compiler::fgTailMerge'::`2'::<lambda_1>::operator() :-128142453:-100.00%:16.42%:-0.1109%

(Note that fgTailMerge() was changed to fgHeadTailMerge(bool), so the tail merging lambda shows up both as appearing with the new name and disappearing with the old). So it seems like it is pretty close to the same TP cost as the tail merging.

fgCanMoveFirstStatementIntoPred is not costly enough to show up in the trace. gtHasLocalsWithAddrOp barely shows up.

I collected stats on the checks, and over libraries.pmi fgCanMoveFirstStatementIntoPred is called 18110 times and returns true 15688 times and false 2422 times.

@AndyAyersMS

Copy link
Copy Markdown
Member

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

It over halves the TP impact with only a couple non-test regressions -- I will switch to that. I wonder how much it is about visiting switches compared to the Succs enumerator being expensive -- I am introducing a visitor based regular successor enumerator in #89328 that could probably also have helped.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Failures are known according to build analysis.

@jakobbotsch
jakobbotsch merged commit e9ce3aa into dotnet:mainAug 18, 2023
@jakobbotsch
jakobbotsch deleted the head-merging branch August 18, 2023 09:39
@ghostghost locked as resolved and limited conversation to collaborators Sep 17, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

cmove is not emitted for a simple expression

2 participants

@jakobbotsch@AndyAyersMS
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); JIT: Add a head merging transformation alongside the tail merging transformation by jakobbotsch · Pull Request #90468 · dotnet/runtime · GitHub
Skip to content

JIT: Add a head merging transformation alongside the tail merging transformation - #90468

Merged
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging
Aug 18, 2023
Merged

JIT: Add a head merging transformation alongside the tail merging transformation#90468
jakobbotsch merged 12 commits into
dotnet:mainfrom
jakobbotsch:head-merging

Conversation

@jakobbotsch

@jakobbotschjakobbotsch commented Aug 12, 2023

Copy link
Copy Markdown
Member

Add a pass that does head merging to complement the existing tail merging pass. Unlike tail merging this either requires spilling or reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix#90017

Add a pass that does head merging to compliment the existing tail
merging pass. Unlike tail merging this requires reordering the first
statement with the terminator node of the predecessor, which requires
some interference checking.
Fixdotnet#90017
@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Aug 12, 2023
@ghost

Copy link
Copy Markdown

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

Issue Details

Add a pass that does head merging to compliment the existing tail merging pass. Unlike tail merging this requires reordering the first statement with the terminator node of the predecessor, which requires some interference checking.

Fix #90017

Author:jakobbotsch
Assignees:-
Labels:

area-CodeGen-coreclr

Milestone:-

@jakobbotschjakobbotsch added this to the 9.0.0 milestone Aug 14, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 10:17
@jakobbotsch
jakobbotsch marked this pull request as draft August 16, 2023 10:25
@jakobbotschjakobbotsch changed the title JIT: Add a head merging passJIT: Add a head merging transformation alongside the tail merging transformationAug 16, 2023
@jakobbotsch
jakobbotsch marked this pull request as ready for review August 16, 2023 13:08
@jakobbotsch

jakobbotsch commented Aug 16, 2023

Copy link
Copy Markdown
MemberAuthor

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Diffs. Quite skewed because of one particular test, but still a fair amount of improvements, in a lot of cases creating new conditional selects (which both bring size-wise improvements and regressions). The reordering also can bring regressions with it, in the same way that we see from forward sub sometimes.

There's also a consideration that tail merging and head merging can create new opportunities for each other, but this change doesn't try to rerun either of them when that potentially happens.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn, runtime-coreclr jitstress, runtime-coreclr libraries-jitstress

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

Comment threadsrc/coreclr/jit/fgopt.cpp Outdated
{
if (gtHasRef(tree1, dsc->lvFieldLclStart + i))
{
JITDUMP(" cannot reorder with interferring use of struct field\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
JITDUMP(" cannot reorder with interferring use of struct field\n");
JITDUMP(" cannot reorder with interfering use of struct field\n");

similar elsehwere

@AndyAyersMS

Copy link
Copy Markdown
Member

cc @dotnet/jit-contrib PTAL @AndyAyersMS. Thoughts on this? Better to unify them more? Split them more apart?

Seems like a pretty natural fit.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

@jakobbotsch

jakobbotsch commented Aug 17, 2023

Copy link
Copy Markdown
MemberAuthor

The Fuzzlyn failures are #7539 (hitting this a lot after adding Unsafe.As support -- need to figure out what to do about it). Runtime and jitstress failures are #90593.

I always worry that interference checking (particularly when repeated) can be costly. Current TP cost does not look too bad, but suggests a lot of failed checks (since if we can head merge it likely improves TP). So I wonder if there are ways to fail faster?

Do you know how often we end up moving multiple statements?

For libraries.pmi the histogram of how many statements we head merge in each block (where we head merge any) looks like:

1 .. 1===>4173 count ( 56% of total)
2 .. 2===>972 count ( 70% of total)
3 .. 3===>919 count ( 82% of total)
4 .. 4===>366 count ( 87% of total)
5 .. 5===>487 count ( 94% of total)
6 .. 10===>360 count ( 99% of total)
11 .. 15===>40 count ( 99% of total)
16 .. 20===>5 count (100% of total)

I can try to see if I can improve TP a bit -- for one we shouldn't need to iterate over all BBs twice if we just call both head and tail merging from one loop.
I'm not sure that the interference checks are that costly, but certainly we could do fewer tree walks as part of it.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

The detailed TP breakdown is, after moving the head merging into fgHeadMerge:

Base:115595112161, Diff:115766296686, +0.1481%?fgHeadMerge@Compiler@@QEAA_NPEAUBasicBlock@@AEAV?$ArrayStack@UPredSuccInfo@@@@_N@Z:159867209:NA:20.48%:+0.1383%
`Compiler::fgHeadTailMerge'::`2'::<lambda_1>::operator() :128143167:NA:16.42%:+0.1109%?NumSucc@BasicBlock@@QEAAIPEAVCompiler@@@Z:55787892:+32.82%:7.15%:+0.0483%?fgHeadTailMerge@Compiler@@QEAA?AW4PhaseStatus@@_N@Z:53696551:NA:6.88%:+0.0465%?GetSucc@BasicBlock@@QEAAPEAU1@IPEAVCompiler@@@Z:30154807:+13.41%:3.86%:+0.0261%?Compare@GenTree@@SA_NPEAU1@0_N@Z:15846220:+21.62%:2.03%:+0.0137%
`Compiler::compCompile'::`2'::<lambda_3>::operator() :12277667:NA:1.57%:+0.0106%??$Emplace@AEAUPredSuccInfo@@@?$ArrayStack@UPredSuccInfo@@@@QEAAXAEAUPredSuccInfo@@@Z:5529537:NA:0.71%:+0.0048%?compCompile@Compiler@@IEAAXPEAPEAXPEAIPEAVJitFlags@@@Z:1684987:+1.37%:0.22%:+0.0015%GenTreeVisitor<`Compiler::gtHasLocalsWithAddrOp'::`2'::LocalsWithAddrOpVisitor>::WalkTree:1252917:+1.84%:0.16%:+0.0011%?fgUpdateFlowGraph@Compiler@@QEAA_N_N0@Z:1130065:+0.08%:0.14%:+0.0010%BasicBlock::VisitAllSuccs<`Compiler::optReachable'::`12'::<lambda_1>>:879816:+0.47%:0.11%:+0.0008%?fgReorderBlocks@Compiler@@QEAA_N_N@Z:-790057:-0.21%:0.10%:-0.0007%?newRefPosition@LinearScan@@AEAAPEAVRefPosition@@PEAVInterval@@IW4RefType@@PEAUGenTree@@_KI@Z:-801471:-0.09%:0.10%:-0.0007%?RenameDef@SsaBuilder@@AEAAXPEAUGenTree@@PEAUBasicBlock@@@Z:-812236:-0.86%:0.10%:-0.0007%?incRefCnts@LclVarDsc@@QEAAXNPEAVCompiler@@W4RefCountState@@_N@Z:-814351:-0.27%:0.10%:-0.0007%?OptimizeRangeCheck@RangeCheck@@QEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTree@@@Z:-825515:-0.37%:0.11%:-0.0007%?genCodeForTreeNode@CodeGen@@IEAAXPEAUGenTree@@@Z:-825588:-0.12%:0.11%:-0.0007%?MakeCopy@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAPEA_KPEAVCompiler@@PEA_K@Z:-835566:-0.32%:0.11%:-0.0007%?fgValueNumberBlock@Compiler@@QEAAXPEAUBasicBlock@@@Z:-846018:-0.31%:0.11%:-0.0007%?AddPhiArg@SsaBuilder@@AEAAXPEAUBasicBlock@@PEAUStatement@@PEAUGenTreePhi@@II0@Z:-862799:-1.49%:0.11%:-0.0007%?getWeight@LinearScan@@AEAANPEAVRefPosition@@@Z:-866614:-0.29%:0.11%:-0.0007%?UnionD@?$BitSetOps@PEA_K$00PEAVCompiler@@VTrackedVarBitSetTraits@@@@SAXPEAVCompiler@@AEAPEA_KPEA_K@Z:-871931:-0.20%:0.11%:-0.0008%?fgMorphTree@Compiler@@QEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@@Z:-883522:-0.10%:0.11%:-0.0008%?RenamePushDef@SsaBuilder@@AEAAIPEAUGenTree@@PEAUBasicBlock@@I_N@Z:-886870:-1.13%:0.11%:-0.0008%?EnsureCoversInd@?$JitExpandArray@PEAUChunk@ValueNumStore@@@@IEAAXI@Z:-892604:-0.31%:0.11%:-0.0008%?gtSetEvalOrder@Compiler@@QEAAIPEAUGenTree@@@Z:-905597:-0.05%:0.12%:-0.0008%??$resolveRegisters@$00@LinearScan@@QEAAXXZ:-934671:-0.15%:0.12%:-0.0008%?fgInterBlockLocalVarLiveness@Compiler@@QEAAXXZ:-998691:-0.17%:0.13%:-0.0009%?optVnCopyProp@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1013931:-0.51%:0.13%:-0.0009%?RewriteNode@Rationalizer@@AEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@AEAV?$ArrayStack@PEAUGenTree@@@@@Z:-1016909:-0.13%:0.13%:-0.0009%?fgValueNumberStore@Compiler@@QEAAXPEAUGenTree@@@Z:-1027387:-0.72%:0.13%:-0.0009%?fgComputeLifeLIR@Compiler@@QEAAXAEAPEA_KPEAUBasicBlock@@AEBQEA_K@Z:-1032432:-0.25%:0.13%:-0.0009%?BuildNode@LinearScan@@AEAAHPEAUGenTree@@@Z:-1036010:-0.15%:0.13%:-0.0009%?fgPerBlockLocalVarLiveness@Compiler@@QEAAXXZ:-1052193:-0.16%:0.13%:-0.0009%?InsertPhiFunctions@SsaBuilder@@AEAAXPEAPEAUBasicBlock@@H@Z:-1106749:-0.58%:0.14%:-0.0010%?optBlockCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-1144389:-0.32%:0.15%:-0.0010%?fgValueNumberTree@Compiler@@QEAAXPEAUGenTree@@@Z:-1149567:-0.17%:0.15%:-0.0010%
`Compiler::optCopyPropPushDef'::`2'::<lambda_1>::operator() :-1166866:-1.11%:0.15%:-0.0010%?optAssertionProp@Compiler@@QEAAPEAUGenTree@@AEBQEA_KPEAU2@PEAUStatement@@PEAUBasicBlock@@@Z:-1194100:-0.26%:0.15%:-0.0010%?fgMorphSmpOp@Compiler@@AEAAPEAUGenTree@@PEAU2@PEAUMorphAddrContext@1@PEA_N@Z:-1206778:-0.07%:0.15%:-0.0010%?fgComputeLifeTrackedLocalDef@Compiler@@QEAA_NAEAPEA_KAEBQEA_KAEAVLclVarDsc@@PEAUGenTreeLclVarCommon@@@Z:-1229223:-0.67%:0.16%:-0.0011%?optAssertionPropMain@Compiler@@QEAA?AW4PhaseStatus@@XZ:-1373368:-0.34%:0.18%:-0.0012%?PerBlockAnalysis@LiveVarAnalysis@@AEAA_NPEAUBasicBlock@@_N1@Z:-1390878:-0.10%:0.18%:-0.0012%??$buildIntervals@$00@LinearScan@@QEAAXXZ:-1420236:-0.28%:0.18%:-0.0012%?doLinearScan@LinearScan@@UEAA?AW4PhaseStatus@@XZ:-1472138:-0.40%:0.19%:-0.0013%?WalkTree@?$GenTreeVisitor@V?$GenericTreeWalker@$0A@$00$0A@$00@@@@QEAA?AW4fgWalkResult@Compiler@@PEAPEAUGenTree@@PEAU4@@Z:-1480816:-0.34%:0.19%:-0.0013%?UpdateLifeVar@?$TreeLifeUpdater@$00@@AEAAXPEAUGenTree@@PEAUGenTreeLclVarCommon@@@Z:-1492533:-0.53%:0.19%:-0.0013%?resolveLocalRef@LinearScan@@AEAAXPEAUBasicBlock@@PEAUGenTreeLclVar@@PEAVRefPosition@@@Z:-1708209:-0.47%:0.22%:-0.0015%?optVNAssertionPropCurStmtVisitor@Compiler@@KA?AW4fgWalkResult@1@PEAPEAUGenTree@@PEAUfgWalkData@1@@Z:-1787018:-0.34%:0.23%:-0.0015%?genCodeForBBlist@CodeGen@@IEAAXXZ:-1863492:-0.20%:0.24%:-0.0016%?optAssertionGen@Compiler@@QEAAXPEAUGenTree@@@Z:-1953068:-0.28%:0.25%:-0.0017%?lvaComputeRefCounts@Compiler@@QEAAX_N0@Z:-1990712:-0.26%:0.26%:-0.0017%
jitstd::`anonymous namespace'::quick_sort<unsigned int *,LclVarDsc_BlendedCode_Less> :-2055001:-0.47%:0.26%:-0.0018%?allocateMemory@ArenaAllocator@@QEAAPEAX_K@Z:-2058385:-0.08%:0.26%:-0.0018%?fgMarkUseDef@Compiler@@AEAAXPEAUGenTreeLclVarCommon@@@Z:-2423637:-0.39%:0.31%:-0.0021%?allocateRegisters@LinearScan@@QEAAXXZ:-2501343:-0.08%:0.32%:-0.0022%??$select@$0A@@RegisterSelection@LinearScan@@QEAA_KPEAVInterval@@PEAVRefPosition@@@Z:-3296353:-0.12%:0.42%:-0.0029%?DoPhase@@YAXPEAVCompiler@@W4Phases@@P81@EAA?AW4PhaseStatus@@XZ@Z:-3654638:-1.32%:0.47%:-0.0032%?processBlockStartLocations@LinearScan@@AEAAXPEAUBasicBlock@@@Z:-3668164:-0.25%:0.47%:-0.0032%ArrayStack<`Compiler::fgTailMerge'::`2'::PredInfo>::Emplace<`Compiler::fgTailMerge'::`2'::PredInfo&>:-5529385:-100.00%:0.71%:-0.0048%?optCopyProp@Compiler@@QEAA_NPEAUBasicBlock@@PEAUStatement@@PEAUGenTreeLclVarCommon@@IPEAV?$JitHashTable@IU?$JitSmallPrimitiveKeyFuncs@I@@PEAV?$ArrayStack@VCopyPropSsaDef@Compiler@@@@VCompAllocator@@VJitHashTableBehavior@@@@@Z:-10813657:-0.93%:1.39%:-0.0094%
`Compiler::compCompile'::`2'::<lambda_2>::operator() :-12285906:-100.00%:1.57%:-0.0106%?fgTailMerge@Compiler@@QEAA?AW4PhaseStatus@@XZ:-28273557:-100.00%:3.62%:-0.0245%
`Compiler::fgTailMerge'::`2'::<lambda_1>::operator() :-128142453:-100.00%:16.42%:-0.1109%

(Note that fgTailMerge() was changed to fgHeadTailMerge(bool), so the tail merging lambda shows up both as appearing with the new name and disappearing with the old). So it seems like it is pretty close to the same TP cost as the tail merging.

fgCanMoveFirstStatementIntoPred is not costly enough to show up in the trace. gtHasLocalsWithAddrOp barely shows up.

I collected stats on the checks, and over libraries.pmi fgCanMoveFirstStatementIntoPred is called 18110 times and returns true 15688 times and false 2422 times.

@AndyAyersMS

Copy link
Copy Markdown
Member

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

What happens if you just restrict head merge to BBJ_COND -- do we see any interesting cases with switches?

It over halves the TP impact with only a couple non-test regressions -- I will switch to that. I wonder how much it is about visiting switches compared to the Succs enumerator being expensive -- I am introducing a visitor based regular successor enumerator in #89328 that could probably also have helped.

@jakobbotsch

Copy link
Copy Markdown
MemberAuthor

Failures are known according to build analysis.

@jakobbotsch
jakobbotsch merged commit e9ce3aa into dotnet:mainAug 18, 2023
@jakobbotsch
jakobbotsch deleted the head-merging branch August 18, 2023 09:39
@ghostghost locked as resolved and limited conversation to collaborators Sep 17, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR 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.

cmove is not emitted for a simple expression

2 participants

@jakobbotsch@AndyAyersMS