Skip to content

Commit

Permalink
Use PackedIndexOfIsSupported checks in more places
Browse files Browse the repository at this point in the history
This should avoids the size regression on WebAssembly and possibly other
platforms without Sse2.

The regression is side effect of dotnet#78861
which uses `PackedSpanHelpers.CanUsePackedIndexOf (!!T)` and TShouldUsePacked.Value
to guard the usage of PackedSpanHelpers.

Because these involve generics, illinker is unable to link
the PackedSpanHelpers type away and that pulls other parts in, like
System.Runtime.Intrinsics.X86.* types. See https://gist.github.com/radekdoulik/c0b52247d472f69bcf983ade78a924ea
for more complete list.

This change gets us back 9,216 bytes in the case of app used to repro
the regression.

    ...
      -             Type System.PackedSpanHelpers
      -             Type System.Runtime.Intrinsics.X86.X86Base
      -             Type System.Runtime.Intrinsics.X86.Sse
      -             Type System.Runtime.Intrinsics.X86.Sse2
    Summary:
      -       9,216 File size -0.76% (of 1,215,488)
      -       2,744 Metadata size -0.43% (of 636,264)
      -           4 Types count
  • Loading branch information
radekdoulik committed Jan 5, 2023
1 parent 3454d8c commit 7f93bd6
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 17 deletions.
Expand Up @@ -22,7 +22,7 @@ internal sealed class IndexOfAny1CharValue<TShouldUsePacked> : IndexOfAnyValues<

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAny(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
(PackedSpanHelpers.PackedIndexOfIsSupported && TShouldUsePacked.Value)
? PackedSpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), _e0, span.Length)
: SpanHelpers.NonPackedIndexOfValueType<short, SpanHelpers.DontNegate<short>>(
ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(span)),
Expand All @@ -31,7 +31,7 @@ internal sealed class IndexOfAny1CharValue<TShouldUsePacked> : IndexOfAnyValues<

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAnyExcept(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
(PackedSpanHelpers.PackedIndexOfIsSupported && TShouldUsePacked.Value)
? PackedSpanHelpers.IndexOfAnyExcept(ref MemoryMarshal.GetReference(span), _e0, span.Length)
: SpanHelpers.NonPackedIndexOfValueType<short, SpanHelpers.Negate<short>>(
ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(span)),
Expand Down
Expand Up @@ -22,7 +22,7 @@ internal sealed class IndexOfAny2CharValue<TShouldUsePacked> : IndexOfAnyValues<

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAny(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
(PackedSpanHelpers.PackedIndexOfIsSupported && TShouldUsePacked.Value)
? PackedSpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), _e0, _e1, span.Length)
: SpanHelpers.NonPackedIndexOfAnyValueType<short, SpanHelpers.DontNegate<short>>(
ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(span)),
Expand All @@ -32,7 +32,7 @@ internal sealed class IndexOfAny2CharValue<TShouldUsePacked> : IndexOfAnyValues<

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAnyExcept(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
(PackedSpanHelpers.PackedIndexOfIsSupported && TShouldUsePacked.Value)
? PackedSpanHelpers.IndexOfAnyExcept(ref MemoryMarshal.GetReference(span), _e0, _e1, span.Length)
: SpanHelpers.NonPackedIndexOfAnyValueType<short, SpanHelpers.Negate<short>>(
ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(span)),
Expand Down
Expand Up @@ -22,7 +22,7 @@ internal sealed class IndexOfAny3CharValue<TShouldUsePacked> : IndexOfAnyValues<

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAny(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
(PackedSpanHelpers.PackedIndexOfIsSupported && TShouldUsePacked.Value)
? PackedSpanHelpers.IndexOfAny(ref MemoryMarshal.GetReference(span), _e0, _e1, _e2, span.Length)
: SpanHelpers.NonPackedIndexOfAnyValueType<short, SpanHelpers.DontNegate<short>>(
ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(span)),
Expand All @@ -33,7 +33,7 @@ internal sealed class IndexOfAny3CharValue<TShouldUsePacked> : IndexOfAnyValues<

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAnyExcept(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
(PackedSpanHelpers.PackedIndexOfIsSupported && TShouldUsePacked.Value)
? PackedSpanHelpers.IndexOfAnyExcept(ref MemoryMarshal.GetReference(span), _e0, _e1, _e2, span.Length)
: SpanHelpers.NonPackedIndexOfAnyValueType<short, SpanHelpers.Negate<short>>(
ref Unsafe.As<char, short>(ref MemoryMarshal.GetReference(span)),
Expand Down
Expand Up @@ -38,7 +38,7 @@ internal override char[] GetValues()

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAny(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
(PackedSpanHelpers.PackedIndexOfIsSupported && TShouldUsePacked.Value)
? PackedSpanHelpers.IndexOfAnyInRange(ref MemoryMarshal.GetReference(span), _lowInclusive, _rangeInclusive, span.Length)
: SpanHelpers.NonPackedIndexOfAnyInRangeUnsignedNumber<ushort, SpanHelpers.DontNegate<ushort>>(
ref Unsafe.As<char, ushort>(ref MemoryMarshal.GetReference(span)),
Expand All @@ -48,7 +48,7 @@ internal override char[] GetValues()

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal override int IndexOfAnyExcept(ReadOnlySpan<char> span) =>
TShouldUsePacked.Value
(PackedSpanHelpers.PackedIndexOfIsSupported && TShouldUsePacked.Value)
? PackedSpanHelpers.IndexOfAnyExceptInRange(ref MemoryMarshal.GetReference(span), _lowInclusive, _rangeInclusive, span.Length)
: SpanHelpers.NonPackedIndexOfAnyInRangeUnsignedNumber<ushort, SpanHelpers.Negate<ushort>>(
ref Unsafe.As<char, ushort>(ref MemoryMarshal.GetReference(span)),
Expand Down
Expand Up @@ -80,7 +80,7 @@ public static IndexOfAnyValues<char> Create(ReadOnlySpan<char> values)
if (values.Length == 1)
{
char value = values[0];
return PackedSpanHelpers.CanUsePackedIndexOf(value)
return PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(value)
? new IndexOfAny1CharValue<TrueConst>(value)
: new IndexOfAny1CharValue<FalseConst>(value);
}
Expand All @@ -95,7 +95,7 @@ public static IndexOfAnyValues<char> Create(ReadOnlySpan<char> values)
{
char value0 = values[0];
char value1 = values[1];
return PackedSpanHelpers.CanUsePackedIndexOf(value0) && PackedSpanHelpers.CanUsePackedIndexOf(value1)
return PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(value0) && PackedSpanHelpers.CanUsePackedIndexOf(value1)
? new IndexOfAny2CharValue<TrueConst>(value0, value1)
: new IndexOfAny2CharValue<FalseConst>(value0, value1);
}
Expand All @@ -105,7 +105,7 @@ public static IndexOfAnyValues<char> Create(ReadOnlySpan<char> values)
char value0 = values[0];
char value1 = values[1];
char value2 = values[2];
return PackedSpanHelpers.CanUsePackedIndexOf(value0) && PackedSpanHelpers.CanUsePackedIndexOf(value1) && PackedSpanHelpers.CanUsePackedIndexOf(value2)
return PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(value0) && PackedSpanHelpers.CanUsePackedIndexOf(value1) && PackedSpanHelpers.CanUsePackedIndexOf(value2)
? new IndexOfAny3CharValue<TrueConst>(value0, value1, value2)
: new IndexOfAny3CharValue<FalseConst>(value0, value1, value2);
}
Expand Down Expand Up @@ -185,7 +185,7 @@ public static IndexOfAnyValues<char> Create(ReadOnlySpan<char> values)
}

Debug.Assert(typeof(T) == typeof(char));
return (IndexOfAnyValues<T>)(object)(PackedSpanHelpers.CanUsePackedIndexOf(min) && PackedSpanHelpers.CanUsePackedIndexOf(max)
return (IndexOfAnyValues<T>)(object)(PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(min) && PackedSpanHelpers.CanUsePackedIndexOf(max)
? new IndexOfAnyCharValuesInRange<TrueConst>(*(char*)&min, *(char*)&max)
: new IndexOfAnyCharValuesInRange<FalseConst>(*(char*)&min, *(char*)&max));
}
Expand Down
10 changes: 5 additions & 5 deletions src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs
Expand Up @@ -1306,7 +1306,7 @@ public static int SequenceCompareTo<T>(ref T first, int firstLength, ref T secon
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe bool ContainsValueType<T>(ref T searchSpace, T value, int length) where T : struct, INumber<T>
{
if (PackedSpanHelpers.CanUsePackedIndexOf(value))
if (PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(value))
{
return PackedSpanHelpers.Contains(ref Unsafe.As<T, short>(ref searchSpace), *(short*)&value, length);
}
Expand Down Expand Up @@ -1448,7 +1448,7 @@ internal static int IndexOfChar(ref char searchSpace, char value, int length)
where TValue : struct, INumber<TValue>
where TNegator : struct, INegator<TValue>
{
if (PackedSpanHelpers.CanUsePackedIndexOf(value))
if (PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(value))
{
return typeof(TNegator) == typeof(DontNegate<short>)
? PackedSpanHelpers.IndexOf(ref Unsafe.As<TValue, char>(ref searchSpace), *(char*)&value, length)
Expand Down Expand Up @@ -1605,7 +1605,7 @@ internal static int IndexOfAnyChar(ref char searchSpace, char value0, char value
where TValue : struct, INumber<TValue>
where TNegator : struct, INegator<TValue>
{
if (PackedSpanHelpers.CanUsePackedIndexOf(value0) && PackedSpanHelpers.CanUsePackedIndexOf(value1))
if (PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(value0) && PackedSpanHelpers.CanUsePackedIndexOf(value1))
{
return typeof(TNegator) == typeof(DontNegate<short>)
? PackedSpanHelpers.IndexOfAny(ref Unsafe.As<TValue, char>(ref searchSpace), *(char*)&value0, *(char*)&value1, length)
Expand Down Expand Up @@ -1782,7 +1782,7 @@ internal static int IndexOfAnyChar(ref char searchSpace, char value0, char value
where TValue : struct, INumber<TValue>
where TNegator : struct, INegator<TValue>
{
if (PackedSpanHelpers.CanUsePackedIndexOf(value0) && PackedSpanHelpers.CanUsePackedIndexOf(value1) && PackedSpanHelpers.CanUsePackedIndexOf(value2))
if (PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(value0) && PackedSpanHelpers.CanUsePackedIndexOf(value1) && PackedSpanHelpers.CanUsePackedIndexOf(value2))
{
return typeof(TNegator) == typeof(DontNegate<short>)
? PackedSpanHelpers.IndexOfAny(ref Unsafe.As<TValue, char>(ref searchSpace), *(char*)&value0, *(char*)&value1, *(char*)&value2, length)
Expand Down Expand Up @@ -3085,7 +3085,7 @@ internal static int IndexOfAnyExceptInRangeUnsignedNumber<T>(ref T searchSpace,
where T : struct, IUnsignedNumber<T>, IComparisonOperators<T, T, bool>
where TNegator : struct, INegator<T>
{
if (PackedSpanHelpers.CanUsePackedIndexOf(lowInclusive) && PackedSpanHelpers.CanUsePackedIndexOf(highInclusive) && highInclusive >= lowInclusive)
if (PackedSpanHelpers.PackedIndexOfIsSupported && PackedSpanHelpers.CanUsePackedIndexOf(lowInclusive) && PackedSpanHelpers.CanUsePackedIndexOf(highInclusive) && highInclusive >= lowInclusive)
{
ref char charSearchSpace = ref Unsafe.As<T, char>(ref searchSpace);
char charLowInclusive = *(char*)&lowInclusive;
Expand Down
9 changes: 9 additions & 0 deletions src/mono/wasm/build/ILLink.Substitutions.NoWasmIntrinsics.xml
Expand Up @@ -9,5 +9,14 @@
<type fullname="System.Runtime.Intrinsics.Wasm.PackedSimd">
<method signature="System.Boolean get_IsSupported()" body="stub" value="false" />
</type>
<type fullname="System.Runtime.Intrinsics.X86.X86Base">
<method signature="System.Boolean get_IsSupported()" body="stub" value="false" />
</type>
<type fullname="System.Runtime.Intrinsics.X86.Sse">
<method signature="System.Boolean get_IsSupported()" body="stub" value="false" />
</type>
<type fullname="System.Runtime.Intrinsics.X86.Sse2">
<method signature="System.Boolean get_IsSupported()" body="stub" value="false" />
</type>
</assembly>
</linker>

0 comments on commit 7f93bd6

Please sign in to comment.