Skip to content
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

Annotate platform specific hardware intrinsics with the ConstExpected attribute #80192

Merged
merged 3 commits into from
Jan 6, 2023

Conversation

tannergooding
Copy link
Member

@tannergooding tannergooding commented Jan 4, 2023

The xplat intrinsics do not need this as they use alternative instruction sequences and handling where possible. They do not need to fallback to anything like a jump table.

@dotnet-issue-labeler
Copy link

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost ghost assigned tannergooding Jan 4, 2023
@ghost
Copy link

ghost commented Jan 4, 2023

Tagging subscribers to this area: @dotnet/area-system-runtime-intrinsics
See info in area-owners.md if you want to be subscribed.

Issue Details

null

Author: tannergooding
Assignees: -
Labels:

area-System.Runtime.Intrinsics, new-api-needs-documentation

Milestone: -

@@ -51,25 +51,25 @@ public abstract class AdvSimd : ArmBase
// /// float32x2_t vmla_lane_f32 (float32x2_t a, float32x2_t b, float32x2_t v, const int lane)
// /// A32: VMLA.F32 Dd, Dn, Dm[lane]
// /// </summary>
// public static Vector64<float> MultiplyAddBySelectedScalar(Vector64<float> addend, Vector64<float> left, Vector64<float> right, byte rightIndex) => MultiplyAddBySelectedScalar(addend, left, right, rightIndex);
// public static Vector64<float> MultiplyAddBySelectedScalar(Vector64<float> addend, Vector64<float> left, Vector64<float> right, [ConstantExpected(Max = (byte)(1))] byte rightIndex) => MultiplyAddBySelectedScalar(addend, left, right, rightIndex);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arm64 and WASM expect values to be exactly in range. As such, we strictly limit the input between 0 and Max or 1 and Max.

The exact semantics is dependent on the instruction and is table driven in the JIT: https://github.com/dotnet/runtime/blob/main/src/coreclr/jit/hwintrinsicarm64.cpp#L215-L271

@@ -398,61 +399,61 @@ public new abstract class X64 : Sse42.X64
/// __m128i _mm256_extractf128_si256 (__m256i a, const int imm8)
/// VEXTRACTF128 xmm/m128, ymm, imm8
/// </summary>
public static Vector128<byte> ExtractVector128(Vector256<byte> value, byte index) => ExtractVector128(value, index);
public static Vector128<byte> ExtractVector128(Vector256<byte> value, [ConstantExpected] byte index) => ExtractVector128(value, index);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

x86/x64 on the other hand typically allows any input and will mask off to only the bits needed.

There are a couple exceptions, but it is also table driven on the JIT side: https://github.com/dotnet/runtime/blob/main/src/coreclr/jit/hwintrinsicxarch.cpp#L196-L230


/// <summary>
/// __m128i _mm_i32gather_epi32 (int const* base_addr, __m128i vindex, const int scale)
/// VPGATHERDD xmm, vm32x, xmm
/// The scale parameter should be 1, 2, 4 or 8, otherwise, ArgumentOutOfRangeException will be thrown.
/// </summary>
public static unsafe Vector128<int> GatherVector128(int* baseAddress, Vector128<int> index, byte scale)
public static unsafe Vector128<int> GatherVector128(int* baseAddress, Vector128<int> index, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The one particularly interesting case for x86/x64 is GatherVector and GatherMaskVector. These take exactly 1, 2, 4, or 8 with other values being disallowed.

This is most closely modeled on the attribute by restricting to between 1 and 8 inclusive.

Copy link
Contributor

@dakersnar dakersnar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were these annotations all manually added? What were your source of truth for the expected constants in each annotation? How (if at all) are these tested?

@tannergooding
Copy link
Member Author

Were these annotations all manually added?

I wrote a small program that added them.

What were your source of truth for the expected constants in each annotation?

The existing JIT conditions, which were originally seeded from the Architecture Manuals

How (if at all) are these tested?

Manual validation in VS that the analyzer gets triggered

Copy link
Contributor

@dakersnar dakersnar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarifications, this LGTM at a high level.

@tannergooding tannergooding merged commit e0a6771 into dotnet:main Jan 6, 2023
@tannergooding tannergooding deleted the const-expected branch January 6, 2023 00:47
@radical
Copy link
Member

radical commented Jan 6, 2023

@tannergooding
Copy link
Member Author

The fix is easy, but I'm unsure why it didn't trigger these failures in the PR.

@tannergooding
Copy link
Member Author

Fix is here: #80282

@ghost ghost locked as resolved and limited conversation to collaborators Feb 5, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants