6
6
using System . Numerics ;
7
7
using System . Runtime . CompilerServices ;
8
8
using System . Runtime . Intrinsics ;
9
- using System . Runtime . Intrinsics . Arm ;
10
9
using System . Runtime . Intrinsics . X86 ;
11
10
12
11
#pragma warning disable IDE0060 // https://github.com/dotnet/roslyn-analyzers/issues/6228
@@ -19,53 +18,51 @@ namespace System
19
18
// included in this file which are specific to the packed implementation.
20
19
internal static partial class PackedSpanHelpers
21
20
{
22
- public static bool PackedIndexOfIsSupported => Sse2 . IsSupported || AdvSimd . IsSupported ;
21
+ // We only do this optimization on X86 as the packing is noticeably more expensive on ARM in comparison.
22
+ // While the impact on worst-case (match at the start) is minimal on X86, it's prohibitively large on ARM.
23
+ public static bool PackedIndexOfIsSupported => Sse2 . IsSupported ;
23
24
24
25
// Not all values can benefit from packing the searchSpace. See comments in PackSources below.
25
- // On X86, the values must be in the [1, 254] range.
26
- // On ARM, the values must be in the [0, 254] range.
27
26
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
28
27
public static unsafe bool CanUsePackedIndexOf < T > ( T value ) =>
29
28
PackedIndexOfIsSupported &&
30
29
RuntimeHelpers . IsBitwiseEquatable < T > ( ) &&
31
30
sizeof ( T ) == sizeof ( ushort ) &&
32
- ( Sse2 . IsSupported
33
- ? * ( ushort * ) & value - 1u < 254u
34
- : * ( ushort * ) & value < 255u ) ;
31
+ * ( ushort * ) & value - 1u < 254u ;
35
32
36
33
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
37
- public static int PackedIndexOf ( ref char searchSpace , char value , int length ) =>
38
- PackedIndexOf < SpanHelpers . DontNegate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) value , length ) ;
34
+ public static int IndexOf ( ref char searchSpace , char value , int length ) =>
35
+ IndexOf < SpanHelpers . DontNegate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) value , length ) ;
39
36
40
37
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
41
- public static int PackedIndexOfAnyExcept ( ref char searchSpace , char value , int length ) =>
42
- PackedIndexOf < SpanHelpers . Negate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) value , length ) ;
38
+ public static int IndexOfAnyExcept ( ref char searchSpace , char value , int length ) =>
39
+ IndexOf < SpanHelpers . Negate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) value , length ) ;
43
40
44
41
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
45
- public static int PackedIndexOfAny ( ref char searchSpace , char value0 , char value1 , int length ) =>
46
- PackedIndexOfAny < SpanHelpers . DontNegate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) value0 , ( short ) value1 , length ) ;
42
+ public static int IndexOfAny ( ref char searchSpace , char value0 , char value1 , int length ) =>
43
+ IndexOfAny < SpanHelpers . DontNegate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) value0 , ( short ) value1 , length ) ;
47
44
48
45
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
49
- public static int PackedIndexOfAnyExcept ( ref char searchSpace , char value0 , char value1 , int length ) =>
50
- PackedIndexOfAny < SpanHelpers . Negate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) value0 , ( short ) value1 , length ) ;
46
+ public static int IndexOfAnyExcept ( ref char searchSpace , char value0 , char value1 , int length ) =>
47
+ IndexOfAny < SpanHelpers . Negate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) value0 , ( short ) value1 , length ) ;
51
48
52
49
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
53
- public static int PackedIndexOfAny ( ref char searchSpace , char value0 , char value1 , char value2 , int length ) =>
54
- PackedIndexOfAny < SpanHelpers . DontNegate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) value0 , ( short ) value1 , ( short ) value2 , length ) ;
50
+ public static int IndexOfAny ( ref char searchSpace , char value0 , char value1 , char value2 , int length ) =>
51
+ IndexOfAny < SpanHelpers . DontNegate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) value0 , ( short ) value1 , ( short ) value2 , length ) ;
55
52
56
53
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
57
- public static int PackedIndexOfAnyExcept ( ref char searchSpace , char value0 , char value1 , char value2 , int length ) =>
58
- PackedIndexOfAny < SpanHelpers . Negate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) value0 , ( short ) value1 , ( short ) value2 , length ) ;
54
+ public static int IndexOfAnyExcept ( ref char searchSpace , char value0 , char value1 , char value2 , int length ) =>
55
+ IndexOfAny < SpanHelpers . Negate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) value0 , ( short ) value1 , ( short ) value2 , length ) ;
59
56
60
57
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
61
- public static int PackedIndexOfAnyInRange ( ref char searchSpace , char lowInclusive , char rangeInclusive , int length ) =>
62
- PackedIndexOfAnyInRange < SpanHelpers . DontNegate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) lowInclusive , ( short ) rangeInclusive , length ) ;
58
+ public static int IndexOfAnyInRange ( ref char searchSpace , char lowInclusive , char rangeInclusive , int length ) =>
59
+ IndexOfAnyInRange < SpanHelpers . DontNegate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) lowInclusive , ( short ) rangeInclusive , length ) ;
63
60
64
61
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
65
- public static int PackedIndexOfAnyExceptInRange ( ref char searchSpace , char lowInclusive , char rangeInclusive , int length ) =>
66
- PackedIndexOfAnyInRange < SpanHelpers . Negate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) lowInclusive , ( short ) rangeInclusive , length ) ;
62
+ public static int IndexOfAnyExceptInRange ( ref char searchSpace , char lowInclusive , char rangeInclusive , int length ) =>
63
+ IndexOfAnyInRange < SpanHelpers . Negate < short > > ( ref Unsafe . As < char , short > ( ref searchSpace ) , ( short ) lowInclusive , ( short ) rangeInclusive , length ) ;
67
64
68
- public static bool PackedContains ( ref short searchSpace , short value , int length )
65
+ public static bool Contains ( ref short searchSpace , short value , int length )
69
66
{
70
67
Debug . Assert ( CanUsePackedIndexOf ( value ) ) ;
71
68
@@ -207,7 +204,7 @@ public static bool PackedContains(ref short searchSpace, short value, int length
207
204
return false;
208
205
}
209
206
210
- private static int PackedIndexOf < TNegator > ( ref short searchSpace , short value , int length )
207
+ private static int IndexOf < TNegator > ( ref short searchSpace , short value , int length )
211
208
where TNegator : struct , SpanHelpers . INegator < short >
212
209
{
213
210
Debug . Assert ( CanUsePackedIndexOf ( value ) ) ;
@@ -348,7 +345,7 @@ private static int PackedIndexOf<TNegator>(ref short searchSpace, short value, i
348
345
return - 1 ;
349
346
}
350
347
351
- private static int PackedIndexOfAny < TNegator> ( ref short searchSpace, short value0, short value1, int length)
348
+ private static int IndexOfAny < TNegator> ( ref short searchSpace, short value0, short value1, int length)
352
349
where TNegator : struct , SpanHelpers. INegator< short >
353
350
{
354
351
Debug. Assert( CanUsePackedIndexOf( value0) ) ;
@@ -498,7 +495,7 @@ private static int PackedIndexOfAny<TNegator>(ref short searchSpace, short value
498
495
return - 1 ;
499
496
}
500
497
501
- private static int PackedIndexOfAny < TNegator> ( ref short searchSpace, short value0, short value1, short value2, int length)
498
+ private static int IndexOfAny < TNegator> ( ref short searchSpace, short value0, short value1, short value2, int length)
502
499
where TNegator : struct , SpanHelpers. INegator< short >
503
500
{
504
501
Debug. Assert( CanUsePackedIndexOf( value0) ) ;
@@ -651,7 +648,7 @@ private static int PackedIndexOfAny<TNegator>(ref short searchSpace, short value
651
648
return - 1 ;
652
649
}
653
650
654
- private static int PackedIndexOfAnyInRange < TNegator> ( ref short searchSpace, short lowInclusive, short rangeInclusive, int length)
651
+ private static int IndexOfAnyInRange < TNegator> ( ref short searchSpace, short lowInclusive, short rangeInclusive, int length)
655
652
where TNegator : struct , SpanHelpers. INegator< short >
656
653
{
657
654
Debug. Assert( CanUsePackedIndexOf( lowInclusive) ) ;
@@ -798,15 +795,12 @@ private static Vector256<byte> PackSources(Vector256<short> source0, Vector256<s
798
795
[ MethodImpl( MethodImplOptions. AggressiveInlining) ]
799
796
private static Vector128< byte > PackSources( Vector128< short > source0, Vector128< short > source1)
800
797
{
798
+ Debug. Assert( Sse2. IsSupported) ;
801
799
// Pack two vectors of characters into bytes. While the type is Vector128<short>, these are really UInt16 characters.
802
800
// X86: Downcast every character using saturation.
803
801
// - Values <= 32767 result in min(value, 255).
804
802
// - Values > 32767 result in 0. Because of this we can't accept needles that contain 0.
805
- // ARM64: Do narrowing saturation over unsigned values.
806
- // - All values result in min(value, 255)
807
- return Sse2. IsSupported
808
- ? Sse2. PackUnsignedSaturate( source0, source1) . AsByte( )
809
- : AdvSimd. ExtractNarrowingSaturateUpper( AdvSimd. ExtractNarrowingSaturateLower( source0. AsUInt16( ) ) , source1. AsUInt16( ) ) ;
803
+ return Sse2. PackUnsignedSaturate( source0, source1) . AsByte( ) ;
810
804
}
811
805
812
806
[ MethodImpl( MethodImplOptions. AggressiveInlining) ]
0 commit comments