-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Fix value numbering of field assignments #61113
Fix value numbering of field assignments #61113
Conversation
Tagging subscribers to this area: @JulieLeeMSFT Issue DetailsWhen value numbering an assignment to a field, A handful of positive diffs for this commit resulting from more CSEs and redundant branch optimizations, due to more precise liberal VNs. Some regressions for the same reasons, e. g. CSE discovering new defs for CSEs without the exception sets of all uses. Diffs:
|
5f538cb
to
152eb02
Compare
@dotnet/jit-contrib |
When value numbering an assignment to a field, VNApplySelectorsAssign was called twice, first for the field sequence to find the exact value, then for the heap VN update. This is not correct as the method expects to be called only for sequences that will end up updating a map with exact values, as it type checks the store with the helper VNApplySelectorsAssignTypeCoerce. Usage of VNApplySelectorsAssign to update the heap ended up meaning that any stores to struct fields ended up with casts for maps, blocking traversal in VNForMapSelect. A handful of positive diffs for this commit resulting from more CSEs and redundant branch optimizations, due to more precise liberal VNs.
It was confusing in the dumps to look at unused results of VNForMapSelect, so just avoid looking for the first field's value if we do not need it.
This is a temporary change to minimize diffs. The issue is that we need to update both the reading and writing code at once if we want to change the types of the maps without some regressions due to new artificial mismatches.
152eb02
to
352acf4
Compare
|
||
// construct the ValueNumber for 'fldMap at obj' | ||
valAtAddr = vnStore->VNForMapSelect(VNK_Liberal, firstFieldType, fldMapVN, normVal); | ||
firstFieldValueSelectorVN = vnStore->VNLiberalNormalValue(obj->gtVNPair); |
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.
Do we not need to unpack the VN like before?
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.
Ah, scratch that, I see this just uses VNLiberalNormalValue now.
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.
Note that the tracking of exception sets this code did before, i. e.
vnExcSet = vnStore->VNExcSetUnion(vnExcSet, vnObjExcSet);
was dead code because nothing uses vnExcSet
in this method - the ASG
tree is assigned VNForVoid()
at the end, always, i. e. we were always losing all the exceptions. We are "ok" correctness-wise here only because CSE is the only consumer of exception sets right now and it does not look at trees marked with GTF_ASG
.
(Edit: in general, one should assume that the exception sets are only correct "for CSE purposes", because e. g. VNHasExc(unique VN assigned to a user call)
will be false
)
ValueNum fldMapVN = vnStore->VNForMapSelect(VNK_Liberal, firstFieldType, | ||
fgCurMemoryVN[GcHeap], firstFieldSelectorVN); |
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.
Should we be using TYP_REF
instead of firstFieldType
here accordingly to the discussion last week?
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.
Yes we should, but as standalone change, it will create regressions because the reading side of this code needs to be updated to use the same type (it is using firstFieldType
at the moment). This is the reason for the 4th commit:
This is a temporary change to minimize diffs.
The issue is that we need to update both the
reading and writing code at once if we want
to change the types of the maps without some
regressions due to new artificial mismatches.
In the next change, I will update the reading side, and in the change after that - the types for the heaps/"first field maps" (then will come the many changes needed to enable clean validation, after that the validation itself, and finally the actual bugfixes).
storeVal, indType); | ||
// Plain static field. | ||
newHeapVN = vnStore->VNApplySelectorsAssign(VNK_Liberal, fgCurMemoryVN[GcHeap], fldSeq, | ||
storeVal, indType); |
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.
Is this dead code?
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.
As far as I know, yes, because we use CLS_VAR
for these cases.
(I would not be surprised if it is reachable under some exotic circumstances of course)
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 don't think so, IsFieldAddr
can never return true without assigning one of the out args. Maybe at some point code like the following would hit this path:
public class Program
{
public static S s_s;
public static int s_i;
public static void Main()
{
s_s = s_s;
Foo();
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static unsafe void Foo()
{
Bar(ref s_i);
}
public static void Bar(ref int i) => i = 10;
}
but currently we do not manage to VN this:
***** BB01, STMT00002(before)
N004 ( 6, 14) [000006] -A--G------- ▌ ASG int
N002 ( 4, 12) [000005] *------N---- ├──▌ IND int
N001 ( 2, 10) [000003] I----------- │ └──▌ CNS_INT(h) byref 0x7ffa80d505b8 static Fseq[s_i]
N003 ( 1, 1) [000004] ------------ └──▌ CNS_INT int 10
N001 [000003] CNS_INT(h) 0x7ffa80d505b8 static Fseq[s_i] => $c0 {Hnd const: 0x00007FFA80D505B8}
N003 [000004] CNS_INT 10 => $41 {IntCns 10}
fgCurMemoryVN[GcHeap] assigned for assign-of-IND at [000006] to VN: $81.
N004 [000006] ASG => $VN.Void
***** BB01, STMT00002(after)
N004 ( 6, 14) [000006] -A--G------- ▌ ASG int $VN.Void
N002 ( 4, 12) [000005] *------N---- ├──▌ IND int $41
N001 ( 2, 10) [000003] I----------- │ └──▌ CNS_INT(h) byref 0x7ffa80d505b8 static Fseq[s_i] $c0
N003 ( 1, 1) [000004] ------------ └──▌ CNS_INT int 10 $41
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, thanks!
windows/x64 improvements - dotnet/perf-autofiling-issues#2204 |
When value numbering an assignment to a field,
VNApplySelectorsAssign
was called twice, first for the field sequence to find the exact value, then for the heap VN update. This is not correct as the method expects to be called only for sequences that will end up updating a map with exact values, as it type checks the store with the helperVNApplySelectorsAssignTypeCoerce
. Usage of VNApplySelectorsAssign to update the heap ended up meaning that any stores to struct fields ended up with casts for maps, blocking traversal inVNForMapSelect
.A handful of positive diffs for this commit resulting from more CSEs and redundant branch optimizations, due to more precise liberal VNs. About the same number of (size) regressions for the same reasons, e. g. CSE discovering new defs for CSEs without the exception sets of all uses.
Diffs:
win-x64
,win-arm64
,win-x86
.Part of #58312.