-
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
Add GT_ARR_LEN to optNonNullAssertionProp_Ind #93531
Conversation
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch Issue DetailsCloses #84248 void Test(int[]? arr)
{
if (arr != null)
{
var _ = arr.Length;
}
} ; Assembly listing for method Prog:Test(int[]):this (FullOpts)
- test rdx, rdx
- je SHORT G_M2580_IG04
- mov eax, dword ptr [rdx+0x08]
-G_M2580_IG04:
ret
-; Total bytes of code 9
+; Total bytes of code 1
|
@@ -4465,7 +4465,7 @@ bool Compiler::optNonNullAssertionProp_Ind(ASSERT_VALARG_TP assertions, GenTree* | |||
bool vnBased = false; | |||
AssertionIndex index = NO_ASSERTION_INDEX; | |||
#endif | |||
if (optAssertionIsNonNull(indir->AsIndir()->Addr(), assertions DEBUGARG(&vnBased) DEBUGARG(&index))) | |||
if (optAssertionIsNonNull(indir->GetIndirOrArrMetaDataAddr(), assertions DEBUGARG(&vnBased) DEBUGARG(&index))) |
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 will note a subtle property of this code: it is relying on array metadata only being used for arrays (TYP_REF
, aka heap objects). Array metadata indirections contain an implicit offset addition before the dereference - if array metadata nodes were more "general-purpose" (applicable to random pointers), the code would needs to be made aware of it. However, TYP_REF
is either null or a valid object, so this is not necessary.
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. Diffs look a bit mixed, any idea why? Do we end up kicking out useful assertions?
Also seems somewhat costly TP wise.
Thanks, yeah it sounds like the PR itself doesn't do anything unusual. Some of the diffs are regressions because we enabled more conditions to be folded in optOptimizeBool/ifConvert (and branchless version often bigger). but some look weird, e.g.: int _i;
internal void Test(long[] items)
{
items[_i] = 0;
items[_i] = 0;
} this regressed to perform two bound checks while previosly it was just one. I am investigating these now.. Also, noticed a problem in optOptimizeBool - it didn't update flags so it could end up with a "Missing flag" assert:
fixed by |
So for void Test(int i, long[] items)
{
items[i] = 0;
items[i] = 0;
} with this PR we regress by emitting two bound checks instead of one, it seems to be happening because the 2nd bound check now has a differen VN (same VN as the first one but without NullExc set), JITDUMP diff: https://www.diffchecker.com/CJGsabh8/ Quoting @jakobbotsch:
So as the actual change seems to be harmless and useful, it unintentionally hits problems we want to fix first before landing it, will re-open it if we fix them. |
Closes #84248
We were not taking advantage of assert propagation for GT_ARR_LENGTH (and MD_LENGHT).