-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Apply arm64 intrinsics to System.Text.Encodings.Web #38707
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
Merged
eiriktsarpalis
merged 32 commits into
dotnet:master
from
eiriktsarpalis:vectorize-encodings-web
Jul 15, 2020
Merged
Changes from all commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
79fb08d
use arm64 intrinsics in FindFirstCharacterToEncodeUtf8
eiriktsarpalis bc69c5e
remove whitespace
eiriktsarpalis 67c3eef
shim intrinsics apis for netstandard & netcoreapp targets
eiriktsarpalis 2055a00
use shimmed APIs in DefaultJavascripEncoder.cs
eiriktsarpalis f0f6ff6
implement MoveMask over AdvSimd
eiriktsarpalis d05afc6
Fix build and remove x86 shims
eiriktsarpalis 3aeef10
remove stub goto labels
eiriktsarpalis 74b7448
implement optimizations for FindFirstCharacterToEncodeUtf8
eiriktsarpalis a65af06
optimize FindFirstCharacterToEncode
eiriktsarpalis 3994520
fix bug
eiriktsarpalis 1a1fd15
implement optimizations for FindFirstCharacterToEncodeUtf8
eiriktsarpalis 6634260
remove goto labels
eiriktsarpalis 8f9b52f
optimize FindFirstCharacterToEncode
eiriktsarpalis 119be4c
Optimiize FindFirstCharacterToEncodeUtf8
eiriktsarpalis ec4a2b0
bug fix
eiriktsarpalis f88ec4b
add missing shim methods
eiriktsarpalis 6258a97
fix bug
eiriktsarpalis 3c76a7e
minor cleanups
eiriktsarpalis c3e66f3
cleanup and add comments
eiriktsarpalis 2a24500
address feedback
eiriktsarpalis ca4180c
address feedback and add checks for endianness
eiriktsarpalis 874a030
address feedback
eiriktsarpalis 46467bc
Use shims from CoreLib
eiriktsarpalis 0a0d8f6
Remove AdvSimdHelper.MoveMask and factor non-ascii byte locator logic…
eiriktsarpalis 70349d8
address feedback
eiriktsarpalis 448376d
reinstate goto labels
eiriktsarpalis 100ba88
revert removed goto labels
eiriktsarpalis 3954447
revert more changes
eiriktsarpalis e4fc529
address feedback
eiriktsarpalis 70d02ae
address feedback
eiriktsarpalis 6f0f2d1
further optimize GetIndexOfFirstNonAsciiByte
eiriktsarpalis 0ff134f
add TODO comment
eiriktsarpalis File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
157 changes: 157 additions & 0 deletions
157
src/libraries/System.Text.Encodings.Web/src/System/Text/Encodings/Web/AdvSimdHelper.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Diagnostics; | ||
using System.Numerics; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.Intrinsics; | ||
using System.Runtime.Intrinsics.Arm; | ||
|
||
namespace System.Text.Encodings.Web | ||
{ | ||
internal static class AdvSimdHelper | ||
{ | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public static Vector128<short> CreateEscapingMask_UnsafeRelaxedJavaScriptEncoder(Vector128<short> sourceValue) | ||
{ | ||
if (!AdvSimd.Arm64.IsSupported) | ||
{ | ||
throw new PlatformNotSupportedException(); | ||
} | ||
|
||
// Anything in the control characters range, and anything above short.MaxValue but less than or equal char.MaxValue | ||
// That's because anything between 32768 and 65535 (inclusive) will overflow and become negative. | ||
Vector128<short> mask = AdvSimd.CompareLessThan(sourceValue, s_spaceMaskInt16); | ||
|
||
mask = AdvSimd.Or(mask, AdvSimd.CompareEqual(sourceValue, s_quotationMarkMaskInt16)); | ||
mask = AdvSimd.Or(mask, AdvSimd.CompareEqual(sourceValue, s_reverseSolidusMaskInt16)); | ||
|
||
// Anything above the ASCII range, and also including the leftover control character in the ASCII range - 0x7F | ||
// When this method is called with only ASCII data, 0x7F is the only value that would meet this comparison. | ||
// However, when called from "Default", the source could contain characters outside the ASCII range. | ||
mask = AdvSimd.Or(mask, AdvSimd.CompareGreaterThan(sourceValue, s_tildeMaskInt16)); | ||
|
||
return mask; | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public static Vector128<sbyte> CreateEscapingMask_UnsafeRelaxedJavaScriptEncoder(Vector128<sbyte> sourceValue) | ||
{ | ||
if (!AdvSimd.Arm64.IsSupported) | ||
{ | ||
throw new PlatformNotSupportedException(); | ||
} | ||
|
||
// Anything in the control characters range (except 0x7F), and anything above sbyte.MaxValue but less than or equal byte.MaxValue | ||
// That's because anything between 128 and 255 (inclusive) will overflow and become negative. | ||
Vector128<sbyte> mask = AdvSimd.CompareLessThan(sourceValue, s_spaceMaskSByte); | ||
|
||
mask = AdvSimd.Or(mask, AdvSimd.CompareEqual(sourceValue, s_quotationMarkMaskSByte)); | ||
mask = AdvSimd.Or(mask, AdvSimd.CompareEqual(sourceValue, s_reverseSolidusMaskSByte)); | ||
|
||
// Leftover control character in the ASCII range - 0x7F | ||
// Since we are dealing with sbytes, 0x7F is the only value that would meet this comparison. | ||
mask = AdvSimd.Or(mask, AdvSimd.CompareGreaterThan(sourceValue, s_tildeMaskSByte)); | ||
|
||
return mask; | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public static Vector128<sbyte> CreateEscapingMask_DefaultJavaScriptEncoderBasicLatin(Vector128<sbyte> sourceValue) | ||
{ | ||
if (!AdvSimd.Arm64.IsSupported) | ||
{ | ||
throw new PlatformNotSupportedException(); | ||
} | ||
|
||
Vector128<sbyte> mask = CreateEscapingMask_UnsafeRelaxedJavaScriptEncoder(sourceValue); | ||
|
||
mask = AdvSimd.Or(mask, AdvSimd.CompareEqual(sourceValue, s_ampersandMaskSByte)); | ||
mask = AdvSimd.Or(mask, AdvSimd.CompareEqual(sourceValue, s_apostropheMaskSByte)); | ||
mask = AdvSimd.Or(mask, AdvSimd.CompareEqual(sourceValue, s_plusSignMaskSByte)); | ||
mask = AdvSimd.Or(mask, AdvSimd.CompareEqual(sourceValue, s_lessThanSignMaskSByte)); | ||
mask = AdvSimd.Or(mask, AdvSimd.CompareEqual(sourceValue, s_greaterThanSignMaskSByte)); | ||
mask = AdvSimd.Or(mask, AdvSimd.CompareEqual(sourceValue, s_graveAccentMaskSByte)); | ||
|
||
return mask; | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public static Vector128<short> CreateAsciiMask(Vector128<short> sourceValue) | ||
{ | ||
if (!AdvSimd.Arm64.IsSupported) | ||
{ | ||
throw new PlatformNotSupportedException(); | ||
} | ||
|
||
// Anything above short.MaxValue but less than or equal char.MaxValue | ||
// That's because anything between 32768 and 65535 (inclusive) will overflow and become negative. | ||
Vector128<short> mask = AdvSimd.CompareLessThan(sourceValue, s_nullMaskInt16); | ||
|
||
// Anything above the ASCII range | ||
mask = AdvSimd.Or(mask, AdvSimd.CompareGreaterThan(sourceValue, s_maxAsciiCharacterMaskInt16)); | ||
|
||
return mask; | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public static bool ContainsNonAsciiByte(Vector128<sbyte> value) | ||
{ | ||
if (!AdvSimd.Arm64.IsSupported) | ||
{ | ||
throw new PlatformNotSupportedException(); | ||
} | ||
|
||
// most significant bit mask for a 64-bit byte vector | ||
const ulong MostSignficantBitMask = 0x8080808080808080; | ||
|
||
value = AdvSimd.Arm64.MinPairwise(value, value); | ||
return (value.AsUInt64().ToScalar() & MostSignficantBitMask) != 0; | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public static int GetIndexOfFirstNonAsciiByte(Vector128<byte> value) | ||
{ | ||
if (!AdvSimd.Arm64.IsSupported || !BitConverter.IsLittleEndian) | ||
{ | ||
throw new PlatformNotSupportedException(); | ||
} | ||
|
||
// extractedBits[i] = (value[i] >> 7) & (1 << (12 * (i % 2))); | ||
Vector128<byte> mostSignificantBitIsSet = AdvSimd.ShiftRightArithmetic(value.AsSByte(), 7).AsByte(); | ||
Vector128<byte> extractedBits = AdvSimd.And(mostSignificantBitIsSet, s_bitmask); | ||
|
||
// collapse mask to lower bits | ||
extractedBits = AdvSimd.Arm64.AddPairwise(extractedBits, extractedBits); | ||
eiriktsarpalis marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ulong mask = extractedBits.AsUInt64().ToScalar(); | ||
|
||
// calculate the index | ||
int index = BitOperations.TrailingZeroCount(mask) >> 2; | ||
Debug.Assert((mask != 0) ? index < 16 : index >= 16); | ||
return index; | ||
} | ||
|
||
private static readonly Vector128<short> s_nullMaskInt16 = Vector128<short>.Zero; | ||
private static readonly Vector128<short> s_spaceMaskInt16 = Vector128.Create((short)' '); | ||
private static readonly Vector128<short> s_quotationMarkMaskInt16 = Vector128.Create((short)'"'); | ||
private static readonly Vector128<short> s_reverseSolidusMaskInt16 = Vector128.Create((short)'\\'); | ||
private static readonly Vector128<short> s_tildeMaskInt16 = Vector128.Create((short)'~'); | ||
private static readonly Vector128<short> s_maxAsciiCharacterMaskInt16 = Vector128.Create((short)0x7F); // Delete control character | ||
|
||
private static readonly Vector128<sbyte> s_spaceMaskSByte = Vector128.Create((sbyte)' '); | ||
private static readonly Vector128<sbyte> s_quotationMarkMaskSByte = Vector128.Create((sbyte)'"'); | ||
private static readonly Vector128<sbyte> s_ampersandMaskSByte = Vector128.Create((sbyte)'&'); | ||
private static readonly Vector128<sbyte> s_apostropheMaskSByte = Vector128.Create((sbyte)'\''); | ||
private static readonly Vector128<sbyte> s_plusSignMaskSByte = Vector128.Create((sbyte)'+'); | ||
private static readonly Vector128<sbyte> s_lessThanSignMaskSByte = Vector128.Create((sbyte)'<'); | ||
private static readonly Vector128<sbyte> s_greaterThanSignMaskSByte = Vector128.Create((sbyte)'>'); | ||
private static readonly Vector128<sbyte> s_reverseSolidusMaskSByte = Vector128.Create((sbyte)'\\'); | ||
private static readonly Vector128<sbyte> s_graveAccentMaskSByte = Vector128.Create((sbyte)'`'); | ||
private static readonly Vector128<sbyte> s_tildeMaskSByte = Vector128.Create((sbyte)'~'); | ||
|
||
private static readonly Vector128<byte> s_bitmask = BitConverter.IsLittleEndian ? | ||
Vector128.Create((ushort)0x1001).AsByte() : | ||
Vector128.Create((ushort)0x0110).AsByte(); | ||
} | ||
} |
24 changes: 0 additions & 24 deletions
24
src/libraries/System.Text.Encodings.Web/src/System/Text/Encodings/Web/BitHelper.cs
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.