Skip to content

Commit

Permalink
Base64 encoding with simd-support (dotnet/corefx#34529)
Browse files Browse the repository at this point in the history
* Optimized scalar code-path

* Fixed label names

* Implemented vectorized versions

* Added reference to source of algorithm

* Added back missing namespace

* Unsafe.Add instead of Unsafe.Subtract

Fixed build-failure (https://ci3.dot.net/job/dotnet_corefx/job/master/job/linux-musl-TGroup_netcoreapp+CGroup_Debug+AGroup_x64+TestOuter_false_prtest/8247/console)
Seems like the internal Unsafe doesn't have a Subtract method, so use Add instead.

* Added THIRD-PARTY-NOTICES

* PR Feedback

* THIRD-PARTY-NOTICES in repo-base instead instead in folder

Cf. dotnet/corefx#34529 (comment)

* PR Feedback

* dotnet/corefx#34529 (comment)
* dotnet/corefx#34529 (comment)

* Rewritten to use raw-pointers instead of GC-tracked refs

Cf. dotnet/corefx#34529 (comment)

* Initialized the static fields directly (i.e. w/o cctor)

Cf. dotnet/corefx#34529 (comment)

* Added a test for decoding a (encoded) Guid

The case with decoding encoded 16 bytes was not covered by tests, so a wrong code got commited before, resulting
in DestinationTooSmall instead of the correct Done.

* EncodingMap / DecodingMap as byref instead of pointer

So got rid of the `rep stosd` in the prolog. Cf. dotnet/corefx#34529 (comment)

* PR Feedback

* dotnet/corefx#34529 (comment)

* Debug.Fail instead throwing for the assertion

Cf. dotnet/corefx#34529 (comment)

* ROSpan for static data

* ROS for lookup maps

* In decode avoided stack spill and hoisted zero-vector outside the loops

Cf. dotnet/corefx#34529 (comment)

* Assert assumption about destLength

Cf. dotnet/corefx#34529 (comment)

* Added comments from original source and some changes to variable names

Cf. dotnet/corefx#34529 (comment) and dotnet/corefx#34529 (comment)

* Use TestZ instead of MoveMask in AVX2-path

Cf. dotnet/corefx#34529 (comment)

* Fixed too complicated mask2F creation

Improved the version done in dotnet/corefx@c8b6cb3, so the static data isn't needed and code is more compact and readable.


Commit migrated from dotnet/corefx@036e0a6
  • Loading branch information
gfoidl authored and tannergooding committed May 29, 2019
1 parent 822e91e commit af1995c
Show file tree
Hide file tree
Showing 5 changed files with 1,102 additions and 316 deletions.
1 change: 1 addition & 0 deletions src/libraries/System.Memory/src/System.Memory.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<Compile Include="System\Buffers\SequenceReader.cs" />
<Compile Include="System\Buffers\SequenceReader.Search.cs" />
<Compile Include="System\Buffers\SequenceReaderExtensions.Binary.cs" />
<Compile Include="System\Buffers\Text\Base64.cs" />
<Compile Include="System\Buffers\Text\Base64Decoder.cs" />
<Compile Include="System\Buffers\Text\Base64Encoder.cs" />
<Compile Include="System\Runtime\InteropServices\SequenceMarshal.cs" />
Expand Down
48 changes: 48 additions & 0 deletions src/libraries/System.Memory/src/System/Buffers/Text/Base64.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// 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.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Internal.Runtime.CompilerServices;

namespace System.Buffers.Text
{
public static partial class Base64
{
private static TVector ReadVector<TVector>(ReadOnlySpan<sbyte> data)
{
ref sbyte tmp = ref MemoryMarshal.GetReference(data);
return Unsafe.As<sbyte, TVector>(ref tmp);
}

[Conditional("DEBUG")]
private static unsafe void AssertRead<TVector>(byte* src, byte* srcStart, int srcLength)
{
int vectorElements = Unsafe.SizeOf<TVector>();
byte* readEnd = src + vectorElements;
byte* srcEnd = srcStart + srcLength;

if (readEnd > srcEnd)
{
int srcIndex = (int)(src - srcStart);
Debug.Fail($"Read for {typeof(TVector)} is not within safe bounds. srcIndex: {srcIndex}, srcLength: {srcLength}");
}
}

[Conditional("DEBUG")]
private static unsafe void AssertWrite<TVector>(byte* dest, byte* destStart, int destLength)
{
int vectorElements = Unsafe.SizeOf<TVector>();
byte* writeEnd = dest + vectorElements;
byte* destEnd = destStart + destLength;

if (writeEnd > destEnd)
{
int destIndex = (int)(dest - destStart);
Debug.Fail($"Write for {typeof(TVector)} is not within safe bounds. destIndex: {destIndex}, destLength: {destLength}");
}
}
}
}
Loading

0 comments on commit af1995c

Please sign in to comment.