Repository navigation
Expose cross-platform helpers for Vector64, Vector128, and Vector256 #49397
Copy link
Copy link
Closed
Labels
Team:Librariesapi-approvedAPI was approved in API review, it can be implementedAPI was approved in API review, it can be implementedarea-System.Runtime.Intrinsics
Milestone
Description
Activity
- addedapi-suggestionEarly API idea and discussion, it is NOT ready for implementationEarly API idea and discussion, it is NOT ready for implementation
on Mar 9, 2021 - ghost addeduntriagedNew issue has not been triaged by the area ownerNew issue has not been triaged by the area owner
on Mar 9, 2021 Can we also have rsqrt, and approximate versions of sqrt/rsqrt?
Can we also have rsqrt, and approximate versions of sqrt/rsqrt?
Likely yes, but I think that qualifies under a separate API review since its new surface, rather than mirroring what's on Vector already.
Reacted by Cory NelsonCC. @pgovind @echesakovMSFT
Any concerns with me marking this "API Ready for Review"?
Nope, this looks good to me!
- addedapi-ready-for-reviewAPI is ready for review, it is NOT ready for implementationAPI is ready for review, it is NOT ready for implementationand removedapi-suggestionEarly API idea and discussion, it is NOT ready for implementationEarly API idea and discussion, it is NOT ready for implementationuntriagedNew issue has not been triaged by the area ownerNew issue has not been triaged by the area owner
on Mar 12, 2021 - Looks good as proposed, modulo typos.
- There are some names that are changed (SquareRoot => Sqrt) and some members moved from instance to extension, but both of these changes make sense with recent API in similar scopes.
namespace System.Runtime.Intrinsics { public static partial class Vector64 { public bool IsHardwareAccelerated { get; } public static Vector64<T> Abs(Vector64<T> value); public static Vector64<T> Negate(Vector64<T> value); public static Vector64<T> OnesComplement(Vector64<T> value); public static Vector64<T> Sqrt(Vector64<T> value); // SquareRoot public static Vector64<T> Add(Vector64<T> left, Vector64<T> right); public static Vector64<T> Subtract(Vector64<T> left, Vector64<T> right); public static Vector64<T> Multiply(Vector64<T> left, Vector64<T> right); public static Vector64<T> Divide(Vector64<T> left, Vector64<T> right); public static Vector64<T> Dot(Vector64<T> left, Vector64<T> right); public static Vector64<T> AndNot(Vector64<T> left, Vector64<T> right); public static Vector64<T> BitwiseAnd(Vector64<T> left, Vector64<T> right); public static Vector64<T> BitwiseOr(Vector64<T> left, Vector64<T> right); public static Vector64<T> Xor(Vector64<T> left, Vector64<T> right); public static Vector64<double> Ceiling(Vector64<double> value); public static Vector64<float> Ceiling(Vector64<float> value); public static Vector64<double> Floor(Vector64<double> value); public static Vector64<float> Floor(Vector64<float> value); public static Vector64<T> ConditionalSelect(Vector64<T> condition, Vector64<T> left, Vector64<T> right); public static Vector64<double> ConvertToDouble(Vector64<long> value); public static Vector64<double> ConvertToDouble(Vector64<ulong> value); public static Vector64<int> ConvertToInt32(Vector64<float> value); public static Vector64<long> ConvertToInt64(Vector64<double> value); public static Vector64<float> ConvertToSingle(Vector64<int> value); public static Vector64<float> ConvertToSingle(Vector64<uint> value); public static Vector64<uint> ConvertToUInt32(Vector64<float> value); public static Vector64<ulong> ConvertToUInt64(Vector64<double> value); public static Vector64<T> Equals(Vector64<T> left, Vector64<T> right); public static bool EqualsAll(Vector64<T> left, Vector64<T> right); public static bool EqualsAny(Vector64<T> left, Vector64<T> right); public static Vector64<T> GreaterThan(Vector64<T> left, Vector64<T> right); public static bool GreaterThanAll(Vector64<T> left, Vector64<T> right); public static bool GreaterThanAny(Vector64<T> left, Vector64<T> right); public static Vector64<T> GreaterThanOrEqual(Vector64<T> left, Vector64<T> right); public static bool GreaterThanOrEqualAll(Vector64<T> left, Vector64<T> right); public static bool GreaterThanOrEqualAny(Vector64<T> left, Vector64<T> right); public static Vector64<T> LessThan(Vector64<T> left, Vector64<T> right); public static bool LessThanAll(Vector64<T> left, Vector64<T> right); public static bool LessThanAny(Vector64<T> left, Vector64<T> right); public static Vector64<T> LessThanOrEqual(Vector64<T> left, Vector64<T> right); public static bool LessThanOrEqualAll(Vector64<T> left, Vector64<T> right); public static bool LessThanOrEqualAny(Vector64<T> left, Vector64<T> right); public static Vector64<T> Max(Vector64<T> left, Vector64<T> right); public static Vector64<T> Min(Vector64<T> left, Vector64<T> right); public static Vector64<float> Narrow(Vector64<double> lower, Vector64<T> upper); public static Vector64<sbyte> Narrow(Vector64<short> lower, Vector64<short> upper); public static Vector64<short> Narrow(Vector64<int> lower, Vector64<int> upper); public static Vector64<int> Narrow(Vector64<long> lower, Vector64<long> upper); public static Vector64<byte> Narrow(Vector64<ushort> lower, Vector64<ushort> upper); public static Vector64<ushort> Narrow(Vector64<uint> lower, Vector64<uint> upper); public static Vector64<uint> Narrow(Vector64<ulong> lower, Vector64<ulong> upper); public static (Vector64<short> Lower, Vector64<short> Upper) Widen(Vector64<sbyte> value); public static (Vector64<int> Lower, Vector64<int> Upper) Widen(Vector64<short> value); public static (Vector64<long> Lower, Vector64<long> Upper) Widen(Vector64<int> value); public static (Vector64<double> Lower, Vector64<double> Upper) Widen(Vector64<flaot> value); public static (Vector64<ushort> Lower, Vector64<ushort> Upper) Widen(Vector64<byte> value); public static (Vector64<uint> Lower, Vector64<uint> Upper) Widen(Vector64<ushort> value); public static (Vector64<ulong> Lower, Vector64<ulong> Upper) Widen(Vector64<uint> value); public static Vector64<T> Create<T>(ReadOnlySpan<byte> values); public static Vector64<T> Create<T>(ReadOnlySpan<T> values); public static Vector64<T> Create<T>(T[] values); public static Vector64<T> Create<T>(T[] values, int index); public static void CopyTo<T>(this Vector64<T> vector, Span<byte> destination); public static void CopyTo<T>(this Vector64<T> vector, Span<T> destination); public static void CopyTo<T>(this Vector64<T> vector, T[] destination); public static void CopyTo<T>(this Vector64<T> vector, T[] destination, int index); public static bool TryCopyTo(this Vector64<T> vector, Span<byte> destination); public static bool TryCopyTo(this Vector64<T> vector, Span<T> destination); } public partial struct Vector64<T> where T : struct { public static Vector64<T> operator +(Vector64<T> value); public static Vector64<T> operator -(Vector64<T> value); public static Vector64<T> operator ~(Vector64<T> value); public static bool operator ==(Vector64<T> left, Vector64<T> right); public static bool operator !=(Vector64<T> left, Vector64<T> right); public static Vector64<T> operator +(Vector64<T> left, Vector64<T> right); public static Vector64<T> operator -(Vector64<T> left, Vector64<T> right); public static Vector64<T> operator *(Vector64<T> left, Vector64<T> right); public static Vector64<T> operator /(Vector64<T> left, Vector64<T> right); public static Vector64<T> operator &(Vector64<T> left, Vector64<T> right); public static Vector64<T> operator |(Vector64<T> left, Vector64<T> right); public static Vector64<T> operator ^(Vector64<T> left, Vector64<T> right); } public static partial class Vector128 { public bool IsHardwareAccelerated { get; } public static Vector128<T> Abs(Vector128<T> value); public static Vector128<T> Negate(Vector128<T> value); public static Vector128<T> OnesComplement(Vector128<T> value); public static Vector128<T> Sqrt(Vector128<T> value); // SquareRoot public static Vector128<T> Add(Vector128<T> left, Vector128<T> right); public static Vector128<T> Subtract(Vector128<T> left, Vector128<T> right); public static Vector128<T> Multiply(Vector128<T> left, Vector128<T> right); public static Vector128<T> Divide(Vector128<T> left, Vector128<T> right); public static Vector128<T> Dot(Vector128<T> left, Vector128<T> right); public static Vector128<T> AndNot(Vector128<T> left, Vector128<T> right); public static Vector128<T> BitwiseAnd(Vector128<T> left, Vector128<T> right); public static Vector128<T> BitwiseOr(Vector128<T> left, Vector128<T> right); public static Vector128<T> Xor(Vector128<T> left, Vector128<T> right); public static Vector128<double> Ceiling(Vector128<double> value); public static Vector128<float> Ceiling(Vector128<float> value); public static Vector128<double> Floor(Vector128<double> value); public static Vector128<float> Floor(Vector128<float> value); public static Vector128<T> ConditionalSelect(Vector128<T> condition, Vector128<T> left, Vector128<T> right); public static Vector128<double> ConvertToDouble(Vector128<long> value); public static Vector128<double> ConvertToDouble(Vector128<ulong> value); public static Vector128<int> ConvertToInt32(Vector128<float> value); public static Vector128<long> ConvertToInt64(Vector128<double> value); public static Vector128<float> ConvertToSingle(Vector128<int> value); public static Vector128<float> ConvertToSingle(Vector128<uint> value); public static Vector128<uint> ConvertToUInt32(Vector128<float> value); public static Vector128<ulong> ConvertToUInt64(Vector128<double> value); public static Vector128<T> Equals(Vector128<T> left, Vector128<T> right); public static bool EqualsAll(Vector128<T> left, Vector128<T> right); public static bool EqualsAny(Vector128<T> left, Vector128<T> right); public static Vector128<T> GreaterThan(Vector128<T> left, Vector128<T> right); public static bool GreaterThanAll(Vector128<T> left, Vector128<T> right); public static bool GreaterThanAny(Vector128<T> left, Vector128<T> right); public static Vector128<T> GreaterThanOrEqual(Vector128<T> left, Vector128<T> right); public static bool GreaterThanOrEqualAll(Vector128<T> left, Vector128<T> right); public static bool GreaterThanOrEqualAny(Vector128<T> left, Vector128<T> right); public static Vector128<T> LessThan(Vector128<T> left, Vector128<T> right); public static bool LessThanAll(Vector128<T> left, Vector128<T> right); public static bool LessThanAny(Vector128<T> left, Vector128<T> right); public static Vector128<T> LessThanOrEqual(Vector128<T> left, Vector128<T> right); public static bool LessThanOrEqualAll(Vector128<T> left, Vector128<T> right); public static bool LessThanOrEqualAny(Vector128<T> left, Vector128<T> right); public static Vector128<T> Max(Vector128<T> left, Vector128<T> right); public static Vector128<T> Min(Vector128<T> left, Vector128<T> right); public static Vector128<float> Narrow(Vector128<double> lower, Vector128<T> upper); public static Vector128<sbyte> Narrow(Vector128<short> lower, Vector128<short> upper); public static Vector128<short> Narrow(Vector128<int> lower, Vector128<int> upper); public static Vector128<int> Narrow(Vector128<long> lower, Vector128<long> upper); public static Vector128<byte> Narrow(Vector128<ushort> lower, Vector128<ushort> upper); public static Vector128<ushort> Narrow(Vector128<uint> lower, Vector128<uint> upper); public static Vector128<uint> Narrow(Vector128<ulong> lower, Vector128<ulong> upper); public static (Vector128<short> Lower, Vector128<short> Upper) Widen(Vector128<sbyte> value); public static (Vector128<int> Lower, Vector128<int> Upper) Widen(Vector128<short> value); public static (Vector128<long> Lower, Vector128<long> Upper) Widen(Vector128<int> value); public static (Vector128<double> Lower, Vector128<double> Upper) Widen(Vector128<flaot> value); public static (Vector128<ushort> Lower, Vector128<ushort> Upper) Widen(Vector128<byte> value); public static (Vector128<uint> Lower, Vector128<uint> Upper) Widen(Vector128<ushort> value); public static (Vector128<ulong> Lower, Vector128<ulong> Upper) Widen(Vector128<uint> value); public static Vector128<T> Create<T>(ReadOnlySpan<byte> values); public static Vector128<T> Create<T>(ReadOnlySpan<T> values); public static Vector128<T> Create<T>(T[] values); public static Vector128<T> Create<T>(T[] values, int index); public static void CopyTo<T>(this Vector128<T> vector, Span<byte> destination); public static void CopyTo<T>(this Vector128<T> vector, Span<T> destination); public static void CopyTo<T>(this Vector128<T> vector, T[] destination); public static void CopyTo<T>(this Vector128<T> vector, T[] destination, int index); public static bool TryCopyTo(this Vector128<T> vector, Span<byte> destination); public static bool TryCopyTo(this Vector128<T> vector, Span<T> destination); } public partial struct Vector128<T> where T : struct { public static Vector128<T> operator +(Vector128<T> value); public static Vector128<T> operator -(Vector128<T> value); public static Vector128<T> operator ~(Vector128<T> value); public static bool operator ==(Vector128<T> left, Vector128<T> right); public static bool operator !=(Vector128<T> left, Vector128<T> right); public static Vector128<T> operator +(Vector128<T> left, Vector128<T> right); public static Vector128<T> operator -(Vector128<T> left, Vector128<T> right); public static Vector128<T> operator *(Vector128<T> left, Vector128<T> right); public static Vector128<T> operator /(Vector128<T> left, Vector128<T> right); public static Vector128<T> operator &(Vector128<T> left, Vector128<T> right); public static Vector128<T> operator |(Vector128<T> left, Vector128<T> right); public static Vector128<T> operator ^(Vector128<T> left, Vector128<T> right); } public static partial class Vector256 { public bool IsHardwareAccelerated { get; } public static Vector256<T> Abs(Vector256<T> value); public static Vector256<T> Negate(Vector256<T> value); public static Vector256<T> OnesComplement(Vector256<T> value); public static Vector256<T> Sqrt(Vector256<T> value); // SquareRoot public static Vector256<T> Add(Vector256<T> left, Vector256<T> right); public static Vector256<T> Subtract(Vector256<T> left, Vector256<T> right); public static Vector256<T> Multiply(Vector256<T> left, Vector256<T> right); public static Vector256<T> Divide(Vector256<T> left, Vector256<T> right); public static Vector256<T> Dot(Vector256<T> left, Vector256<T> right); public static Vector256<T> AndNot(Vector256<T> left, Vector256<T> right); public static Vector256<T> BitwiseAnd(Vector256<T> left, Vector256<T> right); public static Vector256<T> BitwiseOr(Vector256<T> left, Vector256<T> right); public static Vector256<T> Xor(Vector256<T> left, Vector256<T> right); public static Vector256<double> Ceiling(Vector256<double> value); public static Vector256<float> Ceiling(Vector256<float> value); public static Vector256<double> Floor(Vector256<double> value); public static Vector256<float> Floor(Vector256<float> value); public static Vector256<T> ConditionalSelect(Vector256<T> condition, Vector256<T> left, Vector256<T> right); public static Vector256<double> ConvertToDouble(Vector256<long> value); public static Vector256<double> ConvertToDouble(Vector256<ulong> value); public static Vector256<int> ConvertToInt32(Vector256<float> value); public static Vector256<long> ConvertToInt64(Vector256<double> value); public static Vector256<float> ConvertToSingle(Vector256<int> value); public static Vector256<float> ConvertToSingle(Vector256<uint> value); public static Vector256<uint> ConvertToUInt32(Vector256<float> value); public static Vector256<ulong> ConvertToUInt64(Vector256<double> value); public static Vector256<T> Equals(Vector256<T> left, Vector256<T> right); public static bool EqualsAll(Vector256<T> left, Vector256<T> right); public static bool EqualsAny(Vector256<T> left, Vector256<T> right); public static Vector256<T> GreaterThan(Vector256<T> left, Vector256<T> right); public static bool GreaterThanAll(Vector256<T> left, Vector256<T> right); public static bool GreaterThanAny(Vector256<T> left, Vector256<T> right); public static Vector256<T> GreaterThanOrEqual(Vector256<T> left, Vector256<T> right); public static bool GreaterThanOrEqualAll(Vector256<T> left, Vector256<T> right); public static bool GreaterThanOrEqualAny(Vector256<T> left, Vector256<T> right); public static Vector256<T> LessThan(Vector256<T> left, Vector256<T> right); public static bool LessThanAll(Vector256<T> left, Vector256<T> right); public static bool LessThanAny(Vector256<T> left, Vector256<T> right); public static Vector256<T> LessThanOrEqual(Vector256<T> left, Vector256<T> right); public static bool LessThanOrEqualAll(Vector256<T> left, Vector256<T> right); public static bool LessThanOrEqualAny(Vector256<T> left, Vector256<T> right); public static Vector256<T> Max(Vector256<T> left, Vector256<T> right); public static Vector256<T> Min(Vector256<T> left, Vector256<T> right); public static Vector256<float> Narrow(Vector256<double> lower, Vector256<T> upper); public static Vector256<sbyte> Narrow(Vector256<short> lower, Vector256<short> upper); public static Vector256<short> Narrow(Vector256<int> lower, Vector256<int> upper); public static Vector256<int> Narrow(Vector256<long> lower, Vector256<long> upper); public static Vector256<byte> Narrow(Vector256<ushort> lower, Vector256<ushort> upper); public static Vector256<ushort> Narrow(Vector256<uint> lower, Vector256<uint> upper); public static Vector256<uint> Narrow(Vector256<ulong> lower, Vector256<ulong> upper); public static (Vector256<short> Lower, Vector256<short> Upper) Widen(Vector256<sbyte> value); public static (Vector256<int> Lower, Vector256<int> Upper) Widen(Vector256<short> value); public static (Vector256<long> Lower, Vector256<long> Upper) Widen(Vector256<int> value); public static (Vector256<double> Lower, Vector256<double> Upper) Widen(Vector256<flaot> value); public static (Vector256<ushort> Lower, Vector256<ushort> Upper) Widen(Vector256<byte> value); public static (Vector256<uint> Lower, Vector256<uint> Upper) Widen(Vector256<ushort> value); public static (Vector256<ulong> Lower, Vector256<ulong> Upper) Widen(Vector256<uint> value); public static Vector256<T> Create<T>(ReadOnlySpan<byte> values); public static Vector256<T> Create<T>(ReadOnlySpan<T> values); public static Vector256<T> Create<T>(T[] values); public static Vector256<T> Create<T>(T[] values, int index); public static void CopyTo<T>(this Vector256<T> vector, Span<byte> destination); public static void CopyTo<T>(this Vector256<T> vector, Span<T> destination); public static void CopyTo<T>(this Vector256<T> vector, T[] destination); public static void CopyTo<T>(this Vector256<T> vector, T[] destination, int index); public static bool TryCopyTo(this Vector256<T> vector, Span<byte> destination); public static bool TryCopyTo(this Vector256<T> vector, Span<T> destination); } public partial struct Vector256<T> where T : struct { public static Vector256<T> operator +(Vector256<T> value); public static Vector256<T> operator -(Vector256<T> value); public static Vector256<T> operator ~(Vector256<T> value); public static bool operator ==(Vector256<T> left, Vector256<T> right); public static bool operator !=(Vector256<T> left, Vector256<T> right); public static Vector256<T> operator +(Vector256<T> left, Vector256<T> right); public static Vector256<T> operator -(Vector256<T> left, Vector256<T> right); public static Vector256<T> operator *(Vector256<T> left, Vector256<T> right); public static Vector256<T> operator /(Vector256<T> left, Vector256<T> right); public static Vector256<T> operator &(Vector256<T> left, Vector256<T> right); public static Vector256<T> operator |(Vector256<T> left, Vector256<T> right); public static Vector256<T> operator ^(Vector256<T> left, Vector256<T> right); } }
- addedapi-approvedAPI was approved in API review, it can be implementedAPI was approved in API review, it can be implementedand removedapi-ready-for-reviewAPI is ready for review, it is NOT ready for implementationAPI is ready for review, it is NOT ready for implementation
on May 21, 2021 - ghost addedin-prThere is an active PR which will close this issue when it is mergedThere is an active PR which will close this issue when it is merged
on May 28, 2021 This is in PR and is just awaiting review. Keeping in 6.0.0 for the time being.
- ghost removedin-prThere is an active PR which will close this issue when it is mergedThere is an active PR which will close this issue when it is merged
on Sep 30, 2021 Keeping this open as there are still a few more APIs that aren't addressed yet.
public static Vector64<float> Narrow(Vector64<double> lower, Vector64<T> upper);
Is this a typo? Should it say
Vector64<double> upper? Same withVector128andVector256.Yes, that's just a typo.
This was resolved with #61649
Reacted by David Maas- ghost locked as resolved and limited conversation to collaborators
on Feb 8, 2022
Metadata
Metadata
Assignees
Labels
Team:Librariesapi-approvedAPI was approved in API review, it can be implementedAPI was approved in API review, it can be implementedarea-System.Runtime.Intrinsics
Summary
Today .NET exposes two sets of SIMD types meant for use in general purpose algorithms:
System.Numerics.Vector<T>andSystem.Runtime.Intrinsics.Vector64/128/256<T>.Vector<T>is variable sized and has existed for several years (going back to .NET Framework). It exposes a set of core functionality that allowed many algorithms to be written but where, primarily due to it being variable sized, other core functionality was not as easily exposed (such asPermuteand a few others).Vector64<T>,Vector128<T>, andVector256<T>are all newer and are meant to be use with the hardware specific instructions such as those exposed forx86orArm. This allows much finer grained control and for algorithms to be expose the full power of the underlying platform. The downside is that because the only exposed functionality is hardware specific, you may end up with two code paths that are near identical minus a couple specific paths.As such, I propose we effectively take what is exposed on
Vector<T>today and mirror that ontoVector64/128/256<T>. This will allow many of theif (Sse2.IsSupported) { } else if (AdvSimd.Arm64.IsSupported) { }code paths into a singleif (Vector128.IsHardwareAccelerated) {}code path and where you can fall back to hardware specific instructions only where that is important (such as usingMoveMaskon x86 vs a different check on ARM).After this is done, we can also look at exposing additional shared functionality (such as
Permute) where that can make sense for fixed sized types but where it did not make sense for the variable sizedVector<T>.API Proposal
The commented out methods are exposed on
Vector<T>and are not suggested to be exposed onVector64/128/256<T>. This is normally because it is takingfloat/doubleand returningint/longor where it is more performant to expose them as extension methods.Vector64
Vector128
Vector256