Skip to content

Commit 6cea093

Browse files
Update a few code paths to ensure the trimmer can do its job (#106777)
* Update a few code paths to ensure the trimmer can do its job * Ensure that the throw helper works on downlevel targets
1 parent d6ca550 commit 6cea093

File tree

9 files changed

+164
-30
lines changed

9 files changed

+164
-30
lines changed

src/libraries/Common/src/System/HexConverter.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,14 +292,20 @@ public static bool TryDecodeFromUtf16_Vector128(ReadOnlySpan<char> chars, Span<b
292292
output = Ssse3.MultiplyAddAdjacent(nibbles,
293293
Vector128.Create((short)0x0110).AsSByte()).AsByte();
294294
}
295-
else
295+
else if (AdvSimd.Arm64.IsSupported)
296296
{
297297
// Workaround for missing MultiplyAddAdjacent on ARM
298298
Vector128<short> even = AdvSimd.Arm64.TransposeEven(nibbles, Vector128<byte>.Zero).AsInt16();
299299
Vector128<short> odd = AdvSimd.Arm64.TransposeOdd(nibbles, Vector128<byte>.Zero).AsInt16();
300300
even = AdvSimd.ShiftLeftLogical(even, 4).AsInt16();
301301
output = AdvSimd.AddSaturate(even, odd).AsByte();
302302
}
303+
else
304+
{
305+
// We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead
306+
ThrowHelper.ThrowUnreachableException();
307+
output = default;
308+
}
303309
// Accumulate output in lower INT64 half and take care about endianness
304310
output = Vector128.Shuffle(output, Vector128.Create((byte)0, 2, 4, 6, 8, 10, 12, 14, 0, 0, 0, 0, 0, 0, 0, 0));
305311
// Store 8 bytes in dest by given offset

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,12 +1105,18 @@ private static unsafe void Vector128Decode<TBase64Decoder, T>(TBase64Decoder dec
11051105
{
11061106
merge_ab_and_bc = Ssse3.MultiplyAddAdjacent(str.AsByte(), mergeConstant0.AsSByte());
11071107
}
1108-
else
1108+
else if (AdvSimd.Arm64.IsSupported)
11091109
{
11101110
Vector128<ushort> evens = AdvSimd.ShiftLeftLogicalWideningLower(AdvSimd.Arm64.UnzipEven(str, one).GetLower(), 6);
11111111
Vector128<ushort> odds = AdvSimd.Arm64.TransposeOdd(str, Vector128<byte>.Zero).AsUInt16();
11121112
merge_ab_and_bc = Vector128.Add(evens, odds).AsInt16();
11131113
}
1114+
else
1115+
{
1116+
// We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead
1117+
ThrowUnreachableException();
1118+
merge_ab_and_bc = default;
1119+
}
11141120
// 0000kkkk LLllllll 0000JJJJ JJjjKKKK
11151121
// 0000hhhh IIiiiiii 0000GGGG GGggHHHH
11161122
// 0000eeee FFffffff 0000DDDD DDddEEEE
@@ -1121,12 +1127,18 @@ private static unsafe void Vector128Decode<TBase64Decoder, T>(TBase64Decoder dec
11211127
{
11221128
output = Sse2.MultiplyAddAdjacent(merge_ab_and_bc, mergeConstant1);
11231129
}
1124-
else
1130+
else if (AdvSimd.Arm64.IsSupported)
11251131
{
11261132
Vector128<int> ievens = AdvSimd.ShiftLeftLogicalWideningLower(AdvSimd.Arm64.UnzipEven(merge_ab_and_bc, one.AsInt16()).GetLower(), 12);
11271133
Vector128<int> iodds = AdvSimd.Arm64.TransposeOdd(merge_ab_and_bc, Vector128<short>.Zero).AsInt32();
11281134
output = Vector128.Add(ievens, iodds).AsInt32();
11291135
}
1136+
else
1137+
{
1138+
// We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead
1139+
ThrowUnreachableException();
1140+
output = default;
1141+
}
11301142
// 00000000 JJJJJJjj KKKKkkkk LLllllll
11311143
// 00000000 GGGGGGgg HHHHhhhh IIiiiiii
11321144
// 00000000 DDDDDDdd EEEEeeee FFffffff

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -505,12 +505,18 @@ private static unsafe void Vector128Encode<TBase64Encoder, T>(TBase64Encoder enc
505505
{
506506
t1 = Sse2.MultiplyHigh(t0.AsUInt16(), shiftAC);
507507
}
508-
else
508+
else if (AdvSimd.Arm64.IsSupported)
509509
{
510510
Vector128<ushort> odd = Vector128.ShiftRightLogical(AdvSimd.Arm64.UnzipOdd(t0.AsUInt16(), t0.AsUInt16()), 6);
511511
Vector128<ushort> even = Vector128.ShiftRightLogical(AdvSimd.Arm64.UnzipEven(t0.AsUInt16(), t0.AsUInt16()), 10);
512512
t1 = AdvSimd.Arm64.ZipLow(even, odd);
513513
}
514+
else
515+
{
516+
// We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead
517+
ThrowUnreachableException();
518+
t1 = default;
519+
}
514520
// 00000000 00kkkkLL 00000000 00JJJJJJ
515521
// 00000000 00hhhhII 00000000 00GGGGGG
516522
// 00000000 00eeeeFF 00000000 00DDDDDD
@@ -545,10 +551,16 @@ private static unsafe void Vector128Encode<TBase64Encoder, T>(TBase64Encoder enc
545551
{
546552
indices = Sse2.SubtractSaturate(str.AsByte(), const51);
547553
}
548-
else
554+
else if (AdvSimd.IsSupported)
549555
{
550556
indices = AdvSimd.SubtractSaturate(str.AsByte(), const51);
551557
}
558+
else
559+
{
560+
// We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead
561+
ThrowUnreachableException();
562+
indices = default;
563+
}
552564

553565
// mask is 0xFF (-1) for range #[1..4] and 0x00 for range #0:
554566
Vector128<sbyte> mask = Vector128.GreaterThan(str.AsSByte(), const25);

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Diagnostics;
5+
using System.Diagnostics.CodeAnalysis;
56
using System.Runtime.CompilerServices;
67
#if NET
78
using System.Runtime.Intrinsics;
@@ -181,6 +182,16 @@ internal static Vector128<byte> ShuffleUnsafe(Vector128<byte> vector, Vector128<
181182
}
182183
#endif
183184

185+
[DoesNotReturn]
186+
internal static void ThrowUnreachableException()
187+
{
188+
#if NET
189+
throw new UnreachableException();
190+
#else
191+
throw new Exception("Unreachable");
192+
#endif
193+
}
194+
184195
internal interface IBase64Encoder<T> where T : unmanaged
185196
{
186197
ReadOnlySpan<byte> EncodingMap { get; }

src/libraries/System.Private.CoreLib/src/System/SearchValues/IndexOfAnyAsciiSearcher.cs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,9 +1368,20 @@ public static Vector128<byte> PackSources(Vector128<ushort> lower, Vector128<ush
13681368
Vector128<short> lowerMin = Vector128.Min(lower, Vector128.Create((ushort)255)).AsInt16();
13691369
Vector128<short> upperMin = Vector128.Min(upper, Vector128.Create((ushort)255)).AsInt16();
13701370

1371-
return Sse2.IsSupported
1372-
? Sse2.PackUnsignedSaturate(lowerMin, upperMin)
1373-
: PackedSimd.ConvertNarrowingSaturateUnsigned(lowerMin, upperMin);
1371+
if (Sse2.IsSupported)
1372+
{
1373+
return Sse2.PackUnsignedSaturate(lowerMin, upperMin);
1374+
}
1375+
else if (PackedSimd.IsSupported)
1376+
{
1377+
return PackedSimd.ConvertNarrowingSaturateUnsigned(lowerMin, upperMin);
1378+
}
1379+
else
1380+
{
1381+
// We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead
1382+
ThrowHelper.ThrowUnreachableException();
1383+
return default;
1384+
}
13741385
}
13751386

13761387
// Replace with Vector256.NarrowWithSaturation once https://github.com/dotnet/runtime/issues/75724 is implemented.
@@ -1392,10 +1403,24 @@ public static Vector256<byte> PackSources(Vector256<ushort> lower, Vector256<ush
13921403
[CompExactlyDependsOn(typeof(PackedSimd))]
13931404
public static Vector128<byte> PackSources(Vector128<ushort> lower, Vector128<ushort> upper)
13941405
{
1395-
return
1396-
Sse2.IsSupported ? Sse2.PackUnsignedSaturate(lower.AsInt16(), upper.AsInt16()) :
1397-
AdvSimd.IsSupported ? AdvSimd.ExtractNarrowingSaturateUpper(AdvSimd.ExtractNarrowingSaturateLower(lower), upper) :
1398-
PackedSimd.ConvertNarrowingSaturateUnsigned(lower.AsInt16(), upper.AsInt16());
1406+
if (Sse2.IsSupported)
1407+
{
1408+
return Sse2.PackUnsignedSaturate(lower.AsInt16(), upper.AsInt16());
1409+
}
1410+
else if (AdvSimd.IsSupported)
1411+
{
1412+
return AdvSimd.ExtractNarrowingSaturateUpper(AdvSimd.ExtractNarrowingSaturateLower(lower), upper);
1413+
}
1414+
else if (PackedSimd.IsSupported)
1415+
{
1416+
return PackedSimd.ConvertNarrowingSaturateUnsigned(lower.AsInt16(), upper.AsInt16());
1417+
}
1418+
else
1419+
{
1420+
// We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead
1421+
ThrowHelper.ThrowUnreachableException();
1422+
return default;
1423+
}
13991424
}
14001425

14011426
[CompExactlyDependsOn(typeof(Avx2))]

src/libraries/System.Private.CoreLib/src/System/SearchValues/ProbabilisticMap.cs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -219,13 +219,27 @@ private static Vector128<byte> ContainsMask16Chars(Vector128<byte> charMapLower,
219219
Vector128<ushort> source0 = Vector128.LoadUnsafe(ref searchSpace);
220220
Vector128<ushort> source1 = Vector128.LoadUnsafe(ref searchSpace, (nuint)Vector128<ushort>.Count);
221221

222-
Vector128<byte> sourceLower = Sse2.IsSupported
223-
? Sse2.PackUnsignedSaturate((source0 & Vector128.Create((ushort)255)).AsInt16(), (source1 & Vector128.Create((ushort)255)).AsInt16())
224-
: AdvSimd.Arm64.UnzipEven(source0.AsByte(), source1.AsByte());
222+
Vector128<byte> sourceLower;
223+
Vector128<byte> sourceUpper;
225224

226-
Vector128<byte> sourceUpper = Sse2.IsSupported
227-
? Sse2.PackUnsignedSaturate((source0 >>> 8).AsInt16(), (source1 >>> 8).AsInt16())
228-
: AdvSimd.Arm64.UnzipOdd(source0.AsByte(), source1.AsByte());
225+
if (Sse2.IsSupported)
226+
{
227+
sourceLower = Sse2.PackUnsignedSaturate((source0 & Vector128.Create((ushort)255)).AsInt16(), (source1 & Vector128.Create((ushort)255)).AsInt16());
228+
sourceUpper = Sse2.PackUnsignedSaturate((source0 >>> 8).AsInt16(), (source1 >>> 8).AsInt16());
229+
}
230+
else if (AdvSimd.Arm64.IsSupported)
231+
{
232+
sourceLower = AdvSimd.Arm64.UnzipEven(source0.AsByte(), source1.AsByte());
233+
sourceUpper = AdvSimd.Arm64.UnzipOdd(source0.AsByte(), source1.AsByte());
234+
}
235+
else
236+
{
237+
// We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead
238+
ThrowHelper.ThrowUnreachableException();
239+
240+
sourceLower = default;
241+
sourceUpper = default;
242+
}
229243

230244
Vector128<byte> resultLower = IsCharBitNotSet(charMapLower, charMapUpper, sourceLower);
231245
Vector128<byte> resultUpper = IsCharBitNotSet(charMapLower, charMapUpper, sourceUpper);

src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/TeddyHelper.cs

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,20 @@ public static Vector128<byte> LoadAndPack16AsciiChars(ref char source)
217217
Vector128<ushort> source0 = Vector128.LoadUnsafe(ref source);
218218
Vector128<ushort> source1 = Vector128.LoadUnsafe(ref source, (nuint)Vector128<ushort>.Count);
219219

220-
return Sse2.IsSupported
221-
? Sse2.PackUnsignedSaturate(source0.AsInt16(), source1.AsInt16())
222-
: AdvSimd.ExtractNarrowingSaturateUpper(AdvSimd.ExtractNarrowingSaturateLower(source0), source1);
220+
if (Sse2.IsSupported)
221+
{
222+
return Sse2.PackUnsignedSaturate(source0.AsInt16(), source1.AsInt16());
223+
}
224+
else if (AdvSimd.IsSupported)
225+
{
226+
return AdvSimd.ExtractNarrowingSaturateUpper(AdvSimd.ExtractNarrowingSaturateLower(source0), source1);
227+
}
228+
else
229+
{
230+
// We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead
231+
ThrowHelper.ThrowUnreachableException();
232+
return default;
233+
}
223234
}
224235

225236
// Read two Vector512<ushort> and concatenate their lower bytes together into a single Vector512<byte>.
@@ -323,9 +334,20 @@ private static Vector128<byte> RightShift1(Vector128<byte> left, Vector128<byte>
323334
// We want to shift the last element of left (15) to be the first element of the result
324335
// result: [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
325336

326-
return Ssse3.IsSupported
327-
? Ssse3.AlignRight(right, left, 15)
328-
: AdvSimd.ExtractVector128(left, right, 15);
337+
if (Ssse3.IsSupported)
338+
{
339+
return Ssse3.AlignRight(right, left, 15);
340+
}
341+
else if (AdvSimd.IsSupported)
342+
{
343+
return AdvSimd.ExtractVector128(left, right, 15);
344+
}
345+
else
346+
{
347+
// We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead
348+
ThrowHelper.ThrowUnreachableException();
349+
return default;
350+
}
329351
}
330352

331353
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -339,9 +361,20 @@ private static Vector128<byte> RightShift2(Vector128<byte> left, Vector128<byte>
339361
// We want to shift the last two elements of left (14, 15) to be the first elements of the result
340362
// result: [14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
341363

342-
return Ssse3.IsSupported
343-
? Ssse3.AlignRight(right, left, 14)
344-
: AdvSimd.ExtractVector128(left, right, 14);
364+
if (Ssse3.IsSupported)
365+
{
366+
return Ssse3.AlignRight(right, left, 14);
367+
}
368+
else if (AdvSimd.IsSupported)
369+
{
370+
return AdvSimd.ExtractVector128(left, right, 14);
371+
}
372+
else
373+
{
374+
// We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead
375+
ThrowHelper.ThrowUnreachableException();
376+
return default;
377+
}
345378
}
346379

347380
[MethodImpl(MethodImplOptions.AggressiveInlining)]

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,7 @@ public static OperationStatus TranscodeToUtf8(char* pInputBuffer, int inputLengt
966966
Vector64<byte> lower = AdvSimd.ExtractNarrowingSaturateUnsignedLower(utf16Data);
967967
AdvSimd.Store(pOutputBuffer, lower);
968968
}
969-
else
969+
else if (Sse41.IsSupported)
970970
{
971971
if (!Sse41.TestZ(utf16Data, nonAsciiUtf16DataMask))
972972
{
@@ -976,6 +976,11 @@ public static OperationStatus TranscodeToUtf8(char* pInputBuffer, int inputLengt
976976
// narrow and write
977977
Sse2.StoreScalar((ulong*)pOutputBuffer /* unaligned */, Sse2.PackUnsignedSaturate(utf16Data, utf16Data).AsUInt64());
978978
}
979+
else
980+
{
981+
// We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead
982+
ThrowHelper.ThrowUnreachableException();
983+
}
979984

980985
pInputBuffer += 8;
981986
pOutputBuffer += 8;
@@ -1000,10 +1005,15 @@ public static OperationStatus TranscodeToUtf8(char* pInputBuffer, int inputLengt
10001005
Vector64<byte> lower = AdvSimd.ExtractNarrowingSaturateUnsignedLower(utf16Data);
10011006
AdvSimd.StoreSelectedScalar((uint*)pOutputBuffer, lower.AsUInt32(), 0);
10021007
}
1003-
else
1008+
else if (Sse2.IsSupported)
10041009
{
10051010
Unsafe.WriteUnaligned(pOutputBuffer, Sse2.ConvertToUInt32(Sse2.PackUnsignedSaturate(utf16Data, utf16Data).AsUInt32()));
10061011
}
1012+
else
1013+
{
1014+
// We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead
1015+
ThrowHelper.ThrowUnreachableException();
1016+
}
10071017

10081018
pInputBuffer += 4;
10091019
pOutputBuffer += 4;
@@ -1038,10 +1048,15 @@ public static OperationStatus TranscodeToUtf8(char* pInputBuffer, int inputLengt
10381048
Vector64<byte> lower = AdvSimd.ExtractNarrowingSaturateUnsignedLower(utf16Data);
10391049
AdvSimd.StoreSelectedScalar((uint*)pOutputBuffer, lower.AsUInt32(), 0);
10401050
}
1041-
else
1051+
else if (Sse2.IsSupported)
10421052
{
10431053
Unsafe.WriteUnaligned(pOutputBuffer, Sse2.ConvertToUInt32(Sse2.PackUnsignedSaturate(utf16Data, utf16Data).AsUInt32()));
10441054
}
1055+
else
1056+
{
1057+
// We explicitly recheck each IsSupported query to ensure that the trimmer can see which paths are live/dead
1058+
ThrowHelper.ThrowUnreachableException();
1059+
}
10451060
pInputBuffer += 4;
10461061
pOutputBuffer += 4;
10471062
outputBytesRemaining -= 4;

src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ namespace System
5353
[StackTraceHidden]
5454
internal static class ThrowHelper
5555
{
56+
[DoesNotReturn]
57+
internal static void ThrowUnreachableException()
58+
{
59+
throw new UnreachableException();
60+
}
61+
5662
[DoesNotReturn]
5763
internal static void ThrowArithmeticException(string message)
5864
{

0 commit comments

Comments
 (0)