Skip to content

Commit 66c93ca

Browse files
authored
port SpanHelpers.IndexOf(ref char, char, int) (#73368)
1 parent a0a03e4 commit 66c93ca

1 file changed

Lines changed: 16 additions & 48 deletions

File tree

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

Lines changed: 16 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ public static unsafe int IndexOf(ref char searchSpace, char value, int length)
526526
{
527527
// Input isn't char aligned, we won't be able to align it to a Vector
528528
}
529-
else if (Sse2.IsSupported || AdvSimd.Arm64.IsSupported)
529+
else if (Vector128.IsHardwareAccelerated)
530530
{
531531
// Avx2 branch also operates on Sse2 sizes, so check is combined.
532532
// Needs to be double length to allow us to align the data first.
@@ -575,13 +575,14 @@ public static unsafe int IndexOf(ref char searchSpace, char value, int length)
575575
lengthToExamine--;
576576
}
577577

578-
// We get past SequentialScan only if IsHardwareAccelerated or intrinsic .IsSupported is true. However, we still have the redundant check to allow
578+
// We get past SequentialScan only if IsHardwareAccelerated is true. However, we still have the redundant check to allow
579579
// the JIT to see that the code is unreachable and eliminate it when the platform does not have hardware accelerated.
580-
if (Avx2.IsSupported)
580+
if (Vector256.IsHardwareAccelerated)
581581
{
582582
if (offset < length)
583583
{
584584
Debug.Assert(length - offset >= Vector128<ushort>.Count);
585+
ref ushort ushortSearchSpace = ref Unsafe.As<char, ushort>(ref searchSpace);
585586
if (((nint)Unsafe.AsPointer(ref Unsafe.Add(ref searchSpace, (nint)offset)) & (nint)(Vector256<byte>.Count - 1)) != 0)
586587
{
587588
// Not currently aligned to Vector256 (is aligned to Vector128); this can cause a problem for searches
@@ -600,10 +601,10 @@ public static unsafe int IndexOf(ref char searchSpace, char value, int length)
600601
// the misalignment that may occur after; to we default to giving the GC a free hand to relocate and
601602
// its up to the caller whether they are operating over fixed data.
602603
Vector128<ushort> values = Vector128.Create((ushort)value);
603-
Vector128<ushort> search = LoadVector128(ref searchSpace, offset);
604+
Vector128<ushort> search = Vector128.LoadUnsafe(ref ushortSearchSpace, (nuint)offset);
604605

605606
// Same method as below
606-
int matches = Sse2.MoveMask(Sse2.CompareEqual(values, search).AsByte());
607+
uint matches = Vector128.Equals(values, search).AsByte().ExtractMostSignificantBits();
607608
if (matches == 0)
608609
{
609610
// Zero flags set so no matches
@@ -624,8 +625,8 @@ public static unsafe int IndexOf(ref char searchSpace, char value, int length)
624625
{
625626
Debug.Assert(lengthToExamine >= Vector256<ushort>.Count);
626627

627-
Vector256<ushort> search = LoadVector256(ref searchSpace, offset);
628-
int matches = Avx2.MoveMask(Avx2.CompareEqual(values, search).AsByte());
628+
Vector256<ushort> search = Vector256.LoadUnsafe(ref ushortSearchSpace, (nuint)offset);
629+
uint matches = Vector256.Equals(values, search).AsByte().ExtractMostSignificantBits();
629630
// Note that MoveMask has converted the equal vector elements into a set of bit flags,
630631
// So the bit position in 'matches' corresponds to the element offset.
631632
if (matches == 0)
@@ -648,10 +649,10 @@ public static unsafe int IndexOf(ref char searchSpace, char value, int length)
648649
Debug.Assert(lengthToExamine >= Vector128<ushort>.Count);
649650

650651
Vector128<ushort> values = Vector128.Create((ushort)value);
651-
Vector128<ushort> search = LoadVector128(ref searchSpace, offset);
652+
Vector128<ushort> search = Vector128.LoadUnsafe(ref ushortSearchSpace, (nuint)offset);
652653

653654
// Same method as above
654-
int matches = Sse2.MoveMask(Sse2.CompareEqual(values, search).AsByte());
655+
uint matches = Vector128.Equals(values, search).AsByte().ExtractMostSignificantBits();
655656
if (matches == 0)
656657
{
657658
// Zero flags set so no matches
@@ -673,11 +674,12 @@ public static unsafe int IndexOf(ref char searchSpace, char value, int length)
673674
}
674675
}
675676
}
676-
else if (Sse2.IsSupported)
677+
else if (Vector128.IsHardwareAccelerated)
677678
{
678679
if (offset < length)
679680
{
680681
Debug.Assert(length - offset >= Vector128<ushort>.Count);
682+
ref ushort ushortSearchSpace = ref Unsafe.As<char, ushort>(ref searchSpace);
681683

682684
lengthToExamine = GetCharVector128SpanLength(offset, length);
683685
if (lengthToExamine > 0)
@@ -687,11 +689,11 @@ public static unsafe int IndexOf(ref char searchSpace, char value, int length)
687689
{
688690
Debug.Assert(lengthToExamine >= Vector128<ushort>.Count);
689691

690-
Vector128<ushort> search = LoadVector128(ref searchSpace, offset);
692+
Vector128<ushort> search = Vector128.LoadUnsafe(ref ushortSearchSpace, (uint)offset);
691693

692694
// Same method as above
693-
int matches = Sse2.MoveMask(Sse2.CompareEqual(values, search).AsByte());
694-
if (matches == 0)
695+
Vector128<ushort> compareResult = Vector128.Equals(values, search);
696+
if (compareResult == Vector128<ushort>.Zero)
695697
{
696698
// Zero flags set so no matches
697699
offset += Vector128<ushort>.Count;
@@ -701,6 +703,7 @@ public static unsafe int IndexOf(ref char searchSpace, char value, int length)
701703

702704
// Find bitflag offset of first match and add to current offset,
703705
// flags are in bytes so divide for chars
706+
uint matches = compareResult.AsByte().ExtractMostSignificantBits();
704707
return (int)(offset + ((uint)BitOperations.TrailingZeroCount(matches) / sizeof(char)));
705708
} while (lengthToExamine > 0);
706709
}
@@ -712,41 +715,6 @@ public static unsafe int IndexOf(ref char searchSpace, char value, int length)
712715
}
713716
}
714717
}
715-
else if (AdvSimd.Arm64.IsSupported)
716-
{
717-
if (offset < length)
718-
{
719-
Debug.Assert(length - offset >= Vector128<ushort>.Count);
720-
721-
lengthToExamine = GetCharVector128SpanLength(offset, length);
722-
if (lengthToExamine > 0)
723-
{
724-
Vector128<ushort> values = Vector128.Create((ushort)value);
725-
do
726-
{
727-
Debug.Assert(lengthToExamine >= Vector128<ushort>.Count);
728-
729-
Vector128<ushort> search = LoadVector128(ref searchSpace, offset);
730-
Vector128<ushort> compareResult = AdvSimd.CompareEqual(values, search);
731-
732-
if (compareResult == Vector128<ushort>.Zero)
733-
{
734-
offset += Vector128<ushort>.Count;
735-
lengthToExamine -= Vector128<ushort>.Count;
736-
continue;
737-
}
738-
739-
return (int)(offset + FindFirstMatchedLane(compareResult));
740-
} while (lengthToExamine > 0);
741-
}
742-
743-
if (offset < length)
744-
{
745-
lengthToExamine = length - offset;
746-
goto SequentialScan;
747-
}
748-
}
749-
}
750718
else if (Vector.IsHardwareAccelerated)
751719
{
752720
if (offset < length)

0 commit comments

Comments
 (0)