Skip to content

Commit 04cc76b

Browse files
xtqqczzetannergooding
authored andcommitted
Replace use of target dependent TestZ intrinsic (dotnet#104488)
* Replace uses of `TestZ` intrinsic * remove pragma warning disable IntrinsicsInSystemPrivateCoreLibConditionParsing * refactor control flow --------- Co-authored-by: Tanner Gooding <tagoo@outlook.com>
1 parent fae4afc commit 04cc76b

File tree

4 files changed

+33
-46
lines changed

4 files changed

+33
-46
lines changed

src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Base64Helper/Base64DecoderHelper.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1331,7 +1331,7 @@ public bool TryDecode256Core(
13311331
Vector256<sbyte> hi = Avx2.Shuffle(lutHigh, hiNibbles);
13321332
Vector256<sbyte> lo = Avx2.Shuffle(lutLow, loNibbles);
13331333

1334-
if (!Avx.TestZ(lo, hi))
1334+
if ((lo & hi) != Vector256<sbyte>.Zero)
13351335
{
13361336
result = default;
13371337
return false;

src/libraries/System.Private.CoreLib/src/System/Text/Ascii.Utility.cs

+23-36
Original file line numberDiff line numberDiff line change
@@ -1501,10 +1501,10 @@ private static bool VectorContainsNonAsciiChar(Vector128<byte> asciiVector)
15011501
{
15021502
// max ASCII character is 0b_0111_1111, so the most significant bit (0x80) tells whether it contains non ascii
15031503

1504-
// prefer architecture specific intrinsic as they offer better perf
1504+
// For performance, prefer architecture specific implementation
15051505
if (Sse41.IsSupported)
15061506
{
1507-
return !Sse41.TestZ(asciiVector, Vector128.Create((byte)0x80));
1507+
return (asciiVector & Vector128.Create((byte)0x80)) != Vector128<byte>.Zero;
15081508
}
15091509
else if (AdvSimd.Arm64.IsSupported)
15101510
{
@@ -1520,23 +1520,21 @@ private static bool VectorContainsNonAsciiChar(Vector128<byte> asciiVector)
15201520
[MethodImpl(MethodImplOptions.AggressiveInlining)]
15211521
internal static bool VectorContainsNonAsciiChar(Vector128<ushort> utf16Vector)
15221522
{
1523-
// prefer architecture specific intrinsic as they offer better perf
1524-
if (Sse2.IsSupported)
1523+
// For performance, prefer architecture specific implementation
1524+
if (Sse41.IsSupported)
15251525
{
1526-
if (Sse41.IsSupported)
1527-
{
1528-
Vector128<ushort> asciiMaskForTestZ = Vector128.Create((ushort)0xFF80);
1529-
// If a non-ASCII bit is set in any WORD of the vector, we have seen non-ASCII data.
1530-
return !Sse41.TestZ(utf16Vector.AsInt16(), asciiMaskForTestZ.AsInt16());
1531-
}
1532-
else
1533-
{
1534-
Vector128<ushort> asciiMaskForAddSaturate = Vector128.Create((ushort)0x7F80);
1535-
// The operation below forces the 0x8000 bit of each WORD to be set iff the WORD element
1536-
// has value >= 0x0800 (non-ASCII). Then we'll treat the vector as a BYTE vector in order
1537-
// to extract the mask. Reminder: the 0x0080 bit of each WORD should be ignored.
1538-
return (Sse2.MoveMask(Sse2.AddSaturate(utf16Vector, asciiMaskForAddSaturate).AsByte()) & 0b_1010_1010_1010_1010) != 0;
1539-
}
1526+
const ushort asciiMask = ushort.MaxValue - 127; // 0xFF80
1527+
Vector128<ushort> zeroIsAscii = utf16Vector & Vector128.Create(asciiMask);
1528+
// If a non-ASCII bit is set in any WORD of the vector, we have seen non-ASCII data.
1529+
return zeroIsAscii != Vector128<ushort>.Zero;
1530+
}
1531+
else if (Sse2.IsSupported)
1532+
{
1533+
Vector128<ushort> asciiMaskForAddSaturate = Vector128.Create((ushort)0x7F80);
1534+
// The operation below forces the 0x8000 bit of each WORD to be set iff the WORD element
1535+
// has value >= 0x0800 (non-ASCII). Then we'll treat the vector as a BYTE vector in order
1536+
// to extract the mask. Reminder: the 0x0080 bit of each WORD should be ignored.
1537+
return (Sse2.MoveMask(Sse2.AddSaturate(utf16Vector, asciiMaskForAddSaturate).AsByte()) & 0b_1010_1010_1010_1010) != 0;
15401538
}
15411539
else if (AdvSimd.Arm64.IsSupported)
15421540
{
@@ -1557,18 +1555,10 @@ internal static bool VectorContainsNonAsciiChar(Vector128<ushort> utf16Vector)
15571555
[MethodImpl(MethodImplOptions.AggressiveInlining)]
15581556
internal static bool VectorContainsNonAsciiChar(Vector256<ushort> utf16Vector)
15591557
{
1560-
if (Avx.IsSupported)
1561-
{
1562-
Vector256<ushort> asciiMaskForTestZ = Vector256.Create((ushort)0xFF80);
1563-
return !Avx.TestZ(utf16Vector.AsInt16(), asciiMaskForTestZ.AsInt16());
1564-
}
1565-
else
1566-
{
1567-
const ushort asciiMask = ushort.MaxValue - 127; // 0xFF80
1568-
Vector256<ushort> zeroIsAscii = utf16Vector & Vector256.Create(asciiMask);
1569-
// If a non-ASCII bit is set in any WORD of the vector, we have seen non-ASCII data.
1570-
return zeroIsAscii != Vector256<ushort>.Zero;
1571-
}
1558+
const ushort asciiMask = ushort.MaxValue - 127; // 0xFF80
1559+
Vector256<ushort> zeroIsAscii = utf16Vector & Vector256.Create(asciiMask);
1560+
// If a non-ASCII bit is set in any WORD of the vector, we have seen non-ASCII data.
1561+
return zeroIsAscii != Vector256<ushort>.Zero;
15721562
}
15731563

15741564
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1601,14 +1591,13 @@ private static bool AllCharsInVectorAreAscii<T>(Vector128<T> vector)
16011591
if (typeof(T) == typeof(byte))
16021592
{
16031593
return
1604-
Sse41.IsSupported ? Sse41.TestZ(vector.AsByte(), Vector128.Create((byte)0x80)) :
1594+
Sse41.IsSupported ? (vector.AsByte() & Vector128.Create((byte)0x80)) == Vector128<byte>.Zero :
16051595
AdvSimd.Arm64.IsSupported ? AllBytesInUInt64AreAscii(AdvSimd.Arm64.MaxPairwise(vector.AsByte(), vector.AsByte()).AsUInt64().ToScalar()) :
16061596
vector.AsByte().ExtractMostSignificantBits() == 0;
16071597
}
16081598
else
16091599
{
16101600
return
1611-
Sse41.IsSupported ? Sse41.TestZ(vector.AsUInt16(), Vector128.Create((ushort)0xFF80)) :
16121601
AdvSimd.Arm64.IsSupported ? AllCharsInUInt64AreAscii(AdvSimd.Arm64.MaxPairwise(vector.AsUInt16(), vector.AsUInt16()).AsUInt64().ToScalar()) :
16131602
(vector.AsUInt16() & Vector128.Create((ushort)0xFF80)) == Vector128<ushort>.Zero;
16141603
}
@@ -1624,14 +1613,12 @@ private static bool AllCharsInVectorAreAscii<T>(Vector256<T> vector)
16241613
if (typeof(T) == typeof(byte))
16251614
{
16261615
return
1627-
Avx.IsSupported ? Avx.TestZ(vector.AsByte(), Vector256.Create((byte)0x80)) :
1616+
Avx.IsSupported ? (vector.AsByte() & Vector256.Create((byte)0x80)) == Vector256<byte>.Zero:
16281617
vector.AsByte().ExtractMostSignificantBits() == 0;
16291618
}
16301619
else
16311620
{
1632-
return
1633-
Avx.IsSupported ? Avx.TestZ(vector.AsUInt16(), Vector256.Create((ushort)0xFF80)) :
1634-
(vector.AsUInt16() & Vector256.Create((ushort)0xFF80)) == Vector256<ushort>.Zero;
1621+
return (vector.AsUInt16() & Vector256.Create((ushort)0xFF80)) == Vector256<ushort>.Zero;
16351622
}
16361623
}
16371624

src/libraries/System.Private.CoreLib/src/System/Text/Latin1Utility.cs

+8-8
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ private static unsafe nuint GetIndexOfFirstNonLatin1Char_Sse2(char* pBuffer, nui
267267
{
268268
// If a non-Latin-1 bit is set in any WORD of the combined vector, we have seen non-Latin-1 data.
269269
// Jump to the non-Latin-1 handler to figure out which particular vector contained non-Latin-1 data.
270-
if (!Sse41.TestZ(combinedVector, latin1MaskForTestZ))
270+
if ((combinedVector & latin1MaskForTestZ) != Vector128<ushort>.Zero)
271271
{
272272
goto FoundNonLatin1DataInFirstOrSecondVector;
273273
}
@@ -312,7 +312,7 @@ private static unsafe nuint GetIndexOfFirstNonLatin1Char_Sse2(char* pBuffer, nui
312312
{
313313
// If a non-Latin-1 bit is set in any WORD of the combined vector, we have seen non-Latin-1 data.
314314
// Jump to the non-Latin-1 handler to figure out which particular vector contained non-Latin-1 data.
315-
if (!Sse41.TestZ(firstVector, latin1MaskForTestZ))
315+
if ((firstVector & latin1MaskForTestZ) != Vector128<ushort>.Zero)
316316
{
317317
goto FoundNonLatin1DataInFirstVector;
318318
}
@@ -347,7 +347,7 @@ private static unsafe nuint GetIndexOfFirstNonLatin1Char_Sse2(char* pBuffer, nui
347347
{
348348
// If a non-Latin-1 bit is set in any WORD of the combined vector, we have seen non-Latin-1 data.
349349
// Jump to the non-Latin-1 handler to figure out which particular vector contained non-Latin-1 data.
350-
if (!Sse41.TestZ(firstVector, latin1MaskForTestZ))
350+
if ((firstVector & latin1MaskForTestZ) != Vector128<ushort>.Zero)
351351
{
352352
goto FoundNonLatin1DataInFirstVector;
353353
}
@@ -381,7 +381,7 @@ private static unsafe nuint GetIndexOfFirstNonLatin1Char_Sse2(char* pBuffer, nui
381381
if (Sse41.IsSupported)
382382
#pragma warning restore IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough
383383
{
384-
if (!Sse41.TestZ(firstVector, latin1MaskForTestZ))
384+
if ((firstVector & latin1MaskForTestZ) != Vector128<ushort>.Zero)
385385
{
386386
goto FoundNonLatin1DataInFirstVector;
387387
}
@@ -795,7 +795,7 @@ private static unsafe nuint NarrowUtf16ToLatin1_Sse2(char* pUtf16Buffer, byte* p
795795
if (Sse41.IsSupported)
796796
#pragma warning restore IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough
797797
{
798-
if (!Sse41.TestZ(utf16VectorFirst, latin1MaskForTestZ))
798+
if ((utf16VectorFirst & latin1MaskForTestZ) != Vector128<short>.Zero)
799799
{
800800
return 0;
801801
}
@@ -837,7 +837,7 @@ private static unsafe nuint NarrowUtf16ToLatin1_Sse2(char* pUtf16Buffer, byte* p
837837
if (Sse41.IsSupported)
838838
#pragma warning restore IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough
839839
{
840-
if (!Sse41.TestZ(utf16VectorFirst, latin1MaskForTestZ))
840+
if ((utf16VectorFirst & latin1MaskForTestZ) != Vector128<short>.Zero)
841841
{
842842
goto Finish;
843843
}
@@ -878,7 +878,7 @@ private static unsafe nuint NarrowUtf16ToLatin1_Sse2(char* pUtf16Buffer, byte* p
878878
if (Sse41.IsSupported)
879879
#pragma warning restore IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough
880880
{
881-
if (!Sse41.TestZ(combinedVector, latin1MaskForTestZ))
881+
if ((combinedVector & latin1MaskForTestZ) != Vector128<short>.Zero)
882882
{
883883
goto FoundNonLatin1DataInLoop;
884884
}
@@ -914,7 +914,7 @@ private static unsafe nuint NarrowUtf16ToLatin1_Sse2(char* pUtf16Buffer, byte* p
914914
if (Sse41.IsSupported)
915915
#pragma warning restore IntrinsicsInSystemPrivateCoreLibAttributeNotSpecificEnough
916916
{
917-
if (!Sse41.TestZ(utf16VectorFirst, latin1MaskForTestZ))
917+
if ((utf16VectorFirst & latin1MaskForTestZ) != Vector128<short>.Zero)
918918
{
919919
goto Finish; // found non-Latin-1 data
920920
}

src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Transcoding.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -968,7 +968,7 @@ public static OperationStatus TranscodeToUtf8(char* pInputBuffer, int inputLengt
968968
}
969969
else if (Sse41.IsSupported)
970970
{
971-
if (!Sse41.TestZ(utf16Data, nonAsciiUtf16DataMask))
971+
if ((utf16Data & nonAsciiUtf16DataMask) != Vector128<short>.Zero)
972972
{
973973
goto LoopTerminatedDueToNonAsciiDataInVectorLocal;
974974
}

0 commit comments

Comments
 (0)