forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Avoid scanning isinst checks when building whole program view (dotnet…
…#104148) Before this PR, we were somewhat able to eliminate dead typeof checks such as: ```csharp if (someType is Foo f) { ExpensiveMethod(); } ``` This work was done in dotnet#99761. However, the optimization only happened during codegen. This meant that when building the whole program view, we'd still look at `ExpensiveMethod` and whatever damage this caused to the whole program view was permanent. With this PR, the scanner now becomes aware of the optimization we do during codegen and tries to defer injecting dependencies until we will need them. Despite RyuJIT already doing this optimization, I'm also doing it in the SubstitutedILProvider because this optimization _must_ happen, or we'll get codegen failures. With this change, we detect the conditional branch, and generate whatever dependencies from the basic block as conditional. That way scanning can fully skip scanning `ExpensiveMethod` and the subsequent optimization will ensure the missed scanning will not cause issues at codegen time.
- Loading branch information
1 parent
018fb9d
commit 483db3e
Showing
5 changed files
with
227 additions
and
4 deletions.
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
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
129 changes: 129 additions & 0 deletions
129
src/coreclr/tools/aot/ILCompiler.Compiler/IL/IsInstCheckPatternAnalyzer.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,129 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Diagnostics; | ||
|
||
using Internal.IL; | ||
using Internal.TypeSystem; | ||
|
||
namespace ILCompiler | ||
{ | ||
/// <summary> | ||
/// Simple state machine to analyze IL sequences that represent isinst checks. | ||
/// </summary> | ||
internal struct IsInstCheckPatternAnalyzer | ||
{ | ||
// Captures following sequence: | ||
// | ||
// isinst Foo | ||
// Optional: | ||
// stloc Y | ||
// ldloc Y | ||
// Optional: | ||
// ldnull | ||
// cgt.un | ||
// Optional: | ||
// stloc X | ||
// ldloc X | ||
// brfalse | ||
private enum State : byte | ||
{ | ||
IsInst = 1, | ||
|
||
IsInstStLoc, | ||
|
||
IsInstLdnull, | ||
IsInstLdnullCgt, | ||
IsInstLdnullCgtStLoc, | ||
IsInstLdnullCgtStLocLdLoc, | ||
|
||
Branch, | ||
} | ||
|
||
private State _state; | ||
private int _token; | ||
|
||
public readonly bool IsIsInstBranch => _state is State.Branch; | ||
public int Token => _token; | ||
|
||
public void Advance(ILOpcode opcode, in ILReader reader, MethodIL methodIL) | ||
{ | ||
switch (_state) | ||
{ | ||
case 0: | ||
if (opcode == ILOpcode.isinst) | ||
(_state, _token) = (State.IsInst, reader.PeekILToken()); | ||
return; | ||
case State.IsInst: | ||
if (opcode is ILOpcode.brfalse or ILOpcode.brfalse_s) | ||
_state = State.Branch; | ||
else if (opcode == ILOpcode.ldnull) | ||
_state = State.IsInstLdnull; | ||
else if (IsStlocLdlocSequence(opcode, reader)) | ||
_state = State.IsInstStLoc; | ||
else | ||
break; | ||
return; | ||
case State.IsInstLdnull: | ||
if (opcode == ILOpcode.cgt_un) | ||
_state = State.IsInstLdnullCgt; | ||
else | ||
break; | ||
return; | ||
case State.IsInstLdnullCgt: | ||
if (IsStlocLdlocSequence(opcode, reader)) | ||
_state = State.IsInstLdnullCgtStLoc; | ||
else | ||
break; | ||
return; | ||
case State.IsInstLdnullCgtStLoc: | ||
if (opcode == ILOpcode.ldloc || opcode == ILOpcode.ldloc_s || (opcode >= ILOpcode.ldloc_0 && opcode <= ILOpcode.ldloc_3)) | ||
_state = State.IsInstLdnullCgtStLocLdLoc; | ||
else | ||
throw new UnreachableException(); | ||
return; | ||
case State.IsInstLdnullCgtStLocLdLoc: | ||
if (opcode is ILOpcode.brfalse or ILOpcode.brfalse_s) | ||
_state = State.Branch; | ||
else | ||
break; | ||
return; | ||
case State.IsInstStLoc: | ||
if (opcode == ILOpcode.ldloc || opcode == ILOpcode.ldloc_s || (opcode >= ILOpcode.ldloc_0 && opcode <= ILOpcode.ldloc_3)) | ||
_state = State.IsInst; | ||
else | ||
throw new UnreachableException(); | ||
return; | ||
default: | ||
throw new UnreachableException(); | ||
} | ||
|
||
_state = default; | ||
|
||
static bool IsStlocLdlocSequence(ILOpcode opcode, in ILReader reader) | ||
{ | ||
if (opcode == ILOpcode.stloc || opcode == ILOpcode.stloc_s || (opcode >= ILOpcode.stloc_0 && opcode <= ILOpcode.stloc_3)) | ||
{ | ||
ILReader nestedReader = reader; | ||
int locIndex = opcode switch | ||
{ | ||
ILOpcode.stloc => nestedReader.ReadILUInt16(), | ||
ILOpcode.stloc_s => nestedReader.ReadILByte(), | ||
_ => opcode - ILOpcode.stloc_0, | ||
}; | ||
ILOpcode otherOpcode = nestedReader.ReadILOpcode(); | ||
return (otherOpcode == ILOpcode.ldloc || otherOpcode == ILOpcode.ldloc_s || (otherOpcode >= ILOpcode.ldloc_0 && otherOpcode <= ILOpcode.ldloc_3)) | ||
&& otherOpcode switch | ||
{ | ||
ILOpcode.ldloc => nestedReader.ReadILUInt16(), | ||
ILOpcode.ldloc_s => nestedReader.ReadILByte(), | ||
_ => otherOpcode - ILOpcode.ldloc_0, | ||
} == locIndex; | ||
} | ||
return false; | ||
} | ||
|
||
Advance(opcode, reader, methodIL); | ||
} | ||
} | ||
} |
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
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