#include "tiled-kernel.h"
#include "ggml.h"
#include <cstring>
#if defined(__AVX512VNNI__) || defined(__AVX2__) || defined(__AVX__)
#include <immintrin.h>
#endif
template <int SUBBLK, bool HAS_MIN, int BIAS, int NK>
static void tiled_run_microtile_scalar(const tiled_tile_src0 & src0, const tiled_tile_src1 & src1,
int i0, int j0, int num_k, int slab, float * buf, int buf_stride) {
constexpr int NB = TILED_TILE_K / SUBBLK; constexpr int NS = SUBBLK / 16;
const int nkr = (NK > 0) ? NK : num_k;
const int seff = (NK > 0) ? 0 : slab;
const int qk_stride = nkr * TILED_TILE_K;
const int qk_off = seff * TILED_TILE_K;
const int nb_stride = NB * nkr;
const int nb_off = seff * NB;
const int bs_stride = (nkr == 1) ? TILED_TILE_ROWS : TILED_MICRO;
const int bs_off = seff * TILED_MICRO;
float acc[TILED_MICRO][TILED_MICRO];
memset(acc, 0, sizeof(acc));
for (int s = 0; s < NB; s++) {
for (int j = 0; j < TILED_MICRO; j++) {
const int br = j0 + j;
const int8_t * q1 = &src1.q[br * qk_stride + qk_off + s * SUBBLK];
int32_t bsum = 0;
for (int u = 0; u < NS; u++) {
bsum += src1.bsums[(bs_off + s * NS + u) * bs_stride + br];
}
for (int i = 0; i < TILED_MICRO; i++) {
const int ar = i0 + i;
const int d_off = seff * TILED_MICRO + ar;
const uint8_t * q0 = &src0.q[ar * qk_stride + qk_off + s * SUBBLK];
int32_t raw = 0;
for (int e = 0; e < SUBBLK; e++) {
raw += (int32_t) q0[e] * (int32_t) q1[e];
}
int32_t corr = raw;
if constexpr (BIAS != 0) {
corr -= BIAS * bsum;
}
const int32_t scales_raw = (int32_t) src0.scales[ar * nb_stride + nb_off + s] * corr;
if constexpr (HAS_MIN) {
const int32_t mins_bsum = (int32_t) src0.mins[ar * nb_stride + nb_off + s] * bsum;
acc[i][j] += (float) src0.d[d_off] * (float) scales_raw
- (float) src0.dmin[d_off] * (float) mins_bsum;
} else {
acc[i][j] += (float) src0.d[d_off] * (float) scales_raw;
}
}
}
}
for (int i = 0; i < TILED_MICRO; i++) {
for (int j = 0; j < TILED_MICRO; j++) {
buf[(i0 + i) * buf_stride + (j0 + j)] += src1.d[seff * TILED_MICRO + j0 + j] * acc[i][j];
}
}
}
#if defined(__AVX512VNNI__) && defined(__AVX512VL__) && defined(__AVX512DQ__)
template <int SUBBLK, bool HAS_MIN, int BIAS, int NK>
static void tiled_run_micro_vnni_8x16(const tiled_tile_src0 & src0, const tiled_tile_src1 & src1,
int i0, int j0, int num_k, int slab, float * buf, int buf_stride) {
constexpr int NB = TILED_TILE_K / SUBBLK;
constexpr int NS = SUBBLK / 16;
constexpr int NG = SUBBLK / 4;
constexpr int NUM_ROWS = 8;
const int nkr = (NK > 0) ? NK : num_k;
const int seff = (NK > 0) ? 0 : slab;
const int qk_stride = nkr * TILED_TILE_K;
const int qk_off = seff * TILED_TILE_K;
const int nb_stride = NB * nkr;
const int nb_off = seff * NB;
const int bs_stride = (nkr == 1) ? TILED_TILE_ROWS : TILED_MICRO;
const int bs_off = seff * TILED_MICRO;
const __m512 d1_vec = _mm512_load_ps(&src1.d[seff * TILED_MICRO + j0]);
__m512i s1_acc[NUM_ROWS];
for (int t = 0; t < NUM_ROWS; t++) { s1_acc[t] = _mm512_setzero_si512(); }
__m512i s2_acc[NUM_ROWS];
if constexpr (HAS_MIN) {
for (int t = 0; t < NUM_ROWS; t++) { s2_acc[t] = _mm512_setzero_si512(); }
}
const int32_t * bsums = src1.bsums; for (int s = 0; s < NB; s++) {
__m512i bsums32 = _mm512_load_si512((const __m512i *) &bsums[(bs_off + s * NS) * bs_stride + j0]);
for (int u = 1; u < NS; u++) {
bsums32 = _mm512_add_epi32(bsums32, _mm512_load_si512((const __m512i *) &bsums[(bs_off + s * NS + u) * bs_stride + j0]));
}
__m512i bias32 = _mm512_setzero_si512();
if constexpr (BIAS != 0) {
bias32 = _mm512_mullo_epi32(bsums32, _mm512_set1_epi32(BIAS));
}
__m512i acc16[NUM_ROWS];
for (int t = 0; t < NUM_ROWS; t++) { acc16[t] = _mm512_setzero_si512(); }
#ifdef __GNUC__
#pragma GCC unroll 8
#endif
for (int g = 0; g < NG; g++) {
const int kg = s * NG + g;
const __m512i codes = _mm512_load_si512((const __m512i *) &src1.q[(j0 / TILED_MICRO) * (TILED_MICRO * qk_stride)
+ qk_off + (kg % TILED_MICRO) * qk_stride + (kg / TILED_MICRO) * (TILED_MICRO * 4)]);
for (int t = 0; t < NUM_ROWS; t++) {
const uint32_t u4 = *(const uint32_t *) &src0.q[(i0 + t) * qk_stride + qk_off + kg * 4];
const __m512i u4b = _mm512_set1_epi32((int) u4);
acc16[t] = _mm512_dpbusd_epi32(acc16[t], u4b, codes);
}
}
for (int t = 0; t < NUM_ROWS; t++) {
const int ar = i0 + t;
__m512i rawi = acc16[t];
if constexpr (BIAS != 0) {
rawi = _mm512_sub_epi32(rawi, bias32);
}
s1_acc[t] = _mm512_add_epi32(s1_acc[t],
_mm512_mullo_epi32(rawi, _mm512_set1_epi32(src0.scales[ar * nb_stride + nb_off + s])));
}
}
if constexpr (HAS_MIN) {
for (int s = 0; s < NB; s++) {
__m512i bsums32 = _mm512_load_si512((const __m512i *) &bsums[(bs_off + s * NS) * bs_stride + j0]);
for (int u = 1; u < NS; u++) {
bsums32 = _mm512_add_epi32(bsums32, _mm512_load_si512((const __m512i *) &bsums[(bs_off + s * NS + u) * bs_stride + j0]));
}
for (int t = 0; t < NUM_ROWS; t++) {
s2_acc[t] = _mm512_add_epi32(s2_acc[t],
_mm512_mullo_epi32(bsums32, _mm512_set1_epi32(src0.mins[(i0 + t) * nb_stride + nb_off + s])));
}
}
}
for (int t = 0; t < NUM_ROWS; t++) {
const int ar = i0 + t;
const int d_off = seff * TILED_MICRO + ar;
__m512 f1 = _mm512_cvtepi32_ps(s1_acc[t]);
__m512 result = _mm512_mul_ps(f1, _mm512_set1_ps(src0.d[d_off]));
if constexpr (HAS_MIN) {
__m512 f2 = _mm512_cvtepi32_ps(s2_acc[t]);
result = _mm512_fnmadd_ps(_mm512_set1_ps(src0.dmin[d_off]), f2, result);
}
float * p = &buf[(i0 + t) * buf_stride + j0];
_mm512_store_ps(p, _mm512_add_ps(_mm512_load_ps(p), _mm512_mul_ps(result, d1_vec)));
}
}
template <int SUBBLK, bool HAS_MIN, int BIAS, int NK>
static void tiled_run_microtile_vnni(const tiled_tile_src0 & src0, const tiled_tile_src1 & src1,
int i0, int j0, int num_k, int slab, float * buf, int buf_stride) {
tiled_run_micro_vnni_8x16<SUBBLK, HAS_MIN, BIAS, NK>(src0, src1, i0, j0, num_k, slab, buf, buf_stride);
tiled_run_micro_vnni_8x16<SUBBLK, HAS_MIN, BIAS, NK>(src0, src1, i0 + 8, j0, num_k, slab, buf, buf_stride);
}
#endif
#if defined(__AVX2__)
template <int SUBBLK, bool HAS_MIN, int BIAS, int NK, bool ACTBIAS>
static void tiled_run_microtile_avx2(const tiled_tile_src0 & src0, const tiled_tile_src1 & src1,
int i0, int j0, int num_k, int slab, float * buf, int buf_stride) {
constexpr int NB = TILED_TILE_K / SUBBLK;
constexpr int GROUP = 8;
static_assert(SUBBLK == 16 || SUBBLK == 32, "unsupported SUBBLK");
const int nkr = (NK > 0) ? NK : num_k;
const int seff = (NK > 0) ? 0 : slab;
const int qk_stride = nkr * TILED_TILE_K;
const int qk_off = seff * TILED_TILE_K;
const int nb_stride = NB * nkr;
const int nb_off = seff * NB;
const int bs_stride = (nkr == 1) ? TILED_TILE_ROWS : TILED_MICRO;
const int bs_off = seff * TILED_MICRO;
auto hsum256_epi32 = [](const __m256i v) -> int32_t {
__m128i low = _mm256_castsi256_si128(v);
__m128i high = _mm256_extracti128_si256(v, 1);
__m128i sum128 = _mm_add_epi32(low, high);
sum128 = _mm_add_epi32(sum128, _mm_shuffle_epi32(sum128, _MM_SHUFFLE(2, 3, 0, 1)));
sum128 = _mm_add_epi32(sum128, _mm_shuffle_epi32(sum128, _MM_SHUFFLE(1, 0, 3, 2)));
return _mm_cvtsi128_si32(sum128);
};
for (int i = 0; i < TILED_MICRO; i++) {
const int ar = i0 + i;
const int d_off = seff * TILED_MICRO + ar;
const float d0 = src0.d[d_off];
const float dmin0 = src0.dmin[d_off];
const uint8_t * q0 = &src0.q[ar * qk_stride + qk_off];
const int32_t * scales_row = &src0.scales[ar * nb_stride + nb_off];
const int32_t * mins_row = &src0.mins[ar * nb_stride + nb_off];
for (int g = 0; g < TILED_MICRO; g += GROUP) {
const int8_t * q1_ptr[GROUP];
for (int t = 0; t < GROUP; t++) {
q1_ptr[t] = &src1.q[(j0 + g + t) * qk_stride + qk_off];
}
__m256i s2 = _mm256_setzero_si256();
__m256i acc[GROUP];
for (int t = 0; t < GROUP; t++) {
acc[t] = _mm256_setzero_si256();
}
if constexpr (SUBBLK == 32) {
for (int s = 0; s < NB; s++) {
const __m256i q0_32 = _mm256_load_si256((const __m256i *) &q0[s * SUBBLK]);
const __m256i scales16 = _mm256_set1_epi16(scales_row[s]);
if constexpr (BIAS != 0) {
const __m256i w = _mm256_sub_epi8(q0_32, _mm256_set1_epi8((int8_t) BIAS)); if constexpr (ACTBIAS) {
#pragma GCC unroll 8
for (int t = 0; t < GROUP; t++) {
const __m256i q1b_32 = _mm256_load_si256((const __m256i *) &q1_ptr[t][s * SUBBLK]);
acc[t] = _mm256_add_epi32(acc[t],
_mm256_madd_epi16(scales16, _mm256_maddubs_epi16(q1b_32, w)));
}
} else {
const __m256i ax = _mm256_sign_epi8(w, w);
#pragma GCC unroll 8
for (int t = 0; t < GROUP; t++) {
const __m256i q1_32 = _mm256_load_si256((const __m256i *) &q1_ptr[t][s * SUBBLK]);
acc[t] = _mm256_add_epi32(acc[t],
_mm256_madd_epi16(scales16, _mm256_maddubs_epi16(ax, _mm256_sign_epi8(q1_32, w))));
}
}
} else {
#pragma GCC unroll 8
for (int t = 0; t < GROUP; t++) {
const __m256i q1_32 = _mm256_load_si256((const __m256i *) &q1_ptr[t][s * SUBBLK]);
acc[t] = _mm256_add_epi32(acc[t],
_mm256_madd_epi16(scales16, _mm256_maddubs_epi16(q0_32, q1_32)));
}
}
if constexpr (HAS_MIN) {
const __m256i bsums_v = _mm256_add_epi32(
_mm256_load_si256((const __m256i *) &src1.bsums[(bs_off + s * 2) * bs_stride + j0 + g]),
_mm256_load_si256((const __m256i *) &src1.bsums[(bs_off + s * 2 + 1) * bs_stride + j0 + g]));
s2 = _mm256_add_epi32(s2, _mm256_mullo_epi32(bsums_v, _mm256_set1_epi32(mins_row[s])));
}
}
} else { for (int sp = 0; sp < NB; sp += 2) {
const __m256i q0_32 = _mm256_load_si256((const __m256i *) &q0[sp * SUBBLK]);
const __m256i scalesv = _mm256_set_m128i(_mm_set1_epi16(scales_row[sp + 1]), _mm_set1_epi16(scales_row[sp]));
if constexpr (BIAS != 0) {
const __m256i w = _mm256_sub_epi8(q0_32, _mm256_set1_epi8((int8_t) BIAS)); if constexpr (ACTBIAS) {
#pragma GCC unroll 8
for (int t = 0; t < GROUP; t++) {
const __m256i q1b_32 = _mm256_load_si256((const __m256i *) &q1_ptr[t][sp * SUBBLK]);
acc[t] = _mm256_add_epi32(acc[t], _mm256_madd_epi16(
scalesv, _mm256_maddubs_epi16(q1b_32, w)));
}
} else {
const __m256i ax = _mm256_sign_epi8(w, w);
#pragma GCC unroll 8
for (int t = 0; t < GROUP; t++) {
const __m256i q1_32 = _mm256_load_si256((const __m256i *) &q1_ptr[t][sp * SUBBLK]);
acc[t] = _mm256_add_epi32(acc[t], _mm256_madd_epi16(
scalesv, _mm256_maddubs_epi16(ax, _mm256_sign_epi8(q1_32, w))));
}
}
} else {
#pragma GCC unroll 8
for (int t = 0; t < GROUP; t++) {
const __m256i q1_32 = _mm256_load_si256((const __m256i *) &q1_ptr[t][sp * SUBBLK]);
acc[t] = _mm256_add_epi32(acc[t], _mm256_madd_epi16(
scalesv, _mm256_maddubs_epi16(q0_32, q1_32)));
}
}
if constexpr (HAS_MIN) {
const __m256i bsums0_v = _mm256_load_si256((const __m256i *) &src1.bsums[(bs_off + sp) * bs_stride + j0 + g]);
const __m256i bsums1_v = _mm256_load_si256((const __m256i *) &src1.bsums[(bs_off + sp + 1) * bs_stride + j0 + g]);
s2 = _mm256_add_epi32(s2, _mm256_add_epi32(
_mm256_mullo_epi32(bsums0_v, _mm256_set1_epi32(mins_row[sp])),
_mm256_mullo_epi32(bsums1_v, _mm256_set1_epi32(mins_row[sp + 1]))));
}
}
}
alignas(32) int32_t s1_vals[GROUP];
#pragma GCC unroll 8
for (int t = 0; t < GROUP; t++) {
s1_vals[t] = hsum256_epi32(acc[t]);
}
__m256i s1_vec = _mm256_load_si256((const __m256i *) s1_vals);
if constexpr (BIAS != 0 && ACTBIAS) {
s1_vec = _mm256_sub_epi32(s1_vec, _mm256_set1_epi32(mins_row[0]));
}
const __m256 src1_d_vec = _mm256_load_ps(&src1.d[seff * TILED_MICRO + j0 + g]);
__m256 res_vec = _mm256_mul_ps(_mm256_set1_ps(d0), _mm256_cvtepi32_ps(s1_vec));
if constexpr (HAS_MIN) {
#if defined(__FMA__)
res_vec = _mm256_fnmadd_ps(_mm256_set1_ps(dmin0), _mm256_cvtepi32_ps(s2), res_vec);
#else
res_vec = _mm256_sub_ps(res_vec, _mm256_mul_ps(_mm256_set1_ps(dmin0), _mm256_cvtepi32_ps(s2)));
#endif
}
float * buf_ptr = &buf[ar * buf_stride + j0 + g];
__m256 current_buf = _mm256_loadu_ps(buf_ptr);
#if defined(__FMA__)
__m256 updated_buf = _mm256_fmadd_ps(res_vec, src1_d_vec, current_buf);
#else
__m256 updated_buf = _mm256_add_ps(current_buf, _mm256_mul_ps(res_vec, src1_d_vec));
#endif
_mm256_storeu_ps(buf_ptr, updated_buf);
}
}
}
#endif
#if defined(__AVX__) && !defined(__AVX2__)
template <int SUBBLK, bool HAS_MIN, int BIAS, int NK>
static void tiled_run_microtile_avx(const tiled_tile_src0 & src0, const tiled_tile_src1 & src1,
int i0, int j0, int num_k, int slab, float * buf, int buf_stride) {
constexpr int NB = TILED_TILE_K / SUBBLK;
constexpr int NS = SUBBLK / 16;
constexpr int GROUP = 4;
const int nkr = (NK > 0) ? NK : num_k;
const int seff = (NK > 0) ? 0 : slab;
const int qk_stride = nkr * TILED_TILE_K;
const int qk_off = seff * TILED_TILE_K;
const int nb_stride = NB * nkr;
const int nb_off = seff * NB;
const int bs_stride = (nkr == 1) ? TILED_TILE_ROWS : TILED_MICRO;
const int bs_off = seff * TILED_MICRO;
for (int i = 0; i < TILED_MICRO; i++) {
const int ar = i0 + i;
const int d_off = seff * TILED_MICRO + ar;
const float d0 = src0.d[d_off];
const float dmin0 = src0.dmin[d_off];
const uint8_t * q0 = &src0.q[ar * qk_stride + qk_off];
const int32_t * scales_row = &src0.scales[ar * nb_stride + nb_off];
const int32_t * mins_row = &src0.mins[ar * nb_stride + nb_off];
for (int g = 0; g < TILED_MICRO; g += GROUP) {
const int8_t * q1g[GROUP];
__m128i acc[GROUP];
__m128i s2 = _mm_setzero_si128(); for (int t = 0; t < GROUP; t++) {
q1g[t] = &src1.q[(j0 + g + t) * qk_stride + qk_off];
acc[t] = _mm_setzero_si128();
}
for (int s = 0; s < NB; s++) {
const __m128i scales16 = _mm_set1_epi16(scales_row[s]);
if constexpr (HAS_MIN) {
__m128i bsums_v = _mm_setzero_si128(); for (int u = 0; u < NS; u++) {
bsums_v = _mm_add_epi32(bsums_v, _mm_loadu_si128(
(const __m128i *) &src1.bsums[(bs_off + s * NS + u) * bs_stride + j0 + g]));
}
s2 = _mm_add_epi32(s2, _mm_mullo_epi32(bsums_v, _mm_set1_epi32(mins_row[s])));
}
for (int u = 0; u < NS; u++) {
const __m128i a16 = _mm_loadu_si128((const __m128i *) &q0[s * SUBBLK + u * 16]);
if constexpr (BIAS != 0) {
const __m128i a16s = _mm_sub_epi8(a16, _mm_set1_epi8((int8_t) BIAS));
const __m128i ax = _mm_sign_epi8(a16s, a16s);
for (int t = 0; t < GROUP; t++) {
const __m128i q1_16 = _mm_loadu_si128((const __m128i *) &q1g[t][s * SUBBLK + u * 16]);
acc[t] = _mm_add_epi32(acc[t],
_mm_madd_epi16(scales16, _mm_maddubs_epi16(ax, _mm_sign_epi8(q1_16, a16s))));
}
} else {
for (int t = 0; t < GROUP; t++) {
acc[t] = _mm_add_epi32(acc[t], _mm_madd_epi16(scales16,
_mm_maddubs_epi16(a16,
_mm_loadu_si128((const __m128i *) &q1g[t][s * SUBBLK + u * 16]))));
}
}
}
}
int32_t s2_s[GROUP] = { 0, 0, 0, 0 };
if constexpr (HAS_MIN) {
_mm_storeu_si128((__m128i *) s2_s, s2);
}
for (int t = 0; t < GROUP; t++) {
__m128i v = _mm_shuffle_epi32(acc[t], _MM_SHUFFLE(2, 3, 0, 1));
acc[t] = _mm_add_epi32(acc[t], v);
v = _mm_shuffle_epi32(acc[t], _MM_SHUFFLE(1, 0, 3, 2));
acc[t] = _mm_add_epi32(acc[t], v);
const int32_t s1 = _mm_cvtsi128_si32(acc[t]);
float res = d0 * (float) s1;
if constexpr (HAS_MIN) {
res -= dmin0 * (float) s2_s[t];
}
buf[ar * buf_stride + j0 + g + t] += src1.d[seff * TILED_MICRO + j0 + g + t] * res;
}
}
}
}
#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) {
const bool standard = (num_k == 1);
#if defined(__AVX512VNNI__) && defined(__AVX512VL__) && defined(__AVX512DQ__)
if (standard) {
tiled_run_microtile_vnni<SUBBLK, HAS_MIN, BIAS, 1>(src0, src1, i0, j0, num_k, slab, buf, buf_stride);
} else {
tiled_run_microtile_vnni<SUBBLK, HAS_MIN, BIAS, 0>(src0, src1, i0, j0, num_k, slab, buf, buf_stride);
}
#elif defined(__AVX2__)
if (standard) {
tiled_run_microtile_avx2<SUBBLK, HAS_MIN, BIAS, 1, ACTBIAS>(src0, src1, i0, j0, num_k, slab, buf, buf_stride);
} else {
tiled_run_microtile_avx2<SUBBLK, HAS_MIN, BIAS, 0, ACTBIAS>(src0, src1, i0, j0, num_k, slab, buf, buf_stride);
}
#elif defined(__AVX__)
if (standard) {
tiled_run_microtile_avx<SUBBLK, HAS_MIN, BIAS, 1>(src0, src1, i0, j0, num_k, slab, buf, buf_stride);
} else {
tiled_run_microtile_avx<SUBBLK, HAS_MIN, BIAS, 0>(src0, src1, i0, j0, num_k, slab, buf, buf_stride);
}
#else
if (standard) {
tiled_run_microtile_scalar<SUBBLK, HAS_MIN, BIAS, 1>(src0, src1, i0, j0, num_k, slab, buf, buf_stride);
} else {
tiled_run_microtile_scalar<SUBBLK, HAS_MIN, BIAS, 0>(src0, src1, i0, j0, num_k, slab, buf, buf_stride);
}
#endif
}
template void tiled_run_microtile<32, true, 0, false>(const tiled_tile_src0 & src0, const tiled_tile_src1 & src1,
int i0, int j0, int num_k, int slab, float * buf, int buf_stride);
template void tiled_run_microtile<32, false, 128, false>(const tiled_tile_src0 & src0, const tiled_tile_src1 & src1,
int i0, int j0, int num_k, int slab, float * buf, int buf_stride);
template void tiled_run_microtile<32, false, 128, true>(const tiled_tile_src0 & src0, const tiled_tile_src1 & src1,
int i0, int j0, int num_k, int slab, float * buf, int buf_stride);
template void tiled_run_microtile<16, false, 128, true>(const tiled_tile_src0 & src0, const tiled_tile_src1 & src1,
int i0, int j0, int num_k, int slab, float * buf, int buf_stride);
template void tiled_run_microtile<16, false, 32, true>(const tiled_tile_src0 & src0, const tiled_tile_src1 & src1,
int i0, int j0, int num_k, int slab, float * buf, int buf_stride);
template void tiled_run_microtile<16, false, 4, true>(const tiled_tile_src0 & src0, const tiled_tile_src1 & src1,
int i0, int j0, int num_k, int slab, float * buf, int buf_stride);
template void tiled_run_microtile<16, true, 0, false>(const tiled_tile_src0 & src0, const tiled_tile_src1 & src1,
int i0, int j0, int num_k, int slab, float * buf, int buf_stride);
#define MIN(a, b) ((a) < (b) ? (a) : (b))
static_assert(sizeof(block_q8_K) == 292 && offsetof(block_q8_K, qs) == 4,
"block_q8_K layout changed, fix the src1 repack");
#if defined(__AVX512VNNI__) && defined(__AVX512VL__) && defined(__AVX512DQ__)
void tiled_repack_src1(tiled_tile_src1 * src1, int row0, int num_k, bool bias) {
GGML_UNUSED(bias);
const int n_tiles = num_k * (TILED_TILE_K / (TILED_MICRO * 4));
const int row_stride = num_k * TILED_TILE_K;
uint8_t * base = (uint8_t *) src1->q + row0 * row_stride;
for (int t = 0; t < n_tiles; t++) {
uint8_t * cbase = base + t * (TILED_MICRO * 4);
__m512i v[16];
for (int r = 0; r < 16; r++) {
v[r] = _mm512_load_si512((const __m512i *) (cbase + r * row_stride));
}
{
const __m512i idx_a = _mm512_setr_epi32(0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23);
const __m512i idx_b = _mm512_setr_epi32(8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31);
for (int i = 0; i < 16; i += 2) {
__m512i a = v[i], b = v[i+1];
v[i] = _mm512_permutex2var_epi32(a, idx_a, b);
v[i+1] = _mm512_permutex2var_epi32(a, idx_b, b);
}
}
{
const __m512i idx_a = _mm512_setr_epi32(0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29);
const __m512i idx_b = _mm512_setr_epi32(2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31);
for (int i = 0; i < 16; i += 4) {
__m512i a = v[i], b = v[i+2];
v[i] = _mm512_permutex2var_epi32(a, idx_a, b);
v[i+2] = _mm512_permutex2var_epi32(a, idx_b, b);
a = v[i+1], b = v[i+3];
v[i+1] = _mm512_permutex2var_epi32(a, idx_a, b);
v[i+3] = _mm512_permutex2var_epi32(a, idx_b, b);
}
}
{
const __m512i idx_a = _mm512_setr_epi32(0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23);
const __m512i idx_b = _mm512_setr_epi32(8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31);
for (int i = 0; i < 16; i += 8) {
for (int j = 0; j < 4; j++) {
__m512i a = v[i+j], b = v[i+4+j];
v[i+j] = _mm512_permutex2var_epi32(a, idx_a, b);
v[i+4+j] = _mm512_permutex2var_epi32(a, idx_b, b);
}
}
}
{
const __m512i idx_a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23);
const __m512i idx_b = _mm512_setr_epi32(8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31);
for (int i = 0; i < 8; i++) {
__m512i a = v[i], b = v[i+8];
v[i] = _mm512_permutex2var_epi32(a, idx_a, b);
v[i+8] = _mm512_permutex2var_epi32(a, idx_b, b);
}
}
static const int col_order[16] = {0, 8, 1, 9, 4, 12, 5, 13, 2, 10, 3, 11, 6, 14, 7, 15};
for (int g = 0; g < 16; g++) {
_mm512_store_si512((void *) (cbase + col_order[g] * row_stride), v[g]);
}
}
}
#elif defined(__AVX2__)
void tiled_repack_src1(tiled_tile_src1 * src1, int row0, int num_k, bool bias) {
if (!bias) {
return;
}
const int row_stride = num_k * TILED_TILE_K;
uint8_t * base = (uint8_t *) src1->q + row0 * row_stride;
const int nbytes = row_stride; const __m256i b128 = _mm256_set1_epi8((int8_t) 0x80);
for (int r = 0; r < TILED_MICRO; r++) {
uint8_t * row = base + r * row_stride;
for (int off = 0; off < nbytes; off += 32) {
const __m256i v = _mm256_loadu_si256((const __m256i *) (row + off));
_mm256_storeu_si256((__m256i *) (row + off), _mm256_xor_si256(v, b128));
}
}
}
#else
void tiled_repack_src1(tiled_tile_src1 * src1, int row0, int num_k, bool bias) {
GGML_UNUSED(src1); GGML_UNUSED(row0); GGML_UNUSED(num_k); GGML_UNUSED(bias);
}
#endif
#if defined(__AVX2__)
static int32_t tiled_byte_sum_32(const uint8_t * p) {
const __m256i dot = _mm256_maddubs_epi16(_mm256_loadu_si256((const __m256i *) p), _mm256_set1_epi8(1));
const __m256i sum = _mm256_madd_epi16(_mm256_set1_epi16(1), dot); const __m128i t = _mm_add_epi32(_mm256_castsi256_si128(sum), _mm256_extracti128_si256(sum, 1));
const __m128i h = _mm_hadd_epi32(t, t);
return _mm_cvtsi128_si32(_mm_hadd_epi32(h, h));
}
static int32_t tiled_byte_sum_16(const uint8_t * p) {
const __m128i dot = _mm_maddubs_epi16(_mm_loadu_si128((const __m128i *) p), _mm_set1_epi8(1));
const __m128i sum = _mm_madd_epi16(_mm_set1_epi16(1), dot); const __m128i h = _mm_hadd_epi32(sum, sum);
return _mm_cvtsi128_si32(_mm_hadd_epi32(h, h));
}
#endif
template <int SUBBLK>
void tiled_repack_src0(tiled_tile_src0 * tile, int n_rows, int num_k, int BIAS, bool corr) {
#if defined(__AVX2__)
if (!corr) {
return;
}
constexpr int NB = TILED_TILE_K / SUBBLK;
const int nb_stride = NB * num_k;
for (int slab = 0; slab < num_k; slab++) {
for (int r = 0; r < n_rows; r++) {
const uint8_t * q = &tile->q[r * (num_k * TILED_TILE_K) + slab * TILED_TILE_K];
const int32_t * scales = &tile->scales[r * nb_stride + slab * NB];
int32_t corr_val = 0;
for (int s = 0; s < NB; s++) {
const int32_t qsum = (SUBBLK == 32) ? tiled_byte_sum_32(&q[s * SUBBLK]) : tiled_byte_sum_16(&q[s * SUBBLK]);
corr_val += 128 * scales[s] * (qsum - SUBBLK * BIAS);
}
tile->mins[r * nb_stride + slab * NB] = corr_val;
}
}
#else
GGML_UNUSED(tile); GGML_UNUSED(n_rows); GGML_UNUSED(num_k); GGML_UNUSED(BIAS); GGML_UNUSED(corr);
#endif
}
template void tiled_repack_src0<16>(tiled_tile_src0 * tile, int n_rows, int num_k, int BIAS, bool corr);
template void tiled_repack_src0<32>(tiled_tile_src0 * tile, int n_rows, int num_k, int BIAS, bool corr);