-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JIT: redundant branch destructure dominating and/or #69291
JIT: redundant branch destructure dominating and/or #69291
Conversation
Tagging subscribers to this area: @JulieLeeMSFT Issue DetailsIf a branch predicate This is useful on its own, and should help unblock #62689.
|
@jakobbotsch PTAL 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. |
/azp run Fuzzlyn |
Azure Pipelines successfully started running 1 pipeline(s). |
if (!matched && vnStore->IsVNFunc(domCmpNormVN)) | ||
{ | ||
VNFuncApp funcApp; | ||
if (vnStore->GetVNFunc(domCmpNormVN, &funcApp)) | ||
{ | ||
genTreeOps const oper = genTreeOps(funcApp.m_func); | ||
|
||
if ((oper == GT_EQ) || (oper == GT_NE)) | ||
{ | ||
ValueNum predVN = funcApp.m_args[0]; | ||
ValueNum constantVN = funcApp.m_args[1]; | ||
|
||
if ((constantVN == vnStore->VNZeroForType(TYP_INT)) && vnStore->IsVNFunc(predVN)) | ||
{ | ||
VNFuncApp predFuncApp; | ||
|
||
if (vnStore->GetVNFunc(predVN, &predFuncApp)) | ||
{ | ||
genTreeOps const predOper = genTreeOps(predFuncApp.m_func); | ||
|
||
// Also perhaps GT_NOT? | ||
// | ||
if ((predOper == GT_AND) || (predOper == GT_OR) || (predOper == GT_NOT)) | ||
{ | ||
// If dominating compare is AND/OR(p1, p2) and one of | ||
// the p's is related to our predicate.... | ||
// | ||
for (unsigned int i = 0; (i < predFuncApp.m_arity) && !matched; i++) | ||
{ | ||
ValueNum pVN = predFuncApp.m_args[i]; | ||
|
||
// Also consider perhaps handling N-Ary cases AND(AND(...), ...) and so on. | ||
// | ||
// Abstractly it would be nice if VN allowed n-ary commutative operators | ||
// even though the IR does not support this. | ||
// | ||
for (auto vnRelation : vnRelations) | ||
{ | ||
const ValueNum relatedVN = vnStore->GetRelatedRelop(pVN, vnRelation); | ||
|
||
if ((relatedVN != ValueNumStore::NoVN) && (relatedVN == treeNormVN)) | ||
{ | ||
vnRelationMatch = vnRelation; | ||
matched = true; | ||
|
||
// If dom predicate is wrapped in EQ(*,0) then a true dom | ||
// predicate implies a false branch outcome, and vice versa. | ||
// | ||
// And if the dom predicate is GT_NOT we reverse yet again. | ||
// | ||
reverseSense = (oper == GT_EQ) ^ (predOper == GT_NOT); | ||
|
||
// We only get partial knowledge in these cases. | ||
// | ||
// AND(p1,p2) = true ==> both p1 and p2 must be true | ||
// AND(p1,p2) = false ==> don't know p1 or p2 | ||
// OR(p1,p2) = true ==> don't know p1 or p2 | ||
// OR(p1,p2) = false ==> both p1 and p2 must be false | ||
// | ||
if (predOper != GT_NOT) | ||
{ | ||
canInferFromFalse = reverseSense ^ (predOper == GT_OR); | ||
canInferFromTrue = reverseSense ^ (predOper == GT_AND); | ||
} | ||
|
||
JITDUMP("Inferring predicate value from %s\n", | ||
GenTree::OpName(predOper)); | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
The Fuzzlyn examples may be easier to use than the failing tests to iron out the issues. |
/azp run Fuzzlyn |
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.
0071ece
to
d0366d6
Compare
/azp run Fuzzlyn |
Azure Pipelines successfully started running 1 pipeline(s). |
@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.
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)
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. |
There was a problem hiding this comment.
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.
/azp run Fuzzlyn |
Azure Pipelines successfully started running 1 pipeline(s). |
Wow, great diffs. -1% code size and -3% TP on coreclr_tests, looks like that |
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.
|
Also skimmed Fuzzlyn failures; they don't seem to be related? |
Agreed, all of them look like #69659. |
Nice improvements on x64: dotnet/perf-autofiling-issues#5617 |
If a branch predicate
p
is dominated by another branch with predicateAND(p, ..)
orOR(p, ...)
we may be able to infer the value ofp
.This is useful on its own, and should help unblock #62689.