diff --git a/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs b/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs index 418cd3b485c9..d99c6c5d3a1a 100644 --- a/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs +++ b/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs @@ -667,11 +667,13 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu do { Vector256 search = LoadVector256(ref searchSpace, offset); + // Bitwise Or to combine the matches and MoveMask to convert them to bitflags + int matches = Avx2.MoveMask( + Avx2.Or( + Avx2.CompareEqual(values0, search), + Avx2.CompareEqual(values1, search))); // Note that MoveMask has converted the equal vector elements into a set of bit flags, // So the bit position in 'matches' corresponds to the element offset. - int matches = Avx2.MoveMask(Avx2.CompareEqual(values0, search)); - // Bitwise Or to combine the flagged matches for the second value to our match flags - matches |= Avx2.MoveMask(Avx2.CompareEqual(values1, search)); if (matches == 0) { // Zero flags set so no matches @@ -692,8 +694,10 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu Vector128 search = LoadVector128(ref searchSpace, offset); // Same method as above - int matches = Sse2.MoveMask(Sse2.CompareEqual(values0, search)); - matches |= Sse2.MoveMask(Sse2.CompareEqual(values1, search)); + int matches = Sse2.MoveMask( + Sse2.Or( + Sse2.CompareEqual(values0, search), + Sse2.CompareEqual(values1, search))); if (matches == 0) { // Zero flags set so no matches @@ -726,8 +730,10 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu { Vector128 search = LoadVector128(ref searchSpace, offset); // Same method as above - int matches = Sse2.MoveMask(Sse2.CompareEqual(values0, search)); - matches |= Sse2.MoveMask(Sse2.CompareEqual(values1, search)); + int matches = Sse2.MoveMask( + Sse2.Or( + Sse2.CompareEqual(values0, search), + Sse2.CompareEqual(values1, search))); if (matches == 0) { // Zero flags set so no matches @@ -901,13 +907,14 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu do { Vector256 search = LoadVector256(ref searchSpace, offset); + + Vector256 matches0 = Avx2.CompareEqual(values0, search); + Vector256 matches1 = Avx2.CompareEqual(values1, search); + Vector256 matches2 = Avx2.CompareEqual(values2, search); + // Bitwise Or to combine the matches and MoveMask to convert them to bitflags + int matches = Avx2.MoveMask(Avx2.Or(Avx2.Or(matches0, matches1), matches2)); // Note that MoveMask has converted the equal vector elements into a set of bit flags, // So the bit position in 'matches' corresponds to the element offset. - int matches = Avx2.MoveMask(Avx2.CompareEqual(values0, search)); - // Bitwise Or to combine the flagged matches for the second value to our match flags - matches |= Avx2.MoveMask(Avx2.CompareEqual(values1, search)); - // Bitwise Or to combine the flagged matches for the third value to our match flags - matches |= Avx2.MoveMask(Avx2.CompareEqual(values2, search)); if (matches == 0) { // Zero flags set so no matches @@ -928,10 +935,12 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu Vector128 values2 = Vector128.Create(value2); Vector128 search = LoadVector128(ref searchSpace, offset); + + Vector128 matches0 = Sse2.CompareEqual(values0, search); + Vector128 matches1 = Sse2.CompareEqual(values1, search); + Vector128 matches2 = Sse2.CompareEqual(values2, search); // Same method as above - int matches = Sse2.MoveMask(Sse2.CompareEqual(values0, search)); - matches |= Sse2.MoveMask(Sse2.CompareEqual(values1, search)); - matches |= Sse2.MoveMask(Sse2.CompareEqual(values2, search)); + int matches = Sse2.MoveMask(Sse2.Or(Sse2.Or(matches0, matches1), matches2)); if (matches == 0) { // Zero flags set so no matches @@ -964,10 +973,12 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu while ((byte*)lengthToExamine > (byte*)offset) { Vector128 search = LoadVector128(ref searchSpace, offset); + + Vector128 matches0 = Sse2.CompareEqual(values0, search); + Vector128 matches1 = Sse2.CompareEqual(values1, search); + Vector128 matches2 = Sse2.CompareEqual(values2, search); // Same method as above - int matches = Sse2.MoveMask(Sse2.CompareEqual(values0, search)); - matches |= Sse2.MoveMask(Sse2.CompareEqual(values1, search)); - matches |= Sse2.MoveMask(Sse2.CompareEqual(values2, search)); + int matches = Sse2.MoveMask(Sse2.Or(Sse2.Or(matches0, matches1), matches2)); if (matches == 0) { // Zero flags set so no matches diff --git a/src/System.Private.CoreLib/shared/System/SpanHelpers.Char.cs b/src/System.Private.CoreLib/shared/System/SpanHelpers.Char.cs index 288090e6bdc4..2ad6f63a0c8b 100644 --- a/src/System.Private.CoreLib/shared/System/SpanHelpers.Char.cs +++ b/src/System.Private.CoreLib/shared/System/SpanHelpers.Char.cs @@ -570,11 +570,14 @@ public static int IndexOfAny(ref char searchSpace, char value0, char value1, int do { Vector256 search = LoadVector256(ref searchSpace, offset); + // Bitwise Or to combine the flagged matches for the second value to our match flags + int matches = Avx2.MoveMask( + Avx2.Or( + Avx2.CompareEqual(values0, search), + Avx2.CompareEqual(values1, search)) + .AsByte()); // Note that MoveMask has converted the equal vector elements into a set of bit flags, // So the bit position in 'matches' corresponds to the element offset. - int matches = Avx2.MoveMask(Avx2.CompareEqual(values0, search).AsByte()); - // Bitwise Or to combine the flagged matches for the second value to our match flags - matches |= Avx2.MoveMask(Avx2.CompareEqual(values1, search).AsByte()); if (matches == 0) { // Zero flags set so no matches @@ -596,8 +599,11 @@ public static int IndexOfAny(ref char searchSpace, char value0, char value1, int Vector128 search = LoadVector128(ref searchSpace, offset); // Same method as above - int matches = Sse2.MoveMask(Sse2.CompareEqual(values0, search).AsByte()); - matches |= Sse2.MoveMask(Sse2.CompareEqual(values1, search).AsByte()); + int matches = Sse2.MoveMask( + Sse2.Or( + Sse2.CompareEqual(values0, search), + Sse2.CompareEqual(values1, search)) + .AsByte()); if (matches == 0) { // Zero flags set so no matches @@ -631,8 +637,11 @@ public static int IndexOfAny(ref char searchSpace, char value0, char value1, int Vector128 search = LoadVector128(ref searchSpace, offset); // Same method as above - int matches = Sse2.MoveMask(Sse2.CompareEqual(values0, search).AsByte()); - matches |= Sse2.MoveMask(Sse2.CompareEqual(values1, search).AsByte()); + int matches = Sse2.MoveMask( + Sse2.Or( + Sse2.CompareEqual(values0, search), + Sse2.CompareEqual(values1, search)) + .AsByte()); if (matches == 0) { // Zero flags set so no matches @@ -767,12 +776,16 @@ public static int IndexOfAny(ref char searchSpace, char value0, char value1, cha do { Vector256 search = LoadVector256(ref searchSpace, offset); + + Vector256 matches0 = Avx2.CompareEqual(values0, search); + Vector256 matches1 = Avx2.CompareEqual(values1, search); + Vector256 matches2 = Avx2.CompareEqual(values2, search); + // Bitwise Or to combine the flagged matches for the second and third values to our match flags + int matches = Avx2.MoveMask( + Avx2.Or(Avx2.Or(matches0, matches1), matches2) + .AsByte()); // Note that MoveMask has converted the equal vector elements into a set of bit flags, // So the bit position in 'matches' corresponds to the element offset. - int matches = Avx2.MoveMask(Avx2.CompareEqual(values0, search).AsByte()); - // Bitwise Or to combine the flagged matches for the second and third values to our match flags - matches |= Avx2.MoveMask(Avx2.CompareEqual(values1, search).AsByte()); - matches |= Avx2.MoveMask(Avx2.CompareEqual(values2, search).AsByte()); if (matches == 0) { // Zero flags set so no matches @@ -792,12 +805,17 @@ public static int IndexOfAny(ref char searchSpace, char value0, char value1, cha Vector128 values0 = Vector128.Create(value0); Vector128 values1 = Vector128.Create(value1); Vector128 values2 = Vector128.Create(value2); + Vector128 search = LoadVector128(ref searchSpace, offset); + Vector128 matches0 = Sse2.CompareEqual(values0, search); + Vector128 matches1 = Sse2.CompareEqual(values1, search); + Vector128 matches2 = Sse2.CompareEqual(values2, search); + // Same method as above - int matches = Sse2.MoveMask(Sse2.CompareEqual(values0, search).AsByte()); - matches |= Sse2.MoveMask(Sse2.CompareEqual(values1, search).AsByte()); - matches |= Sse2.MoveMask(Sse2.CompareEqual(values2, search).AsByte()); + int matches = Sse2.MoveMask( + Sse2.Or(Sse2.Or(matches0, matches1), matches2) + .AsByte()); if (matches == 0) { // Zero flags set so no matches @@ -831,10 +849,14 @@ public static int IndexOfAny(ref char searchSpace, char value0, char value1, cha { Vector128 search = LoadVector128(ref searchSpace, offset); + Vector128 matches0 = Sse2.CompareEqual(values0, search); + Vector128 matches1 = Sse2.CompareEqual(values1, search); + Vector128 matches2 = Sse2.CompareEqual(values2, search); + // Same method as above - int matches = Sse2.MoveMask(Sse2.CompareEqual(values0, search).AsByte()); - matches |= Sse2.MoveMask(Sse2.CompareEqual(values1, search).AsByte()); - matches |= Sse2.MoveMask(Sse2.CompareEqual(values2, search).AsByte()); + int matches = Sse2.MoveMask( + Sse2.Or(Sse2.Or(matches0, matches1), matches2) + .AsByte()); if (matches == 0) { // Zero flags set so no matches @@ -973,13 +995,15 @@ public static int IndexOfAny(ref char searchSpace, char value0, char value1, cha do { Vector256 search = LoadVector256(ref searchSpace, offset); - // Note that MoveMask has converted the equal vector elements into a set of bit flags, - // So the bit position in 'matches' corresponds to the element offset. + // We preform the Or at non-Vector level as we are using the maximum number of non-preserved registers, + // and more causes them first to be pushed to stack and then popped on exit to preseve their values. int matches = Avx2.MoveMask(Avx2.CompareEqual(values0, search).AsByte()); // Bitwise Or to combine the flagged matches for the second, third and fourth values to our match flags matches |= Avx2.MoveMask(Avx2.CompareEqual(values1, search).AsByte()); matches |= Avx2.MoveMask(Avx2.CompareEqual(values2, search).AsByte()); matches |= Avx2.MoveMask(Avx2.CompareEqual(values3, search).AsByte()); + // Note that MoveMask has converted the equal vector elements into a set of bit flags, + // So the bit position in 'matches' corresponds to the element offset. if (matches == 0) { // Zero flags set so no matches @@ -1186,14 +1210,16 @@ public static int IndexOfAny(ref char searchSpace, char value0, char value1, cha do { Vector256 search = LoadVector256(ref searchSpace, offset); - // Note that MoveMask has converted the equal vector elements into a set of bit flags, - // So the bit position in 'matches' corresponds to the element offset. + // We preform the Or at non-Vector level as we are using the maximum number of non-preserved registers (+ 1), + // and more causes them first to be pushed to stack and then popped on exit to preseve their values. int matches = Avx2.MoveMask(Avx2.CompareEqual(values0, search).AsByte()); // Bitwise Or to combine the flagged matches for the second, third, fourth and fifth values to our match flags matches |= Avx2.MoveMask(Avx2.CompareEqual(values1, search).AsByte()); matches |= Avx2.MoveMask(Avx2.CompareEqual(values2, search).AsByte()); matches |= Avx2.MoveMask(Avx2.CompareEqual(values3, search).AsByte()); matches |= Avx2.MoveMask(Avx2.CompareEqual(values4, search).AsByte()); + // Note that MoveMask has converted the equal vector elements into a set of bit flags, + // So the bit position in 'matches' corresponds to the element offset. if (matches == 0) { // Zero flags set so no matches