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

Switch from direct intrinsics usage to Vector/Vector64/Vector128/Vector256 #64451

Open
47 of 75 tasks
Tracked by #79005
stephentoub opened this issue Jan 28, 2022 · 9 comments
Open
47 of 75 tasks
Tracked by #79005
Labels
area-System.Runtime.Intrinsics help wanted [up-for-grabs] Good issue for external contributors
Milestone

Comments

@stephentoub
Copy link
Member

stephentoub commented Jan 28, 2022

We have a bunch of implementations in the core libraries that make direct use of intrinsics. .NET 7 includes cross-platform support via Vector/Vector64/Vector128/Vector256, and we prefer to use those whenever possible over using the intrinsics directly. This issue tracks converting all of our implementations over, or on a case-by-case basis deciding they can't or shouldn't be updated:

@stephentoub stephentoub added area-System.Runtime.Intrinsics help wanted [up-for-grabs] Good issue for external contributors labels Jan 28, 2022
@stephentoub stephentoub added this to the 7.0.0 milestone Jan 28, 2022
@ghost
Copy link

ghost commented Jan 28, 2022

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

Issue Details

We have a bunch of implementations in the core libraries that make direct use of intrinsics. .NET 7 includes cross-platform support via Vector/Vector64/Vector128/Vector256, and we prefer to use those whenever possible over using the intrinsics directly. This issue tracks converting all of our implementations over, or on a case-by-case basis deciding they can't or shouldn't be updated:

  • ASCIIUtility.ContainsNonAsciiByte(Vector12<byte>)
  • ASCIIUtility.GetIndexOfFirstNonAsciiByte(byte*, nuint)
  • ASCIIUtility.GetIndexOfFirstNonAsciiChar(char*, nuint)
  • ASCIIUtility.NarrowUtf16ToAscii(char*, byte*, nuint)
  • ASCIIUtility.WidenAsciiToUtf16(byte*, char*, nuint)
  • Base64.DecodeFromUtf8(ReadOnlySpan<byte>, Span<byte>, out int, out int, bool)
  • Base64.EncodeToUtf8(ReadOnlySpan<byte>, Span<byte>, out int, out int, bool)
  • BitArray(bool[])
  • BitArray.And(BitArray)
  • BitArray.CopyTo(Array, int)
  • BitArray.Not(BitArray)
  • BitArray.Or(BitArray)
  • BitArray.Xor(BitArray)
  • BitConverter.DoubleToInt64Bits(double)
  • BitConverter.Int32BitsToSingle(int)
  • BitConverter.Int64BitsToDouble(long)
  • BitConverter.SingleToInt32Bits(float)
  • BitOperations.LeadingZeroCount(uint)
  • BitOperations.LeadingZeroCount(ulong)
  • BitOperations.Log2(uint)
  • BitOperations.Log2(ulong)
  • BitOperations.PopCount(uint)
  • BitOperations.PopCount(ulong)
  • BitOperations.RoundUpToPowerOf2(uint)
  • BitOperations.RoundUpToPowerOf2(ulong)
  • BitOperations.TrailingZeroCount(ulong)
  • Decimal.VarDecFromR4(float, out DecCalc)
  • Decimal.VarDecFromR8(double, out DecCalc)
  • HexConverter.EncodeToUtf16(ReadOnlySpan<byte>, Span<char>, Casing)
  • Latin1Utility.GetIndexOfFirstNonLatin1Char(char*, nuint)
  • Latin1Utility.NarrowUtf16ToLatin1(char*, byte*, nuint)
  • Latin1Utility.WidenLatin1ToUtf16(byte*, char*, nuint)
  • Math.BigMul(ulong, ulong, out ulong)
  • Math.CopySign(double, double)
  • Math.ReciprocalEstimate(double)
  • Math.ReciprocalSqrtEstimate(double)
  • MathF.CopySign(float, float)
  • MathF.ReciprocalEstimate(float)
  • MathF.ReciprocalSqrtEstimate(float)
  • Matrix4x4.Invert(Matrix4x4, out Matrix4x4)
  • Matrix4x4.Lerp(Matrix4x4, Matrix4x4, float)
  • Matrix4x4.operator !=(Matrix4x4, Matrix4x4)
  • Matrix4x4.operator -(Matrix4x4)
  • Matrix4x4.operator -(Matrix4x4, Matrix4x4)
  • Matrix4x4.operator *(Matrix4x4, float)
  • Matrix4x4.operator *(Matrix4x4, Matrix4x4)
  • Matrix4x4.operator +(Matrix4x4, Matrix4x4)
  • Matrix4x4.operator ==(Matrix4x4, Matrix4x4)
  • Matrix4x4.Permute(Vector128<float>, byte)
  • Matrix4x4.Transpose(Matrix4x4)
  • OptimizedInboxTextEncoder.GetIndexOfFirstByteToEncode(ReadOnlySpan<byte> data)
  • OptimizedInboxTextEncoder.GetIndexOfFirstCharToEncode(ReadOnlySpan<char> data)
  • SpanHelpers.IndexOf(ref byte, byte, int)
  • SpanHelpers.IndexOf(ref char, char, int)
  • SpanHelpers.IndexOf(ref char, int, ref char, int)
  • SpanHelpers.IndexOfAny(ref byte, byte, byte, byte, int)
  • SpanHelpers.IndexOfAny(ref byte, byte, byte, int)
  • SpanHelpers.IndexOfAny(ref char, char, char, char, char, char, int)
  • SpanHelpers.IndexOfAny(ref char, char, char, char, char, int)
  • SpanHelpers.IndexOfAny(ref char, char, char, char, int)
  • SpanHelpers.IndexOfAny(ref char, char, char, int)
  • SpanHelpers.SequenceCompareTo(ref byte, int, ref byte, int)
  • SpanHelpers.SequenceEquals(ref byte, byte, nuint)
  • String.MakeSeparatorList(ReadOnlySpan<char>, ref ValueListBuilder<int>)
  • Utf8Utility.GetPointerToFirstInvalidByte(byte*, int, out int, out int)
  • Utf8Utility.TranscodeToUtf8(char*, int, byte*, int, out char*, out byte*)
  • VectorMath.ConditionalSelectBitwise(Vector128<double>, Vector128<double>, Vector128<double>)
  • VectorMath.ConditionalSelectBitwise(Vector128<float>, Vector128<float>, Vector128<float>)
  • VectorMath.Equal(Vector128<float>, Vector128<float>)
  • VectorMath.Lerp(Vector128<float>, Vector128<float>, Vector128<float>)
  • VectorMath.NotEqual(Vector128<float>, Vector128<float>)
Author: stephentoub
Assignees: -
Labels:

area-System.Runtime.Intrinsics, up-for-grabs

Milestone: 7.0.0

@dotnet-issue-labeler dotnet-issue-labeler bot added the untriaged New issue has not been triaged by the area owner label Jan 28, 2022
@teo-tsirpanis
Copy link
Contributor

The BitOperations methods use non-SIMD intrinsics (except for PopCount on ARM64 which uses Vector64). I don't see how they can be converted.

@stephentoub
Copy link
Member Author

stephentoub commented Jan 28, 2022

I listed everything directly accessing intrinsics. As noted, not everything here may need changes ("or on a case-by-case basis deciding they can't or shouldn't be updated").

@teo-tsirpanis
Copy link
Contributor

I know, just told it to strike them as false positives.

@jeffschwMSFT jeffschwMSFT removed the untriaged New issue has not been triaged by the area owner label Jan 28, 2022
@tannergooding
Copy link
Member

Thanks for logging this @stephentoub! I've checked off a few entries above.

Most notably, I've checked off the following as they represent the public xplat API (and as @teo-tsirpanis indicated are generally the scalar version, not the SIMD):

  • BitConverter.DoubleToInt64Bits(double)
  • BitConverter.Int32BitsToSingle(int)
  • BitConverter.Int64BitsToDouble(long)
  • BitConverter.SingleToInt32Bits(float)
  • BitOperations.LeadingZeroCount(uint)
  • BitOperations.LeadingZeroCount(ulong)
  • BitOperations.Log2(uint)
  • BitOperations.Log2(ulong)
  • BitOperations.PopCount(uint)
  • BitOperations.PopCount(ulong)
  • BitOperations.RoundUpToPowerOf2(uint)
  • BitOperations.RoundUpToPowerOf2(ulong)
  • BitOperations.TrailingZeroCount(ulong)
  • Math.BigMul(ulong, ulong, out ulong)
  • Math.CopySign(double, double)
  • Math.ReciprocalEstimate(double)
  • Math.ReciprocalSqrtEstimate(double)
  • MathF.CopySign(float, float)
  • MathF.ReciprocalEstimate(float)
  • MathF.ReciprocalSqrtEstimate(float)
  • VectorMath.ConditionalSelectBitwise(Vector128, Vector128, Vector128)
  • VectorMath.ConditionalSelectBitwise(Vector128, Vector128, Vector128)
  • VectorMath.Equal(Vector128, Vector128)
  • VectorMath.Lerp(Vector128, Vector128, Vector128)
  • VectorMath.NotEqual(Vector128, Vector128)

Since these are the "public xplat API" for those, we could potentially recognize them as JIT helper intrinsics to ensure "optimal codegen" and not have to rely on inlining, etc; but that's probably something worth looking at independently.

@SwapnilGaikwad
Copy link
Contributor

Are you looking at SpanHelpers.T.IndexOf(ref T, T, int) ?

@deeprobin
Copy link
Contributor

@stephentoub String.MakeSeparatorList(ReadOnlySpan<char>, ref ValueListBuilder<int>) is already using vectors? Is there anything missing or did you forget to check it off?

@stephentoub
Copy link
Member Author

String.MakeSeparatorList(ReadOnlySpan, ref ValueListBuilder) is already using vectors?

That was addressed by #64899.

@tannergooding tannergooding added this to the Future milestone Jul 24, 2023
@tannergooding
Copy link
Member

Still more work to be done here for .NET 9+, so moving to future.

@stephentoub stephentoub self-assigned this Jan 11, 2024
@stephentoub stephentoub removed their assignment Jan 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.Runtime.Intrinsics help wanted [up-for-grabs] Good issue for external contributors
Projects
None yet
Development

No branches or pull requests

7 participants