-
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
Removed range checks have ordered side effects (#78554) #78561
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Runtime.CompilerServices; | ||
|
||
public class Runtime_78554 | ||
{ | ||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
static void Consume(uint op) | ||
{ | ||
return; | ||
} | ||
|
||
[MethodImplAttribute(MethodImplOptions.NoInlining)] | ||
static void ArrayIndexConsume(uint[] a, uint i) | ||
{ | ||
if (i < a.Length) | ||
{ | ||
i = a[i]; | ||
} | ||
Consume(i); | ||
} | ||
|
||
public static int Main() | ||
{ | ||
var arr = new uint[] { 1, 42, 3000 }; | ||
ArrayIndexConsume(arr, 0xffffffff); | ||
return 100; | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<Optimize>True</Optimize> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Compile Include="$(MSBuildProjectName).cs" /> | ||
|
||
<CLRTestEnvironmentVariable Include="DOTNET_TieredCompilation" Value="0" /> | ||
<CLRTestEnvironmentVariable Include="DOTNET_JITMinOpts" Value="0" /> | ||
<CLRTestEnvironmentVariable Include="DOTNET_JitStressModeNames" Value="STRESS_IF_CONVERSION_COST" /> | ||
</ItemGroup> | ||
</Project> |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 would've expected we would set this in the same place we set
GTF_IND_NONFAULTING
on the indirection and remove its exception flags. Where do we do that?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.
That would be in morph.cpp....
The
IND
is moved after theBOUNDS_CHECK_Rng
and then it removes theGTF_EXCEPT
flag:I'll move the change to here.
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 think it fits better where we set
GTF_IND_NONFAULTING
. There are manyGTF_IND_NONFAULTING
indirs that are safe to reorder (in particular handles).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.
The original place the IND gets marked as non faulting is when it gets created:
At that point it's still safe to move around. (I think).
The INDEX_ADDR node 15 gets turned into a COMMA with bounds check (without changing the IND)
Then finally the IND is moved after the bounds check and the exception flag is dropped:
It was this final step I was adding the order side effect.
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.
So, at creation of
BOUNDS_CHECK_Rng
? Or do you still think at the original creation of the IND (during the import stages)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.
You are right. I think it makes sense to do it at the point you were considering in morph.cpp. We'll probably need to check that this only hits the expected cases (the transformation seems a bit more general than just for bounds checks, but being conservative about it will hopefully be ok).
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.
It looks like the morph fix causes something else to break - so, yes, looks like it needs some additional checks.
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.
What issues did you hit doing this in morph? I assume the diff was
?
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 had a more in depth look at this and discussed it with @SingleAccretion.
Essentially the problem here is that morphing of
INDEX_ADDR
nodes turns a value dependency into a flow dependency by introducing a comma. Before that, we have:after that, we end up with
From an IR standpoint we are already in trouble by not having introduced
GTF_ORDER_SIDEEFF
here. The reason is that we do not model "access violation" as a side effect of indirections; only NullReferenceException is a modelled side effect. So now, or later, the JIT is free to notice thatARR_ADDR
is never null and consider the indirection to be side effect free (which is what happens).While there is sort of an explicit dependency between
[000030]
and[000016]
in HIR, it is not the case in LIR, and even if we didn't do theIND(COMMA(x, ..., z)) -> COMMA(x, ..., IND(z))
transformation here the backend would not be able to check interference properly after we have done this transformation.So that suggests to me that we should be setting
GTF_ORDER_SIDEEFF
on the bounds check here (in other words,op1
of the comma, since we turned the value dependency into a flow dependency by introducing it).I think this will fix the issue in practice, but that's primarily because the
GTF_ORDER_SIDEEFF
flag will be propagated upwards to theIND
node. It might not fix the problem if the IR shape was not very particular here, but I think this is sufficient for our purposes for now.For an ideal long term fix I think we have several other places that ought to introduce
GTF_ORDER_SIDEEFF
on bounds checks (by which I mean eitherBOUNDS_CHECK_Rng
nodes or user-written bounds checks) when acting on them, particularly some in loop cloning and assertion prop. The assertion prop one is difficult as we do not store the original node in assertions; conservatively we could mark any bounds check that generated an assertion with this flag, but even that would require some additional work we do not expect to introduce flags at this point.I think, in addition, if-conversion needs to also check that the condition does not have
GTF_ORDER_SIDEEFF
.Do you want to submit these changes or do you want me to handle it? I expect that there might be some work involved in checking and dealing with regressions.
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 ended up with this in morph.cpp:
Checking
GTF_EXCEPT
was set onop1
was essential.That mostly worked, except for about 6 failures in spmi replay.
src/coreclr/jit/fgdiagnostic.cpp (3202) - Assertion failed '!"Missing flags on tree"' in 'ILGEN_0xedada940:Method_0x7f75():int' during 'Morph - Global' (IL size 142; hash 0x631c06ca; FullOpts)
In the above graph, 000100 is missing the
GTF_ORDER_SIDEEFF
. And I suspect 000101 and 000045 is too. I think we have the originalASG
node at being passed into the morph function, so should be fairly easy to propagate.Looking at your analysis:
I think I had assumed that was ok, because the bounds check and arr addr were connected by the comma. But what your saying makes sense.
I'm mostly away from my computer this week until Thursday. So, if you've got a solution, then I'm happy for you to go ahead with it. And thanks for looking into this.