Skip to content

Commit 73cf30d

Browse files
authored
port SpanHelpers.IndexOfAny(ref byte, byte, byte, int) to Vector128/256 (#73384)
1 parent 66c93ca commit 73cf30d

1 file changed

Lines changed: 21 additions & 76 deletions

File tree

src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Byte.cs

Lines changed: 21 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,7 @@ public static int IndexOfAny(ref byte searchSpace, byte value0, byte value1, int
781781
nuint offset = 0; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations
782782
nuint lengthToExamine = (nuint)(uint)length;
783783

784-
if (Sse2.IsSupported || AdvSimd.Arm64.IsSupported)
784+
if (Vector128.IsHardwareAccelerated)
785785
{
786786
// Avx2 branch also operates on Sse2 sizes, so check is combined.
787787
nint vectorDiff = (nint)length - Vector128<byte>.Count;
@@ -897,10 +897,10 @@ public static int IndexOfAny(ref byte searchSpace, byte value0, byte value1, int
897897
// the end and forwards, which may overlap on an earlier compare.
898898

899899
// We include the Supported check again here even though path will not be taken, so the asm isn't generated if not supported.
900-
if (Sse2.IsSupported)
900+
if (Vector128.IsHardwareAccelerated)
901901
{
902-
int matches;
903-
if (Avx2.IsSupported)
902+
uint matches;
903+
if (Vector256.IsHardwareAccelerated)
904904
{
905905
Vector256<byte> search;
906906
// Guard as we may only have a valid size for Vector128; when we will move to the Sse2
@@ -916,13 +916,10 @@ public static int IndexOfAny(ref byte searchSpace, byte value0, byte value1, int
916916
// First time this checks again against 0, however we will move into final compare if it fails.
917917
while (lengthToExamine > offset)
918918
{
919-
search = LoadVector256(ref searchSpace, offset);
919+
search = Vector256.LoadUnsafe(ref searchSpace, offset);
920920
// Bitwise Or to combine the flagged matches for the second value to our match flags
921-
matches = Avx2.MoveMask(
922-
Avx2.Or(
923-
Avx2.CompareEqual(values0, search),
924-
Avx2.CompareEqual(values1, search)));
925-
// Note that MoveMask has converted the equal vector elements into a set of bit flags,
921+
matches = (Vector256.Equals(values0, search) | Vector256.Equals(values1, search)).ExtractMostSignificantBits();
922+
// Note that ExtractMostSignificantBits has converted the equal vector elements into a set of bit flags,
926923
// So the bit position in 'matches' corresponds to the element offset.
927924
if (matches == 0)
928925
{
@@ -935,13 +932,10 @@ public static int IndexOfAny(ref byte searchSpace, byte value0, byte value1, int
935932
}
936933

937934
// Move to Vector length from end for final compare
938-
search = LoadVector256(ref searchSpace, lengthToExamine);
935+
search = Vector256.LoadUnsafe(ref searchSpace, lengthToExamine);
939936
offset = lengthToExamine;
940937
// Same as method as above
941-
matches = Avx2.MoveMask(
942-
Avx2.Or(
943-
Avx2.CompareEqual(values0, search),
944-
Avx2.CompareEqual(values1, search)));
938+
matches = (Vector256.Equals(values0, search) | Vector256.Equals(values1, search)).ExtractMostSignificantBits();
945939
if (matches == 0)
946940
{
947941
// None matched
@@ -953,6 +947,7 @@ public static int IndexOfAny(ref byte searchSpace, byte value0, byte value1, int
953947
}
954948

955949
// Initial size check was done on method entry.
950+
Vector128<byte> compareResult;
956951
Debug.Assert(length >= Vector128<byte>.Count);
957952
{
958953
Vector128<byte> search;
@@ -961,90 +956,40 @@ public static int IndexOfAny(ref byte searchSpace, byte value0, byte value1, int
961956
// First time this checks against 0 and we will move into final compare if it fails.
962957
while (lengthToExamine > offset)
963958
{
964-
search = LoadVector128(ref searchSpace, offset);
959+
search = Vector128.LoadUnsafe(ref searchSpace, offset);
965960

966-
matches = Sse2.MoveMask(
967-
Sse2.Or(
968-
Sse2.CompareEqual(values0, search),
969-
Sse2.CompareEqual(values1, search))
970-
.AsByte());
971-
// Note that MoveMask has converted the equal vector elements into a set of bit flags,
972-
// So the bit position in 'matches' corresponds to the element offset.
973-
if (matches == 0)
961+
compareResult = Vector128.Equals(values0, search) | Vector128.Equals(values1, search);
962+
963+
if (compareResult == Vector128<byte>.Zero)
974964
{
975965
// None matched
976966
offset += (nuint)Vector128<byte>.Count;
977967
continue;
978968
}
979969

970+
matches = compareResult.ExtractMostSignificantBits();
980971
goto IntrinsicsMatch;
981972
}
982973
// Move to Vector length from end for final compare
983-
search = LoadVector128(ref searchSpace, lengthToExamine);
974+
search = Vector128.LoadUnsafe(ref searchSpace, lengthToExamine);
984975
offset = lengthToExamine;
985976
// Same as method as above
986-
matches = Sse2.MoveMask(
987-
Sse2.Or(
988-
Sse2.CompareEqual(values0, search),
989-
Sse2.CompareEqual(values1, search)));
990-
if (matches == 0)
977+
compareResult = Vector128.Equals(values0, search) | Vector128.Equals(values1, search);
978+
979+
if (compareResult == Vector128<byte>.Zero)
991980
{
992981
// None matched
993982
goto NotFound;
994983
}
984+
985+
matches = compareResult.ExtractMostSignificantBits();
995986
}
996987

997988
IntrinsicsMatch:
998989
// Find bitflag offset of first difference and add to current offset
999990
offset += (nuint)BitOperations.TrailingZeroCount(matches);
1000991
goto Found;
1001992
}
1002-
else if (AdvSimd.Arm64.IsSupported)
1003-
{
1004-
Vector128<byte> search;
1005-
Vector128<byte> matches;
1006-
Vector128<byte> values0 = Vector128.Create(value0);
1007-
Vector128<byte> values1 = Vector128.Create(value1);
1008-
// First time this checks against 0 and we will move into final compare if it fails.
1009-
while (lengthToExamine > offset)
1010-
{
1011-
search = LoadVector128(ref searchSpace, offset);
1012-
1013-
matches = AdvSimd.Or(
1014-
AdvSimd.CompareEqual(values0, search),
1015-
AdvSimd.CompareEqual(values1, search));
1016-
1017-
if (matches == Vector128<byte>.Zero)
1018-
{
1019-
offset += (nuint)Vector128<byte>.Count;
1020-
continue;
1021-
}
1022-
1023-
// Find bitflag offset of first match and add to current offset
1024-
offset += FindFirstMatchedLane(matches);
1025-
1026-
goto Found;
1027-
}
1028-
1029-
// Move to Vector length from end for final compare
1030-
search = LoadVector128(ref searchSpace, lengthToExamine);
1031-
offset = lengthToExamine;
1032-
// Same as method as above
1033-
matches = AdvSimd.Or(
1034-
AdvSimd.CompareEqual(values0, search),
1035-
AdvSimd.CompareEqual(values1, search));
1036-
1037-
if (matches == Vector128<byte>.Zero)
1038-
{
1039-
// None matched
1040-
goto NotFound;
1041-
}
1042-
1043-
// Find bitflag offset of first match and add to current offset
1044-
offset += FindFirstMatchedLane(matches);
1045-
1046-
goto Found;
1047-
}
1048993
else if (Vector.IsHardwareAccelerated)
1049994
{
1050995
Vector<byte> values0 = new Vector<byte>(value0);

0 commit comments

Comments
 (0)