diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs index e19298acef92f2..93b30ec96795bb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs @@ -2068,20 +2068,7 @@ internal static void MakeSeparatorListAny(ReadOnlySpan source, ReadOnlySpa sep0 = separators[0]; sep1 = separators.Length > 1 ? separators[1] : sep0; sep2 = separators.Length > 2 ? separators[2] : sep1; - if (Vector128.IsHardwareAccelerated && source.Length >= Vector128.Count * 2) - { - MakeSeparatorListVectorized(source, ref sepListBuilder, sep0, sep1, sep2); - return; - } - - for (int i = 0; i < source.Length; i++) - { - char c = source[i]; - if (c == sep0 || c == sep1 || c == sep2) - { - sepListBuilder.Append(i); - } - } + MakeSeparatorListFewChars(source, ref sepListBuilder, sep0, sep1, sep2); } // Handle > 3 separators with a probabilistic map, ala IndexOfAny. @@ -2101,14 +2088,22 @@ internal static void MakeSeparatorListAny(ReadOnlySpan source, ReadOnlySpa } } - private static void MakeSeparatorListVectorized(ReadOnlySpan sourceSpan, ref ValueListBuilder sepListBuilder, char c, char c2, char c3) + private static void MakeSeparatorListFewChars(ReadOnlySpan sourceSpan, ref ValueListBuilder sepListBuilder, char c, char c2, char c3) { - // Redundant test so we won't prejit remainder of this method - // on platforms where it is not supported - if (!Vector128.IsHardwareAccelerated) + if (!Vector128.IsHardwareAccelerated || (uint)sourceSpan.Length < (uint)Vector128.Count*2) { - throw new PlatformNotSupportedException(); + for (int i = 0; i < sourceSpan.Length; i++) + { + char v = sourceSpan[i]; + if (v == c || v == c2 || v == c3) + { + sepListBuilder.Append(i); + } + } + + return; } + Debug.Assert(sourceSpan.Length >= Vector128.Count*2); int baseIndex = 0; ReadOnlySpan sourceSpanUInt16 = MemoryMarshal.Cast(sourceSpan); @@ -2198,16 +2193,20 @@ private static void MakeSeparatorListVectorized(ReadOnlySpan sourceSpan, r { Vector512 vector = Vector512.Create(sourceSpanUInt16.Slice(sourceSpanUInt16.Length - Vector512.Count)); Vector512 cmp = Vector512.Equals(vector, v1).AsByte() | Vector512.Equals(vector, v2).AsByte() | Vector512.Equals(vector, v3).AsByte(); - int finalIndex = sourceSpanUInt16.Length - Vector512.Count; - ulong mask = cmp.ExtractMostSignificantBits() & 0x5555555555555555 & ~((1UL << (Vector512.Count - remaining.Length * sizeof(char))) - 1); - while (mask != 0) + if (cmp != Vector512.Zero) { - uint bitPos = (uint)BitOperations.TrailingZeroCount(mask) / sizeof(char); - sepListBuilder.Append(finalIndex + (int)bitPos); - mask = BitOperations.ResetLowestSetBit(mask); + int finalIndex = sourceSpanUInt16.Length - Vector512.Count; + ulong mask = cmp.ExtractMostSignificantBits() & 0x5555555555555555 & ~((1UL << (Vector512.Count - remaining.Length * sizeof(char))) - 1); + while (mask != 0) + { + uint bitPos = (uint)BitOperations.TrailingZeroCount(mask) / sizeof(char); + sepListBuilder.Append(finalIndex + (int)bitPos); + mask = BitOperations.ResetLowestSetBit(mask); + } } + + return; } - return; } else if (Vector256.IsHardwareAccelerated && (uint)remaining.Length >= (uint)Vector256.Count*2) { @@ -2293,19 +2292,24 @@ private static void MakeSeparatorListVectorized(ReadOnlySpan sourceSpan, r { Vector256 vector = Vector256.Create(sourceSpanUInt16.Slice(sourceSpanUInt16.Length - Vector256.Count)); Vector256 cmp = Vector256.Equals(vector, v1).AsByte() | Vector256.Equals(vector, v2).AsByte() | Vector256.Equals(vector, v3).AsByte(); - int finalIndex = sourceSpanUInt16.Length - Vector256.Count; - uint mask = cmp.ExtractMostSignificantBits() & 0x55555555 & ~((1u << (Vector256.Count - remaining.Length * sizeof(char))) - 1); - while (mask != 0) + if (cmp != Vector256.Zero) { - uint bitPos = (uint)BitOperations.TrailingZeroCount(mask) / sizeof(char); - sepListBuilder.Append(finalIndex + (int)bitPos); - mask = BitOperations.ResetLowestSetBit(mask); + int finalIndex = sourceSpanUInt16.Length - Vector256.Count; + uint mask = cmp.ExtractMostSignificantBits() & 0x55555555 & ~((1u << (Vector256.Count - remaining.Length * sizeof(char))) - 1); + while (mask != 0) + { + uint bitPos = (uint)BitOperations.TrailingZeroCount(mask) / sizeof(char); + sepListBuilder.Append(finalIndex + (int)bitPos); + mask = BitOperations.ResetLowestSetBit(mask); + } } } - return; } - else if (Vector128.IsHardwareAccelerated) + else { + Debug.Assert(Vector128.IsHardwareAccelerated); + Debug.Assert(remaining.Length >= Vector128.Count*2); + Vector128 v1 = Vector128.Create((ushort)c); Vector128 v2 = Vector128.Create((ushort)c2); Vector128 v3 = Vector128.Create((ushort)c3); @@ -2388,19 +2392,19 @@ private static void MakeSeparatorListVectorized(ReadOnlySpan sourceSpan, r { Vector128 vector = Vector128.Create(sourceSpanUInt16.Slice(sourceSpanUInt16.Length - Vector128.Count)); Vector128 cmp = Vector128.Equals(vector, v1).AsByte() | Vector128.Equals(vector, v2).AsByte() | Vector128.Equals(vector, v3).AsByte(); - int finalIndex = sourceSpanUInt16.Length - Vector128.Count; - uint mask = cmp.ExtractMostSignificantBits() & 0x5555 & ~((1u << (Vector128.Count - remaining.Length * sizeof(char))) - 1); - while (mask != 0) + if (cmp != Vector128.Zero) { - uint bitPos = (uint)BitOperations.TrailingZeroCount(mask) / sizeof(char); - sepListBuilder.Append(finalIndex + (int)bitPos); - mask = BitOperations.ResetLowestSetBit(mask); + int finalIndex = sourceSpanUInt16.Length - Vector128.Count; + uint mask = cmp.ExtractMostSignificantBits() & 0x5555 & ~((1u << (Vector128.Count - remaining.Length * sizeof(char))) - 1); + while (mask != 0) + { + uint bitPos = (uint)BitOperations.TrailingZeroCount(mask) / sizeof(char); + sepListBuilder.Append(finalIndex + (int)bitPos); + mask = BitOperations.ResetLowestSetBit(mask); + } } } - return; } - - Debug.Fail("We should not be able to reach this point of MakeSeparatorListVectorized."); } ///