From a351adc3095e3bfe90741c3f6c50927bcc9d8a11 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Wed, 11 Jun 2025 16:18:59 +0100 Subject: [PATCH 1/2] Use `ExtractAsciiVector` instead of `Vector128.Narrow` --- .../src/System/Text/Ascii.CaseConversion.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.CaseConversion.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.CaseConversion.cs index 3db74d75044f4e..6db2a4bc773bfd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.CaseConversion.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.CaseConversion.cs @@ -352,8 +352,10 @@ private static unsafe nuint ChangeCase(TFrom* pSrc, TTo* pD } else { + // Narrowing operation required, we know data is all-ASCII so use extract helper. + Vector128 blockAsVectorOfUInt16 = blockAsVectorOfUInt64.AsUInt16(); - Vector128 narrowedBlock = Vector128.Narrow(blockAsVectorOfUInt16, blockAsVectorOfUInt16).AsUInt32(); + Vector128 narrowedBlock = ExtractAsciiVector(blockAsVectorOfUInt16, blockAsVectorOfUInt16).AsUInt32(); Unsafe.WriteUnaligned(&pDest[i], narrowedBlock.ToScalar()); } } @@ -412,8 +414,10 @@ private static unsafe nuint ChangeCase(TFrom* pSrc, TTo* pD } else { + // Narrowing operation required, we know data is all-ASCII so use extract helper. + Vector128 blockAsVectorOfUInt16 = blockAsVectorOfUInt32.AsUInt16(); - Vector128 narrowedBlock = Vector128.Narrow(blockAsVectorOfUInt16, blockAsVectorOfUInt16).AsUInt16(); + Vector128 narrowedBlock = ExtractAsciiVector(blockAsVectorOfUInt16, blockAsVectorOfUInt16).AsUInt16(); Unsafe.WriteUnaligned(&pDest[i], narrowedBlock.ToScalar()); } } From 79745efd9428a6d5482e8f270828a47fbe1da226 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 12 Jun 2025 16:52:33 +0100 Subject: [PATCH 2/2] Add vector `NarrowNative` --- .../Common/src/System/HexConverter.cs | 2 +- .../Text/Base64Url/Base64UrlDecoder.cs | 27 +++++++--- .../src/System/Numerics/Vector.cs | 18 +++++++ .../System/Runtime/Intrinsics/Vector128.cs | 25 ++++++++++ .../System/Runtime/Intrinsics/Vector256.cs | 15 ++++++ .../System/Runtime/Intrinsics/Vector512.cs | 16 ++++++ .../src/System/Text/Ascii.CaseConversion.cs | 13 ++--- .../src/System/Text/Ascii.Utility.cs | 50 +++++++++++++++++++ .../src/System/Text/Latin1Utility.cs | 2 +- 9 files changed, 152 insertions(+), 16 deletions(-) diff --git a/src/libraries/Common/src/System/HexConverter.cs b/src/libraries/Common/src/System/HexConverter.cs index 261009571f8cfa..89cdba3fae9d21 100644 --- a/src/libraries/Common/src/System/HexConverter.cs +++ b/src/libraries/Common/src/System/HexConverter.cs @@ -276,7 +276,7 @@ public static bool TryDecodeFromUtf16_Vector128(ReadOnlySpan chars, Span vec1 = Vector128.LoadUnsafe(ref srcRef, offset); Vector128 vec2 = Vector128.LoadUnsafe(ref srcRef, offset + (nuint)Vector128.Count); - Vector128 vec = Ascii.ExtractAsciiVector(vec1, vec2); + Vector128 vec = Vector128.NarrowNative(vec1, vec2); // Based on "Algorithm #3" https://github.com/WojciechMula/toys/blob/master/simd-parse-hex/geoff_algorithm.cpp // by Geoff Langdale and Wojciech Mula diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Base64Url/Base64UrlDecoder.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Base64Url/Base64UrlDecoder.cs index 6f7a96cfcda07d..b8bfd50b258018 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Base64Url/Base64UrlDecoder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Base64Url/Base64UrlDecoder.cs @@ -675,7 +675,9 @@ public unsafe bool TryLoadVector512(ushort* src, ushort* srcStart, int sourceLen return false; } -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER + str = Vector512.NarrowNative(utf16VectorLower, utf16VectorUpper).AsSByte(); +#elif NET9_0_OR_GREATER str = Ascii.ExtractAsciiVector(utf16VectorLower, utf16VectorUpper).AsSByte(); #else str = Vector512.Narrow(utf16VectorLower, utf16VectorUpper).AsSByte(); @@ -703,7 +705,9 @@ public unsafe bool TryLoadAvxVector256(ushort* src, ushort* srcStart, int source return false; } -#if NET9_0_OR_GREATER +#if NET10_0_OR_GREATER + str = Vector256.NarrowNative(utf16VectorLower, utf16VectorUpper).AsSByte(); +#elif NET9_0_OR_GREATER str = Ascii.ExtractAsciiVector(utf16VectorLower, utf16VectorUpper).AsSByte(); #else str = Vector256.Narrow(utf16VectorLower, utf16VectorUpper).AsSByte(); @@ -719,19 +723,19 @@ public unsafe bool TryLoadVector128(ushort* src, ushort* srcStart, int sourceLen Vector128 utf16VectorUpper = Vector128.LoadUnsafe(ref *src, 8); #if NET9_0_OR_GREATER if (Ascii.VectorContainsNonAsciiChar(utf16VectorLower | utf16VectorUpper)) - { - str = default; - return false; - } - - str = Ascii.ExtractAsciiVector(utf16VectorLower, utf16VectorUpper); #else if (Base64Helper.VectorContainsNonAsciiChar(utf16VectorLower | utf16VectorUpper)) +#endif { str = default; return false; } +#if NET10_0_OR_GREATER + str = Vector128.NarrowNative(utf16VectorLower, utf16VectorUpper); +#elif NET9_0_OR_GREATER + str = Ascii.ExtractAsciiVector(utf16VectorLower, utf16VectorUpper); +#else str = Base64Helper.ExtractAsciiVector(utf16VectorLower, utf16VectorUpper); #endif return true; @@ -752,10 +756,17 @@ public unsafe bool TryLoadArmVector128x4(ushort* src, ushort* srcStart, int sour return false; } +#if NET10_0_OR_GREATER + str1 = Vector128.NarrowNative(s11, s31); + str2 = Vector128.NarrowNative(s12, s32); + str3 = Vector128.NarrowNative(s21, s41); + str4 = Vector128.NarrowNative(s22, s42); +#else str1 = Ascii.ExtractAsciiVector(s11, s31); str2 = Ascii.ExtractAsciiVector(s12, s32); str3 = Ascii.ExtractAsciiVector(s21, s41); str4 = Ascii.ExtractAsciiVector(s22, s42); +#endif return true; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index 32166a6f4ecedd..fd18f741a6de4c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -2383,6 +2383,24 @@ public static Vector Narrow(Vector low, Vector high) public static Vector Narrow(Vector low, Vector high) => Narrow(low, high); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector NarrowNative(Vector low, Vector high) + { + if (Vector.Count == Vector512.Count) + { + return Vector512.NarrowNative(low.AsVector512(), high.AsVector512()).AsVector(); + } + else if (Vector.Count == Vector256.Count) + { + return Vector256.NarrowNative(low.AsVector256(), high.AsVector256()).AsVector(); + } + else + { + Debug.Assert(Vector.Count == Vector128.Count); + return Vector128.NarrowNative(low.AsVector128(), high.AsVector128()).AsVector(); + } + } + [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vector NarrowWithSaturation(Vector low, Vector high) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index c5d877a3be0562..8b1decbfb472c3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -2711,6 +2711,31 @@ public static Vector128 Narrow(Vector128 lower, Vector128 up public static Vector128 Narrow(Vector128 lower, Vector128 upper) => Narrow(lower, upper); + /// Narrows two vector of instances into one vector of using platform specific behavior. + /// The vector that will be narrowed to the lower half of the result vector. + /// The vector that will be narrowed to the upper half of the result vector. + /// A vector of containing elements narrowed from and . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector128 NarrowNative(Vector128 lower, Vector128 upper) + { + if (Sse2.IsSupported) + { + return Sse2.PackUnsignedSaturate(lower.AsInt16(), upper.AsInt16()); + } + else if (AdvSimd.Arm64.IsSupported) + { + return AdvSimd.Arm64.UnzipEven(lower.AsByte(), upper.AsByte()); + } + else if (PackedSimd.IsSupported) + { + return PackedSimd.ConvertNarrowingSaturateUnsigned(lower.AsInt16(), upper.AsInt16()); + } + else + { + return Narrow(lower, upper); + } + } + [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vector128 NarrowWithSaturation(Vector128 lower, Vector128 upper) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index 8f8580a1fb11c9..865e95aed6aa3b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -2776,6 +2776,21 @@ public static Vector256 Narrow(Vector256 lower, Vector256 up public static Vector256 Narrow(Vector256 lower, Vector256 upper) => Narrow(lower, upper); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector256 NarrowNative(Vector256 lower, Vector256 upper) + { + if (Avx2.IsSupported) + { + const byte control = 0b_11_01_10_00; + return Avx2.Permute4x64(Avx2.PackUnsignedSaturate(lower.AsInt16(), upper.AsInt16()).AsInt64(), control).AsByte(); + } + else + { + return Narrow(lower, upper); + } + } + [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vector256 NarrowWithSaturation(Vector256 lower, Vector256 upper) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs index 29b10dba0310aa..b160279825dc7c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs @@ -5,6 +5,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; namespace System.Runtime.Intrinsics { @@ -2801,6 +2802,21 @@ public static Vector512 Narrow(Vector512 lower, Vector512 up public static Vector512 Narrow(Vector512 lower, Vector512 upper) => Narrow(lower, upper); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector512 NarrowNative(Vector512 lower, Vector512 upper) + { + if (Avx512BW.IsSupported) + { + Vector512 control = Create(0, 2, 4, 6, 1, 3, 5, 7); + return Avx512F.PermuteVar8x64(Avx512BW.PackUnsignedSaturate(lower.AsInt16(), upper.AsInt16()).AsInt64(), control).AsByte(); + } + else + { + return Narrow(lower, upper); + } + } + [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vector512 NarrowWithSaturation(Vector512 lower, Vector512 upper) diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.CaseConversion.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.CaseConversion.cs index 6db2a4bc773bfd..6276827827a291 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.CaseConversion.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.CaseConversion.cs @@ -352,10 +352,10 @@ private static unsafe nuint ChangeCase(TFrom* pSrc, TTo* pD } else { - // Narrowing operation required, we know data is all-ASCII so use extract helper. + // Narrowing operation required, platform-dependent narrowing is safe as data is all-ASCII. Vector128 blockAsVectorOfUInt16 = blockAsVectorOfUInt64.AsUInt16(); - Vector128 narrowedBlock = ExtractAsciiVector(blockAsVectorOfUInt16, blockAsVectorOfUInt16).AsUInt32(); + Vector128 narrowedBlock = Vector128.NarrowNative(blockAsVectorOfUInt16, blockAsVectorOfUInt16).AsUInt32(); Unsafe.WriteUnaligned(&pDest[i], narrowedBlock.ToScalar()); } } @@ -414,10 +414,10 @@ private static unsafe nuint ChangeCase(TFrom* pSrc, TTo* pD } else { - // Narrowing operation required, we know data is all-ASCII so use extract helper. + // Narrowing operation required, platform-dependent narrowing is safe as data is all-ASCII. Vector128 blockAsVectorOfUInt16 = blockAsVectorOfUInt32.AsUInt16(); - Vector128 narrowedBlock = ExtractAsciiVector(blockAsVectorOfUInt16, blockAsVectorOfUInt16).AsUInt16(); + Vector128 narrowedBlock = Vector128.NarrowNative(blockAsVectorOfUInt16, blockAsVectorOfUInt16).AsUInt16(); Unsafe.WriteUnaligned(&pDest[i], narrowedBlock.ToScalar()); } } @@ -493,8 +493,9 @@ private static unsafe void ChangeWidthAndWriteTo(Vector128 ve } else if (sizeof(TFrom) == 2 && sizeof(TTo) == 1) { - // narrowing operation required, we know data is all-ASCII so use extract helper - Vector128 narrow = ExtractAsciiVector(vector.AsUInt16(), vector.AsUInt16()); + // Narrowing operation required, platform-dependent narrowing is safe as data is all-ASCII. + + Vector128 narrow = Vector128.NarrowNative(vector.AsUInt16(), vector.AsUInt16()); narrow.StoreLowerUnsafe(ref *(byte*)pDest, elementOffset); } else diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.Utility.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.Utility.cs index 2362eb79b36512..724b463340b180 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.Utility.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Ascii.Utility.cs @@ -1662,6 +1662,7 @@ private static bool AllCharsInVectorAreAscii(Vector512 vector) } } +#if !NET10_0_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vector128 ExtractAsciiVector(Vector128 vectorFirst, Vector128 vectorSecond) { @@ -1702,6 +1703,7 @@ internal static Vector512 ExtractAsciiVector(Vector512 vectorFirst ? PackedSpanHelpers.FixUpPackedVector512Result(Avx512BW.PackUnsignedSaturate(vectorFirst.AsInt16(), vectorSecond.AsInt16())) : Vector512.Narrow(vectorFirst, vectorSecond); } +#endif [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe nuint NarrowUtf16ToAscii_Intrinsified(char* pUtf16Buffer, byte* pAsciiBuffer, nuint elementCount) @@ -1735,7 +1737,11 @@ private static unsafe nuint NarrowUtf16ToAscii_Intrinsified(char* pUtf16Buffer, // Turn the 8 ASCII chars we just read into 8 ASCII bytes, then copy it to the destination. ref byte asciiBuffer = ref *pAsciiBuffer; +#if NET10_0_OR_GREATER + Vector128 asciiVector = Vector128.NarrowNative(utf16VectorFirst, utf16VectorFirst); +#else Vector128 asciiVector = ExtractAsciiVector(utf16VectorFirst, utf16VectorFirst); +#endif asciiVector.StoreLowerUnsafe(ref asciiBuffer, 0); nuint currentOffsetInElements = SizeOfVector128 / 2; // we processed 8 elements so far @@ -1762,7 +1768,11 @@ private static unsafe nuint NarrowUtf16ToAscii_Intrinsified(char* pUtf16Buffer, } // Turn the 8 ASCII chars we just read into 8 ASCII bytes, then copy it to the destination. +#if NET10_0_OR_GREATER + asciiVector = Vector128.NarrowNative(utf16VectorFirst, utf16VectorFirst); +#else asciiVector = ExtractAsciiVector(utf16VectorFirst, utf16VectorFirst); +#endif asciiVector.StoreLowerUnsafe(ref asciiBuffer, currentOffsetInElements); } @@ -1792,7 +1802,11 @@ private static unsafe nuint NarrowUtf16ToAscii_Intrinsified(char* pUtf16Buffer, // Build up the ASCII vector and perform the store. Debug.Assert(((nuint)pAsciiBuffer + currentOffsetInElements) % SizeOfVector128 == 0, "Write should be aligned."); +#if NET10_0_OR_GREATER + asciiVector = Vector128.NarrowNative(utf16VectorFirst, utf16VectorSecond); +#else asciiVector = ExtractAsciiVector(utf16VectorFirst, utf16VectorSecond); +#endif asciiVector.StoreUnsafe(ref asciiBuffer, currentOffsetInElements); currentOffsetInElements += SizeOfVector128; @@ -1815,7 +1829,11 @@ private static unsafe nuint NarrowUtf16ToAscii_Intrinsified(char* pUtf16Buffer, // First part was all ASCII, narrow and aligned write. Note we're only filling in the low half of the vector. Debug.Assert(((nuint)pAsciiBuffer + currentOffsetInElements) % sizeof(ulong) == 0, "Destination should be ulong-aligned."); +#if NET10_0_OR_GREATER + asciiVector = Vector128.NarrowNative(utf16VectorFirst, utf16VectorFirst); +#else asciiVector = ExtractAsciiVector(utf16VectorFirst, utf16VectorFirst); +#endif asciiVector.StoreLowerUnsafe(ref asciiBuffer, currentOffsetInElements); currentOffsetInElements += SizeOfVector128 / 2; @@ -1853,7 +1871,11 @@ private static unsafe nuint NarrowUtf16ToAscii_Intrinsified_256(char* pUtf16Buff // Turn the 16 ASCII chars we just read into 16 ASCII bytes, then copy it to the destination. ref byte asciiBuffer = ref *pAsciiBuffer; +#if NET10_0_OR_GREATER + Vector256 asciiVector = Vector256.NarrowNative(utf16VectorFirst, utf16VectorFirst); +#else Vector256 asciiVector = ExtractAsciiVector(utf16VectorFirst, utf16VectorFirst); +#endif asciiVector.GetLower().StoreUnsafe(ref asciiBuffer, 0); nuint currentOffsetInElements = Vector256.Size / 2; // we processed 16 elements so far @@ -1879,7 +1901,11 @@ private static unsafe nuint NarrowUtf16ToAscii_Intrinsified_256(char* pUtf16Buff } // Turn the 16 ASCII chars we just read into 16 ASCII bytes, then copy it to the destination. +#if NET10_0_OR_GREATER + asciiVector = Vector256.NarrowNative(utf16VectorFirst, utf16VectorFirst); +#else asciiVector = ExtractAsciiVector(utf16VectorFirst, utf16VectorFirst); +#endif asciiVector.GetLower().StoreUnsafe(ref asciiBuffer, currentOffsetInElements); } @@ -1909,7 +1935,11 @@ private static unsafe nuint NarrowUtf16ToAscii_Intrinsified_256(char* pUtf16Buff // Build up the ASCII vector and perform the store. Debug.Assert(((nuint)pAsciiBuffer + currentOffsetInElements) % Vector256.Size == 0, "Write should be aligned."); +#if NET10_0_OR_GREATER + asciiVector = Vector256.NarrowNative(utf16VectorFirst, utf16VectorSecond); +#else asciiVector = ExtractAsciiVector(utf16VectorFirst, utf16VectorSecond); +#endif asciiVector.StoreUnsafe(ref asciiBuffer, currentOffsetInElements); currentOffsetInElements += Vector256.Size; @@ -1932,7 +1962,11 @@ private static unsafe nuint NarrowUtf16ToAscii_Intrinsified_256(char* pUtf16Buff // First part was all ASCII, narrow and aligned write. Note we're only filling in the low half of the vector. Debug.Assert(((nuint)pAsciiBuffer + currentOffsetInElements) % Vector128.Size == 0, "Destination should be 128-bit-aligned."); +#if NET10_0_OR_GREATER + asciiVector = Vector256.NarrowNative(utf16VectorFirst, utf16VectorFirst); +#else asciiVector = ExtractAsciiVector(utf16VectorFirst, utf16VectorFirst); +#endif asciiVector.GetLower().StoreUnsafe(ref asciiBuffer, currentOffsetInElements); currentOffsetInElements += Vector256.Size / 2; @@ -1970,7 +2004,11 @@ private static unsafe nuint NarrowUtf16ToAscii_Intrinsified_512(char* pUtf16Buff // Turn the 32 ASCII chars we just read into 32 ASCII bytes, then copy it to the destination. ref byte asciiBuffer = ref *pAsciiBuffer; +#if NET10_0_OR_GREATER + Vector512 asciiVector = Vector512.NarrowNative(utf16VectorFirst, utf16VectorFirst); +#else Vector512 asciiVector = ExtractAsciiVector(utf16VectorFirst, utf16VectorFirst); +#endif asciiVector.GetLower().StoreUnsafe(ref asciiBuffer, 0); // how to store the lower part of a avx512 nuint currentOffsetInElements = Vector512.Size / 2; // we processed 32 elements so far @@ -1997,7 +2035,11 @@ private static unsafe nuint NarrowUtf16ToAscii_Intrinsified_512(char* pUtf16Buff } // Turn the 32 ASCII chars we just read into 32 ASCII bytes, then copy it to the destination. +#if NET10_0_OR_GREATER + asciiVector = Vector512.NarrowNative(utf16VectorFirst, utf16VectorFirst); +#else asciiVector = ExtractAsciiVector(utf16VectorFirst, utf16VectorFirst); +#endif asciiVector.GetLower().StoreUnsafe(ref asciiBuffer, currentOffsetInElements); } @@ -2027,7 +2069,11 @@ private static unsafe nuint NarrowUtf16ToAscii_Intrinsified_512(char* pUtf16Buff // Build up the ASCII vector and perform the store. Debug.Assert(((nuint)pAsciiBuffer + currentOffsetInElements) % Vector512.Size == 0, "Write should be aligned."); +#if NET10_0_OR_GREATER + asciiVector = Vector512.NarrowNative(utf16VectorFirst, utf16VectorSecond); +#else asciiVector = ExtractAsciiVector(utf16VectorFirst, utf16VectorSecond); +#endif asciiVector.StoreUnsafe(ref asciiBuffer, currentOffsetInElements); currentOffsetInElements += Vector512.Size; @@ -2050,7 +2096,11 @@ private static unsafe nuint NarrowUtf16ToAscii_Intrinsified_512(char* pUtf16Buff // First part was all ASCII, narrow and aligned write. Note we're only filling in the low half of the vector. Debug.Assert(((nuint)pAsciiBuffer + currentOffsetInElements) % Vector256.Size == 0, "Destination should be 256-bit-aligned."); +#if NET10_0_OR_GREATER + asciiVector = Vector512.NarrowNative(utf16VectorFirst, utf16VectorFirst); +#else asciiVector = ExtractAsciiVector(utf16VectorFirst, utf16VectorFirst); +#endif asciiVector.GetLower().StoreUnsafe(ref asciiBuffer, currentOffsetInElements); currentOffsetInElements += Vector512.Size / 2; diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Latin1Utility.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Latin1Utility.cs index 14d336ace4e484..2009bdc7fca71a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Latin1Utility.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Latin1Utility.cs @@ -619,7 +619,7 @@ public static unsafe nuint NarrowUtf16ToLatin1(char* pUtf16Buffer, byte* pLatin1 } // TODO: Is the below logic also valid for big-endian platforms? - Vector latin1Vector = Vector.Narrow(utf16VectorHigh, utf16VectorLow); + Vector latin1Vector = Vector.NarrowNative(utf16VectorHigh, utf16VectorLow); Unsafe.WriteUnaligned(pLatin1Buffer + currentOffset, latin1Vector); currentOffset += SizeOfVector;