') + ')', '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('^' + ".*" + ', '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" + ', '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('^' + ".*" + ', '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); } })(); })(); JIT: redundant branch destructure dominating and/or by AndyAyersMS · Pull Request #69291 · dotnet/runtime · GitHub
Skip to content

JIT: redundant branch destructure dominating and/or - #69291

Merged
AndyAyersMS merged 7 commits into
dotnet:mainfrom
AndyAyersMS:RedunantBranchOptSeeThroughAndOrCombinedPredicates
May 23, 2022
Merged

JIT: redundant branch destructure dominating and/or#69291
AndyAyersMS merged 7 commits into
dotnet:mainfrom
AndyAyersMS:RedunantBranchOptSeeThroughAndOrCombinedPredicates

Conversation

@AndyAyersMS

Copy link
Copy Markdown
Member

If a branch predicate p is dominated by another branch with predicate
AND(p, ..) or OR(p, ...) we may be able to infer the value of p.

This is useful on its own, and should help unblock #62689.

@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label May 13, 2022
@ghost

Copy link
Copy Markdown

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

Issue Details

If a branch predicate p is dominated by another branch with predicate
AND(p, ..) or OR(p, ...) we may be able to infer the value of p.

This is useful on its own, and should help unblock #62689.

Author:AndyAyersMS
Assignees:AndyAyersMS
Labels:

area-CodeGen-coreclr

Milestone:-

@AndyAyersMS

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch PTAL
@dotnet/jit-contrib FYI

Not sure how correct this is yet, I can't seem to run pri0 tests locally anymore. Small number of SPMI diffs, but many are sizeable.

I am tempted to recast this as a general VN utility where we can ask if knowing the value of a VN implies knowing the value of another VN; there are lots of other inferences we can draw of this kind. But I'm not sure how to structure this without it getting overly complicated.

@jakobbotsch

Copy link
Copy Markdown
Member

/azp run Fuzzlyn

@azure-pipelines

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

Comment on lines 180 to 266

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.

I am tempted to recast this as a general VN utility where we can ask if knowing the value of a VN implies knowing the value of another VN; there are lots of other inferences we can draw of this kind. But I'm not sure how to structure this without it getting overly complicated.

I think this would be great, and in any case it would be nice to extract this to a function to avoid some of the nesting.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I am tempted to recast this as a general VN utility where we can ask if knowing the value of a VN implies knowing the value of another VN; there are lots of other inferences we can draw of this kind. But I'm not sure how to structure this without it getting overly complicated.

I think this would be great, and in any case it would be nice to extract this to a function to avoid some of the nesting

Let me get the logic right and then I'll look into refactoring.

@jakobbotsch

Copy link
Copy Markdown
Member

The Fuzzlyn examples may be easier to use than the failing tests to iron out the issues.

@AndyAyersMS

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

If a branch predicate `p` is dominated by another branch with predicate
`AND(p, ..)` or `OR(p, ...)` we may be able to infer the value of `p`.
This is useful on its own, and should help unblock dotnet#62689.
@AndyAyersMS
AndyAyersMSforce-pushed the RedunantBranchOptSeeThroughAndOrCombinedPredicates branch from 0071ece to d0366d6CompareMay 20, 2022 01:51
@AndyAyersMS

Copy link
Copy Markdown
MemberAuthor

/azp run Fuzzlyn

@azure-pipelines

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

@AndyAyersMS

Copy link
Copy Markdown
MemberAuthor

@jakobbotsch see if this version reads any better. I could pull functionality into the helper struct but have left it basic for now.

Looking at a few of the larger diffs I realized that the existing version of redundant branch opts has a bug; if the tree VN is a constant than the outcome of the branch it controls is independent of any dominating branch, but we were (previously) using inferencing here. This lead to at least one instance where we made the wrong deduction, 57396 in coreclr_tests. Fixing this keeps a bunch of code around that should never have been deleted. I added a note to the code indicating that checking for the constant case is necessary and not just nice to have.

Seemingly these constant VN relops are somewhat rare and having more than one in the right arrangement even rarer, which is why we haven't seen complaints about this before.

;; bogus deduction with constant VNs (now fixed)
N002 [000032] CNS_INT 1 => $41 {IntCns 1}
...
Dominator BB01 of BB07 has relop with same liberal VN
N003 ( 5, 4) [000008] J------N--- * LE int $41
N001 ( 3, 2) [000006] ----------- +--* LCL_VAR int V03 loc1 u:2 (last use) $40
N002 ( 1, 1) [000007] ----------- \--* CNS_INT int 0 $40
Redundant compare; current relop:
N003 ( 3, 3) [000259] J------N--- * GE int $41
N001 ( 1, 1) [000260] ----------- +--* LCL_VAR int V04 loc2 u:2 $40
N002 ( 1, 1) [000261] ----------- \--* CNS_INT int -1 $42
Fall through successor BB02 of BB01 reaches, relop must be false

The other large regression 247114 from libraries_tests.pmi also has constant cases but there we ended up getting it right as the dominating predicate was the same predicate (here $42 is 0)

N005 [000047] CNS_INT 0 => $42 {IntCns 0}
...
Dominator BB210 of BB215 has relop with same liberal VN
N003 ( 3, 3) [003642] J------N--- * EQ int $42
N001 ( 1, 1) [000486] ----------- +--* LCL_VAR ref V19 tmp15 u:2 $13c5
N002 ( 1, 1) [003641] ----------- \--* CNS_INT ref null $VN.Null
Redundant compare; current relop:
N003 ( 3, 3) [003711] J------N--- * EQ int $42
N001 ( 1, 1) [000491] ----------- +--* LCL_VAR ref V19 tmp15 u:2 $13c5
N002 ( 1, 1) [003710] ----------- \--* CNS_INT ref null $VN.Null

The large regression in this method seems to come from LSRA finding many more single-def cases to spill upfront. Did not try and drill into this further.

@jakobbotschjakobbotsch left a comment

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.

LGTM. I'll do a last Fuzzlyn run.

@jakobbotsch

Copy link
Copy Markdown
Member

/azp run Fuzzlyn

@azure-pipelines

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

@jakobbotsch

Copy link
Copy Markdown
Member

Wow, great diffs. -1% code size and -3% TP on coreclr_tests, looks like that testout test case really hits this pattern.

@AndyAyersMS

AndyAyersMS commented May 23, 2022

Copy link
Copy Markdown
MemberAuthor

Wow, great diffs. -1% code size and -3% TP on coreclr_tests, looks like that testout test case really hits this pattern.

Turns out those methods were all optimized by the "constant" case. I put "constant" in quotes because we're now looking at the liberal VN for a read of a static that we haven't modified since we set its value and haven't done any in-between heap updates.

We would not optimize these before, eg here's some pre-PR IR post-lower.

N001 [000001] CNS_INT 1 => $42 {IntCns 1}
N002 [000820] IND => <l:$42 {IntCns 1}, c:$500 {MemOpaque:NotInLoop}>
...
------------ BB02 [06B..072) -> BB04 (cond), preds={BB01} succs={BB03,BB04}
N001 ( 2, 10) [000939] H---------- t939 = CNS_INT(h) long 0x177d7f3d9f1 static Fseq[hackishFieldName] $c9
/--* t939 long N002 ( 5, 13) [000820] n---G------ t820 = * IND bool <l:$42, c:$500>
N003 ( 1, 1) [000821] ----------- t821 = CNS_INT int 0 $40
/--* t820 bool +--* t821 int N004 ( 7, 15) [000822] J---G--N--- t822 = * NE int <l:$42, c:$4c2>
/--* t822 int N005 ( 9, 17) [000823] ----G------ * JTRUE void $VN.Void

@AndyAyersMS

Copy link
Copy Markdown
MemberAuthor

Also skimmed Fuzzlyn failures; they don't seem to be related?

@jakobbotsch

Copy link
Copy Markdown
Member

Also skimmed Fuzzlyn failures; they don't seem to be related?

Agreed, all of them look like #69659.

@AndyAyersMS
AndyAyersMS merged commit 315c31c into dotnet:mainMay 23, 2022
@EgorBo

EgorBo commented Jun 28, 2022

Copy link
Copy Markdown
Member

Nice improvements on x64: dotnet/perf-autofiling-issues#5617

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.

3 participants

@AndyAyersMS@jakobbotsch@EgorBo