diff --git a/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs b/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs index 3b8cdfb235cf..eb5af044b861 100644 --- a/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs +++ b/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs @@ -1384,19 +1384,118 @@ public static unsafe int SequenceCompareTo(ref byte first, int firstLength, ref IntPtr i = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations IntPtr n = (IntPtr)(void*)minLength; - if (Vector.IsHardwareAccelerated && (byte*)n > (byte*)Vector.Count) + if (Avx2.IsSupported) { - n -= Vector.Count; - while ((byte*)n > (byte*)i) + if ((byte*)n >= (byte*)Vector256.Count) { - if (Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref first, i)) != - Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref second, i))) + n -= Vector256.Count; + int matches; + while ((byte*)n > (byte*)i) { - goto NotEqual; + matches = Avx2.MoveMask(Avx2.CompareEqual( + Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref first, i)), + Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref second, i)))); + if (matches == -1) + { + // All matched + i += Vector256.Count; + continue; + } + + goto Difference; } - i += Vector.Count; + // Move to Vector length from end for final compare + i = n; + matches = Avx2.MoveMask(Avx2.CompareEqual( + Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref first, i)), + Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref second, i)))); + if (matches == -1) + { + // All matched + goto Equal; + } + Difference: + // Invert matches to find differences + int differences = ~matches; + if (Bmi1.IsSupported) + { + i = (IntPtr)((int)(byte*)i) + (int)Bmi1.TrailingZeroCount((uint)differences); + } + else + { + i = (IntPtr)(int)(byte*)i + TrailingZeroCountFallback(differences); + } + + int result = Unsafe.AddByteOffset(ref first, i).CompareTo(Unsafe.AddByteOffset(ref second, i)); + Debug.Assert(result != 0); + + return result; + } + } + else if (Sse2.IsSupported) + { + if ((byte*)n >= (byte*)Vector128.Count) + { + n -= Vector128.Count; + int matches; + while ((byte*)n > (byte*)i) + { + matches = Sse2.MoveMask(Sse2.CompareEqual( + Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref first, i)), + Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref second, i)))); + if (matches == 0xFFFF) + { + // All matched + i += Vector128.Count; + continue; + } + + goto Difference; + } + // Move to Vector length from end for final compare + i = n; + matches = Sse2.MoveMask(Sse2.CompareEqual( + Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref first, i)), + Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref second, i)))); + if (matches == 0xFFFF) + { + // All matched + goto Equal; + } + Difference: + // Invert matches to find differences + int differences = ~matches; + if (Bmi1.IsSupported) + { + i = (IntPtr)((int)(byte*)i) + (int)Bmi1.TrailingZeroCount((uint)differences); + } + else + { + i = (IntPtr)(int)(byte*)i + TrailingZeroCountFallback(differences); + } + + int result = Unsafe.AddByteOffset(ref first, i).CompareTo(Unsafe.AddByteOffset(ref second, i)); + Debug.Assert(result != 0); + + return result; + } + } + else if (Vector.IsHardwareAccelerated) + { + if ((byte*) n > (byte*)Vector.Count) + { + n -= Vector.Count; + while ((byte*)n > (byte*)i) + { + if (Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref first, i)) != + Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref second, i))) + { + goto NotEqual; + } + i += Vector.Count; + } + goto NotEqual; } - goto NotEqual; } if ((byte*)n > (byte*)sizeof(UIntPtr))