Last active
April 23, 2026 15:11
-
-
Save tannergooding/37e69efe58a478ad573b2d3ce3260e08 to your computer and use it in GitHub Desktop.
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
| public static int Sum(ReadOnlySpan<int> x) | |
| { | |
| if (Vector128.IsHardwareAccelerated) | |
| { | |
| int result; | |
| if (x.Length >= Vector128<int>.Count) | |
| { | |
| result = Vectorized128(x); | |
| } | |
| else | |
| { | |
| result = VectorizedSmall(x); | |
| } | |
| return result; | |
| } | |
| else | |
| { | |
| return SoftwareFallback(x); | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| static int SoftwareFallback(ReadOnlySpan<int> x) | |
| { | |
| int result = 0; | |
| for (int i = 0; i < x.Length; i++) | |
| { | |
| result += x[i]; | |
| } | |
| return result; | |
| } | |
| static int Vectorized128(ReadOnlySpan<int> x) | |
| { | |
| Vector128<int> vresult = Vector128<int>.Zero; | |
| Vector128<int> beg = Vector128.Create(x); | |
| Vector128<int> end = Vector128.Create(x[^Vector128<int>.Count..]); | |
| if (x.Length > (Vector128<int>.Count * 4)) | |
| { | |
| x = x[Vector128<int>.Count..]; | |
| Vector128<int> vector1; | |
| Vector128<int> vector2; | |
| Vector128<int> vector3; | |
| Vector128<int> vector4; | |
| while (x.Length >= (Vector128<int>.Count * 4)) | |
| { | |
| vector1 = Vector128.Create(x[(Vector128<int>.Count * 0)..]); | |
| vector2 = Vector128.Create(x[(Vector128<int>.Count * 1)..]); | |
| vector3 = Vector128.Create(x[(Vector128<int>.Count * 2)..]); | |
| vector4 = Vector128.Create(x[(Vector128<int>.Count * 3)..]); | |
| vresult += vector1; | |
| vresult += vector2; | |
| vresult += vector3; | |
| vresult += vector4; | |
| x = x[(Vector128<int>.Count * 4)..]; | |
| } | |
| } | |
| vresult += beg; | |
| (int blocks, int trailing) = Math.DivRem(x.Length, Vector128<int>.Count); | |
| x = x[..^trailing]; | |
| switch (blocks) | |
| { | |
| case 3: | |
| { | |
| Vector128<int> vector = Vector128.Create(x[^(Vector128<int>.Count * 3)..]); | |
| vresult += vector; | |
| goto case 2; | |
| } | |
| case 2: | |
| { | |
| Vector128<int> vector = Vector128.Create(x[^(Vector128<int>.Count * 2)..]); | |
| vresult += vector; | |
| goto case 1; | |
| } | |
| case 1: | |
| { | |
| Vector128<int> vector = Vector128.Create(x[^(Vector128<int>.Count * 1)..]); | |
| vresult += vector; | |
| goto case 0; | |
| } | |
| case 0: | |
| { | |
| end = Vector128.ConditionalSelect(CreateRemainderMaskVector128(trailing), end, Vector128<int>.Zero); | |
| vresult += end; | |
| break; | |
| } | |
| } | |
| return Vector128.Sum(vresult); | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| static int VectorizedSmall(ReadOnlySpan<int> x) | |
| { | |
| int result = 0; | |
| switch (x.Length) | |
| { | |
| case 3: | |
| { | |
| result += x[2]; | |
| goto case 2; | |
| } | |
| case 2: | |
| { | |
| result += x[1]; | |
| goto case 1; | |
| } | |
| case 1: | |
| { | |
| result += x[0]; | |
| goto case 0; | |
| } | |
| case 0: | |
| { | |
| break; | |
| } | |
| } | |
| return result; | |
| } | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| private static Vector128<int> CreateRemainderMaskVector128(int count) | |
| { | |
| return Vector128.Create(RemainderMask[(count * Vector128<int>.Count)..]); | |
| } | |
| private static ReadOnlySpan<int> RemainderMask => | |
| [ | |
| +0, +0, +0, +0, | |
| +0, +0, +0, -1, | |
| +0, +0, -1, -1, | |
| +0, -1, -1, -1, | |
| -1, -1, -1, -1, | |
| ]; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment