diff --git a/src/libraries/Common/src/System/HexConverter.cs b/src/libraries/Common/src/System/HexConverter.cs index bcc64dcf1a7045..0339a186f7c55d 100644 --- a/src/libraries/Common/src/System/HexConverter.cs +++ b/src/libraries/Common/src/System/HexConverter.cs @@ -292,7 +292,7 @@ public static bool TryDecodeFromUtf16_Vector128(ReadOnlySpan chars, Span even = AdvSimd.Arm64.TransposeEven(nibbles, Vector128.Zero).AsInt16(); @@ -300,6 +300,12 @@ public static bool TryDecodeFromUtf16_Vector128(ReadOnlySpan chars, Span(TBase64Decoder dec { merge_ab_and_bc = Ssse3.MultiplyAddAdjacent(str.AsByte(), mergeConstant0.AsSByte()); } - else + else if (AdvSimd.Arm64.IsSupported) { Vector128 evens = AdvSimd.ShiftLeftLogicalWideningLower(AdvSimd.Arm64.UnzipEven(str, one).GetLower(), 6); Vector128 odds = AdvSimd.Arm64.TransposeOdd(str, Vector128.Zero).AsUInt16(); merge_ab_and_bc = Vector128.Add(evens, odds).AsInt16(); } + else + { + // We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead + ThrowUnreachableException(); + merge_ab_and_bc = default; + } // 0000kkkk LLllllll 0000JJJJ JJjjKKKK // 0000hhhh IIiiiiii 0000GGGG GGggHHHH // 0000eeee FFffffff 0000DDDD DDddEEEE @@ -1121,12 +1127,18 @@ private static unsafe void Vector128Decode(TBase64Decoder dec { output = Sse2.MultiplyAddAdjacent(merge_ab_and_bc, mergeConstant1); } - else + else if (AdvSimd.Arm64.IsSupported) { Vector128 ievens = AdvSimd.ShiftLeftLogicalWideningLower(AdvSimd.Arm64.UnzipEven(merge_ab_and_bc, one.AsInt16()).GetLower(), 12); Vector128 iodds = AdvSimd.Arm64.TransposeOdd(merge_ab_and_bc, Vector128.Zero).AsInt32(); output = Vector128.Add(ievens, iodds).AsInt32(); } + else + { + // We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead + ThrowUnreachableException(); + output = default; + } // 00000000 JJJJJJjj KKKKkkkk LLllllll // 00000000 GGGGGGgg HHHHhhhh IIiiiiii // 00000000 DDDDDDdd EEEEeeee FFffffff diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Base64Helper/Base64EncoderHelper.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Base64Helper/Base64EncoderHelper.cs index 23c42e547b6fa8..6368e17c4c942a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Base64Helper/Base64EncoderHelper.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Base64Helper/Base64EncoderHelper.cs @@ -505,12 +505,18 @@ private static unsafe void Vector128Encode(TBase64Encoder enc { t1 = Sse2.MultiplyHigh(t0.AsUInt16(), shiftAC); } - else + else if (AdvSimd.Arm64.IsSupported) { Vector128 odd = Vector128.ShiftRightLogical(AdvSimd.Arm64.UnzipOdd(t0.AsUInt16(), t0.AsUInt16()), 6); Vector128 even = Vector128.ShiftRightLogical(AdvSimd.Arm64.UnzipEven(t0.AsUInt16(), t0.AsUInt16()), 10); t1 = AdvSimd.Arm64.ZipLow(even, odd); } + else + { + // We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead + ThrowUnreachableException(); + t1 = default; + } // 00000000 00kkkkLL 00000000 00JJJJJJ // 00000000 00hhhhII 00000000 00GGGGGG // 00000000 00eeeeFF 00000000 00DDDDDD @@ -545,10 +551,16 @@ private static unsafe void Vector128Encode(TBase64Encoder enc { indices = Sse2.SubtractSaturate(str.AsByte(), const51); } - else + else if (AdvSimd.IsSupported) { indices = AdvSimd.SubtractSaturate(str.AsByte(), const51); } + else + { + // We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead + ThrowUnreachableException(); + indices = default; + } // mask is 0xFF (-1) for range #[1..4] and 0x00 for range #0: Vector128 mask = Vector128.GreaterThan(str.AsSByte(), const25); diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Base64Helper/Base64Helper.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Base64Helper/Base64Helper.cs index 4a4d9bd5def0f3..a73449216e7748 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Base64Helper/Base64Helper.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Base64Helper/Base64Helper.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; #if NET using System.Runtime.Intrinsics; @@ -181,6 +182,16 @@ internal static Vector128 ShuffleUnsafe(Vector128 vector, Vector128< } #endif + [DoesNotReturn] + internal static void ThrowUnreachableException() + { +#if NET + throw new UnreachableException(); +#else + throw new Exception("Unreachable"); +#endif + } + internal interface IBase64Encoder where T : unmanaged { ReadOnlySpan EncodingMap { get; } diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs index c722387c4f4e14..2c1c19d8878315 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs @@ -1368,9 +1368,20 @@ public static Vector128 PackSources(Vector128 lower, Vector128 lowerMin = Vector128.Min(lower, Vector128.Create((ushort)255)).AsInt16(); Vector128 upperMin = Vector128.Min(upper, Vector128.Create((ushort)255)).AsInt16(); - return Sse2.IsSupported - ? Sse2.PackUnsignedSaturate(lowerMin, upperMin) - : PackedSimd.ConvertNarrowingSaturateUnsigned(lowerMin, upperMin); + if (Sse2.IsSupported) + { + return Sse2.PackUnsignedSaturate(lowerMin, upperMin); + } + else if (PackedSimd.IsSupported) + { + return PackedSimd.ConvertNarrowingSaturateUnsigned(lowerMin, upperMin); + } + else + { + // We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead + ThrowHelper.ThrowUnreachableException(); + return default; + } } // Replace with Vector256.NarrowWithSaturation once https://github.com/dotnet/runtime/issues/75724 is implemented. @@ -1392,10 +1403,24 @@ public static Vector256 PackSources(Vector256 lower, Vector256 PackSources(Vector128 lower, Vector128 upper) { - return - Sse2.IsSupported ? Sse2.PackUnsignedSaturate(lower.AsInt16(), upper.AsInt16()) : - AdvSimd.IsSupported ? AdvSimd.ExtractNarrowingSaturateUpper(AdvSimd.ExtractNarrowingSaturateLower(lower), upper) : - PackedSimd.ConvertNarrowingSaturateUnsigned(lower.AsInt16(), upper.AsInt16()); + if (Sse2.IsSupported) + { + return Sse2.PackUnsignedSaturate(lower.AsInt16(), upper.AsInt16()); + } + else if (AdvSimd.IsSupported) + { + return AdvSimd.ExtractNarrowingSaturateUpper(AdvSimd.ExtractNarrowingSaturateLower(lower), upper); + } + else if (PackedSimd.IsSupported) + { + return PackedSimd.ConvertNarrowingSaturateUnsigned(lower.AsInt16(), upper.AsInt16()); + } + else + { + // We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead + ThrowHelper.ThrowUnreachableException(); + return default; + } } [CompExactlyDependsOn(typeof(Avx2))] diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticMap.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticMap.cs index 482dd4bc1de010..fcbd64758fc8ec 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticMap.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticMap.cs @@ -219,13 +219,27 @@ private static Vector128 ContainsMask16Chars(Vector128 charMapLower, Vector128 source0 = Vector128.LoadUnsafe(ref searchSpace); Vector128 source1 = Vector128.LoadUnsafe(ref searchSpace, (nuint)Vector128.Count); - Vector128 sourceLower = Sse2.IsSupported - ? Sse2.PackUnsignedSaturate((source0 & Vector128.Create((ushort)255)).AsInt16(), (source1 & Vector128.Create((ushort)255)).AsInt16()) - : AdvSimd.Arm64.UnzipEven(source0.AsByte(), source1.AsByte()); + Vector128 sourceLower; + Vector128 sourceUpper; - Vector128 sourceUpper = Sse2.IsSupported - ? Sse2.PackUnsignedSaturate((source0 >>> 8).AsInt16(), (source1 >>> 8).AsInt16()) - : AdvSimd.Arm64.UnzipOdd(source0.AsByte(), source1.AsByte()); + if (Sse2.IsSupported) + { + sourceLower = Sse2.PackUnsignedSaturate((source0 & Vector128.Create((ushort)255)).AsInt16(), (source1 & Vector128.Create((ushort)255)).AsInt16()); + sourceUpper = Sse2.PackUnsignedSaturate((source0 >>> 8).AsInt16(), (source1 >>> 8).AsInt16()); + } + else if (AdvSimd.Arm64.IsSupported) + { + sourceLower = AdvSimd.Arm64.UnzipEven(source0.AsByte(), source1.AsByte()); + sourceUpper = AdvSimd.Arm64.UnzipOdd(source0.AsByte(), source1.AsByte()); + } + else + { + // We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead + ThrowHelper.ThrowUnreachableException(); + + sourceLower = default; + sourceUpper = default; + } Vector128 resultLower = IsCharBitNotSet(charMapLower, charMapUpper, sourceLower); Vector128 resultUpper = IsCharBitNotSet(charMapLower, charMapUpper, sourceUpper); diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/TeddyHelper.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/TeddyHelper.cs index a162bad30bcf45..2b197367b1421f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/TeddyHelper.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/TeddyHelper.cs @@ -217,9 +217,20 @@ public static Vector128 LoadAndPack16AsciiChars(ref char source) Vector128 source0 = Vector128.LoadUnsafe(ref source); Vector128 source1 = Vector128.LoadUnsafe(ref source, (nuint)Vector128.Count); - return Sse2.IsSupported - ? Sse2.PackUnsignedSaturate(source0.AsInt16(), source1.AsInt16()) - : AdvSimd.ExtractNarrowingSaturateUpper(AdvSimd.ExtractNarrowingSaturateLower(source0), source1); + if (Sse2.IsSupported) + { + return Sse2.PackUnsignedSaturate(source0.AsInt16(), source1.AsInt16()); + } + else if (AdvSimd.IsSupported) + { + return AdvSimd.ExtractNarrowingSaturateUpper(AdvSimd.ExtractNarrowingSaturateLower(source0), source1); + } + else + { + // We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead + ThrowHelper.ThrowUnreachableException(); + return default; + } } // Read two Vector512 and concatenate their lower bytes together into a single Vector512. @@ -323,9 +334,20 @@ private static Vector128 RightShift1(Vector128 left, Vector128 // We want to shift the last element of left (15) to be the first element of the result // result: [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30] - return Ssse3.IsSupported - ? Ssse3.AlignRight(right, left, 15) - : AdvSimd.ExtractVector128(left, right, 15); + if (Ssse3.IsSupported) + { + return Ssse3.AlignRight(right, left, 15); + } + else if (AdvSimd.IsSupported) + { + return AdvSimd.ExtractVector128(left, right, 15); + } + else + { + // We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead + ThrowHelper.ThrowUnreachableException(); + return default; + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -339,9 +361,20 @@ private static Vector128 RightShift2(Vector128 left, Vector128 // We want to shift the last two elements of left (14, 15) to be the first elements of the result // result: [14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29] - return Ssse3.IsSupported - ? Ssse3.AlignRight(right, left, 14) - : AdvSimd.ExtractVector128(left, right, 14); + if (Ssse3.IsSupported) + { + return Ssse3.AlignRight(right, left, 14); + } + else if (AdvSimd.IsSupported) + { + return AdvSimd.ExtractVector128(left, right, 14); + } + else + { + // We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead + ThrowHelper.ThrowUnreachableException(); + return default; + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Transcoding.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Transcoding.cs index 1a58b8b928b695..e700f8ad48359d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Transcoding.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Transcoding.cs @@ -966,7 +966,7 @@ public static OperationStatus TranscodeToUtf8(char* pInputBuffer, int inputLengt Vector64 lower = AdvSimd.ExtractNarrowingSaturateUnsignedLower(utf16Data); AdvSimd.Store(pOutputBuffer, lower); } - else + else if (Sse41.IsSupported) { if (!Sse41.TestZ(utf16Data, nonAsciiUtf16DataMask)) { @@ -976,6 +976,11 @@ public static OperationStatus TranscodeToUtf8(char* pInputBuffer, int inputLengt // narrow and write Sse2.StoreScalar((ulong*)pOutputBuffer /* unaligned */, Sse2.PackUnsignedSaturate(utf16Data, utf16Data).AsUInt64()); } + else + { + // We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead + ThrowHelper.ThrowUnreachableException(); + } pInputBuffer += 8; pOutputBuffer += 8; @@ -1000,10 +1005,15 @@ public static OperationStatus TranscodeToUtf8(char* pInputBuffer, int inputLengt Vector64 lower = AdvSimd.ExtractNarrowingSaturateUnsignedLower(utf16Data); AdvSimd.StoreSelectedScalar((uint*)pOutputBuffer, lower.AsUInt32(), 0); } - else + else if (Sse2.IsSupported) { Unsafe.WriteUnaligned(pOutputBuffer, Sse2.ConvertToUInt32(Sse2.PackUnsignedSaturate(utf16Data, utf16Data).AsUInt32())); } + else + { + // We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead + ThrowHelper.ThrowUnreachableException(); + } pInputBuffer += 4; pOutputBuffer += 4; @@ -1038,10 +1048,15 @@ public static OperationStatus TranscodeToUtf8(char* pInputBuffer, int inputLengt Vector64 lower = AdvSimd.ExtractNarrowingSaturateUnsignedLower(utf16Data); AdvSimd.StoreSelectedScalar((uint*)pOutputBuffer, lower.AsUInt32(), 0); } - else + else if (Sse2.IsSupported) { Unsafe.WriteUnaligned(pOutputBuffer, Sse2.ConvertToUInt32(Sse2.PackUnsignedSaturate(utf16Data, utf16Data).AsUInt32())); } + else + { + // We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead + ThrowHelper.ThrowUnreachableException(); + } pInputBuffer += 4; pOutputBuffer += 4; outputBytesRemaining -= 4; diff --git a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs index 41ab0698b0bd9b..192346f01dc510 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs @@ -53,6 +53,12 @@ namespace System [StackTraceHidden] internal static class ThrowHelper { + [DoesNotReturn] + internal static void ThrowUnreachableException() + { + throw new UnreachableException(); + } + [DoesNotReturn] internal static void ThrowArithmeticException(string message) {