-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Intrinsics analyzer and fixes #85481
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
Intrinsics analyzer and fixes #85481
Conversation
This analyzer detects the use of all platform intrinsics and checks to
ensure that they are all used either protected by an if statement OR
ternary operator which checks an appropriate IsSupported flag, or that
the intrinsic is used within a method where the behavior of platform
support for the intrinsic is not allowed to vary between compile time
and runtime.
The supported conditional checks are
1. Simple if statement checking IsSupported flag surrounding usage
```
if (PlatformIntrinsicType.IsSupported)
{
PlatformIntrinsicType.IntrinsicMethod();
}
```
2. If statement check checking a platform intrinsic type which implies
that the intrinsic used is supported.
```
if (Avx2.X64.IsSupported)
{
Avx2.IntrinsicMethod();
}
```
3. Nested if statement where there is an outer condition which is an
OR'd together series of IsSupported checks for mutually exclusive
conditions and where the inner check is an else clause where some checks
are excluded from applying.
```
if (Avx2.IsSupported || ArmBase.IsSupported)
{
if (Avx2.IsSupported)
{
// Do something
}
else
{
ArmBase.IntrinsicMethod();
}
}
```
In addtion, this change adds a new attribute, currently named
System.Runtime.BypassReadyToRunForIntrinsicsHelperUse which can be used
to identify methods which are called expecting to use some particular
set of platform intrinsics. These functions do not need to have explicit
checks, and while this is not yet implemented in the change, the
attribute will change the behavior of crossgen2 so that code will only
be generated if the platform intrinsic support is well known to be
either enabled or disabled at runtime. In addition, the method will only
be compiled or be inlineable if the platform intrinsic support is
enabled that matches at least one of the attributes applied to that
method.
… intrinsics usages
…pect the new attribute
jkoritzinsky
left a comment
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.
Can we add unit tests for this just to make it easier to iterate on in the future? Since it's in the libraries test tree, it should be pretty easy to add them.
src/libraries/System.Private.CoreLib/gen/IntrinsicsInSystemPrivateCoreLibAnalyzer.cs
Show resolved
Hide resolved
| // You can change these strings in the Resources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat. | ||
| // See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/Localizing%20Analyzers.md for more on localization |
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 can change these strings in the Resources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat. | |
| // See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/Localizing%20Analyzers.md for more on localization |
src/libraries/System.Private.CoreLib/gen/IntrinsicsInSystemPrivateCoreLibAnalyzer.cs
Show resolved
Hide resolved
|
|
||
| ACCEPTABLE Code | ||
| ```csharp | ||
| using System.Runtime.Intrinsics.X86; |
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 found this example helpful; could we keep it in the crossgen2 section?
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 issue is that the example is no longer correct. With the new attribute, the "Unacceptable" code is now legal to use, and the analyzer will ensure that you put the attribute on it.
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 unacceptable code is still illegal without an attribute if I understand correctly - I found it helpful in understanding the problem that the attribute solves.
| InstructionSetInfo vlInstructionSet = null; | ||
| foreach (var potentialVLinstructionSet in _instructionSets) | ||
| { | ||
| if (instructionSet.Architecture != architecture) continue; |
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.
| if (instructionSet.Architecture != architecture) continue; | |
| if (potentialVLinstructionSet.Architecture != architecture) continue; |
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.
This check still looks redundant with the check above.
src/coreclr/tools/Common/JitInterface/ThunkGenerator/InstructionSetGenerator.cs
Show resolved
Hide resolved
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilationModuleGroupBase.cs
Outdated
Show resolved
Hide resolved
| try | ||
| { | ||
| if (!CorInfoImpl.ShouldSkipCompilation(method)) | ||
| if (!CorInfoImpl.ShouldSkipCompilation(null, method)) |
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.
Why don't we pass the InstructionSetSupport everywhere this is called?
...ibraries/System.Private.CoreLib/src/System/Runtime/BypassReadyToRunForIntrinsicsHelperUse.cs
Outdated
Show resolved
Hide resolved
| [System.Runtime.BypassReadyToRunForIntrinsicsHelperUse(typeof(Sse))] | ||
| [System.Runtime.BypassReadyToRunForIntrinsicsHelperUse(typeof(AdvSimd))] | ||
| [System.Runtime.BypassReadyToRunForIntrinsicsHelperUse(typeof(PackedSimd))] |
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.
Nit:
| [System.Runtime.BypassReadyToRunForIntrinsicsHelperUse(typeof(Sse))] | |
| [System.Runtime.BypassReadyToRunForIntrinsicsHelperUse(typeof(AdvSimd))] | |
| [System.Runtime.BypassReadyToRunForIntrinsicsHelperUse(typeof(PackedSimd))] | |
| [BypassReadyToRunForIntrinsicsHelperUse(typeof(Sse))] | |
| [BypassReadyToRunForIntrinsicsHelperUse(typeof(AdvSimd))] | |
| [BypassReadyToRunForIntrinsicsHelperUse(typeof(PackedSimd))] |
Should it be Sse2 instead of Sse 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.
Yes. This is actually showing one of the limitations of the analyzer, which is that if you follow the pattern of having a helper which uses multiple variants which are explicitly checked, it isn't good at requiring the exact right attribute.
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 should be able to make the analyzer detect this situation and issue a slightly different diagnostic, which could be suppressed with a pragma warning disable for legit cases.
- These use a peculiar construct but its legal as its all containing in 1 method. If it got more complex than that, the analysis would be quite a bit harder
- Handle intrinsics calls from nested intrinsics types - Handle IsSupported checks in the presence of an attribute which explicitly allows an IsSupported check as well as one which doesn't, but is related - Add suppressions for Avx2 IsSupported checks in IndexOfAnyAsciiSearcher helper functions
…don't pass a null InstructionSetSupport into the ShouldSkipCompilation logic, just feed it around everywhere.
|
@MihaZupan @sbomer @jkoritzinsky all of you had good feedback. I believe I've addressed it all, and things are working again. Could you please take another look at this? |
sbomer
left a comment
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.
A couple more nits, otherwise LGTM. Thanks!
src/libraries/System.Private.CoreLib/gen/IntrinsicsInSystemPrivateCoreLibAnalyzer.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/gen/IntrinsicsInSystemPrivateCoreLibAnalyzer.cs
Outdated
Show resolved
Hide resolved
…of them. Also we needed some new pragma warning disables to make the new logic work
MihaZupan
left a comment
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.
Just questions around where the annotations are needed
src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs
Show resolved
Hide resolved
| [CompExactlyDependsOn(typeof(Sse2))] | ||
| [CompExactlyDependsOn(typeof(AdvSimd))] | ||
| [CompExactlyDependsOn(typeof(PackedSimd))] |
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.
Are these needed here given that the method doesn't directly use any of them?
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. Direct use is not particular important. Its transitive use which is most important. Effectively, we need to a be aware of all possible inlining behaviors.
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.
Effectively, we need to a be aware of all possible inlining behaviors.
Thanks, this part wasn't obvious to me (and pretty much answers all the other questions as well).
src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticMap.cs
Show resolved
Hide resolved
| Vector128<byte> packedValue0 = Vector128.Create((byte)value0); | ||
| Vector128<byte> packedValue1 = Vector128.Create((byte)value1); | ||
|
|
||
| #pragma warning disable IntrinsicsInSystemPrivateCoreLibConditionParsing // A negated IsSupported condition isn't parseable by the intrinsics analyzer, but in this case, it is only used in combination |
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.
Nit: can this comment be moved before the pragmas, it's hard to read the way it's indented currently.
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.
Feel free to refactor after I check in. This comment style has made it much easier to get the correct pragmas into place as I look at lots of code, but that need will evaporate once everything is in.
src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf16Utility.Validation.cs
Show resolved
Hide resolved
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilerContext.cs
Outdated
Show resolved
Hide resolved
src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
Outdated
Show resolved
Hide resolved
| SolutionTransforms.Add((solution, projectId) => | ||
| { | ||
| var compilationOptions = solution.GetProject(projectId).CompilationOptions; | ||
| solution = solution.WithProjectCompilationOptions(projectId, compilationOptions); | ||
|
|
||
| return solution; | ||
| }); |
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.
Does this solution transform do anything? It looks like a no-op.
In any case, there's a CreateCompilationOptions method that you can override to customize the compilation options instead of using a solution transform.
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.
Honestly, I have no idea. It came from the default make an analyzer template in VS, and doesn't seem to hurt anything.
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.
Weird. I'm surprised that this is in the template. It's not important one way or the other.
...IntrinsicsInSystemPrivatecoreLibAnalyzer.Tests/IntrinsicsInSystemPrivateCoreLib.Tests.csproj
Outdated
Show resolved
Hide resolved
| return null; | ||
| } | ||
|
|
||
| private static INamedTypeSymbol[] GatherAndConditions(SemanticModel model, ExpressionSyntax expressionToDecompose) |
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.
This would be better done operating on IOperation instances than syntax, but that can be a later refactoring (as this does work).
src/libraries/System.Private.CoreLib/gen/IntrinsicsInSystemPrivateCoreLibAnalyzer.cs
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/gen/IntrinsicsInSystemPrivateCoreLibAnalyzer.cs
Outdated
Show resolved
Hide resolved
…foImpl.ReadyToRun.cs Co-authored-by: Jeremy Koritzinsky <[email protected]>
…rivatecoreLibAnalyzer.Tests/IntrinsicsInSystemPrivateCoreLib.Tests.csproj Co-authored-by: Jeremy Koritzinsky <[email protected]>
…vateCoreLibAnalyzer.cs Co-authored-by: Jeremy Koritzinsky <[email protected]>
As a follow up to #85275, implement an analyzer and an attribute the Crossgen2 will respect which will make it difficult to encounter unexpected behavior at runtime due to quirks of how we compile System.Private.CoreLib.dll with Crossgen2.
See the change to vectors-and-intrinsics.md for details of what the new system will check.
NOTE: I believe that functionally this change is complete. I need to check crossgen2 performance, and the name of the new attribute is terrible. I'm looking for better names.