#pragma once
#define GGML_COMMON_DECL_CPP
#include "ggml-common.h"
#include <stddef.h>
#include <stdint.h>
#if defined(__AVX2__)
#include <immintrin.h>
#endif
#define TILED_TILE_K 256
#define TILED_TILE_ROWS 256
#define TILED_MICRO 16
#define TILED_WS_SLOT (512 * 1024)
struct tiled_tile_src0 {
static constexpr int NB_MAX = TILED_TILE_K / 16;
alignas(64) uint8_t q[TILED_TILE_ROWS * TILED_TILE_K]; float d[TILED_TILE_ROWS]; float dmin[TILED_TILE_ROWS]; int32_t scales[TILED_TILE_ROWS * NB_MAX]; int32_t mins[TILED_TILE_ROWS * NB_MAX]; };
struct tiled_tile_src1 {
alignas(64) int8_t q[TILED_TILE_ROWS * TILED_TILE_K];
alignas(64) int32_t bsums[(TILED_TILE_K / 16) * TILED_TILE_ROWS];
float d[TILED_TILE_ROWS];
};
struct tiled_ws {
tiled_tile_src0 src0;
tiled_tile_src1 src1;
alignas(64) float acc[TILED_TILE_ROWS * TILED_TILE_ROWS];
};
static_assert(sizeof(tiled_ws) <= TILED_WS_SLOT, "tiled workspace exceeds the 512KB per-thread slot");
static_assert(offsetof(tiled_ws, src0) % 64 == 0, "src0 not 64B-aligned in the workspace");
static_assert(offsetof(tiled_ws, src1) % 64 == 0, "src1 not 64B-aligned in the workspace");
static_assert(offsetof(tiled_ws, acc) % 64 == 0, "acc not 64B-aligned in the workspace");
#if defined(__AVX2__)
inline void tiled_unpk_nib4(const uint8_t * src, uint8_t * lo, uint8_t * hi) {
const __m256i v = _mm256_loadu_si256((const __m256i *) src);
_mm256_storeu_si256((__m256i *) lo, _mm256_and_si256(v, _mm256_set1_epi8(0x0F)));
_mm256_storeu_si256((__m256i *) hi, _mm256_srli_epi32(_mm256_and_si256(v, _mm256_set1_epi8((int8_t) 0xF0)), 4));
}
template <int S> inline void tiled_unpk_2bit(const uint8_t * src, uint8_t * dst) {
_mm256_storeu_si256((__m256i *) dst, _mm256_and_si256(
_mm256_srli_epi32(_mm256_loadu_si256((const __m256i *) src), S), _mm256_set1_epi8(0x03)));
}
template <int S, int D, int M>
inline void tiled_unpk_or(uint8_t * dst, const uint8_t * src) {
const __m256i v = _mm256_slli_epi32(_mm256_and_si256(
_mm256_srli_epi32(_mm256_loadu_si256((const __m256i *) src), S), _mm256_set1_epi8((uint8_t) M)), D);
_mm256_storeu_si256((__m256i *) dst, _mm256_or_si256(_mm256_loadu_si256((const __m256i *) dst), v));
}
inline void tiled_lut8(const uint8_t * lut, const uint8_t * src, uint8_t * dst) {
_mm_storeu_si128((__m128i *) dst, _mm_shuffle_epi8(_mm_loadu_si128((const __m128i *) lut),
_mm_loadu_si128((const __m128i *) src)));
}
inline void tiled_unpk_sign32(uint64_t g0, uint64_t g1, uint64_t g2, uint64_t g3,
const uint8_t signs[4], uint8_t * dst32) {
const __m256i v = _mm256_set_epi64x((int64_t) g3, (int64_t) g2, (int64_t) g1, (int64_t) g0);
const __m256i sv = _mm256_shuffle_epi8(_mm256_set1_epi32((int32_t) (signs[0] | signs[1] << 8 | signs[2] << 16 | signs[3] << 24)),
_mm256_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3));
const __m256i sel = _mm256_set1_epi64x((int64_t) 0x8040201008040201ULL);
#ifdef __GFNI__
const __m256i mask = _mm256_gf2p8affine_epi64_epi8(sel, sv, 0);
#else
const __m256i mask = _mm256_cmpeq_epi8(_mm256_and_si256(sv, sel), sel);
#endif
const __m256i sgn = _mm256_sub_epi8(_mm256_xor_si256(v, mask), mask);
_mm256_storeu_si256((__m256i *) dst32, _mm256_add_epi8(sgn, _mm256_set1_epi8((int8_t) 128)));
}
inline void tiled_unpk_tern8(const uint8_t * src, int8_t delta, uint8_t * dst) {
const __m128i v = _mm_cvtepi8_epi16(_mm_loadl_epi64((const __m128i *) src));
const __m128i p = _mm_add_epi16(_mm_slli_epi16(v, 3), _mm_set1_epi16(128 + (int) delta));
_mm_storel_epi64((__m128i *) dst, _mm_packus_epi16(p, _mm_setzero_si128()));
}
#else
inline void tiled_unpk_nib4(const uint8_t * src, uint8_t * lo, uint8_t * hi) {
for (int l = 0; l < 32; l++) { lo[l] = (uint8_t) (src[l] & 0xF); hi[l] = (uint8_t) (src[l] >> 4); }
}
template <int S>
inline void tiled_unpk_2bit(const uint8_t * src, uint8_t * dst) {
for (int l = 0; l < 32; l++) { dst[l] = (uint8_t) ((src[l] >> S) & 3); }
}
template <int S, int D, int M>
inline void tiled_unpk_or(uint8_t * dst, const uint8_t * src) {
for (int l = 0; l < 32; l++) { dst[l] = (uint8_t) (dst[l] | (((src[l] >> S) & M) << D)); }
}
inline void tiled_lut8(const uint8_t * lut, const uint8_t * src, uint8_t * dst) {
for (int j = 0; j < 16; j++) { dst[j] = lut[src[j]]; }
}
inline void tiled_unpk_sign32(uint64_t g0, uint64_t g1, uint64_t g2, uint64_t g3,
const uint8_t signs[4], uint8_t * dst32) {
const uint64_t g[4] = { g0, g1, g2, g3 };
for (int l = 0; l < 4; l++) {
const uint8_t * v = (const uint8_t *) &g[l];
const uint8_t s = signs[l];
for (int j = 0; j < 8; j++) {
dst32[8 * l + j] = (s & (1 << j)) ? (uint8_t) (128 - v[j]) : (uint8_t) (128 + v[j]);
}
}
}
inline void tiled_unpk_tern8(const uint8_t * src, int8_t delta, uint8_t * dst) {
for (int j = 0; j < 8; j++) { dst[j] = (uint8_t) (128 + (int) delta + 8 * (int8_t) src[j]); }
}
#endif
template <int SUBBLK, bool HAS_MIN, int BIAS, bool ACTBIAS>
void tiled_run_microtile(const tiled_tile_src0 & src0, const tiled_tile_src1 & src1,
int i0, int j0, int num_k, int slab, float * buf, int buf_stride);
void tiled_repack_src1(tiled_tile_src1 * src1, int row0, int num_k, bool bias);
template <int SUBBLK>
void tiled_repack_src0(tiled_tile_src0 * tile, int n_rows, int num_k, int BIAS, bool corr);