Skip to content

Extend Vector64<T>, Vector128<T>, and Vector256<T> to support nint and nuint #52017

Description

@tannergooding

Proposal

Extend Vector64<T>, Vector128<T>, and Vector256<T> to support nint and nuint as valid primitive types. This will extend a number of existing generic functions which take a Vector<T> to also support taking the new types rather than throwing a PlatformNotSupportedException.

Additionally, the following non-generic APIs should be added for parity with the existing surface area:

namespace System.Runtime.Intrinsics
{
    public static partial class Vector64
    {
        public static Vector64<nint> AsNInt<T>(Vector64<T> value);
        public static Vector64<nuint> AsNUInt<T>(Vector64<T> value);

        public static Vector64<nint> Create(nint value);
        public static Vector64<nuint> Create(nuint value);

        public static Vector64<nint> CreateScalar(nint value);
        public static Vector64<nuint> CreateScalar(nuint value);

        public static Vector64<nint> CreateScalarUnsafe(nint value);
        public static Vector64<nuint> CreateScalarUnsafe(nuint value);
    }

    public static partial class Vector128
    {
        public static Vector128<nint> AsNInt<T>(Vector128<T> value);
        public static Vector128<nuint> AsNUInt<T>(Vector128<T> value);

        public static Vector128<nint> Create(nint value);
        public static Vector128<nuint> Create(nuint value);

        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<nint> CreateScalar(nint value);
        public static Vector128<nuint> CreateScalar(nuint value);

        public static Vector128<nint> CreateScalarUnsafe(nint value);
        public static Vector128<nuint> CreateScalarUnsafe(nuint value);
    }

    public static partial class Vector256
    {
        public static Vector256<nint> AsNInt<T>(Vector256<T> value);
        public static Vector256<nuint> AsNUInt<T>(Vector256<T> value);

        public static Vector256<nint> Create(nint value);
        public static Vector256<nuint> Create(nuint value);

        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<nint> CreateScalar(nint value);
        public static Vector256<nuint> CreateScalar(nuint value);

        public static Vector256<nint> CreateScalarUnsafe(nint value);
        public static Vector256<nuint> CreateScalarUnsafe(nuint value);
    }
}

Activity

  1. ghost added
    untriagedNew issue has not been triaged by the area owner
    on Apr 28, 2021
  2. added
    api-ready-for-reviewAPI is ready for review, it is NOT ready for implementation
    and removed
    untriagedNew issue has not been triaged by the area owner
    on Apr 28, 2021
  3. tannergooding commented on Apr 28, 2021

    @tannergooding
    MemberAuthor

    #52021 represents the x86 ISA changes that would be appropriate

  4. tannergooding commented on Apr 29, 2021

    @tannergooding
    MemberAuthor

    #52027 represents the Arm ISA changes that would be appropriate

  5. gfoidl commented on Apr 29, 2021

    @gfoidl
    Member

    Hm, maybe I miss something now, but in simple words nint will either be int or long* depending on the bitness of the executing platform. So this would result in either Vector128<int> or Vector128<long>.
    Can you give me a use case please? I can't puzzle together anything useful for this right now.

    * please remember: that's in simple words 😉

  6. tannergooding commented on Apr 29, 2021

    @tannergooding
    MemberAuthor

    We use nint/nuint in some of our algorithms, such as https://source.dot.net/#System.Private.CoreLib/Utf16Utility.Validation.cs,359.

    64-bit (long/ulong) intrinsics tend to not be supported or less efficient on 32-bit machines. While 32-bit (int/uint) intrinsics tend to not fully utilize the CPU on 64-bit machines. Using nint allows the "natural" data type to be used and can make the overall algorithm more efficient.

  7. gfoidl commented on Apr 29, 2021

    @gfoidl
    Member

    Got it. Thanks (nice example linked).

  8. added this to the 6.0.0 milestone on May 20, 2021
  9. bartonjs commented on May 27, 2021

    @bartonjs
    Member

    Video

    Looks good as proposed. A very forward looking question of "what about when nint is bigger than 64 bits?" was asked, and deferred to such a hypothetical date.

    namespace System.Runtime.Intrinsics
    {
        public static partial class Vector64
        {
            public static Vector64<nint> AsNInt<T>(Vector64<T> value);
            public static Vector64<nuint> AsNUInt<T>(Vector64<T> value);
    
            public static Vector64<nint> Create(nint value);
            public static Vector64<nuint> Create(nuint value);
    
            public static Vector64<nint> CreateScalar(nint value);
            public static Vector64<nuint> CreateScalar(nuint value);
    
            public static Vector64<nint> CreateScalarUnsafe(nint value);
            public static Vector64<nuint> CreateScalarUnsafe(nuint value);
        }
    
        public static partial class Vector128
        {
            public static Vector128<nint> AsNInt<T>(Vector128<T> value);
            public static Vector128<nuint> AsNUInt<T>(Vector128<T> value);
    
            public static Vector128<nint> Create(nint value);
            public static Vector128<nuint> Create(nuint value);
    
            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<nint> CreateScalar(nint value);
            public static Vector128<nuint> CreateScalar(nuint value);
    
            public static Vector128<nint> CreateScalarUnsafe(nint value);
            public static Vector128<nuint> CreateScalarUnsafe(nuint value);
        }
    
        public static partial class Vector256
        {
            public static Vector256<nint> AsNInt<T>(Vector256<T> value);
            public static Vector256<nuint> AsNUInt<T>(Vector256<T> value);
    
            public static Vector256<nint> Create(nint value);
            public static Vector256<nuint> Create(nuint value);
    
            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<nint> CreateScalar(nint value);
            public static Vector256<nuint> CreateScalar(nuint value);
    
            public static Vector256<nint> CreateScalarUnsafe(nint value);
            public static Vector256<nuint> CreateScalarUnsafe(nuint value);
        }
    }
  10. added
    api-approvedAPI was approved in API review, it can be implemented
    and removed
    api-ready-for-reviewAPI is ready for review, it is NOT ready for implementation
    on May 27, 2021
  11. modified the milestones: 6.0.0, 7.0.0 on Jul 12, 2021
  12. deeprobin commented on Dec 21, 2021

    @deeprobin
    Contributor

    You're welcome to assign me 😄

    Edit: I was bored and couldn't wait for the issue to be assigned to me.... Therefore I have created a PR

  13. ghost added
    in-prThere is an active PR which will close this issue when it is merged
    on Dec 26, 2021
  14. deeprobin commented on Dec 26, 2021

    @deeprobin
    Contributor

    What puzzles me a bit about the proposal is the naming of the methods.
    It is usual in the class that the methods are named after the underlying struct. But in this case it was named after the primitive.

    -        public static Vector64<nint> AsNInt<T>(Vector64<T> value);
    -        public static Vector64<nuint> AsNUInt<T>(Vector64<T> value);
    +        public static Vector64<nint> AsIntPtr<T>(Vector64<T> value);
    +        public static Vector64<nuint> AsUIntPtr<T>(Vector64<T> value);

    Have you considered this?

  15. tannergooding commented on Jan 3, 2022

    @tannergooding
    MemberAuthor

    It is usual in the class that the methods are named after the underlying struct

    NInt means it takes nint and IntPtr means it takes IntPtr and due to the current language differences, that semantic can be meaningful. It may change in the future, particularly due to generic math, but as far as API names go; that's the meaning/intent and how other already shipped APIs differentiate.

  16. tannergooding commented on Jan 3, 2022

    @tannergooding
    MemberAuthor

    Edit: I was bored and couldn't wait for the issue to be assigned to me.... Therefore I have created a PR

    (just posting our Discord conversation for completeness).

    I was on vacation and not checking work related GitHub so this got missed. I've actually already done the work here and its in a local branch waiting for other PRs, such as #61649 to get merged before it gets put up.

  17. ghost removed
    in-prThere is an active PR which will close this issue when it is merged
    on Jan 4, 2022
  18. ghost locked as resolved and limited conversation to collaborators on Feb 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions