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

[API Proposa]: Provide vector functions covering common "mask" checks #98055

Open
tannergooding opened this issue Feb 6, 2024 · 2 comments
Open
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime.Intrinsics
Milestone

Comments

@tannergooding
Copy link
Member

Summary

When working with vectors, it is frequent that you will do some sequence of operations and ultimately do a comparison which produces a mask. For the fixed-width vectors, you can then use var mask = vector.ExtractMostSignificantBits() to get a scalar bitmask that allows you to do many common operations such as determining if any matches existed (mask != 0), getting the total number of matches (BitOperations.PopCount(mask)), or getting the index of the first/last match (BitOperations.LeadingZeroCount(mask) or BitOperations.TrailingZeroCount(mask)).

However, getting this bit mask is not efficient on all platforms (Arm64 doesn't have an instruction similar to pmovmskb)_ nor can it be used with variable width vector types (Vector<T>, which will impact SVE on Arm64). As such, it is proposed that we expose some helpers for these "core" operations that abstract the logic, thus allowing more efficient handling in those scenarios.

API Proposal

namespace System.Numerics
{
    public partial class Vector
    {
        public static bool AnyMatches<T>(Vector<T> value);

        public static int GetMatchCount<T>(Vector<T> value);

        public static int IndexOfFirstMatch<T>(Vector<T> value);
        public static int IndexOfLastMatch<T>(Vector<T> value);
    }
}

namespace System.Runtime.Intrinsics
{
    public partial class Vector64
    {
        public static bool AnyMatches<T>(Vector64<T> value);

        public static int GetMatchCount<T>(Vector64<T> value);

        public static int IndexOfFirstMatch<T>(Vector64<T> value);
        public static int IndexOfLastMatch<T>(Vector64<T> value);
    }

    public partial class Vector128
    {
        public static bool AnyMatches<T>(Vector128<T> value);

        public static int GetMatchCount<T>(Vector128<T> value);

        public static int IndexOfFirstMatch<T>(Vector128<T> value);
        public static int IndexOfLastMatch<T>(Vector128<T> value);
    }

    public partial class Vector256
    {
        public static bool AnyMatches<T>(Vector256<T> value);

        public static int GetMatchCount<T>(Vector256<T> value);

        public static int IndexOfFirstMatch<T>(Vector256<T> value);
        public static int IndexOfLastMatch<T>(Vector256<T> value);
    }

    public partial class Vector512
    {
        public static bool AnyMatches<T>(Vector512<T> value);

        public static int GetMatchCount<T>(Vector512<T> value);

        public static int IndexOfFirstMatch<T>(Vector512<T> value);
        public static int IndexOfLastMatch<T>(Vector512<T> value);
    }
}
@tannergooding tannergooding added area-System.Runtime.Intrinsics api-ready-for-review API is ready for review, it is NOT ready for implementation labels Feb 6, 2024
@tannergooding tannergooding added this to the 9.0.0 milestone Feb 6, 2024
@ghost
Copy link

ghost commented Feb 6, 2024

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

Issue Details

Summary

When working with vectors, it is frequent that you will do some sequence of operations and ultimately do a comparison which produces a mask. For the fixed-width vectors, you can then use var mask = vector.ExtractMostSignificantBits() to get a scalar bitmask that allows you to do many common operations such as determining if any matches existed (mask != 0), getting the total number of matches (BitOperations.PopCount(mask)), or getting the index of the first/last match (BitOperations.LeadingZeroCount(mask) or BitOperations.TrailingZeroCount(mask)).

However, getting this bit mask is not efficient on all platforms (Arm64 doesn't have an instruction similar to pmovmskb)_ nor can it be used with variable width vector types (Vector<T>, which will impact SVE on Arm64). As such, it is proposed that we expose some helpers for these "core" operations that abstract the logic, thus allowing more efficient handling in those scenarios.

API Proposal

namespace System.Numerics
{
    public partial class Vector
    {
        public static bool AnyMatches<T>(Vector<T> value);

        public static int GetMatchCount<T>(Vector<T> value);

        public static int IndexOfFirstMatch<T>(Vector<T> value);
        public static int IndexOfLastMatch<T>(Vector<T> value);
    }
}

namespace System.Runtime.Intrinsics
{
    public partial class Vector64
    {
        public static bool AnyMatches<T>(Vector64<T> value);

        public static int GetMatchCount<T>(Vector64<T> value);

        public static int IndexOfFirstMatch<T>(Vector64<T> value);
        public static int IndexOfLastMatch<T>(Vector64<T> value);
    }

    public partial class Vector128
    {
        public static bool AnyMatches<T>(Vector128<T> value);

        public static int GetMatchCount<T>(Vector128<T> value);

        public static int IndexOfFirstMatch<T>(Vector128<T> value);
        public static int IndexOfLastMatch<T>(Vector128<T> value);
    }

    public partial class Vector256
    {
        public static bool AnyMatches<T>(Vector256<T> value);

        public static int GetMatchCount<T>(Vector256<T> value);

        public static int IndexOfFirstMatch<T>(Vector256<T> value);
        public static int IndexOfLastMatch<T>(Vector256<T> value);
    }

    public partial class Vector512
    {
        public static bool AnyMatches<T>(Vector512<T> value);

        public static int GetMatchCount<T>(Vector512<T> value);

        public static int IndexOfFirstMatch<T>(Vector512<T> value);
        public static int IndexOfLastMatch<T>(Vector512<T> value);
    }
}
Author: tannergooding
Assignees: -
Labels:

area-System.Runtime.Intrinsics, api-ready-for-review

Milestone: 9.0.0

@bartonjs
Copy link
Member

bartonjs commented Apr 2, 2024

Video

  • We added a scalar parameter to all of these to allow expressing what the match should be on
  • While silmutaneously renaming the existing unary ones to express "AllBitsSet"
  • And changed things to look like existing concept names (IndexOfLast => LastIndexOf)
namespace System.Numerics
{
    public partial class Vector
    {
        public static bool Any<T>(Vector<T> vector, T value);
        public static bool AnyWhereAllBitsSet<T>(Vector<T> vector);

        public static int Count<T>(Vector<T> vector, T value);
        public static int CountWhereAllBitsSet<T>(Vector<T> vector);

        public static int IndexOf<T>(Vector<T> vector, T value);
        public static int IndexOfWhereAllBitsSet<T>(Vector<T> vector);
        
        public static int LastIndexOf<T>(Vector<T> vector, T value);
        public static int LastIndexOfWhereAllBitsSet<T>(Vector<T> vector);
    }
}

namespace System.Runtime.Intrinsics
{
    public partial class Vector64
    {
        // ditto.
    }

    public partial class Vector128
    {
        // ditto.
    }

    public partial class Vector256
    {
        // ditto.
    }

    public partial class Vector512
    {
        // ditto.
    }
}

@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 Apr 2, 2024
DeepakRajendrakumaran added a commit to DeepakRajendrakumaran/runtime that referenced this issue Apr 5, 2024
tannergooding pushed a commit that referenced this issue Apr 8, 2024
* Add AnyMatches() to iSimdVector interface

* Switch to iSimdVector and Align WidenAsciiToUtf16.

* Fixing perf

* Addressing Review Comments.

* Mirroring API change : #98055 (comment)
matouskozak pushed a commit to matouskozak/runtime that referenced this issue Apr 30, 2024
* Add AnyMatches() to iSimdVector interface

* Switch to iSimdVector and Align WidenAsciiToUtf16.

* Fixing perf

* Addressing Review Comments.

* Mirroring API change : dotnet#98055 (comment)
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this issue May 30, 2024
* Add AnyMatches() to iSimdVector interface

* Switch to iSimdVector and Align WidenAsciiToUtf16.

* Fixing perf

* Addressing Review Comments.

* Mirroring API change : dotnet#98055 (comment)
@jeffhandley jeffhandley modified the milestones: 9.0.0, 10.0.0 Jul 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime.Intrinsics
Projects
None yet
Development

No branches or pull requests

3 participants