From 4c96f2941dd5d56924ea6e82ebeb04596e30c0ad Mon Sep 17 00:00:00 2001 From: Miha Zupan Date: Thu, 2 Mar 2023 00:20:46 +0100 Subject: [PATCH] Simplify IndexOfAnyAsciiByteValues for needles with 0 on X86 --- .../tests/Span/IndexOfAnyValues.cs | 4 +- .../IndexOfAnyAsciiByteValues.cs | 14 ++--- .../IndexOfAnyAsciiSearcher.cs | 56 ++++--------------- .../IndexOfAnyValues/IndexOfAnyValues.cs | 6 +- 4 files changed, 18 insertions(+), 62 deletions(-) diff --git a/src/libraries/System.Memory/tests/Span/IndexOfAnyValues.cs b/src/libraries/System.Memory/tests/Span/IndexOfAnyValues.cs index 4ca29be532888..44dda7358c705 100644 --- a/src/libraries/System.Memory/tests/Span/IndexOfAnyValues.cs +++ b/src/libraries/System.Memory/tests/Span/IndexOfAnyValues.cs @@ -496,8 +496,8 @@ private static ReadOnlySpan GetRandomSlice(Random rng, ReadOnlySpan spa private static void AssertionFailed(ReadOnlySpan haystack, ReadOnlySpan needle, int expected, int actual, string approach) where T : INumber { - string readableHaystack = string.Join(", ", haystack.ToString().Select(c => int.CreateChecked(c))); - string readableNeedle = string.Join(", ", needle.ToString().Select(c => int.CreateChecked(c))); + string readableHaystack = string.Join(", ", haystack.ToArray().Select(c => int.CreateChecked(c))); + string readableNeedle = string.Join(", ", needle.ToArray().Select(c => int.CreateChecked(c))); Assert.True(false, $"Expected {expected}, got {approach}={actual} for needle='{readableNeedle}', haystack='{readableHaystack}'"); } diff --git a/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiByteValues.cs b/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiByteValues.cs index 3a214b47d6f78..7a502d283920d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiByteValues.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiByteValues.cs @@ -7,17 +7,13 @@ namespace System.Buffers { - internal sealed class IndexOfAnyAsciiByteValues : IndexOfAnyValues - where TOptimizations : struct, IndexOfAnyAsciiSearcher.IOptimizations + internal sealed class IndexOfAnyAsciiByteValues : IndexOfAnyValues { private readonly Vector128 _bitmap; private readonly BitVector256 _lookup; - public IndexOfAnyAsciiByteValues(Vector128 bitmap, BitVector256 lookup) - { - _bitmap = bitmap; - _lookup = lookup; - } + public IndexOfAnyAsciiByteValues(ReadOnlySpan values) => + IndexOfAnyAsciiSearcher.ComputeBitmap(values, out _bitmap, out _lookup); internal override byte[] GetValues() => _lookup.GetByteValues(); @@ -46,7 +42,7 @@ private int IndexOfAny(ref byte searchSpace, int searchSpaceLength) where TNegator : struct, IndexOfAnyAsciiSearcher.INegator { return IndexOfAnyAsciiSearcher.IsVectorizationSupported && searchSpaceLength >= sizeof(ulong) - ? IndexOfAnyAsciiSearcher.IndexOfAnyVectorized(ref searchSpace, searchSpaceLength, _bitmap) + ? IndexOfAnyAsciiSearcher.IndexOfAnyVectorized(ref searchSpace, searchSpaceLength, _bitmap) : IndexOfAnyScalar(ref searchSpace, searchSpaceLength); } @@ -55,7 +51,7 @@ private int LastIndexOfAny(ref byte searchSpace, int searchSpaceLength where TNegator : struct, IndexOfAnyAsciiSearcher.INegator { return IndexOfAnyAsciiSearcher.IsVectorizationSupported && searchSpaceLength >= sizeof(ulong) - ? IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorized(ref searchSpace, searchSpaceLength, _bitmap) + ? IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorized(ref searchSpace, searchSpaceLength, _bitmap) : LastIndexOfAnyScalar(ref searchSpace, searchSpaceLength); } diff --git a/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiSearcher.cs b/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiSearcher.cs index 4cd3b5fbd5755..87296c577835d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiSearcher.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiSearcher.cs @@ -384,9 +384,8 @@ internal static int LastIndexOfAnyVectorized(ref short return -1; } - internal static int IndexOfAnyVectorized(ref byte searchSpace, int searchSpaceLength, Vector128 bitmap) + internal static int IndexOfAnyVectorized(ref byte searchSpace, int searchSpaceLength, Vector128 bitmap) where TNegator : struct, INegator - where TOptimizations : struct, IOptimizations { ref byte currentSearchSpace = ref searchSpace; @@ -408,7 +407,7 @@ internal static int IndexOfAnyVectorized(ref byte sear { Vector256 source = Vector256.LoadUnsafe(ref currentSearchSpace); - Vector256 result = IndexOfAnyLookup(source, bitmap256); + Vector256 result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap256)); if (result != Vector256.Zero) { return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, result); @@ -433,7 +432,7 @@ internal static int IndexOfAnyVectorized(ref byte sear Vector128 source1 = Vector128.LoadUnsafe(ref halfVectorAwayFromEnd); Vector256 source = Vector256.Create(source0, source1); - Vector256 result = IndexOfAnyLookup(source, bitmap256); + Vector256 result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap256)); if (result != Vector256.Zero) { return ComputeFirstIndexOverlapped(ref searchSpace, ref firstVector, ref halfVectorAwayFromEnd, result); @@ -454,7 +453,7 @@ internal static int IndexOfAnyVectorized(ref byte sear { Vector128 source = Vector128.LoadUnsafe(ref currentSearchSpace); - Vector128 result = IndexOfAnyLookup(source, bitmap); + Vector128 result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap)); if (result != Vector128.Zero) { return ComputeFirstIndex(ref searchSpace, ref currentSearchSpace, result); @@ -480,7 +479,7 @@ internal static int IndexOfAnyVectorized(ref byte sear ulong source1 = Unsafe.ReadUnaligned(ref halfVectorAwayFromEnd); Vector128 source = Vector128.Create(source0, source1).AsByte(); - Vector128 result = IndexOfAnyLookup(source, bitmap); + Vector128 result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap)); if (result != Vector128.Zero) { return ComputeFirstIndexOverlapped(ref searchSpace, ref firstVector, ref halfVectorAwayFromEnd, result); @@ -490,9 +489,8 @@ internal static int IndexOfAnyVectorized(ref byte sear return -1; } - internal static int LastIndexOfAnyVectorized(ref byte searchSpace, int searchSpaceLength, Vector128 bitmap) + internal static int LastIndexOfAnyVectorized(ref byte searchSpace, int searchSpaceLength, Vector128 bitmap) where TNegator : struct, INegator - where TOptimizations : struct, IOptimizations { ref byte currentSearchSpace = ref Unsafe.Add(ref searchSpace, searchSpaceLength); @@ -516,7 +514,7 @@ internal static int LastIndexOfAnyVectorized(ref byte Vector256 source = Vector256.LoadUnsafe(ref currentSearchSpace); - Vector256 result = IndexOfAnyLookup(source, bitmap256); + Vector256 result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap256)); if (result != Vector256.Zero) { return ComputeLastIndex(ref searchSpace, ref currentSearchSpace, result); @@ -539,7 +537,7 @@ internal static int LastIndexOfAnyVectorized(ref byte Vector128 source1 = Vector128.LoadUnsafe(ref secondVector); Vector256 source = Vector256.Create(source0, source1); - Vector256 result = IndexOfAnyLookup(source, bitmap256); + Vector256 result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap256)); if (result != Vector256.Zero) { return ComputeLastIndexOverlapped(ref searchSpace, ref secondVector, result); @@ -562,7 +560,7 @@ internal static int LastIndexOfAnyVectorized(ref byte Vector128 source = Vector128.LoadUnsafe(ref currentSearchSpace); - Vector128 result = IndexOfAnyLookup(source, bitmap); + Vector128 result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap)); if (result != Vector128.Zero) { return ComputeLastIndex(ref searchSpace, ref currentSearchSpace, result); @@ -586,7 +584,7 @@ internal static int LastIndexOfAnyVectorized(ref byte ulong source1 = Unsafe.ReadUnaligned(ref secondVector); Vector128 source = Vector128.Create(source0, source1).AsByte(); - Vector128 result = IndexOfAnyLookup(source, bitmap); + Vector128 result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap)); if (result != Vector128.Zero) { return ComputeLastIndexOverlapped(ref searchSpace, ref secondVector, result); @@ -840,23 +838,6 @@ private static Vector128 IndexOfAnyLookup(Vector return TNegator.NegateIfNeeded(result); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector128 IndexOfAnyLookup(Vector128 source, Vector128 bitmapLookup) - where TNegator : struct, INegator - where TOptimizations : struct, IOptimizations - { - Vector128 result = IndexOfAnyLookupCore(source, bitmapLookup); - - // On X86, values above 127 will map to 0. If 0 is present in the needle, we must clear the false positives. - if (TOptimizations.NeedleContainsZero) - { - Vector128 ascii = Vector128.LessThan(source, Vector128.Create((byte)128)); - result &= ascii; - } - - return TNegator.NegateIfNeeded(result); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector128 IndexOfAnyLookupCore(Vector128 source, Vector128 bitmapLookup) { @@ -903,23 +884,6 @@ private static Vector256 IndexOfAnyLookup(Vector return TNegator.NegateIfNeeded(result); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector256 IndexOfAnyLookup(Vector256 source, Vector256 bitmapLookup) - where TNegator : struct, INegator - where TOptimizations : struct, IOptimizations - { - // See comments in IndexOfAnyLookup(Vector128) above for more details. - Vector256 result = IndexOfAnyLookupCore(source, bitmapLookup); - - if (TOptimizations.NeedleContainsZero) - { - Vector256 ascii = Vector256.LessThan(source, Vector256.Create((byte)128)); - result &= ascii; - } - - return TNegator.NegateIfNeeded(result); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector256 IndexOfAnyLookupCore(Vector256 source, Vector256 bitmapLookup) { diff --git a/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyValues.cs b/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyValues.cs index 20e95c15d7523..b8ae1410ee237 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyValues.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyValues.cs @@ -56,11 +56,7 @@ public static IndexOfAnyValues Create(ReadOnlySpan values) if (IndexOfAnyAsciiSearcher.IsVectorizationSupported && maxInclusive < 128) { - IndexOfAnyAsciiSearcher.ComputeBitmap(values, out Vector128 bitmap, out BitVector256 lookup); - - return Ssse3.IsSupported && lookup.Contains(0) - ? new IndexOfAnyAsciiByteValues(bitmap, lookup) - : new IndexOfAnyAsciiByteValues(bitmap, lookup); + return new IndexOfAnyAsciiByteValues(values); } return new IndexOfAnyByteValues(values);