Simplify IndexOfAnyAsciiByteValues for needles with 0 on X86 (#82866)
authorMiha Zupan <mihazupan.zupan1@gmail.com>
Thu, 2 Mar 2023 14:21:20 +0000 (15:21 +0100)
committerGitHub <noreply@github.com>
Thu, 2 Mar 2023 14:21:20 +0000 (06:21 -0800)
src/libraries/System.Memory/tests/Span/IndexOfAnyValues.cs
src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiByteValues.cs
src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiSearcher.cs
src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyValues.cs

index 4ca29be..44dda73 100644 (file)
@@ -496,8 +496,8 @@ namespace System.SpanTests
             private static void AssertionFailed<T>(ReadOnlySpan<T> haystack, ReadOnlySpan<T> needle, int expected, int actual, string approach)
                 where T : INumber<T>
             {
-                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}'");
             }
index 3a214b4..7a502d2 100644 (file)
@@ -7,17 +7,13 @@ using System.Runtime.Intrinsics;
 
 namespace System.Buffers
 {
-    internal sealed class IndexOfAnyAsciiByteValues<TOptimizations> : IndexOfAnyValues<byte>
-        where TOptimizations : struct, IndexOfAnyAsciiSearcher.IOptimizations
+    internal sealed class IndexOfAnyAsciiByteValues : IndexOfAnyValues<byte>
     {
         private readonly Vector128<byte> _bitmap;
         private readonly BitVector256 _lookup;
 
-        public IndexOfAnyAsciiByteValues(Vector128<byte> bitmap, BitVector256 lookup)
-        {
-            _bitmap = bitmap;
-            _lookup = lookup;
-        }
+        public IndexOfAnyAsciiByteValues(ReadOnlySpan<byte> values) =>
+            IndexOfAnyAsciiSearcher.ComputeBitmap(values, out _bitmap, out _lookup);
 
         internal override byte[] GetValues() => _lookup.GetByteValues();
 
@@ -46,7 +42,7 @@ namespace System.Buffers
             where TNegator : struct, IndexOfAnyAsciiSearcher.INegator
         {
             return IndexOfAnyAsciiSearcher.IsVectorizationSupported && searchSpaceLength >= sizeof(ulong)
-                ? IndexOfAnyAsciiSearcher.IndexOfAnyVectorized<TNegator, TOptimizations>(ref searchSpace, searchSpaceLength, _bitmap)
+                ? IndexOfAnyAsciiSearcher.IndexOfAnyVectorized<TNegator>(ref searchSpace, searchSpaceLength, _bitmap)
                 : IndexOfAnyScalar<TNegator>(ref searchSpace, searchSpaceLength);
         }
 
@@ -55,7 +51,7 @@ namespace System.Buffers
             where TNegator : struct, IndexOfAnyAsciiSearcher.INegator
         {
             return IndexOfAnyAsciiSearcher.IsVectorizationSupported && searchSpaceLength >= sizeof(ulong)
-                ? IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorized<TNegator, TOptimizations>(ref searchSpace, searchSpaceLength, _bitmap)
+                ? IndexOfAnyAsciiSearcher.LastIndexOfAnyVectorized<TNegator>(ref searchSpace, searchSpaceLength, _bitmap)
                 : LastIndexOfAnyScalar<TNegator>(ref searchSpace, searchSpaceLength);
         }
 
index 4cd3b5f..87296c5 100644 (file)
@@ -384,9 +384,8 @@ namespace System.Buffers
             return -1;
         }
 
-        internal static int IndexOfAnyVectorized<TNegator, TOptimizations>(ref byte searchSpace, int searchSpaceLength, Vector128<byte> bitmap)
+        internal static int IndexOfAnyVectorized<TNegator>(ref byte searchSpace, int searchSpaceLength, Vector128<byte> bitmap)
             where TNegator : struct, INegator
-            where TOptimizations : struct, IOptimizations
         {
             ref byte currentSearchSpace = ref searchSpace;
 
@@ -408,7 +407,7 @@ namespace System.Buffers
                         {
                             Vector256<byte> source = Vector256.LoadUnsafe(ref currentSearchSpace);
 
-                            Vector256<byte> result = IndexOfAnyLookup<TNegator, TOptimizations>(source, bitmap256);
+                            Vector256<byte> result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap256));
                             if (result != Vector256<byte>.Zero)
                             {
                                 return ComputeFirstIndex<byte, TNegator>(ref searchSpace, ref currentSearchSpace, result);
@@ -433,7 +432,7 @@ namespace System.Buffers
                         Vector128<byte> source1 = Vector128.LoadUnsafe(ref halfVectorAwayFromEnd);
                         Vector256<byte> source = Vector256.Create(source0, source1);
 
-                        Vector256<byte> result = IndexOfAnyLookup<TNegator, TOptimizations>(source, bitmap256);
+                        Vector256<byte> result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap256));
                         if (result != Vector256<byte>.Zero)
                         {
                             return ComputeFirstIndexOverlapped<byte, TNegator>(ref searchSpace, ref firstVector, ref halfVectorAwayFromEnd, result);
@@ -454,7 +453,7 @@ namespace System.Buffers
                     {
                         Vector128<byte> source = Vector128.LoadUnsafe(ref currentSearchSpace);
 
-                        Vector128<byte> result = IndexOfAnyLookup<TNegator, TOptimizations>(source, bitmap);
+                        Vector128<byte> result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap));
                         if (result != Vector128<byte>.Zero)
                         {
                             return ComputeFirstIndex<byte, TNegator>(ref searchSpace, ref currentSearchSpace, result);
@@ -480,7 +479,7 @@ namespace System.Buffers
                 ulong source1 = Unsafe.ReadUnaligned<ulong>(ref halfVectorAwayFromEnd);
                 Vector128<byte> source = Vector128.Create(source0, source1).AsByte();
 
-                Vector128<byte> result = IndexOfAnyLookup<TNegator, TOptimizations>(source, bitmap);
+                Vector128<byte> result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap));
                 if (result != Vector128<byte>.Zero)
                 {
                     return ComputeFirstIndexOverlapped<byte, TNegator>(ref searchSpace, ref firstVector, ref halfVectorAwayFromEnd, result);
@@ -490,9 +489,8 @@ namespace System.Buffers
             return -1;
         }
 
-        internal static int LastIndexOfAnyVectorized<TNegator, TOptimizations>(ref byte searchSpace, int searchSpaceLength, Vector128<byte> bitmap)
+        internal static int LastIndexOfAnyVectorized<TNegator>(ref byte searchSpace, int searchSpaceLength, Vector128<byte> bitmap)
             where TNegator : struct, INegator
-            where TOptimizations : struct, IOptimizations
         {
             ref byte currentSearchSpace = ref Unsafe.Add(ref searchSpace, searchSpaceLength);
 
@@ -516,7 +514,7 @@ namespace System.Buffers
 
                             Vector256<byte> source = Vector256.LoadUnsafe(ref currentSearchSpace);
 
-                            Vector256<byte> result = IndexOfAnyLookup<TNegator, TOptimizations>(source, bitmap256);
+                            Vector256<byte> result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap256));
                             if (result != Vector256<byte>.Zero)
                             {
                                 return ComputeLastIndex<byte, TNegator>(ref searchSpace, ref currentSearchSpace, result);
@@ -539,7 +537,7 @@ namespace System.Buffers
                         Vector128<byte> source1 = Vector128.LoadUnsafe(ref secondVector);
                         Vector256<byte> source = Vector256.Create(source0, source1);
 
-                        Vector256<byte> result = IndexOfAnyLookup<TNegator, TOptimizations>(source, bitmap256);
+                        Vector256<byte> result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap256));
                         if (result != Vector256<byte>.Zero)
                         {
                             return ComputeLastIndexOverlapped<byte, TNegator>(ref searchSpace, ref secondVector, result);
@@ -562,7 +560,7 @@ namespace System.Buffers
 
                         Vector128<byte> source = Vector128.LoadUnsafe(ref currentSearchSpace);
 
-                        Vector128<byte> result = IndexOfAnyLookup<TNegator, TOptimizations>(source, bitmap);
+                        Vector128<byte> result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap));
                         if (result != Vector128<byte>.Zero)
                         {
                             return ComputeLastIndex<byte, TNegator>(ref searchSpace, ref currentSearchSpace, result);
@@ -586,7 +584,7 @@ namespace System.Buffers
                 ulong source1 = Unsafe.ReadUnaligned<ulong>(ref secondVector);
                 Vector128<byte> source = Vector128.Create(source0, source1).AsByte();
 
-                Vector128<byte> result = IndexOfAnyLookup<TNegator, TOptimizations>(source, bitmap);
+                Vector128<byte> result = TNegator.NegateIfNeeded(IndexOfAnyLookupCore(source, bitmap));
                 if (result != Vector128<byte>.Zero)
                 {
                     return ComputeLastIndexOverlapped<byte, TNegator>(ref searchSpace, ref secondVector, result);
@@ -841,23 +839,6 @@ namespace System.Buffers
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        private static Vector128<byte> IndexOfAnyLookup<TNegator, TOptimizations>(Vector128<byte> source, Vector128<byte> bitmapLookup)
-            where TNegator : struct, INegator
-            where TOptimizations : struct, IOptimizations
-        {
-            Vector128<byte> 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<byte> ascii = Vector128.LessThan(source, Vector128.Create((byte)128));
-                result &= ascii;
-            }
-
-            return TNegator.NegateIfNeeded(result);
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static Vector128<byte> IndexOfAnyLookupCore(Vector128<byte> source, Vector128<byte> bitmapLookup)
         {
             // On X86, the Ssse3.Shuffle instruction will already perform an implicit 'AND 0xF' on the indices, so we can skip it.
@@ -904,23 +885,6 @@ namespace System.Buffers
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        private static Vector256<byte> IndexOfAnyLookup<TNegator, TOptimizations>(Vector256<byte> source, Vector256<byte> bitmapLookup)
-            where TNegator : struct, INegator
-            where TOptimizations : struct, IOptimizations
-        {
-            // See comments in IndexOfAnyLookup(Vector128<byte>) above for more details.
-            Vector256<byte> result = IndexOfAnyLookupCore(source, bitmapLookup);
-
-            if (TOptimizations.NeedleContainsZero)
-            {
-                Vector256<byte> ascii = Vector256.LessThan(source, Vector256.Create((byte)128));
-                result &= ascii;
-            }
-
-            return TNegator.NegateIfNeeded(result);
-        }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static Vector256<byte> IndexOfAnyLookupCore(Vector256<byte> source, Vector256<byte> bitmapLookup)
         {
             // See comments in IndexOfAnyLookupCore(Vector128<byte>) above for more details.
index 20e95c1..b8ae141 100644 (file)
@@ -56,11 +56,7 @@ namespace System.Buffers
 
             if (IndexOfAnyAsciiSearcher.IsVectorizationSupported && maxInclusive < 128)
             {
-                IndexOfAnyAsciiSearcher.ComputeBitmap(values, out Vector128<byte> bitmap, out BitVector256 lookup);
-
-                return Ssse3.IsSupported && lookup.Contains(0)
-                    ? new IndexOfAnyAsciiByteValues<IndexOfAnyAsciiSearcher.Ssse3HandleZeroInNeedle>(bitmap, lookup)
-                    : new IndexOfAnyAsciiByteValues<IndexOfAnyAsciiSearcher.Default>(bitmap, lookup);
+                return new IndexOfAnyAsciiByteValues(values);
             }
 
             return new IndexOfAnyByteValues(values);