using System.Runtime.CompilerServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; namespace Robust.Shared.Maths { /// /// Helper stuff for SIMD code. /// internal static class SimdHelpers { /// A vector with the horizontal minimum and maximum values arranged as { min max min max} . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 MinMaxHorizontalSse(Vector128 input) { var tmp = Sse.Shuffle(input, input, 0b00_01_10_11); var min = Sse.Min(tmp, input); var max = Sse.Max(tmp, input); tmp = Sse.Shuffle(min, max, 0b01_00_00_01); min = Sse.Min(tmp, min); max = Sse.Max(tmp, max); tmp = Sse.MoveScalar(max, min); // no generic Vector128 equivalent :( return Sse.Shuffle(tmp, tmp, 0b11_00_11_00); } /// A vector with the horizontal minimum and maximum values arranged as { max min max min} . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 MaxMinHorizontalSse(Vector128 input) { var tmp = Sse.Shuffle(input, input, 0b00_01_10_11); var min = Sse.Min(tmp, input); var max = Sse.Max(tmp, input); tmp = Sse.Shuffle(min, max, 0b01_00_00_01); min = Sse.Min(tmp, min); max = Sse.Max(tmp, max); tmp = Sse.MoveScalar(max, min); // no generic Vector128 equivalent :( return Sse.Shuffle(tmp, tmp, 0b00_11_00_11); } /// The min value is broadcast to the whole vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 MinHorizontal128(Vector128 v) { var b = Vector128.Shuffle(v, Vector128.Create(1, 0, 3, 2)); var m = Vector128.Min(b, v); var c = Vector128.Shuffle(m, Vector128.Create(2, 3, 0, 1)); return Vector128.Min(c, m); } /// The max value is broadcast to the whole vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 MaxHorizontal128(Vector128 v) { var b = Vector128.Shuffle(v, Vector128.Create(1, 0, 3, 2)); var m = Vector128.Max(b, v); var c = Vector128.Shuffle(m, Vector128.Create(2, 3, 0, 1)); return Vector128.Max(c, m); } /// The added value is broadcast to the whole vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 AddHorizontal128(Vector128 v) { var b = Vector128.Shuffle(v, Vector128.Create(1, 0, 3, 2)); var m = b + v; var c = Vector128.Shuffle(m, Vector128.Create(2, 3, 0, 1)); return c + m; } /// The added value is broadcast to the whole vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 AddHorizontal256(Vector256 v) { var b = Vector256.Shuffle(v, Vector256.Create(1, 0, 3, 2, 5, 4, 7, 6)); var m = b + v; var c = Vector256.Shuffle(m, Vector256.Create(2, 3, 0, 1, 6, 7, 4, 5)); var n = c + m; var d = Vector256.Shuffle(n, Vector256.Create(4, 5, 6, 7, 0, 1, 2, 3)); return n + d; } // Given the following vectors: // x: X X X X // y: Y Y Y Y // z: Z Z Z Z // w: W W W W // Returns: X Y Z W [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 MergeRows128( Vector128 x, Vector128 y, Vector128 z, Vector128 w) { if (Sse.IsSupported) { var xy = Sse.UnpackLow(x, y); var zw = Sse.UnpackLow(z, w); return Sse.Shuffle(xy, zw, 0b11_10_01_00); } return Vector128.Create( x.GetElement(0), y.GetElement(0), z.GetElement(0), w.GetElement(0)); } } }