Skip to content

Vector64/128/256/512<T> and Vector<T> Consistency/Enhancements #76593

@tannergooding

Description

@tannergooding

Summary

We've exposed several APIs on Vector64/128/256 and recently approved Vector512. However, there are notably a few missing APIs that make it feel "incomplete". Such APIs were likely simply missed as part of previous review.

API Proposal

namespace System.Numerics
{
    public static partial class Vector
    {
        // Has AsVectorByte and friends, not AsByte and friends

        public static Vector<T> Divide(Vector<T> left, T right);

        public static T GetElement<T>(this Vector<T> vector, int index) where T : struct;

        public static Vector<T> Load<T>(T* source) where T : unmanaged;
        public static Vector<T> LoadAligned<T>(T* source) where T : unmanaged;
        public static Vector<T> LoadAlignedNonTemporal<T>(T* source) where T : unmanaged;
        public static Vector<T> LoadUnsafe<T>(ref T source) where T : struct;
        public static Vector<T> LoadUnsafe<T>(ref T source, nuint index) where T : struct;

        // Shuffle is difficult to expose because the indices often should be "constant"

        // Has SquareRoot, not Sqrt

        public static unsafe void Store<T>(this Vector<T> source, T* destination) where T : unmanaged;
        public static unsafe void StoreAligned<T>(this Vector<T> source, T* destination) where T : unmanaged;
        public static unsafe void StoreAlignedNonTemporal<T>(this Vector<T> source, T* destination) where T : unmanaged;
        public static unsafe void StoreUnsafe<T>(this Vector<T> source, ref T destination) where T : struct;
        public static unsafe void StoreUnsafe<T>(this Vector<T> source, ref T destination, nuint index) where T : struct;

        public static T ToScalar<T>(this Vector<T> vector) where T : struct;

        public static Vector<T> WithElement<T> (this Vector<T> vector, int index, T value) where T : struct;
    }

    public partial struct Vector<T>
    {
        public static Vector<T> AllBitsSet { get; }

        // Has constructors, not Vector.Create()
        // Has explicit cast operators

        public static Vector<T> operator /(Vector<T> left, T right);
        public static Vector<T> operator +(Vector<T> value);
    }
}

namespace System.Runtime.Intrinsics.X86
{
    public static partial class Vector64
    {
        public static Vector64<T> CreateScalar<T>(T value) where T : struct;

        public static Vector64<T>     CreateScalarUnsafe<T>(T     value) where T : struct;
        public static Vector64<long>  CreateScalarUnsafe   (double  value);
        public static Vector64<long>  CreateScalarUnsafe   (long  value);
        public static Vector64<ulong> CreateScalarUnsafe   (ulong value);

        public static Vector64<T> Divide(Vector64<T> left, T right);

        public static Vector64<ushort> WidenLower(Vector64<byte>   value);
        public static Vector64<int>    WidenLower(Vector64<short>  value);
        public static Vector64<long>   WidenLower(Vector64<int>    value);
        public static Vector64<short>  WidenLower(Vector64<sbyte>  value);
        public static Vector64<double> WidenLower(Vector64<float>  value);
        public static Vector64<uint>   WidenLower(Vector64<ushort> value);
        public static Vector64<ulong>  WidenLower(Vector64<uint>   value);

        public static Vector64<ushort> WidenUpper(Vector64<byte>   value);
        public static Vector64<int>    WidenUpper(Vector64<short>  value);
        public static Vector64<long>   WidenUpper(Vector64<int>    value);
        public static Vector64<short>  WidenUpper(Vector64<sbyte>  value);
        public static Vector64<double> WidenUpper(Vector64<float>  value);
        public static Vector64<uint>   WidenUpper(Vector64<ushort> value);
        public static Vector64<ulong>  WidenUpper(Vector64<uint>   value);
    }

    public partial struct Vector64<T>
    {
        public static Vector64<T> One { get; }

        public static Vector64<T> operator /(Vector64<T> left, T right);

        public static Vector64<T> operator <<(Vector64<T> left, int shiftAmount);
        public static Vector64<T> operator >>(Vector64<T> left, int shiftAmount);
        public static Vector64<T> operator >>>(Vector64<T> left, int shiftAmount);
    }

    public static partial class Vector128
    {
        public static Vector128<T>     Create<T>(Vector64<T>     lower, Vector64<T>     upper) where T : struct;
        public static Vector128<nint>  Create   (Vector64<nint>  lower, Vector64<nint>  upper);
        public static Vector128<nuint> Create   (Vector64<nuint> lower, Vector64<nuint> upper);

        public static Vector128<T> CreateScalar<T>(T value) where T : struct;

        public static Vector128<T> CreateScalarUnsafe<T>(T value) where T : struct;

        public static Vector128<T> Divide(Vector128<T> left, T right);

        public static Vector128<ushort> WidenLower(Vector128<byte>   value);
        public static Vector128<int>    WidenLower(Vector128<short>  value);
        public static Vector128<long>   WidenLower(Vector128<int>    value);
        public static Vector128<short>  WidenLower(Vector128<sbyte>  value);
        public static Vector128<double> WidenLower(Vector128<float>  value);
        public static Vector128<uint>   WidenLower(Vector128<ushort> value);
        public static Vector128<ulong>  WidenLower(Vector128<uint>   value);

        public static Vector128<ushort> WidenUpper(Vector128<byte>   value);
        public static Vector128<int>    WidenUpper(Vector128<short>  value);
        public static Vector128<long>   WidenUpper(Vector128<int>    value);
        public static Vector128<short>  WidenUpper(Vector128<sbyte>  value);
        public static Vector128<double> WidenUpper(Vector128<float>  value);
        public static Vector128<uint>   WidenUpper(Vector128<ushort> value);
        public static Vector128<ulong>  WidenUpper(Vector128<uint>   value);
    }

    public partial struct Vector128<T>
    {
        public static Vector128<T> One { get; }

        public static Vector128<T> operator /(Vector128<T> left, T right);

        public static Vector128<T> operator <<(Vector128<T> left, int shiftAmount);
        public static Vector128<T> operator >>(Vector128<T> left, int shiftAmount);
        public static Vector128<T> operator >>>(Vector128<T> left, int shiftAmount);
    }

    public static partial class Vector256
    {
        public static Vector256<T>     Create<T>(Vector128<T>     lower, Vector128<T>     upper) where T : struct;
        public static Vector256<nint>  Create   (Vector128<nint>  lower, Vector128<nint>  upper);
        public static Vector256<nuint> Create   (Vector128<nuint> lower, Vector128<nuint> upper);

        public static Vector256<T> CreateScalar<T>(T value) where T : struct;

        public static Vector256<T> CreateScalarUnsafe<T>(T value) where T : struct;

        public static Vector256<T> Divide(Vector256<T> left, T right);

        public static Vector256<ushort> WidenLower(Vector256<byte>   value);
        public static Vector256<int>    WidenLower(Vector256<short>  value);
        public static Vector256<long>   WidenLower(Vector256<int>    value);
        public static Vector256<short>  WidenLower(Vector256<sbyte>  value);
        public static Vector256<double> WidenLower(Vector256<float>  value);
        public static Vector256<uint>   WidenLower(Vector256<ushort> value);
        public static Vector256<ulong>  WidenLower(Vector256<uint>   value);

        public static Vector256<ushort> WidenUpper(Vector256<byte>   value);
        public static Vector256<int>    WidenUpper(Vector256<short>  value);
        public static Vector256<long>   WidenUpper(Vector256<int>    value);
        public static Vector256<short>  WidenUpper(Vector256<sbyte>  value);
        public static Vector256<double> WidenUpper(Vector256<float>  value);
        public static Vector256<uint>   WidenUpper(Vector256<ushort> value);
        public static Vector256<ulong>  WidenUpper(Vector256<uint>   value);
    }

    public partial struct Vector256<T>
    {
        public static Vector256<T> One { get; }

        public static Vector256<T> operator /(Vector256<T> left, T right);

        public static Vector256<T> operator <<(Vector256<T> left, int shiftAmount);
        public static Vector256<T> operator >>(Vector256<T> left, int shiftAmount);
        public static Vector256<T> operator >>>(Vector256<T> left, int shiftAmount);
    }
}

Considerations

We expose == and != with the semantics of "All". Exposing <, <=, >, and >= with the same semantics likely makes sense. If we do this, then IComparable should likely also be implemented.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions