// ----------------------------------------------------------------------------- // file="MatrixPanel" // Project: StgSharp // Copyright (c) Nitload. // SPDX-License-Identifier: MIT // ----------------------------------------------------------------------------- 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 => MatrixPanel.Elements(ref Head); } }