//----------------------------------------------------------------------- // ----------------------------------------------------------------------- // file="MatrixPanel" // Project: StgSharp // AuthorGroup: Nitload // Copyright (c) Nitload. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS 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. // // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- using StgSharp.Mathematics.Internal; using StgSharp.Mathematics.Numeric; using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace StgSharp.Mathematics.Numeric { public unsafe struct MatrixPanel { public const int AlignmentBytes = 64; private byte Head; // Allocate aligned memory for one panel; caller must free via Destroy. public static unsafe MatrixPanel* Create() where T : unmanaged, INumber { return (MatrixPanel*)NativeMemory.AlignedAlloc(Size(), AlignmentBytes); } public static unsafe void Destroy( MatrixPanel* panel ) where T : unmanaged, INumber { NativeMemory.AlignedFree(panel); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe Span Elements( ref T head ) where T : unmanaged, INumber { void* p = Unsafe.AsPointer(ref head); return new Span(p, MaxElementCount()); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ElementSideLength() where T : unmanaged, INumber { return PanelSideLength(); } public static int MaxElementCount() where T : unmanaged, INumber { int side = ElementSideLength(); return side * side; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static nuint Size() where T : unmanaged, INumber { return (nuint)(MaxElementCount() * sizeof(T)); } /// /// Number of 4x4 kernels that fit in a panel for the given ISA and element T. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int KernelCapacity() where T : unmanaged, INumber { int perSide = KernelSideCount(); return perSide * perSide; } /// /// How many 4x4 kernels fit along a single panel dimension for the given ISA. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int KernelSideCount() where T : unmanaged, INumber { SIMDID id = NumericalModule.GlobalIntrinsicMask; switch (id.MaskByte[0] & 0b_00001111) { case 1: return id.MaskByte[1] switch { 1 => KernelSideCountSse(), 2 => KernelSideCountAvx2(), 3 => KernelSideCountAvx512(), _ => throw new NotSupportedException("Unsupported SIMD level."), }; default: throw new NotSupportedException("Current hardware platform is not supported"); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe nuint Align64( void* p ) { return ((nuint)p + (AlignmentBytes - 1)) & ~(nuint)(AlignmentBytes - 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int KernelSideCountAvx2() where T : unmanaged, INumber { return PanelSideFromBits(256) / 4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int KernelSideCountAvx512() where T : unmanaged, INumber { return PanelSideFromBits(512) / 4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int KernelSideCountSse() where T : unmanaged, INumber { return PanelSideFromBits(128) / 4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int PanelSideFromBits( int vectorBits ) where T : unmanaged, INumber { int elemBits = sizeof(T) * 8; // Q = max(4, vectorBits/64, vectorBits/elemBits) int by64 = vectorBits / 64; int byElem = vectorBits / elemBits; int side = Math.Max(4, Math.Max(by64, byElem)); return side; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int PanelSideLength() where T : unmanaged, INumber { SIMDID id = NumericalModule.GlobalIntrinsicMask; switch (id.MaskByte[0] & 0b_00001111) { case 1: return id.MaskByte[1] switch { 1 => PanelSideFromBits(128), 2 => PanelSideFromBits(256), 3 => PanelSideFromBits(512), _ => throw new NotSupportedException("Unsupported SIMD level."), }; default: throw new NotSupportedException("Current hardware platform is not supported"); } } } // Single POD-style panel: ZMM-compatible size. Alignment handled by allocator, not by the struct. public unsafe struct MatrixPanel where T : unmanaged, INumber { internal T Head; // first element of the panel buffer public ref T this[ int column, int row ] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => ref Unsafe.Add(ref Head, row * MatrixPanel.ElementSideLength() + column); } public Span Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => MatrixPanel.Elements(ref Head); } } }