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

Expose cross-platform helpers for Vector64, Vector128, and Vector256 #49397

Closed
Tracked by #70532
tannergooding opened this issue Mar 9, 2021 · 11 comments · Fixed by #53450
Closed
Tracked by #70532

Expose cross-platform helpers for Vector64, Vector128, and Vector256 #49397

tannergooding opened this issue Mar 9, 2021 · 11 comments · Fixed by #53450
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime.Intrinsics Team:Libraries
Milestone

Comments

@tannergooding
Copy link
Member

tannergooding commented Mar 9, 2021

Summary

Today .NET exposes two sets of SIMD types meant for use in general purpose algorithms: System.Numerics.Vector<T> and System.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 as Permute and a few others).

Vector64<T>, Vector128<T>, and Vector256<T> are all newer and are meant to be use with the hardware specific instructions such as those exposed for x86 or Arm. 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 onto Vector64/128/256<T>. This will allow many of the if (Sse2.IsSupported) { } else if (AdvSimd.Arm64.IsSupported) { } code paths into a single if (Vector128.IsHardwareAccelerated) {} code path and where you can fall back to hardware specific instructions only where that is important (such as using MoveMask on 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 sized Vector<T>.

API Proposal

The commented out methods are exposed on Vector<T> and are not suggested to be exposed on Vector64/128/256<T>. This is normally because it is taking float/double and returning int/long or where it is more performant to expose them as extension methods.

Vector64

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> ConditionalSelect(Vector64<long> condition, Vector64<double> left, Vector64<double> right);
        // public static Vector64<float> ConditionalSelect(Vector64<int> condition, Vector64<float> left, Vector64<float> 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 Vector64<long> Equals(Vector64<double> left, Vector64<double> right);
        // public static Vector64<int> Equals(Vector64<float> left, Vector64<float> 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 Vector64<long> GreaterThan(Vector64<double> left, Vector64<double> right);
        // public static Vector64<int> GreaterThan(Vector64<float> left, Vector64<float> 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 Vector64<long> GreaterThanOrEqual(Vector64<double> left, Vector64<double> right);
        // public static Vector64<int> GreaterThanOrEqual(Vector64<float> left, Vector64<float> 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 Vector64<long> LessThan(Vector64<double> left, Vector64<double> right);
        // public static Vector64<int> LessThan(Vector64<float> left, Vector64<float> 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 Vector64<long> LessThanOrEqual(Vector64<double> left, Vector64<double> right);
        // public static Vector64<int> LessThanOrEqual(Vector64<float> left, Vector64<float> 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 Vector64(ReadOnlySpan<byte> values);
        // public Vector64(ReadOnlySpan<T> values);
        // public Vector64(T value);
        // public Vector64(T[] values);
        // public Vector64(T[] values, int index);

        // public T this[int index] { get; }

        // public void CopyTo(Span<byte> destination);
        // public void CopyTo(Span<T> destination);
        // public void CopyTo(T[] destination);
        // public void CopyTo(T[] destination, int index);

        // public bool TryCopyTo(Span<byte> destination);
        // public bool TryCopyTo(Span<T> destination);

        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);
    }
}

Vector128

namespace System.Runtime.Intrinsics
{
    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> ConditionalSelect(Vector128<long> condition, Vector128<double> left, Vector128<double> right);
        // public static Vector128<float> ConditionalSelect(Vector128<int> condition, Vector128<float> left, Vector128<float> 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 Vector128<long> Equals(Vector128<double> left, Vector128<double> right);
        // public static Vector128<int> Equals(Vector128<float> left, Vector128<float> 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 Vector128<long> GreaterThan(Vector128<double> left, Vector128<double> right);
        // public static Vector128<int> GreaterThan(Vector128<float> left, Vector128<float> 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 Vector128<long> GreaterThanOrEqual(Vector128<double> left, Vector128<double> right);
        // public static Vector128<int> GreaterThanOrEqual(Vector128<float> left, Vector128<float> 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 Vector128<long> LessThan(Vector128<double> left, Vector128<double> right);
        // public static Vector128<int> LessThan(Vector128<float> left, Vector128<float> 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 Vector128<long> LessThanOrEqual(Vector128<double> left, Vector128<double> right);
        // public static Vector128<int> LessThanOrEqual(Vector128<float> left, Vector128<float> 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 Vector128(ReadOnlySpan<byte> values);
        // public Vector128(ReadOnlySpan<T> values);
        // public Vector128(T value);
        // public Vector128(T[] values);
        // public Vector128(T[] values, int index);

        // public T this[int index] { get; }

        // public void CopyTo(Span<byte> destination);
        // public void CopyTo(Span<T> destination);
        // public void CopyTo(T[] destination);
        // public void CopyTo(T[] destination, int index);

        // public bool TryCopyTo(Span<byte> destination);
        // public bool TryCopyTo(Span<T> destination);

        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);
    }

Vector256

namespace System.Runtime.Intrinsics
{
    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> ConditionalSelect(Vector256<long> condition, Vector256<double> left, Vector256<double> right);
        // public static Vector256<float> ConditionalSelect(Vector256<int> condition, Vector256<float> left, Vector256<float> 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 Vector256<long> Equals(Vector256<double> left, Vector256<double> right);
        // public static Vector256<int> Equals(Vector256<float> left, Vector256<float> 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 Vector256<long> GreaterThan(Vector256<double> left, Vector256<double> right);
        // public static Vector256<int> GreaterThan(Vector256<float> left, Vector256<float> 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 Vector256<long> GreaterThanOrEqual(Vector256<double> left, Vector256<double> right);
        // public static Vector256<int> GreaterThanOrEqual(Vector256<float> left, Vector256<float> 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 Vector256<long> LessThan(Vector256<double> left, Vector256<double> right);
        // public static Vector256<int> LessThan(Vector256<float> left, Vector256<float> 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 Vector256<long> LessThanOrEqual(Vector256<double> left, Vector256<double> right);
        // public static Vector256<int> LessThanOrEqual(Vector256<float> left, Vector256<float> 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 Vector256(ReadOnlySpan<byte> values);
        // public Vector256(ReadOnlySpan<T> values);
        // public Vector256(T value);
        // public Vector256(T[] values);
        // public Vector256(T[] values, int index);

        // public T this[int index] { get; }

        // public void CopyTo(Span<byte> destination);
        // public void CopyTo(Span<T> destination);
        // public void CopyTo(T[] destination);
        // public void CopyTo(T[] destination, int index);

        // public bool TryCopyTo(Span<byte> destination);
        // public bool TryCopyTo(Span<T> destination);

        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);
    }
}
@tannergooding tannergooding added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Mar 9, 2021
@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.Runtime.Intrinsics untriaged New issue has not been triaged by the area owner labels Mar 9, 2021
@ghost
Copy link

ghost commented Mar 9, 2021

Tagging subscribers to this area: @tannergooding
See info in area-owners.md if you want to be subscribed.

Issue Details

Summary

Today .NET exposes two sets of SIMD types meant for use in general purpose algorithms: System.Numerics.Vector<T> and System.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 as Permute and a few others).

Vector64<T>, Vector128<T>, and Vector256<T> are all newer and are meant to be use with the hardware specific instructions such as those exposed for x86 or Arm. 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 onto Vector64/128/256<T>. This will allow many of the if (Sse2.IsSupported) { } else if (AdvSimd.Arm64.IsSupported) { } code paths into a single if (Vector128.IsHardwareAccelerated) {} code path and where you can fall back to hardware specific instructions only where that is important (such as using MoveMask on 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 sized Vector<T>.

API Proposal

The commented out methods are exposed on Vector<T> and are not suggested to be exposed on Vector64/128/256<T>. This is normally because it is taking float/double and returning int/long or where it is more performant to expose them as extension methods.

Vector64

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> ConditionalSelect(Vector64<long> condition, Vector64<double> left, Vector64<double> right);
        // public static Vector64<float> ConditionalSelect(Vector64<int> condition, Vector64<float> left, Vector64<float> 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 Vector64<long> Equals(Vector64<double> left, Vector64<double> right);
        // public static Vector64<int> Equals(Vector64<float> left, Vector64<float> 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 Vector64<long> GreaterThan(Vector64<double> left, Vector64<double> right);
        // public static Vector64<int> GreaterThan(Vector64<float> left, Vector64<float> 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 Vector64<long> GreaterThanOrEqual(Vector64<double> left, Vector64<double> right);
        // public static Vector64<int> GreaterThanOrEqual(Vector64<float> left, Vector64<float> 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 Vector64<long> LessThan(Vector64<double> left, Vector64<double> right);
        // public static Vector64<int> LessThan(Vector64<float> left, Vector64<float> 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 Vector64<long> LessThanOrEqual(Vector64<double> left, Vector64<double> right);
        // public static Vector64<int> LessThanOrEqual(Vector64<float> left, Vector64<float> 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 Vector64(ReadOnlySpan<byte> values);
        // public Vector64(ReadOnlySpan<T> values);
        // public Vector64(T value);
        // public Vector64(T[] values);
        // public Vector64(T[] values, int index);

        // public T this[int index] { get; }

        // public void CopyTo(Span<byte> destination);
        // public void CopyTo(Span<T> destination);
        // public void CopyTo(T[] destination);
        // public void CopyTo(T[] destination, int index);

        // public bool TryCopyTo(Span<byte> destination);
        // public bool TryCopyTo(Span<T> destination);

        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 bool operator &(Vector64<T> left, Vector64<T> right);
        public static bool operator |(Vector64<T> left, Vector64<T> right);
        public static bool operator ^(Vector64<T> left, Vector64<T> right);
    }
}

Vector128

namespace System.Runtime.Intrinsics
{
    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> ConditionalSelect(Vector128<long> condition, Vector128<double> left, Vector128<double> right);
        // public static Vector128<float> ConditionalSelect(Vector128<int> condition, Vector128<float> left, Vector128<float> 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 Vector128<long> Equals(Vector128<double> left, Vector128<double> right);
        // public static Vector128<int> Equals(Vector128<float> left, Vector128<float> 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 Vector128<long> GreaterThan(Vector128<double> left, Vector128<double> right);
        // public static Vector128<int> GreaterThan(Vector128<float> left, Vector128<float> 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 Vector128<long> GreaterThanOrEqual(Vector128<double> left, Vector128<double> right);
        // public static Vector128<int> GreaterThanOrEqual(Vector128<float> left, Vector128<float> 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 Vector128<long> LessThan(Vector128<double> left, Vector128<double> right);
        // public static Vector128<int> LessThan(Vector128<float> left, Vector128<float> 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 Vector128<long> LessThanOrEqual(Vector128<double> left, Vector128<double> right);
        // public static Vector128<int> LessThanOrEqual(Vector128<float> left, Vector128<float> 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 Vector128(ReadOnlySpan<byte> values);
        // public Vector128(ReadOnlySpan<T> values);
        // public Vector128(T value);
        // public Vector128(T[] values);
        // public Vector128(T[] values, int index);

        // public T this[int index] { get; }

        // public void CopyTo(Span<byte> destination);
        // public void CopyTo(Span<T> destination);
        // public void CopyTo(T[] destination);
        // public void CopyTo(T[] destination, int index);

        // public bool TryCopyTo(Span<byte> destination);
        // public bool TryCopyTo(Span<T> destination);

        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 bool operator &(Vector128<T> left, Vector128<T> right);
        public static bool operator |(Vector128<T> left, Vector128<T> right);
        public static bool operator ^(Vector128<T> left, Vector128<T> right);
    }

Vector256

namespace System.Runtime.Intrinsics
{
    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> ConditionalSelect(Vector256<long> condition, Vector256<double> left, Vector256<double> right);
        // public static Vector256<float> ConditionalSelect(Vector256<int> condition, Vector256<float> left, Vector256<float> 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 Vector256<long> Equals(Vector256<double> left, Vector256<double> right);
        // public static Vector256<int> Equals(Vector256<float> left, Vector256<float> 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 Vector256<long> GreaterThan(Vector256<double> left, Vector256<double> right);
        // public static Vector256<int> GreaterThan(Vector256<float> left, Vector256<float> 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 Vector256<long> GreaterThanOrEqual(Vector256<double> left, Vector256<double> right);
        // public static Vector256<int> GreaterThanOrEqual(Vector256<float> left, Vector256<float> 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 Vector256<long> LessThan(Vector256<double> left, Vector256<double> right);
        // public static Vector256<int> LessThan(Vector256<float> left, Vector256<float> 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 Vector256<long> LessThanOrEqual(Vector256<double> left, Vector256<double> right);
        // public static Vector256<int> LessThanOrEqual(Vector256<float> left, Vector256<float> 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 Vector256(ReadOnlySpan<byte> values);
        // public Vector256(ReadOnlySpan<T> values);
        // public Vector256(T value);
        // public Vector256(T[] values);
        // public Vector256(T[] values, int index);

        // public T this[int index] { get; }

        // public void CopyTo(Span<byte> destination);
        // public void CopyTo(Span<T> destination);
        // public void CopyTo(T[] destination);
        // public void CopyTo(T[] destination, int index);

        // public bool TryCopyTo(Span<byte> destination);
        // public bool TryCopyTo(Span<T> destination);

        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 bool operator &(Vector256<T> left, Vector256<T> right);
        public static bool operator |(Vector256<T> left, Vector256<T> right);
        public static bool operator ^(Vector256<T> left, Vector256<T> right);
    }
}
Author: tannergooding
Assignees: -
Labels:

api-suggestion, area-System.Runtime.Intrinsics, untriaged

Milestone: -

@scalablecory
Copy link
Contributor

Can we also have rsqrt, and approximate versions of sqrt/rsqrt?

@tannergooding
Copy link
Member Author

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.

@tannergooding
Copy link
Member Author

CC. @pgovind @echesakovMSFT

Any concerns with me marking this "API Ready for Review"?

@pgovind
Copy link

pgovind commented Mar 12, 2021

Nope, this looks good to me!

@tannergooding tannergooding added api-ready-for-review API is ready for review, it is NOT ready for implementation and removed api-suggestion Early API idea and discussion, it is NOT ready for implementation untriaged New issue has not been triaged by the area owner labels Mar 12, 2021
@tannergooding tannergooding added this to the 6.0.0 milestone May 20, 2021
@bartonjs
Copy link
Member

bartonjs commented May 21, 2021

Video

  • 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);
    }
}

@bartonjs bartonjs added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for review, it is NOT ready for implementation labels May 21, 2021
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label May 28, 2021
@tannergooding
Copy link
Member Author

This is in PR and is just awaiting review. Keeping in 6.0.0 for the time being.

@tannergooding tannergooding modified the milestones: 6.0.0, 7.0.0 Jul 12, 2021
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Sep 30, 2021
@tannergooding tannergooding reopened this Sep 30, 2021
@tannergooding
Copy link
Member Author

Keeping this open as there are still a few more APIs that aren't addressed yet.

@teo-tsirpanis
Copy link
Contributor

public static Vector64<float> Narrow(Vector64<double> lower, Vector64<T> upper);

Is this a typo? Should it say Vector64<double> upper? Same with Vector128 and Vector256.

@tannergooding
Copy link
Member Author

Yes, that's just a typo.

@tannergooding
Copy link
Member Author

This was resolved with #61649

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime.Intrinsics Team:Libraries
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants