macro gymnastics to implement storage kernel, buffer op and complex compute panel
This commit is contained in:
@@ -26,98 +26,58 @@
|
||||
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
/* Helpers (all compile-time): */
|
||||
#define SN_LANES(T_VEC, T) (sizeof(T_VEC) / sizeof(T))
|
||||
#define SN_MAX(a, b) (((a)) > ((b)) ? (a) : (b))
|
||||
#define SN_CEIL_DIV(a, b) (((a) + (b) - 1) / (b))
|
||||
|
||||
/* align decoration */
|
||||
/* Panel geometry helpers (all compile-time): */
|
||||
#define PANEL_Q(T, T_VEC, MINQ) SN_MAX(SN_LANES(T_VEC, T), (MINQ))
|
||||
#define PANEL_CHUNKS(T, T_VEC, MINQ) SN_CEIL_DIV(PANEL_Q(T, T_VEC, MINQ), SN_LANES(T_VEC, T))
|
||||
|
||||
#if __cplusplus && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
|
||||
#define ML_ALIGNAS(n) _Alignas(n)
|
||||
#elif defined(_MSC_VER)
|
||||
#define ML_ALIGNAS(n) __declspec(align(n))
|
||||
#else
|
||||
#define ML_ALIGNAS(n) __attribute__((aligned(n)))
|
||||
#endif
|
||||
|
||||
/* Round up to the alignment boundary in bytes */
|
||||
#ifndef ML_ALIGN_UP
|
||||
#define ML_ALIGN_UP(x, a) (((size_t)(x) + ((size_t)(a) - 1)) & ~((size_t)(a) - 1))
|
||||
#endif
|
||||
|
||||
/* Vector register width in bytes */
|
||||
#define ML_BYTES_XMM 16u
|
||||
#define ML_BYTES_YMM 32u
|
||||
#define ML_BYTES_ZMM 64u
|
||||
|
||||
/* Compute the aligned leading-direction element stride (LEp) */
|
||||
#define ML_PANEL_STRIDE_ELEMS(T, LE, ALIGN) \
|
||||
(ML_ALIGN_UP((size_t)(LE) * sizeof(T), (size_t)(ALIGN)) / sizeof(T))
|
||||
|
||||
/* Total element count and total byte count */
|
||||
#define ML_PANEL_TOT_ELEMS(T, LE, MINOR, ALIGN) \
|
||||
((size_t)ML_PANEL_STRIDE_ELEMS(T, (LE), (ALIGN)) * (size_t)(MINOR))
|
||||
|
||||
#define ML_TOT_BYTES(T, ELEMS) ((size_t)(ELEMS) * sizeof(T))
|
||||
|
||||
/* Number of SIMD view slots (ceil by total bytes) */
|
||||
#define ML_XMM_COUNT(TOT_BYTES) (((size_t)(TOT_BYTES) + ML_BYTES_XMM - 1) / ML_BYTES_XMM)
|
||||
#define ML_YMM_COUNT(TOT_BYTES) (((size_t)(TOT_BYTES) + ML_BYTES_YMM - 1) / ML_BYTES_YMM)
|
||||
#define ML_ZMM_COUNT(TOT_BYTES) (((size_t)(TOT_BYTES) + ML_BYTES_ZMM - 1) / ML_BYTES_ZMM)
|
||||
|
||||
/* ========== Unified "panel" union (no enum/descriptor fields) ==========
|
||||
Usage:
|
||||
MAT_PANEL(float, 8, 32, 32) P; // LE=8, MINOR=32, aligned to 32 bytes
|
||||
Views:
|
||||
P.xmm[] / P.ymm[] / P.zmm[] // raw SIMD blocks
|
||||
P.blk[MINOR][LEp] // 2D scalar view (includes padding for alignment)
|
||||
P.flat[MINOR*LEp] // flat array
|
||||
Notes:
|
||||
- LE/MINOR/ALIGN must be compile-time constants
|
||||
- LEp = ML_PANEL_STRIDE_ELEMS(T, LE, ALIGN)
|
||||
- Layout/semantics defined by the calling convention (e.g. blk[k][r] is element r of block k)
|
||||
/*
|
||||
Column-major square panel with minimum side Q:
|
||||
- Let R = lanes per vector = sizeof(T_VEC)/sizeof(T).
|
||||
- Side length Q = max(R, MINQ) to enforce the requested minimum extent.
|
||||
- Each column is stored contiguously via CH = ceil(Q/R) vector chunks.
|
||||
- Memory layout:
|
||||
vec[col][chunk] is a T_VEC holding up to R scalars of column 'col'
|
||||
spanning rows chunk*R .. chunk*R + (R - 1).
|
||||
flat[] mirrors the same column-major order (column stride = Q).
|
||||
- SIMD view remains integer-typed; cast inside micro-kernels to the
|
||||
appropriate floating-point/integer vector type on demand.
|
||||
*/
|
||||
#define MAT_PANEL(T, LE, MINOR, ALIGN) \
|
||||
ML_ALIGNAS(ALIGN) union { \
|
||||
/* Raw SIMD view: cast to __m256/__m512d inside the micro-kernel on demand */ \
|
||||
__m128i xmm[ML_XMM_COUNT( \
|
||||
ML_TOT_BYTES(T, ML_PANEL_TOT_ELEMS(T, (LE), (MINOR), (ALIGN))))]; \
|
||||
__m256i ymm[ML_YMM_COUNT( \
|
||||
ML_TOT_BYTES(T, ML_PANEL_TOT_ELEMS(T, (LE), (MINOR), (ALIGN))))]; \
|
||||
__m512i zmm[ML_ZMM_COUNT( \
|
||||
ML_TOT_BYTES(T, ML_PANEL_TOT_ELEMS(T, (LE), (MINOR), (ALIGN))))]; \
|
||||
/* Scalar 2D view: minor �� LEp (LE dimension contains alignment padding) */ \
|
||||
T blk[(MINOR)][ML_PANEL_STRIDE_ELEMS(T, (LE), (ALIGN))]; \
|
||||
/* Flat view */ \
|
||||
T flat[ML_PANEL_TOT_ELEMS(T, (LE), (MINOR), (ALIGN))]; \
|
||||
#define MAT_PANEL_SQ_MIN(T, T_VEC, MINQ) \
|
||||
SN_ALIGNAS(sizeof(T_VEC)) union { \
|
||||
T_VEC vec[PANEL_Q(T, T_VEC, MINQ)][PANEL_CHUNKS(T, T_VEC, MINQ)]; \
|
||||
T flat[PANEL_Q(T, T_VEC, MINQ) * PANEL_Q(T, T_VEC, MINQ)]; \
|
||||
}
|
||||
|
||||
/* ---------- SSE preset ---------- */
|
||||
#undef PANEL_LE
|
||||
#undef PANEL_MINOR
|
||||
#undef PANEL_ALIGN
|
||||
#define PANEL_LE 4
|
||||
#define PANEL_MINOR 32
|
||||
#define PANEL_ALIGN 16
|
||||
/* ======== SSE preset ========
|
||||
4 x 32, 16B aligned
|
||||
/* ISA presets with minimum square side:
|
||||
- SSE : MINQ=4 (avoid 2x2 for double)
|
||||
- AVX2 : MINQ=8
|
||||
- AVX-512: MINQ=8 (16 for float/i32 naturally, so this is a no-op there)
|
||||
*/
|
||||
#define MAT_PANEL_SSE(T) MAT_PANEL(T, PANEL_LE, PANEL_MINOR, PANEL_ALIGN)
|
||||
|
||||
/* ---------- AVX2 preset ---------- */
|
||||
#undef PANEL_LE
|
||||
#undef PANEL_MINOR
|
||||
#undef PANEL_ALIGN
|
||||
#define PANEL_LE 8
|
||||
#define PANEL_MINOR 64
|
||||
#define PANEL_ALIGN 32
|
||||
#define MAT_PANEL_AVX(T) MAT_PANEL(T, PANEL_LE, PANEL_MINOR, PANEL_ALIGN) /* 8 x 64, 32B aligned */
|
||||
/* SSE panel layout: column-major buffer holding 4 logical columns with MINQ=4.
|
||||
Columns: each column packs up to four scalars so ALIGN equals sizeof(__m128).
|
||||
Alignment: every column boundary lands on a 16-byte multiple for XMM loads. */
|
||||
#define MAT_PANEL_SSE(T) MAT_PANEL_SQ_MIN(T, __m128, 4)
|
||||
/* AVX2 panel layout: column-major buffer holding 8 logical columns with MINQ=8.
|
||||
Columns: each column stores eight elements via two 256-bit chunks when T is 32-bit.
|
||||
Alignment: column starts are 32-byte aligned so AVX2 loads/stores remain contiguous. */
|
||||
#define MAT_PANEL_AVX(T) MAT_PANEL_SQ_MIN(T, __m256, 8)
|
||||
/* AVX-512 panel layout: column-major buffer holding 8 or more columns depending on T.
|
||||
Columns: each column expands to ceil(Q/lanes) ZMM chunks; default MINQ=8 keeps double-wide tiles.
|
||||
Alignment: column starts sit on 64-byte boundaries to match AVX-512 streaming access. */
|
||||
#define MAT_PANEL_512(T) MAT_PANEL_SQ_MIN(T, __m512, 8)
|
||||
|
||||
/* ---------- AVX-512 preset ---------- */
|
||||
#undef PANEL_LE
|
||||
#undef PANEL_MINOR
|
||||
#undef PANEL_ALIGN
|
||||
#define PANEL_LE 16
|
||||
#define PANEL_MINOR 64
|
||||
#define PANEL_ALIGN 64
|
||||
#define MAT_PANEL_512(T) \
|
||||
MAT_PANEL(T, PANEL_LE, PANEL_MINOR, PANEL_ALIGN); /* 16 x 64, 64B aligned */
|
||||
/* Access helpers (all compile-time friendly):
|
||||
Given Q = PANEL_Q(...), CH = PANEL_CHUNKS(...), R = lanes per vector:
|
||||
- Column c occupies vec[c][0..CH-1].
|
||||
- Row r inside column c is located at vec[c][r / R] with lane (r % R).
|
||||
*/
|
||||
#define PANEL_COL_VEC(panel_obj, c, chunk) ((panel_obj).vec[(int)(c)][(int)(chunk)])
|
||||
/* Scalar flat index helper for column-major addressing */
|
||||
#define PANEL_ELEM(panel_obj, T, T_VEC, MINQ, r, c) \
|
||||
((panel_obj).flat[(int)(c) * PANEL_Q(T, T_VEC, MINQ) + (int)(r)])
|
||||
|
||||
Reference in New Issue
Block a user