Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Base64 encoding with simd-support (#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. #34529 (comment)

* PR Feedback

* #34529 (comment)
* #34529 (comment)

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

Cf. #34529 (comment)

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

Cf. #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. #34529 (comment)

* PR Feedback

* #34529 (comment)

* Debug.Fail instead throwing for the assertion

Cf. #34529 (comment)

* ROSpan for static data

* ROS for lookup maps

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

Cf. #34529 (comment)

* Assert assumption about destLength

Cf. #34529 (comment)

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

Cf. #34529 (comment) and #34529 (comment)

* Use TestZ instead of MoveMask in AVX2-path

Cf. #34529 (comment)

* Fixed too complicated mask2F creation

Improved the version done in c8b6cb3, so the static data isn't needed and code is more compact and readable.
  • Loading branch information
gfoidl authored and tannergooding committed May 29, 2019
1 parent 4b27d51 commit 036e0a6
Show file tree
Hide file tree
Showing 6 changed files with 1,134 additions and 316 deletions.
32 changes: 32 additions & 0 deletions THIRD-PARTY-NOTICES.TXT
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,35 @@ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

License notice for vectorized base64 encoding / decoding
--------------------------------------------------------

Copyright (c) 2005-2007, Nick Galbreath
Copyright (c) 2013-2017, Alfred Klomp
Copyright (c) 2015-2017, Wojciech Mula
Copyright (c) 2016-2017, Matthieu Darbois
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1 change: 1 addition & 0 deletions src/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/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 036e0a6

Please sign in to comment.