Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix failure in net472 debug AdvSimd Utf16Utility #39652

Merged
merged 1 commit into from
Jul 20, 2020

Conversation

carlossanlop
Copy link
Member

The Utf16Utility is a static class, and it's consumed in System.Utf8String.Experimental, which is a .NET Standard project, meaning it can be used in .NET Framework too.

Intrinsics code is not available in .NET Framework, so it shouldn't be added to a static field in that class, otherwise it causes net472 to fail on runtime when the static class gets called for the first time (it gets initialized, then tries to initialize the static fields).

The breaking change was introduced in #39050

The fix is to pass the value of the bitMask as a parameter, like we have been doing in other recent intrinsics changes.

cc @ViktorHofer @safern @kunalspathak @tannergooding

@ghost
Copy link

ghost commented Jul 20, 2020

Tagging subscribers to this area: @tannergooding
Notify danmosemsft if you want to be subscribed.

@carlossanlop carlossanlop changed the title Fix build failure in net472 debug AdvSimd Utf16Utility Fix failure in net472 debug AdvSimd Utf16Utility Jul 20, 2020
Comment on lines +91 to +93
Vector128<byte> bitMask128 = BitConverter.IsLittleEndian ?
Vector128.Create(0x80402010_08040201).AsByte() :
Vector128.Create(0x01020408_10204080).AsByte();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the JIT know that Vector128.Create is side-effect free so it can eliminate this code when the bitMask128 variable is unused? If not, this is adding unnecessary overhead to the x86 path.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure. @echesakovMSFT @tannergooding @kunalspathak do you know the answer to this?

Regardless of the answer, since the code was moved from being a static field (which was initialized for all architectures) to a local variable (which is also available for all architectures), I assume the behavior would not be worse than before.

If we think this needs to be addressed to avoid the unnecessary overhead in x86, I can create an issue so it gets fixed later.

I would like to get this merged as soon as possible to unblock net472 (prevent the PNS exception on runtime), so the backport to Prev8 gets approved.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The static would only have been initialized once. The local is created for every invocation.

The simple workaround, if indeed the JIT isn't eliminating it as dead, would just be to re-use the zero vector above so this one becomes an unused alias. i.e.:

Vector128<byte> bitMask128 = !AdvSimd.IsSupported ? vectorZero :
    BitConverter.IsLittleEndian ?
    Vector128.Create(0x80402010_08040201).AsByte() :
    Vector128.Create(0x01020408_10204080).AsByte();

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, thanks for the clarification, @saucecontrol . I'll add it to the list of TODOs to address in the next PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do eliminate dead stores. Here is a sample test on x64:

Vector128<byte> bitMask128 = BitConverter.IsLittleEndian ?
            Vector128.Create(0x80402010_08040201).AsByte() :
            Vector128.Create(0x01020408_10204080).AsByte();

if (AdvSimd.IsSupported)
{
    Console.WriteLine(bitMask128);
}
else
{
    Console.WriteLine(1);
}

Produces:

G_M58174_IG01:
       4883EC28             sub      rsp, 40
                                                ;; bbWeight=1    PerfScore 0.25
G_M58174_IG02:
       B901000000           mov      ecx, 1
       E832FDFFFF           call     System.Console:WriteLine(int)
       B864000000           mov      eax, 100
                                                ;; bbWeight=1    PerfScore 1.50
G_M58174_IG03:
       4883C428             add      rsp, 40
       C3                   ret
                                                ;; bbWeight=1    PerfScore 1.25

@carlossanlop carlossanlop merged commit 562763b into dotnet:master Jul 20, 2020
tannergooding pushed a commit to tannergooding/runtime that referenced this pull request Jul 21, 2020
@carlossanlop carlossanlop deleted the BldFailUtf16 branch July 22, 2020 00:49
tannergooding added a commit that referenced this pull request Jul 22, 2020
…#39738)

* AdvSimd support for System.Text.Unicode.Utf16Utility.GetPointerToFirstInvalidChar (#39050)

* AdvSimd support for System.Text.Unicode.Utf16Utility.GetPointerToFirstInvalidChar

* Move using directive outside #if.
Improve Arm64MoveMask.

* Change overloads

* UIn64 in Arm64MoveMask

* Build error implicit conversion fix

* Rename method and use simpler version

* Use ShiftRightArithmetic instead of CompareEqual + And.

* Remove unnecessary comment

* Add missing shims causing Linux build to fail

* AdvSimd support for System.Text.Unicode.Utf8Utility.TranscodeToUtf8 (#39041)

* AdvSimd support for System.Text.Unicode.Utf8Utility.TranscodeToUtf8

* Readd using to prevent build failure.
Add AdvSimd equivalent operation to TestZ.

* Inverted condition

* Address IsSupported order, improve use ExtractNarrowingSaturated usage

* Rename source to result, second argument utf16Data

* Improve CompareTest

* Add shims causing failures in Linux

* Use unsigned version of ExtractNarrowingSaturate, avoid using MinAcross and use MaxPairwise instead

* Missing support check for Sse2.X64

* Add missing case for AdvSimd

* Use MinPairwise for short

* AdvSimd support for System.Text.Unicode.Utf8Utility.GetPointerToFirstInvalidByte (#38653)

* AdvSimd support for System.Text.Unicode.Utf8Utility.GetPointerToFirstInvalidByte

* Move comment to the top, add shims.

* Little endian checks

* Use custom MoveMask method for AdvSimd

* Address suggestions to improve the AdvSimdMoveMask method

* Define initialMask outside MoveMask method

* UInt64 in Arm64MoveMask

* Add unit test case to verify intrinsics improvement

* Avoid casting to smaller integer type

* Typo and comment

* Use ShiftRightArithmetic instead of CompareEqual + And.
Remove test case causing other unit tests to fail.

* Use AddPairwise version of GetNotAsciiBytes

* Add missing shims causing Linux build to fail

* Simplify GetNonAsciiBytes to only one AddPairwise call, shorter bitmask

* Respect data type returned by masking method

* Address suggestions - assert trailingzerocount and bring back uint mask

* Trailing zeroes in AdvSimd need to be divided by 4, and total number should not be larger than 16

* Avoid declaring static field which causes PNSE in Utf8String.Experimental (S.P.Corelib code is used for being NetStandard)

* Prefer using nuint for BitConverter.TrailingZeroCount

* Fix build failure in net472 debug AdvSimd Utf16Utility (#39652)

Co-authored-by: Carlos Sanchez Lopez <[email protected]>
Jacksondr5 pushed a commit to Jacksondr5/runtime that referenced this pull request Aug 10, 2020
@karelz karelz added this to the 5.0.0 milestone Aug 18, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 8, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants