char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
37a77fb05
char/aliceai-t5-moe
1#if defined(__GNUC__ ) 2#pragma GCC diagnostic ignored "-Wpedantic" 3#pragma GCC diagnostic ignored "-Wunused-local-typedefs" 4#endif 5 6#include "amx.h" 7#include "mmq.h" 8#include "ggml-impl.h" 9#include "ggml-cpu-impl.h" 10#include "simd-mappings.h" 11#include "quants.h" 12#include "ggml-quants.h" 13#include <algorithm> 14#include <type_traits> 15 16#if defined(__gnu_linux__ ) 17#include <sys/syscall.h> 18#include <unistd.h> 19#endif 20 21#if (defined(_WIN32 )|| defined(_WIN64 )) 22#define RESTRICT __restrict 23#else 24#define RESTRICT __restrict__ 25#endif 26 27#if (defined(_WIN32 )|| defined(_WIN64 )) 28#define ALWAYS_INLINE __forceinline 29#elif __has_attribute (always_inline )|| defined(__GNUC__ ) 30#define ALWAYS_INLINE __attribute__((__always_inline__)) inline 31#else 32#define ALWAYS_INLINE inline 33#endif 34 35#if defined(__AMX_INT8__ )&& defined(__AVX512VNNI__ ) 36 37namespace { 38 39// Forced unrolling 40template < int n > 41struct Unroll { 42template < typename Func ,typename ...Args > 43ALWAYS_INLINE void operator()(const Func & f ,Args ...args )const { 44Unroll < n - 1 > {}(f ,args ...); 45f (std::integral_constant < int ,n - 1 > {},args ...); 46 } 47}; 48 49template <> 50struct Unroll < 1 > { 51template < typename Func ,typename ...Args > 52ALWAYS_INLINE void operator()(const Func & f ,Args ...args )const { 53f (std::integral_constant < int ,0 > {},args ...); 54 } 55}; 56 57// type traits 58template < typename T > struct PackedTypes {}; 59template <> struct PackedTypes < block_q4_0 > {using type = int8_t ; }; 60template <> struct PackedTypes < block_q4_1 > {using type = uint8_t ; }; 61template <> struct PackedTypes < block_q8_0 > {using type = int8_t ; }; 62template < typename T > using packed_B_type = typename PackedTypes < T > ::type ; 63 64template < typename T > 65struct do_compensate : std::integral_constant < bool , 66 std::is_same < T ,block_q8_0 > ::value > {}; 67 68template < typename T > 69struct do_unpack : std::integral_constant < bool , 70 std::is_same < T ,block_q4_0 > ::value || 71 std::is_same < T ,block_q4_1 > ::value > {}; 72 73template < typename T > 74struct is_type_qkk : std::integral_constant < bool , 75 std::is_same < T ,block_q4_K > ::value || 76 std::is_same < T ,block_q5_K > ::value || 77 std::is_same < T ,block_q6_K > ::value || 78 std::is_same < T ,block_iq4_xs > ::value > {}; 79 80#define GGML_DISPATCH_FLOATING_TYPES (TYPE , ...) \ 81 [&] { \ 82 switch (TYPE) { \ 83 case GGML_TYPE_F16: { \ 84 using type = ggml_fp16_t; \ 85 constexpr int blck_size = 16; \ 86 return __VA_ARGS__(); \ 87 } \ 88 case GGML_TYPE_BF16: { \ 89 using type = ggml_bf16_t; \ 90 constexpr int blck_size = 32; \ 91 return __VA_ARGS__(); \ 92 } \ 93 default: \ 94 fprintf(stderr, "Unsupported floating data type\n"); \ 95 } \ 96 }() 97 98#define GGML_DISPATCH_QTYPES (QT , ...) \ 99 [&] { \ 100 switch (QT) { \ 101 case GGML_TYPE_Q4_0: { \ 102 using type = block_q4_0; \ 103 using vec_dot_type = block_q8_0; \ 104 constexpr int blck_size = QK4_0; \ 105 return __VA_ARGS__(); \ 106 } \ 107 case GGML_TYPE_Q4_1: { \ 108 using type = block_q4_1; \ 109 using vec_dot_type = block_q8_1; \ 110 constexpr int blck_size = QK4_1; \ 111 return __VA_ARGS__(); \ 112 } \ 113 case GGML_TYPE_Q8_0: { \ 114 using type = block_q8_0; \ 115 using vec_dot_type = block_q8_0; \ 116 constexpr int blck_size = QK8_0; \ 117 return __VA_ARGS__(); \ 118 } \ 119 case GGML_TYPE_Q4_K: { \ 120 using type = block_q4_K; \ 121 using vec_dot_type = block_q8_K; \ 122 constexpr int blck_size = QK_K; \ 123 return __VA_ARGS__(); \ 124 } \ 125 case GGML_TYPE_Q5_K: { \ 126 using type = block_q5_K; \ 127 using vec_dot_type = block_q8_K; \ 128 constexpr int blck_size = QK_K; \ 129 return __VA_ARGS__(); \ 130 } \ 131 case GGML_TYPE_Q6_K: { \ 132 using type = block_q6_K; \ 133 using vec_dot_type = block_q8_K; \ 134 constexpr int blck_size = QK_K; \ 135 return __VA_ARGS__(); \ 136 } \ 137 case GGML_TYPE_IQ4_XS: { \ 138 using type = block_iq4_xs; \ 139 using vec_dot_type = block_q8_K; \ 140 constexpr int blck_size = QK_K; \ 141 return __VA_ARGS__(); \ 142 } \ 143 default: \ 144 fprintf(stderr, "Unsupported quantized data type: %d\n", int(TYPE)); \ 145 } \ 146 }() 147 148#define GGML_DISPATCH_BOOL (BOOL_V ,BOOL_NAME , ...) \ 149 [&] { \ 150 if (BOOL_V) { \ 151 constexpr bool BOOL_NAME = true; \ 152 return __VA_ARGS__(); \ 153 } else { \ 154 constexpr bool BOOL_NAME = false; \ 155 return __VA_ARGS__(); \ 156 } \ 157 }() 158 159// define amx tile config data structure 160struct tile_config_t { 161uint8_t palette_id = 0 ; 162uint8_t start_row = 0 ; 163uint8_t reserved_0 [14 ]= {0 }; 164uint16_t colsb [16 ]= {0 }; 165uint8_t rows [16 ]= {0 }; 166}; 167 168// Notes: amx tile config 169// 170// Typically, TMUL calculates A and B of size 16 x 64 containing INT8 values, 171// and accumulate the result to a 16 x 16 matrix C containing INT32 values, 172// 173// As many GGUF quantized types as `block_size` of 32, so a 16-16-32 config is used 174// instead of the normally used 16-16-64 config. 175// 176// Block A: {16, 32}, dtype = int8_t 177// Block B: {16, 32}, dtype = uint8_t/int8_t 178// Block C: {16, 16}, dtype = int32_t 179// 180// Block B needs to be prepacked to vnni format before feeding into TMUL: 181// packed_B: from {n, k} to {k/vnni_blk, n, vnni_blck}, viewed in 2d, we get {8, 64} 182// 183// Therefore, we get tileconfig: 184// A B C 185// rows 16 8 16 186// colsb 32 64 16 187// 188// For tile distribution, follow a 2-2-4 pattern, e.g. A used TMM2-TMM3, B used TMM0-TMM1, 189// C used TMM4-TMM7: 190// B TMM0 B TMM1 191// A TMM2 C TMM4 C TMM6 192// A TMM3 C TMM5 C TMM7 193// 194// Each `amx` kernel handles 4 blocks at a time: 2MB * 2NB, when m < 2 * BLOCK_M, unpack A 195// will be needed. 196// 197// Here another commonly used pattern 1-3-3 is skipped, as it is mostly used when m <=16; 198// and the single batch gemm (m=1) has a special fast path with `avx512-vnni`. 199// 200// ref: https://www.intel.com/content/www/us/en/developer/articles/code-sample/ 201// advanced-matrix-extensions-intrinsics-functions.html 202// 203 204inline void ggml_tile_config_init (void ) { 205static thread_localbool done = false; 206 207if (done ) { 208return ; 209 } 210 211 alignas(64 )tile_config_t tc = {}; 212tc .palette_id = 1 ; 213tc .start_row = 0 ; 214tc .rows [0 ]= 8 ;tc .colsb [0 ]= 64 ; 215tc .rows [1 ]= 8 ;tc .colsb [1 ]= 64 ; 216tc .rows [2 ]= 16 ;tc .colsb [2 ]= 32 ; 217tc .rows [3 ]= 16 ;tc .colsb [3 ]= 32 ; 218tc .rows [4 ]= 16 ;tc .colsb [4 ]= 64 ; 219tc .rows [5 ]= 16 ;tc .colsb [5 ]= 64 ; 220tc .rows [6 ]= 16 ;tc .colsb [6 ]= 64 ; 221tc .rows [7 ]= 16 ;tc .colsb [7 ]= 64 ; 222 223_tile_loadconfig (& tc ); 224done = true; 225} 226 227// we need an extra 16 * 4B (TILE_N * int32_t) for each NB/KB block for compensation. 228// See the notes `s8s8 igemm compensation in avx512-vnni` for detail. 229template < typename TB > 230int get_tile_size () { 231int tile_size = TILE_N * sizeof (TB ); 232if (do_compensate < TB > ::value ) { 233tile_size += TILE_N * sizeof (int32_t ); 234 } 235if (std::is_same < TB ,block_q4_K > ::value || 236 std::is_same < TB ,block_q5_K > ::value ) { 237tile_size += TILE_N * 4 ; 238 } 239if (std::is_same < TB ,block_iq4_xs > ::value ) { 240tile_size += TILE_N * 2 ; 241 } 242return tile_size ; 243} 244 245template < typename TB ,int BLOCK_K > 246int get_row_size (int K ) { 247int KB = K /BLOCK_K ; 248int row_size = KB * sizeof (TB ); 249if (do_compensate < TB > ::value ) { 250row_size += KB * sizeof (int32_t ); 251 } 252if (std::is_same < TB ,block_q4_K > ::value || 253 std::is_same < TB ,block_q5_K > ::value ) { 254row_size += KB * 4 ; 255 } 256if (std::is_same < TB ,block_iq4_xs > ::value ) { 257row_size += KB * 2 ; 258 } 259return row_size ; 260} 261 262// transpose utils 263#define SHUFFLE_EPI32 (a ,b ,mask ) \ 264 _mm256_castps_si256(_mm256_shuffle_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b), mask)) 265inline void transpose_8x8_32bit (__m256i * v ,__m256i * v1 ) { 266// unpacking and 32-bit elements 267v1 [0 ]= _mm256_unpacklo_epi32 (v [0 ],v [1 ]); 268v1 [1 ]= _mm256_unpackhi_epi32 (v [0 ],v [1 ]); 269v1 [2 ]= _mm256_unpacklo_epi32 (v [2 ],v [3 ]); 270v1 [3 ]= _mm256_unpackhi_epi32 (v [2 ],v [3 ]); 271v1 [4 ]= _mm256_unpacklo_epi32 (v [4 ],v [5 ]); 272v1 [5 ]= _mm256_unpackhi_epi32 (v [4 ],v [5 ]); 273v1 [6 ]= _mm256_unpacklo_epi32 (v [6 ],v [7 ]); 274v1 [7 ]= _mm256_unpackhi_epi32 (v [6 ],v [7 ]); 275 276// shuffling the 32-bit elements 277v [0 ]= SHUFFLE_EPI32 (v1 [0 ],v1 [2 ],0x44 ); 278v [1 ]= SHUFFLE_EPI32 (v1 [0 ],v1 [2 ],0xee ); 279v [2 ]= SHUFFLE_EPI32 (v1 [4 ],v1 [6 ],0x44 ); 280v [3 ]= SHUFFLE_EPI32 (v1 [4 ],v1 [6 ],0xee ); 281v [4 ]= SHUFFLE_EPI32 (v1 [1 ],v1 [3 ],0x44 ); 282v [5 ]= SHUFFLE_EPI32 (v1 [1 ],v1 [3 ],0xee ); 283v [6 ]= SHUFFLE_EPI32 (v1 [5 ],v1 [7 ],0x44 ); 284v [7 ]= SHUFFLE_EPI32 (v1 [5 ],v1 [7 ],0xee ); 285 286// shuffling 128-bit elements 287v1 [0 ]= _mm256_permute2f128_si256 (v [2 ],v [0 ],0x02 ); 288v1 [1 ]= _mm256_permute2f128_si256 (v [3 ],v [1 ],0x02 ); 289v1 [2 ]= _mm256_permute2f128_si256 (v [6 ],v [4 ],0x02 ); 290v1 [3 ]= _mm256_permute2f128_si256 (v [7 ],v [5 ],0x02 ); 291v1 [4 ]= _mm256_permute2f128_si256 (v [2 ],v [0 ],0x13 ); 292v1 [5 ]= _mm256_permute2f128_si256 (v [3 ],v [1 ],0x13 ); 293v1 [6 ]= _mm256_permute2f128_si256 (v [6 ],v [4 ],0x13 ); 294v1 [7 ]= _mm256_permute2f128_si256 (v [7 ],v [5 ],0x13 ); 295} 296 297inline void transpose_16x4_32bit (__m512i * r ,__m512i * d ) { 298 299static const __m512i index1 = _mm512_set_epi32 ( 3000x0f ,0x0b ,0x07 ,0x03 , 3010x0e ,0x0a ,0x06 ,0x02 , 3020x0d ,0x09 ,0x05 ,0x01 , 3030x0c ,0x08 ,0x04 ,0x00 ); 304 305d [0 ]= _mm512_permutexvar_epi32 (index1 ,r [0 ]); 306d [1 ]= _mm512_permutexvar_epi32 (index1 ,r [1 ]); 307d [2 ]= _mm512_permutexvar_epi32 (index1 ,r [2 ]); 308d [3 ]= _mm512_permutexvar_epi32 (index1 ,r [3 ]); 309 310r [0 ]= _mm512_shuffle_i32x4 (d [0 ],d [1 ],0x44 ); 311r [1 ]= _mm512_shuffle_i32x4 (d [0 ],d [1 ],0xee ); 312r [2 ]= _mm512_shuffle_i32x4 (d [2 ],d [3 ],0x44 ); 313r [3 ]= _mm512_shuffle_i32x4 (d [2 ],d [3 ],0xee ); 314 315d [0 ]= _mm512_shuffle_i32x4 (r [0 ],r [2 ],0x88 ); 316d [1 ]= _mm512_shuffle_i32x4 (r [0 ],r [2 ],0xdd ); 317d [2 ]= _mm512_shuffle_i32x4 (r [1 ],r [3 ],0x88 ); 318d [3 ]= _mm512_shuffle_i32x4 (r [1 ],r [3 ],0xdd ); 319} 320 321inline void transpose_16x16_32bit (__m512i * v ) { 322__m512i v1 [16 ]; 323v1 [0 ]= _mm512_unpacklo_epi32 (v [0 ],v [1 ]); 324v1 [1 ]= _mm512_unpackhi_epi32 (v [0 ],v [1 ]); 325v1 [2 ]= _mm512_unpacklo_epi32 (v [2 ],v [3 ]); 326v1 [3 ]= _mm512_unpackhi_epi32 (v [2 ],v [3 ]); 327v1 [4 ]= _mm512_unpacklo_epi32 (v [4 ],v [5 ]); 328v1 [5 ]= _mm512_unpackhi_epi32 (v [4 ],v [5 ]); 329v1 [6 ]= _mm512_unpacklo_epi32 (v [6 ],v [7 ]); 330v1 [7 ]= _mm512_unpackhi_epi32 (v [6 ],v [7 ]); 331v1 [8 ]= _mm512_unpacklo_epi32 (v [8 ],v [9 ]); 332v1 [9 ]= _mm512_unpackhi_epi32 (v [8 ],v [9 ]); 333v1 [10 ]= _mm512_unpacklo_epi32 (v [10 ],v [11 ]); 334v1 [11 ]= _mm512_unpackhi_epi32 (v [10 ],v [11 ]); 335v1 [12 ]= _mm512_unpacklo_epi32 (v [12 ],v [13 ]); 336v1 [13 ]= _mm512_unpackhi_epi32 (v [12 ],v [13 ]); 337v1 [14 ]= _mm512_unpacklo_epi32 (v [14 ],v [15 ]); 338v1 [15 ]= _mm512_unpackhi_epi32 (v [14 ],v [15 ]); 339 340v [0 ]= _mm512_unpacklo_epi64 (v1 [0 ],v1 [2 ]); 341v [1 ]= _mm512_unpackhi_epi64 (v1 [0 ],v1 [2 ]); 342v [2 ]= _mm512_unpacklo_epi64 (v1 [1 ],v1 [3 ]); 343v [3 ]= _mm512_unpackhi_epi64 (v1 [1 ],v1 [3 ]); 344v [4 ]= _mm512_unpacklo_epi64 (v1 [4 ],v1 [6 ]); 345v [5 ]= _mm512_unpackhi_epi64 (v1 [4 ],v1 [6 ]); 346v [6 ]= _mm512_unpacklo_epi64 (v1 [5 ],v1 [7 ]); 347v [7 ]= _mm512_unpackhi_epi64 (v1 [5 ],v1 [7 ]); 348v [8 ]= _mm512_unpacklo_epi64 (v1 [8 ],v1 [10 ]); 349v [9 ]= _mm512_unpackhi_epi64 (v1 [8 ],v1 [10 ]); 350v [10 ]= _mm512_unpacklo_epi64 (v1 [9 ],v1 [11 ]); 351v [11 ]= _mm512_unpackhi_epi64 (v1 [9 ],v1 [11 ]); 352v [12 ]= _mm512_unpacklo_epi64 (v1 [12 ],v1 [14 ]); 353v [13 ]= _mm512_unpackhi_epi64 (v1 [12 ],v1 [14 ]); 354v [14 ]= _mm512_unpacklo_epi64 (v1 [13 ],v1 [15 ]); 355v [15 ]= _mm512_unpackhi_epi64 (v1 [13 ],v1 [15 ]); 356 357v1 [0 ]= _mm512_shuffle_i32x4 (v [0 ],v [4 ],0x88 ); 358v1 [1 ]= _mm512_shuffle_i32x4 (v [1 ],v [5 ],0x88 ); 359v1 [2 ]= _mm512_shuffle_i32x4 (v [2 ],v [6 ],0x88 ); 360v1 [3 ]= _mm512_shuffle_i32x4 (v [3 ],v [7 ],0x88 ); 361v1 [4 ]= _mm512_shuffle_i32x4 (v [0 ],v [4 ],0xdd ); 362v1 [5 ]= _mm512_shuffle_i32x4 (v [1 ],v [5 ],0xdd ); 363v1 [6 ]= _mm512_shuffle_i32x4 (v [2 ],v [6 ],0xdd ); 364v1 [7 ]= _mm512_shuffle_i32x4 (v [3 ],v [7 ],0xdd ); 365v1 [8 ]= _mm512_shuffle_i32x4 (v [8 ],v [12 ],0x88 ); 366v1 [9 ]= _mm512_shuffle_i32x4 (v [9 ],v [13 ],0x88 ); 367v1 [10 ]= _mm512_shuffle_i32x4 (v [10 ],v [14 ],0x88 ); 368v1 [11 ]= _mm512_shuffle_i32x4 (v [11 ],v [15 ],0x88 ); 369v1 [12 ]= _mm512_shuffle_i32x4 (v [8 ],v [12 ],0xdd ); 370v1 [13 ]= _mm512_shuffle_i32x4 (v [9 ],v [13 ],0xdd ); 371v1 [14 ]= _mm512_shuffle_i32x4 (v [10 ],v [14 ],0xdd ); 372v1 [15 ]= _mm512_shuffle_i32x4 (v [11 ],v [15 ],0xdd ); 373 374v [0 ]= _mm512_shuffle_i32x4 (v1 [0 ],v1 [8 ],0x88 ); 375v [1 ]= _mm512_shuffle_i32x4 (v1 [1 ],v1 [9 ],0x88 ); 376v [2 ]= _mm512_shuffle_i32x4 (v1 [2 ],v1 [10 ],0x88 ); 377v [3 ]= _mm512_shuffle_i32x4 (v1 [3 ],v1 [11 ],0x88 ); 378v [4 ]= _mm512_shuffle_i32x4 (v1 [4 ],v1 [12 ],0x88 ); 379v [5 ]= _mm512_shuffle_i32x4 (v1 [5 ],v1 [13 ],0x88 ); 380v [6 ]= _mm512_shuffle_i32x4 (v1 [6 ],v1 [14 ],0x88 ); 381v [7 ]= _mm512_shuffle_i32x4 (v1 [7 ],v1 [15 ],0x88 ); 382v [8 ]= _mm512_shuffle_i32x4 (v1 [0 ],v1 [8 ],0xdd ); 383v [9 ]= _mm512_shuffle_i32x4 (v1 [1 ],v1 [9 ],0xdd ); 384v [10 ]= _mm512_shuffle_i32x4 (v1 [2 ],v1 [10 ],0xdd ); 385v [11 ]= _mm512_shuffle_i32x4 (v1 [3 ],v1 [11 ],0xdd ); 386v [12 ]= _mm512_shuffle_i32x4 (v1 [4 ],v1 [12 ],0xdd ); 387v [13 ]= _mm512_shuffle_i32x4 (v1 [5 ],v1 [13 ],0xdd ); 388v [14 ]= _mm512_shuffle_i32x4 (v1 [6 ],v1 [14 ],0xdd ); 389v [15 ]= _mm512_shuffle_i32x4 (v1 [7 ],v1 [15 ],0xdd ); 390} 391 392void quantize_row_q8_K_vnni (const float * RESTRICT x ,void * RESTRICT vy ,int64_t k ) { 393assert (k %QK_K == 0 ); 394const int KB = k /QK_K ; 395constexpr int kVecs = QK_K /16 ; 396 397block_q8_K * y = reinterpret_cast < block_q8_K *> (vy ); 398 399// hold 16 float vecs from x 400__m512 v [kVecs ]; 401 402// hold the quants vecs 403__m512i vq [kVecs /4 ]; 404 405// hold the packed quants vecs 406__m512i vq_packed [kVecs /4 ]; 407 408const __m512 signBit = _mm512_set1_ps (-0.f ); 409 410for (int i = 0 ;i < KB ;++ i ) { 411// Compute max(abs(e)) for the block 412__m512 vamax = _mm512_set1_ps (0.f ); 413for (int j = 0 ;j < kVecs ;++ j ) { 414v [j ]= _mm512_loadu_ps (x );x += 16 ; 415vamax = _mm512_max_ps (vamax ,_mm512_andnot_ps (signBit ,v [j ])); 416 } 417const float amax = _mm512_reduce_max_ps (vamax ); 418 419// Quantize these floats 420const float iscale = 127.f /amax ; 421y [i ].d = GGML_CPU_FP32_TO_FP16 (1 /iscale ); 422const float id = (amax != 0.0f ) ?iscale :0.f ; 423const __m512 vscale = _mm512_set1_ps (id ); 424 425// Apply multiplier and round to nearest integer 426for (int j = 0 ;j < kVecs ;++ j ) { 427v [j ]= _mm512_mul_ps (v [j ],vscale ); 428v [j ]= _mm512_roundscale_ps (v [j ], (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC )); 429 } 430 431// Pack to epi8 vecs 432for (int j = 0 ;j < kVecs /4 ;++ j ) { 433__m128i q8_0 = _mm512_cvtepi32_epi8 (_mm512_cvtps_epi32 (v [j * 4 + 0 ])); 434__m128i q8_1 = _mm512_cvtepi32_epi8 (_mm512_cvtps_epi32 (v [j * 4 + 1 ])); 435__m128i q8_2 = _mm512_cvtepi32_epi8 (_mm512_cvtps_epi32 (v [j * 4 + 2 ])); 436__m128i q8_3 = _mm512_cvtepi32_epi8 (_mm512_cvtps_epi32 (v [j * 4 + 3 ])); 437 438__m256i q8_01 = _mm256_insertf128_si256 (_mm256_castsi128_si256 (q8_0 ), (q8_1 ),1 ); 439__m256i q8_23 = _mm256_insertf128_si256 (_mm256_castsi128_si256 (q8_2 ), (q8_3 ),1 ); 440 441vq [j ]= _mm512_inserti32x8 (_mm512_castsi256_si512 (q8_01 ),q8_23 ,1 ); 442_mm512_storeu_si512 ((__m512i * )(y [i ].qs + j * 64 ),vq [j ]); 443 } 444 445// Compute the bsums with vnni 446transpose_16x4_32bit (vq ,vq_packed ); 447 448const __m512i one = _mm512_set1_epi8 (1 ); 449__m512i sum = _mm512_setzero_si512 (); 450for (int k = 0 ;k < 4 ;++ k ) { 451sum = _mm512_dpbusd_epi32 (sum ,one ,vq_packed [k ]); 452 } 453_mm256_storeu_si256 ((__m256i * )(y [i ].bsums ),_mm512_cvtepi32_epi16 (sum )); 454 } 455} 456 457// quantize A from float to `vec_dot_type` 458template < typename T > 459inline void from_float (const float * x ,char * vy ,int64_t k ); 460 461template <> 462inline void from_float < block_q8_0 > (const float * x ,char * vy ,int64_t k ) { 463quantize_row_q8_0 (x , (block_q8_0 * )vy ,k ); 464} 465 466template <> 467inline void from_float < block_q8_1 > (const float * x ,char * vy ,int64_t k ) { 468quantize_row_q8_1 (x , (block_q8_1 * )vy ,k ); 469} 470 471template <> 472inline void from_float < block_q8_K > (const float * x ,char * vy ,int64_t k ) { 473#if 1 474// TODO: this is reference impl! 475quantize_row_q8_K_ref (x , (block_q8_K * )vy ,k ); 476#else 477quantize_row_q8_K_vnni (x ,vy ,k ); 478#endif 479} 480 481// load A from memory to array when nrows can not fill in whole tile 482void unpack_A (int8_t * RESTRICT tile ,const block_q8_0 * RESTRICT A ,int lda ,int nr ) { 483assert (nr != TILE_M ); 484for (int m = 0 ;m < nr ;++ m ) { 485const __m256i v = _mm256_loadu_si256 ((const __m256i * )(A [m * lda ].qs )); 486_mm256_storeu_si256 ((__m256i * )(tile + m * TILE_K ),v ); 487 } 488} 489 490void unpack_A (int8_t * RESTRICT tile ,const block_q8_1 * RESTRICT A ,int lda ,int nr ) { 491assert (nr != TILE_M ); 492for (int m = 0 ;m < nr ;++ m ) { 493const __m256i v = _mm256_loadu_si256 ((const __m256i * )(A [m * lda ].qs )); 494_mm256_storeu_si256 ((__m256i * )(tile + m * TILE_K ),v ); 495 } 496} 497 498template < typename TB > 499void unpack_A (int8_t * RESTRICT tile ,const block_q8_K * RESTRICT A ,int lda ,int k ,int nr ) { 500assert (nr <=TILE_M ); 501for (int m = 0 ;m < nr ;++ m ) { 502const __m256i v = _mm256_loadu_si256 ((const __m256i * )(A [m * lda ].qs + k * 32 )); 503_mm256_storeu_si256 ((__m256i * )(tile + m * TILE_K ),v ); 504 } 505} 506 507template <> 508void unpack_A < block_q6_K > (int8_t * RESTRICT tile ,const block_q8_K * RESTRICT A ,int lda ,int k ,int nr ) { 509assert (nr <=TILE_M ); 510// zero padding k from 16 to 32, so that we don't have to re-config amx 511const __m128i zero = _mm_setzero_si128 (); 512for (int m = 0 ;m < nr ;++ m ) { 513const __m128i v = _mm_loadu_si128 ((const __m128i * )(A [m * lda ].qs + k * 16 )); 514const __m256i r = _mm256_insertf128_si256 (_mm256_castsi128_si256 (v ),zero ,1 ); 515_mm256_storeu_si256 ((__m256i * )(tile + m * TILE_K ),r ); 516 } 517} 518 519#define MM256_SET_M128I (a ,b ) _mm256_insertf128_si256(_mm256_castsi128_si256(b), (a), 1) 520inline __m256i bytes_from_nibbles_32 (const uint8_t * rsi ) { 521const __m128i tmp = _mm_loadu_si128 ((const __m128i * )rsi ); 522const __m256i bytes = MM256_SET_M128I (_mm_srli_epi16 (tmp ,4 ),tmp ); 523const __m256i lowMask = _mm256_set1_epi8 (0xF ); 524return _mm256_and_si256 (lowMask ,bytes ); 525} 526 527// used for block_q4_K 528inline __m512i bytes_from_nibbles_64 (const uint8_t * rsi ) { 529const __m256i tmp = _mm256_loadu_si256 ((const __m256i * )rsi ); 530const __m256i lowMask = _mm256_set1_epi8 (0xF ); 531const __m256i q4l = _mm256_and_si256 (tmp ,lowMask ); 532const __m256i q4h = _mm256_and_si256 (_mm256_srli_epi16 (tmp ,4 ),lowMask ); 533return _mm512_inserti32x8 (_mm512_castsi256_si512 (q4l ),q4h ,1 ); 534} 535 536// used for block_q5_K 537inline __m512i bytes_from_nibbles_64 (const uint8_t * qs ,const uint8_t * qh ,int k ) { 538const __m256i lowMask = _mm256_set1_epi8 (0xF ); 539__m256i hmask = _mm256_set1_epi8 (1 ); 540hmask = _mm256_slli_epi16 (hmask ,k ); 541 542const __m256i q5bits = _mm256_loadu_si256 ((const __m256i * )qs ); 543const __m256i hbits = _mm256_loadu_si256 ((const __m256i * )qh ); 544 545const __m256i q5l_0 = _mm256_and_si256 (q5bits ,lowMask ); 546const __m256i q5h_0 = _mm256_slli_epi16 (_mm256_srli_epi16 (_mm256_and_si256 (hbits ,hmask ),k + 0 ),4 ); 547const __m256i q5_0 = _mm256_add_epi8 (q5l_0 ,q5h_0 ); 548hmask = _mm256_slli_epi16 (hmask ,1 ); 549 550const __m256i q5l_1 = _mm256_and_si256 (_mm256_srli_epi16 (q5bits ,4 ),lowMask ); 551const __m256i q5h_1 = _mm256_slli_epi16 (_mm256_srli_epi16 (_mm256_and_si256 (hbits ,hmask ),k + 1 ),4 ); 552const __m256i q5_1 = _mm256_add_epi8 (q5l_1 ,q5h_1 ); 553 554return _mm512_inserti32x8 (_mm512_castsi256_si512 (q5_0 ),q5_1 ,1 ); 555} 556 557// used for block_q6_K 558inline void bytes_from_nibbles_128 (__m512i & r0 ,__m512i & r1 ,const uint8_t * qs ,const uint8_t * qh ) { 559const __m256i m4 = _mm256_set1_epi8 (0xF ); 560const __m256i m2 = _mm256_set1_epi8 (0x3 ); 561 562const __m256i q6bits1 = _mm256_loadu_si256 ((const __m256i * )qs ); 563const __m256i q6bits2 = _mm256_loadu_si256 ((const __m256i * )(qs + 32 )); 564const __m256i q6bitsH = _mm256_loadu_si256 ((const __m256i * )qh ); 565 566const __m256i q6h_0 = _mm256_slli_epi16 (_mm256_and_si256 (q6bitsH ,m2 ),4 ); 567const __m256i q6h_1 = _mm256_slli_epi16 (_mm256_and_si256 (_mm256_srli_epi16 (q6bitsH ,2 ),m2 ),4 ); 568const __m256i q6h_2 = _mm256_slli_epi16 (_mm256_and_si256 (_mm256_srli_epi16 (q6bitsH ,4 ),m2 ),4 ); 569const __m256i q6h_3 = _mm256_slli_epi16 (_mm256_and_si256 (_mm256_srli_epi16 (q6bitsH ,6 ),m2 ),4 ); 570 571const __m256i q6_0 = _mm256_or_si256 (_mm256_and_si256 (q6bits1 ,m4 ),q6h_0 ); 572const __m256i q6_1 = _mm256_or_si256 (_mm256_and_si256 (q6bits2 ,m4 ),q6h_1 ); 573const __m256i q6_2 = _mm256_or_si256 (_mm256_and_si256 (_mm256_srli_epi16 (q6bits1 ,4 ),m4 ),q6h_2 ); 574const __m256i q6_3 = _mm256_or_si256 (_mm256_and_si256 (_mm256_srli_epi16 (q6bits2 ,4 ),m4 ),q6h_3 ); 575 576r0 = _mm512_inserti32x8 (_mm512_castsi256_si512 (q6_0 ),q6_1 ,1 ); 577r1 = _mm512_inserti32x8 (_mm512_castsi256_si512 (q6_2 ),q6_3 ,1 ); 578} 579 580inline __m512i packNibbles (__m512i r0 ,__m512i r1 ) { 581return _mm512_or_si512 (r0 ,_mm512_slli_epi16 (r1 ,4 )); 582} 583 584template < typename TB > 585inline void pack_qs (void * RESTRICT packed_B ,const TB * RESTRICT B ,int KB ) { 586int8_t tmp [8 * 64 ]; 587__m256i v [8 ],v2 [8 ]; 588for (int n = 0 ;n < 8 ;++ n ) { 589v [n ]= bytes_from_nibbles_32 (B [n * KB ].qs ); 590 } 591transpose_8x8_32bit (v ,v2 ); 592for (int n = 0 ;n < 8 ;++ n ) { 593_mm256_storeu_si256 ((__m256i * )(tmp + n * 64 ),v2 [n ]); 594 } 595for (int n = 0 ;n < 8 ;++ n ) { 596v [n ]= bytes_from_nibbles_32 (B [(n + 8 )* KB ].qs ); 597 } 598transpose_8x8_32bit (v ,v2 ); 599for (int n = 0 ;n < 8 ;++ n ) { 600_mm256_storeu_si256 ((__m256i * )(tmp + n * 64 + 32 ),v2 [n ]); 601 } 602 603// pack again with 128 to fully utilize vector length 604for (int n = 0 ;n < 8 ;n += 2 ) { 605__m512i r0 = _mm512_loadu_si512 ((const __m512i * )(tmp + n * 64 )); 606__m512i r1 = _mm512_loadu_si512 ((const __m512i * )(tmp + n * 64 + 64 )); 607__m512i r1r0 = packNibbles (r0 ,r1 ); 608_mm512_storeu_si512 ((__m512i * )((char * )packed_B + n * 32 ),r1r0 ); 609 } 610} 611 612template <> 613inline void pack_qs < block_q8_0 > (void * RESTRICT packed_B ,const block_q8_0 * RESTRICT B ,int KB ) { 614__m256i v [8 ],v2 [8 ]; 615for (int n = 0 ;n < 8 ;++ n ) { 616v [n ]= _mm256_loadu_si256 ((const __m256i * )(B [n * KB ].qs )); 617 } 618transpose_8x8_32bit (v ,v2 ); 619for (int n = 0 ;n < 8 ;++ n ) { 620_mm256_storeu_si256 ((__m256i * )((char * )packed_B + n * 64 ),v2 [n ]); 621 } 622for (int n = 0 ;n < 8 ;++ n ) { 623v [n ]= _mm256_loadu_si256 ((const __m256i * )(B [(n + 8 )* KB ].qs )); 624 } 625transpose_8x8_32bit (v ,v2 ); 626for (int n = 0 ;n < 8 ;++ n ) { 627_mm256_storeu_si256 ((__m256i * )((char * )packed_B + n * 64 + 32 ),v2 [n ]); 628 } 629} 630 631template <> 632inline void pack_qs < block_q4_K > (void * RESTRICT packed_B ,const block_q4_K * RESTRICT B ,int KB ) { 633__m512i v [16 ]; 634// QK_K 256 with 8 groups, handle 2 groups at a time 635char * pb = (char * )packed_B ; 636for (int k = 0 ;k < QK_K /64 ;++ k ) { 637// pack 2 groups { n, g, k} to {g, k/4, 4n} 638// e.g. {16, 2, 32} to {2, 8, 64} 639for (int n = 0 ;n < TILE_N ;++ n ) { 640v [n ]= bytes_from_nibbles_64 (B [n * KB ].qs + k * 32 ); 641 } 642 643transpose_16x16_32bit (v ); 644 645// pack again with 128 to fully utilize vector length 646for (int n = 0 ;n < TILE_N ;n += 2 ) { 647_mm512_storeu_si512 ((__m512i * )pb ,packNibbles (v [n ],v [n + 1 ])); 648pb += 64 ; 649 } 650 } 651} 652 653template <> 654inline void pack_qs < block_q5_K > (void * RESTRICT packed_B ,const block_q5_K * RESTRICT B ,int KB ) { 655__m512i v [16 ]; 656const __m512i lowMask = _mm512_set1_epi8 (0xF ); 657// QK_K 256 with 8 groups, handle 2 groups at a time 658char * pb = (char * )packed_B ; 659char * ph = (char * )packed_B + (QK_K /2 )* TILE_N ; 660for (int k = 0 ;k < QK_K /64 ;++ k ) { 661// pack 2 groups { n, g, k} to {g, k/4, 4n} 662// e.g. {16, 2, 32} to {2, 8, 64} 663for (int n = 0 ;n < TILE_N ;++ n ) { 664v [n ]= bytes_from_nibbles_64 (B [n * KB ].qs + k * 32 ,B [n * KB ].qh ,/* group */ 2 * k ); 665 } 666 667transpose_16x16_32bit (v ); 668 669// 1. pack lower 4bits with 2 groups 670for (int n = 0 ;n < TILE_N ;n += 2 ) { 671// get lower 4 bits 672const __m512i r0 = _mm512_and_si512 (v [n ],lowMask ); 673const __m512i r1 = _mm512_and_si512 (v [n + 1 ],lowMask ); 674_mm512_storeu_si512 ((__m512i * )pb ,packNibbles (r0 ,r1 ));pb += 64 ; 675 } 676 677// 2. pack higher 1bit with 2 groups 678const __m512i hmask = _mm512_set1_epi8 (0x10 ); 679for (int g = 0 ;g < 2 ;++ g ) { 680__m512i hbits = _mm512_setzero_si512 (); 681hbits = _mm512_add_epi8 (hbits ,_mm512_srli_epi16 (_mm512_and_si512 (v [g * 8 + 0 ],hmask ),4 )); 682hbits = _mm512_add_epi8 (hbits ,_mm512_srli_epi16 (_mm512_and_si512 (v [g * 8 + 1 ],hmask ),3 )); 683hbits = _mm512_add_epi8 (hbits ,_mm512_srli_epi16 (_mm512_and_si512 (v [g * 8 + 2 ],hmask ),2 )); 684hbits = _mm512_add_epi8 (hbits ,_mm512_srli_epi16 (_mm512_and_si512 (v [g * 8 + 3 ],hmask ),1 )); 685hbits = _mm512_add_epi8 (hbits ,_mm512_and_si512 (v [g * 8 + 4 ],hmask ) ); 686hbits = _mm512_add_epi8 (hbits ,_mm512_slli_epi16 (_mm512_and_si512 (v [g * 8 + 5 ],hmask ),1 )); 687hbits = _mm512_add_epi8 (hbits ,_mm512_slli_epi16 (_mm512_and_si512 (v [g * 8 + 6 ],hmask ),2 )); 688hbits = _mm512_add_epi8 (hbits ,_mm512_slli_epi16 (_mm512_and_si512 (v [g * 8 + 7 ],hmask ),3 )); 689_mm512_storeu_si512 ((__m512i * )ph ,hbits );ph += 64 ; 690 } 691 } 692} 693 694template <> 695inline void pack_qs < block_q6_K > (void * RESTRICT packed_B ,const block_q6_K * RESTRICT B ,int KB ) { 696__m512i v [32 ]; 697const __m512i lowMask = _mm512_set1_epi8 (0xF ); 698// QK_K 256 with 8 groups, handle 4 groups at a time 699char * pb = (char * )packed_B ; 700char * ph = (char * )packed_B + (QK_K /2 )* TILE_N ; 701for (int k = 0 ;k < QK_K /128 ;++ k ) { 702for (int n = 0 ;n < TILE_N ;++ n ) { 703bytes_from_nibbles_128 (v [n ],v [n + 16 ],B [n * KB ].ql + k * 64 ,B [n * KB ].qh + k * 32 ); 704 } 705 706// top half: group 0,1 or 4,5; bottom half: group 2,3 or 6,7 707transpose_16x16_32bit (v ); 708transpose_16x16_32bit (v + 16 ); 709 710// 1. pack lower 4bits with 4 groups 711for (int n = 0 ;n < 32 ;n += 2 ) { 712const __m512i r0 = _mm512_and_si512 (v [n ],lowMask ); 713const __m512i r1 = _mm512_and_si512 (v [n + 1 ],lowMask ); 714_mm512_storeu_si512 ((__m512i * )pb ,packNibbles (r0 ,r1 ));pb += 64 ; 715 } 716 717// 2. pack higher 2bit with 4 groups 718const __m512i hmask = _mm512_set1_epi8 (0x30 ); 719for (int g = 0 ;g < 8 ;++ g ) { 720__m512i hbits = _mm512_setzero_si512 (); 721hbits = _mm512_add_epi8 (hbits ,_mm512_srli_epi16 (_mm512_and_si512 (v [g * 4 + 0 ],hmask ),4 )); 722hbits = _mm512_add_epi8 (hbits ,_mm512_srli_epi16 (_mm512_and_si512 (v [g * 4 + 1 ],hmask ),2 )); 723hbits = _mm512_add_epi8 (hbits ,_mm512_and_si512 (v [g * 4 + 2 ],hmask ) ); 724hbits = _mm512_add_epi8 (hbits ,_mm512_slli_epi16 (_mm512_and_si512 (v [g * 4 + 3 ],hmask ),2 )); 725_mm512_storeu_si512 ((__m512i * )ph ,hbits );ph += 64 ; 726 } 727 } 728} 729 730template <> 731inline void pack_qs < block_iq4_xs > (void * RESTRICT packed_B ,const block_iq4_xs * RESTRICT B ,int KB ) { 732__m512i v [16 ]; 733char * pb = (char * )packed_B ; 734for (int k = 0 ;k < QK_K /64 ;++ k ) { 735for (int n = 0 ;n < TILE_N ;++ n ) { 736__m256i r0 = bytes_from_nibbles_32 (B [n * KB ].qs + k * 32 + 0 ); 737__m256i r1 = bytes_from_nibbles_32 (B [n * KB ].qs + k * 32 + 16 ); 738v [n ]= _mm512_inserti32x8 (_mm512_castsi256_si512 (r0 ),r1 ,1 ); 739 } 740 741transpose_16x16_32bit (v ); 742 743// pack again with 128 to fully utilize vector length 744for (int n = 0 ;n < TILE_N ;n += 2 ) { 745_mm512_storeu_si512 ((__m512i * )pb ,packNibbles (v [n ],v [n + 1 ])); 746pb += 64 ; 747 } 748 } 749} 750 751// pack B to vnni formats in 4bits or 8 bits 752void pack_B (void * RESTRICT packed_B ,const block_q4_0 * RESTRICT B ,int KB ) { 753pack_qs (packed_B ,B ,KB ); 754ggml_half * d0 = reinterpret_cast < ggml_half *> ((char * )packed_B + TILE_N * TILE_K /2 ); 755for (int n = 0 ;n < TILE_N ;++ n ) { 756d0 [n ]= B [n * KB ].d ; 757 } 758} 759 760void pack_B (void * RESTRICT packed_B ,const block_q4_1 * RESTRICT B ,int KB ) { 761pack_qs (packed_B ,B ,KB ); 762ggml_half * d0 = reinterpret_cast < ggml_half *> ((char * )packed_B + TILE_N * TILE_K /2 ); 763ggml_half * m0 = d0 + TILE_N ; 764for (int n = 0 ;n < TILE_N ;++ n ) { 765d0 [n ]= B [n * KB ].d ; 766m0 [n ]= B [n * KB ].m ; 767 } 768} 769 770inline void s8s8_compensation (void * RESTRICT packed_B ) { 771// packed_B layout: 772// quants {TILE_N, TILEK} int8_t 773// d0 {TILE_N} ggml_half 774// comp {TILE_N} int32_t 775const int offset = TILE_N * TILE_K + TILE_N * sizeof (ggml_half ); 776__m512i vcomp = _mm512_setzero_si512 (); 777const __m512i off = _mm512_set1_epi8 (static_cast < char > (0x80 )); 778for (int k = 0 ;k < 8 ;++ k ) { 779__m512i vb = _mm512_loadu_si512 ((const __m512i * )((const char * )packed_B + k * 64 )); 780vcomp = _mm512_dpbusd_epi32 (vcomp ,off ,vb ); 781 } 782_mm512_storeu_si512 ((__m512i * )((char * )(packed_B )+ offset ),vcomp ); 783} 784 785void pack_B (void * RESTRICT packed_B ,const block_q8_0 * RESTRICT B ,int KB ) { 786pack_qs (packed_B ,B ,KB ); 787ggml_half * d0 = reinterpret_cast < ggml_half *> ((char * )packed_B + TILE_N * TILE_K ); 788for (int n = 0 ;n < TILE_N ;++ n ) { 789d0 [n ]= B [n * KB ].d ; 790 } 791s8s8_compensation (packed_B ); 792} 793 794// convert 8 * {min, scale} from int6 to int8 795inline void unpack_mins_and_scales (const uint8_t * scales ,uint32_t * utmp ) { 796const uint32_t kmask1 = 0x3f3f3f3f ; 797const uint32_t kmask2 = 0x0f0f0f0f ; 798const uint32_t kmask3 = 0x03030303 ; 799 800memcpy (utmp ,scales ,12 ); 801utmp [3 ]= ((utmp [2 ] >>4 )& kmask2 ) | (((utmp [1 ] >>6 )& kmask3 ) <<4 ); 802const uint32_t uaux = utmp [1 ]& kmask1 ; 803utmp [1 ]= (utmp [2 ]& kmask2 ) | (((utmp [0 ] >>6 )& kmask3 ) <<4 ); 804utmp [2 ]= uaux ; 805utmp [0 ] &=kmask1 ; 806} 807 808// packed_B layout: 809// quants {8, TILE_N, 16} uint8 810// scales {8, TILE_N} uint8 811// mins {8, TILE_N} uint8 812// d {TILE_N} ggml_half 813// dmin {TILE_N} ggml_half 814void pack_B (void * RESTRICT packed_B ,const block_q4_K * RESTRICT B ,int KB ) { 815pack_qs (packed_B ,B ,KB ); 816 817uint8_t * scales = reinterpret_cast < uint8_t *> ((char * )packed_B + (QK_K /2 )* TILE_N ); 818uint8_t * mins = scales + 8 * TILE_N ; 819ggml_half * d = reinterpret_cast < ggml_half *> (mins + 8 * TILE_N ); 820ggml_half * dmin = d + TILE_N ; 821 822union { 823uint32_t u32 [4 ]; 824uint8_t u8 [16 ]; 825 }s ; 826 827for (int n = 0 ;n < TILE_N ;++ n ) { 828unpack_mins_and_scales (B [n * KB ].scales ,s .u32 ); 829for (int k = 0 ;k < 8 ;++ k ) { 830scales [k * TILE_N + n ]= s .u8 [k ]; 831mins [(k >>1 )* TILE_N * 2 + n * 2 + (k & 0x1 )]= s .u8 [k + 8 ]; 832 } 833d [n ]= B [n * KB ].d ; 834dmin [n ]= B [n * KB ].dmin ; 835 } 836} 837 838// packed_B layout: 839// quants {8, TILE_N, 16} uint8 840// qh {8, TILE_N, 4} uint8 841// scales {8, TILE_N} uint8 842// mins {8, TILE_N} uint8 843// d {TILE_N} ggml_half 844// dmin {TILE_N} ggml_half 845void pack_B (void * RESTRICT packed_B ,const block_q5_K * RESTRICT B ,int KB ) { 846pack_qs (packed_B ,B ,KB ); 847 848uint8_t * scales = reinterpret_cast < uint8_t *> ((char * )packed_B + (QK_K /2 )* TILE_N + (QK_K /8 )* TILE_N ); 849uint8_t * mins = scales + 8 * TILE_N ; 850ggml_half * d = reinterpret_cast < ggml_half *> (mins + 8 * TILE_N ); 851ggml_half * dmin = d + TILE_N ; 852 853union { 854uint32_t u32 [4 ]; 855uint8_t u8 [16 ]; 856 }s ; 857 858for (int n = 0 ;n < TILE_N ;++ n ) { 859unpack_mins_and_scales (B [n * KB ].scales ,s .u32 ); 860for (int k = 0 ;k < 8 ;++ k ) { 861scales [k * TILE_N + n ]= s .u8 [k ]; 862mins [(k >>1 )* TILE_N * 2 + n * 2 + (k & 0x1 )]= s .u8 [k + 8 ]; 863 } 864d [n ]= B [n * KB ].d ; 865dmin [n ]= B [n * KB ].dmin ; 866 } 867} 868 869// packed_B layout: 870// quants {16, TILE_N, 8} uint8 871// qh {16, TILE_N, 4} uint8 872// scales {16, TILE_N} uint8 873// d {TILE_N} ggml_half 874void pack_B (void * RESTRICT packed_B ,const block_q6_K * RESTRICT B ,int KB ) { 875pack_qs (packed_B ,B ,KB ); 876 877uint8_t * scales = reinterpret_cast < uint8_t *> ((char * )packed_B + (QK_K /2 )* TILE_N + (QK_K /4 )* TILE_N ); 878ggml_half * d = reinterpret_cast < ggml_half *> (scales + 16 * TILE_N ); 879for (int n = 0 ;n < TILE_N ;++ n ) { 880const int8_t * ps = B [n * KB ].scales ; 881for (int k = 0 ;k < 16 ;++ k ) { 882scales [k * TILE_N + n ]= ps [k ]; 883 } 884d [n ]= B [n * KB ].d ; 885 } 886} 887 888// packed_B layout: 889// quants {8, TILE_N, 16} uint8 890// scales {8, TILE_N} int8 891// d {TILE_N} ggml_half 892void pack_B (void * RESTRICT packed_B ,const block_iq4_xs * RESTRICT B ,int KB ) { 893pack_qs (packed_B ,B ,KB ); 894 895int8_t * scales = reinterpret_cast < int8_t *> ((char * )packed_B + (QK_K /2 )* TILE_N ); 896ggml_half * d = reinterpret_cast < ggml_half *> (scales + 8 * TILE_N ); 897 898// pack the scales 899for (int n = 0 ;n < TILE_N ;++ n ) { 900uint16_t sh = B [n * KB ].scales_h ; 901for (int k = 0 ;k < 8 ;k += 2 ) { 902const int16_t ls1 = ((B [n * KB ].scales_l [k /2 ]& 0xf ) | ((sh <<4 )& 0x30 ))- 32 ; 903const int16_t ls2 = ((B [n * KB ].scales_l [k /2 ] >>4 ) | ((sh <<2 )& 0x30 ))- 32 ; 904scales [(k + 0 )* TILE_N + n ]= ls1 ; 905scales [(k + 1 )* TILE_N + n ]= ls2 ; 906sh >>=4 ; 907 } 908d [n ]= B [n * KB ].d ; 909 } 910} 911 912template < typename TB ,typename packed_B_t = packed_B_type < TB >> 913void unpack_B (packed_B_t * RESTRICT tile ,const void * RESTRICT packed_B ) { 914GGML_UNUSED (tile ); 915GGML_UNUSED (packed_B ); 916} 917 918template <> 919void unpack_B < block_q4_0 > (int8_t * RESTRICT tile ,const void * RESTRICT packed_B ) { 920const __m512i off = _mm512_set1_epi8 (8 ); 921const __m512i lowMask = _mm512_set1_epi8 (0xF ); 922for (int n = 0 ;n < 8 ;n += 2 ) { 923__m512i bytes = _mm512_loadu_si512 ((const __m512i * )((const char * )packed_B + n * 32 )); 924const __m512i r0 = _mm512_sub_epi8 (_mm512_and_si512 (bytes ,lowMask ),off ); 925const __m512i r1 = _mm512_sub_epi8 (_mm512_and_si512 (_mm512_srli_epi16 (bytes ,4 ),lowMask ),off ); 926_mm512_storeu_si512 ((__m512i * )(tile + n * 64 + 0 ),r0 ); 927_mm512_storeu_si512 ((__m512i * )(tile + n * 64 + 64 ),r1 ); 928 } 929} 930 931template <> 932void unpack_B < block_q4_1 > (uint8_t * RESTRICT tile ,const void * RESTRICT packed_B ) { 933const __m512i lowMask = _mm512_set1_epi8 (0xF ); 934for (int n = 0 ;n < 8 ;n += 2 ) { 935__m512i bytes = _mm512_loadu_si512 ((const __m512i * )((const char * )packed_B + n * 32 )); 936const __m512i r0 = _mm512_and_si512 (bytes ,lowMask ); 937const __m512i r1 = _mm512_and_si512 (_mm512_srli_epi16 (bytes ,4 ),lowMask ); 938_mm512_storeu_si512 ((__m512i * )(tile + n * 64 + 0 ),r0 ); 939_mm512_storeu_si512 ((__m512i * )(tile + n * 64 + 64 ),r1 ); 940 } 941} 942 943// packed_B_t for QKK is int8_t 944template < typename TB > 945void unpack_B (int8_t * RESTRICT tile ,const void * RESTRICT packed_B ,int k ) { 946const int packed_B_group_size = QK_K /2 * TILE_N /8 ; 947const char * packed_B_group = (const char * )packed_B + k * packed_B_group_size ; 948const __m512i lowMask = _mm512_set1_epi8 (0xF ); 949for (int n = 0 ;n < 8 ;n += 2 ) { 950__m512i bytes = _mm512_loadu_si512 (packed_B_group + n * 32 ); 951const __m512i r0 = _mm512_and_si512 (bytes ,lowMask ); 952const __m512i r1 = _mm512_and_si512 (_mm512_srli_epi16 (bytes ,4 ),lowMask ); 953_mm512_storeu_si512 ((__m512i * )(tile + n * 64 + 0 ),r0 ); 954_mm512_storeu_si512 ((__m512i * )(tile + n * 64 + 64 ),r1 ); 955 } 956} 957 958template <> 959void unpack_B < block_q5_K > (int8_t * RESTRICT tile ,const void * RESTRICT packed_B ,int k ) { 960// lower 4bits, stride 256 bytes 961const int packed_l4_group_size = QK_K /2 * TILE_N /8 ; 962const char * pb = (const char * )packed_B + k * packed_l4_group_size ; 963 964// higher 1bit, stride 64 bytes 965const int packed_h1_group_size = QK_K /8 * TILE_N /8 ; 966const char * ph = (const char * )packed_B + (QK_K /2 )* TILE_N + k * packed_h1_group_size ; 967const __m512i hbits = _mm512_loadu_si512 (ph ); 968 969const __m512i lowMask = _mm512_set1_epi8 (0xF ); 970__m512i hmask0 = _mm512_set1_epi8 (0x1 ); 971__m512i hmask1 = _mm512_set1_epi8 (0x2 ); 972 973for (int n = 0 ;n < 8 ;n += 2 ) { 974__m512i bytes = _mm512_loadu_si512 (pb + n * 32 ); 975__m512i r0 = _mm512_and_si512 (bytes ,lowMask ); 976__m512i r1 = _mm512_and_si512 (_mm512_srli_epi16 (bytes ,4 ),lowMask ); 977__m512i h0 = _mm512_slli_epi16 (_mm512_srli_epi16 (_mm512_and_si512 (hbits ,hmask0 ),n ),4 ); 978__m512i h1 = _mm512_slli_epi16 (_mm512_srli_epi16 (_mm512_and_si512 (hbits ,hmask1 ),n + 1 ),4 ); 979 980hmask0 = _mm512_slli_epi16 (hmask0 ,2 ); 981hmask1 = _mm512_slli_epi16 (hmask1 ,2 ); 982r0 = _mm512_add_epi8 (r0 ,h0 ); 983r1 = _mm512_add_epi8 (r1 ,h1 ); 984_mm512_storeu_si512 ((__m512i * )(tile + n * 64 + 0 ),r0 ); 985_mm512_storeu_si512 ((__m512i * )(tile + n * 64 + 64 ),r1 ); 986 } 987} 988 989template <> 990void unpack_B < block_q6_K > (int8_t * RESTRICT tile ,const void * RESTRICT packed_B ,int k ) { 991// lower 4bits, stride 128 bytes 992const int packed_l4_group_size = QK_K /2 * TILE_N /16 ; 993const char * pb = (const char * )packed_B + k * packed_l4_group_size ; 994 995// higher 2bits, stride 64 bytes 996const int packed_h2_group_size = QK_K /4 * TILE_N /16 ; 997const char * ph = (const char * )packed_B + (QK_K /2 )* TILE_N + k * packed_h2_group_size ; 998const __m512i hbits = _mm512_loadu_si512 (ph ); 999 1000const __m512i off = _mm512_set1_epi8 (32 ); 1001const __m512i lowMask = _mm512_set1_epi8 (0xF ); 1002__m512i hmask0 = _mm512_set1_epi8 (0x3 );// 0011 1003__m512i hmask1 = _mm512_set1_epi8 (0xC );// 1100 1004 1005// notes: skip zero padding from row4 to row7 as we have done so in `unpack_A` 1006__m512i bytes = _mm512_loadu_si512 (pb ); 1007__m512i r0 = _mm512_and_si512 (bytes ,lowMask ); 1008__m512i r1 = _mm512_and_si512 (_mm512_srli_epi16 (bytes ,4 ),lowMask ); 1009__m512i h0 = _mm512_slli_epi16 (_mm512_and_si512 (hbits ,hmask0 ),4 ); 1010__m512i h1 = _mm512_slli_epi16 (_mm512_and_si512 (hbits ,hmask1 ),2 ); 1011_mm512_storeu_si512 ((__m512i * )(tile + 0 ),_mm512_sub_epi8 (_mm512_add_epi8 (r0 ,h0 ),off )); 1012_mm512_storeu_si512 ((__m512i * )(tile + 64 ),_mm512_sub_epi8 (_mm512_add_epi8 (r1 ,h1 ),off )); 1013 1014hmask0 = _mm512_slli_epi16 (hmask0 ,4 ); 1015hmask1 = _mm512_slli_epi16 (hmask1 ,4 ); 1016 1017bytes = _mm512_loadu_si512 (pb + 64 ); 1018r0 = _mm512_and_si512 (bytes ,lowMask ); 1019r1 = _mm512_and_si512 (_mm512_srli_epi16 (bytes ,4 ),lowMask ); 1020h0 = _mm512_and_si512 (hbits ,hmask0 ); 1021h1 = _mm512_srli_epi16 (_mm512_and_si512 (hbits ,hmask1 ),2 ); 1022_mm512_storeu_si512 ((__m512i * )(tile + 128 ),_mm512_sub_epi8 (_mm512_add_epi8 (r0 ,h0 ),off )); 1023_mm512_storeu_si512 ((__m512i * )(tile + 192 ),_mm512_sub_epi8 (_mm512_add_epi8 (r1 ,h1 ),off )); 1024} 1025 1026template <> 1027void unpack_B < block_iq4_xs > (int8_t * RESTRICT tile ,const void * RESTRICT packed_B ,int k ) { 1028static const __m512i values128 = _mm512_set_epi8 ( 1029113 ,89 ,69 ,53 ,38 ,25 ,13 ,1 ,-10 ,-22 ,-35 ,-49 ,-65 ,-83 ,-104 ,-127 , 1030113 ,89 ,69 ,53 ,38 ,25 ,13 ,1 ,-10 ,-22 ,-35 ,-49 ,-65 ,-83 ,-104 ,-127 , 1031113 ,89 ,69 ,53 ,38 ,25 ,13 ,1 ,-10 ,-22 ,-35 ,-49 ,-65 ,-83 ,-104 ,-127 , 1032113 ,89 ,69 ,53 ,38 ,25 ,13 ,1 ,-10 ,-22 ,-35 ,-49 ,-65 ,-83 ,-104 ,-127 1033 ); 1034 1035const int packed_B_group_size = QK_K /2 * TILE_N /8 ; 1036const char * pb = (const char * )packed_B + k * packed_B_group_size ; 1037const __m512i lowMask = _mm512_set1_epi8 (0xF ); 1038 1039for (int n = 0 ;n < 8 ;n += 2 ) { 1040__m512i bytes = _mm512_loadu_si512 (pb + n * 32 ); 1041const __m512i r0 = _mm512_shuffle_epi8 (values128 ,_mm512_and_si512 (bytes ,lowMask )); 1042const __m512i r1 = _mm512_shuffle_epi8 (values128 ,_mm512_and_si512 (_mm512_srli_epi16 (bytes ,4 ),lowMask )); 1043_mm512_storeu_si512 ((__m512i * )(tile + n * 64 + 0 ),r0 ); 1044_mm512_storeu_si512 ((__m512i * )(tile + n * 64 + 64 ),r1 ); 1045 } 1046} 1047 1048template < typename TA ,typename TB ,bool is_acc > 1049struct acc_C {}; 1050 1051template < bool is_acc > 1052struct acc_C < block_q8_0 ,block_q4_0 ,is_acc > { 1053static void apply (float * RESTRICT C ,int ldc ,const int32_t * RESTRICT tile ,const block_q8_0 * A ,int lda ,const void * packed_B ,int nr ) { 1054const int offset = TILE_N * TILE_K /2 ; 1055const __m512 vd0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )((const char * )packed_B + offset ))); 1056 1057for (int m = 0 ;m < nr ;++ m ) { 1058const __m512 vd1 = _mm512_set1_ps (GGML_CPU_FP16_TO_FP32 (A [m * lda ].d )); 1059const __m512 vtile = _mm512_cvtepi32_ps (_mm512_loadu_si512 (tile + m * TILE_N )); 1060 1061__m512 vsum ; 1062if (is_acc ) { 1063vsum = _mm512_loadu_ps (C + m * ldc ); 1064 }else { 1065vsum = _mm512_set1_ps (0.f ); 1066 } 1067vsum = _mm512_fmadd_ps (vtile ,_mm512_mul_ps (vd0 ,vd1 ),vsum ); 1068_mm512_storeu_ps (C + m * ldc ,vsum ); 1069 } 1070 } 1071}; 1072 1073template < bool is_acc > 1074struct acc_C < block_q8_1 ,block_q4_1 ,is_acc > { 1075static void apply (float * RESTRICT C ,int ldc ,const int32_t * RESTRICT tile ,const block_q8_1 * A ,int lda ,const void * packed_B ,int nr ) { 1076const int offset = TILE_N * TILE_K /2 ; 1077const __m512 vd0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )((const char * )packed_B + offset ))); 1078const __m512 vm0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )((const char * )packed_B + offset + TILE_N * sizeof (ggml_half )))); 1079 1080for (int m = 0 ;m < nr ;++ m ) { 1081const __m512 vd1 = _mm512_set1_ps (GGML_CPU_FP16_TO_FP32 (A [m * lda ].d )); 1082const __m512 vs1 = _mm512_set1_ps (GGML_CPU_FP16_TO_FP32 (A [m * lda ].s )); 1083const __m512 vtile = _mm512_cvtepi32_ps (_mm512_loadu_si512 (tile + m * TILE_N )); 1084 1085__m512 vsum ; 1086if (is_acc ) { 1087vsum = _mm512_loadu_ps (C + m * ldc ); 1088 }else { 1089vsum = _mm512_set1_ps (0.f ); 1090 } 1091vsum = _mm512_fmadd_ps (vtile ,_mm512_mul_ps (vd0 ,vd1 ),vsum ); 1092vsum = _mm512_fmadd_ps (vm0 ,vs1 ,vsum ); 1093_mm512_storeu_ps (C + m * ldc ,vsum ); 1094 } 1095 } 1096}; 1097 1098template < bool is_acc > 1099struct acc_C < block_q8_0 ,block_q8_0 ,is_acc > { 1100static void apply (float * RESTRICT C ,int ldc ,const int32_t * RESTRICT tile ,const block_q8_0 * A ,int lda ,const void * packed_B ,int nr ) { 1101const int offset = TILE_N * TILE_K ; 1102const __m512 vd0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )((const char * )packed_B + offset ))); 1103 1104for (int m = 0 ;m < nr ;++ m ) { 1105const __m512 vd1 = _mm512_set1_ps (GGML_CPU_FP16_TO_FP32 (A [m * lda ].d )); 1106const __m512 vtile = _mm512_cvtepi32_ps (_mm512_loadu_si512 (tile + m * TILE_N )); 1107 1108__m512 vsum ; 1109if (is_acc ) { 1110vsum = _mm512_loadu_ps (C + m * ldc ); 1111 }else { 1112vsum = _mm512_set1_ps (0.f ); 1113 } 1114vsum = _mm512_fmadd_ps (vtile ,_mm512_mul_ps (vd0 ,vd1 ),vsum ); 1115_mm512_storeu_ps (C + m * ldc ,vsum ); 1116 } 1117 } 1118}; 1119 1120template < bool is_acc > 1121struct acc_C < block_q8_K ,block_q4_K ,is_acc > { 1122static void apply (float * RESTRICT C ,int ldc ,const int32_t * RESTRICT tile ,const block_q8_K * A ,int lda ,const void * packed_B ,int nr ) { 1123const uint8_t * scales = reinterpret_cast < const uint8_t *> ((const char * )packed_B + (QK_K /2 )* TILE_N ); 1124const uint8_t * mins = scales + 8 * TILE_N ; 1125const ggml_half * d0 = reinterpret_cast < const ggml_half *> (mins + 8 * TILE_N ); 1126const ggml_half * dmin = d0 + TILE_N ; 1127 1128const __m512 vd0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )d0 )); 1129const __m512 vdmin = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )dmin )); 1130 1131for (int m = 0 ;m < nr ;++ m ) { 1132const float d1 = A [m * lda ].d ; 1133const __m512 vd = _mm512_mul_ps (_mm512_set1_ps (d1 ),vd0 ); 1134const __m512 vdm = _mm512_mul_ps (_mm512_set1_ps (- d1 ),vdmin ); 1135const __m512 vtile = _mm512_cvtepi32_ps (_mm512_loadu_si512 (tile + m * TILE_N )); 1136 1137__m512 vsum ; 1138if (is_acc ) { 1139vsum = _mm512_loadu_ps (C + m * ldc ); 1140 }else { 1141vsum = _mm512_set1_ps (0.f ); 1142 } 1143 1144const __m256i q8sums = _mm256_loadu_si256 ((const __m256i * )A [m * lda ].bsums ); 1145const __m128i q8s = _mm_hadd_epi16 (_mm256_extracti128_si256 (q8sums ,0 ),_mm256_extracti128_si256 (q8sums ,1 )); 1146 1147__m512i acc_m = _mm512_setzero_si512 (); 1148for (int k = 0 ;k < 4 ;++ k ) { 1149__m512i vmask = _mm512_set1_epi32 (k ); 1150__m512i va = _mm512_permutexvar_epi32 (vmask ,_mm512_castsi128_si512 (q8s )); 1151__m512i vb = _mm512_cvtepi8_epi16 (_mm256_loadu_si256 ((const __m256i * )(mins + k * 32 ))); 1152acc_m = _mm512_dpwssds_epi32 (acc_m ,va ,vb ); 1153 } 1154 1155vsum = _mm512_fmadd_ps (vtile ,vd ,vsum ); 1156vsum = _mm512_fmadd_ps (_mm512_cvtepi32_ps (acc_m ),vdm ,vsum ); 1157_mm512_storeu_ps (C + m * ldc ,vsum ); 1158 } 1159 } 1160}; 1161 1162template < bool is_acc > 1163struct acc_C < block_q8_K ,block_q5_K ,is_acc > { 1164static void apply (float * RESTRICT C ,int ldc ,const int32_t * RESTRICT tile ,const block_q8_K * A ,int lda ,const void * packed_B ,int nr ) { 1165const uint8_t * scales = reinterpret_cast < const uint8_t *> ((const char * )packed_B + (QK_K /2 )* TILE_N + (QK_K /8 )* TILE_N ); 1166const uint8_t * mins = scales + 8 * TILE_N ; 1167const ggml_half * d0 = reinterpret_cast < const ggml_half *> (mins + 8 * TILE_N ); 1168const ggml_half * dmin = d0 + TILE_N ; 1169 1170const __m512 vd0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )d0 )); 1171const __m512 vdmin = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )dmin )); 1172 1173for (int m = 0 ;m < nr ;++ m ) { 1174const float d1 = A [m * lda ].d ; 1175const __m512 vd = _mm512_mul_ps (_mm512_set1_ps (d1 ),vd0 ); 1176const __m512 vdm = _mm512_mul_ps (_mm512_set1_ps (- d1 ),vdmin ); 1177const __m512 vtile = _mm512_cvtepi32_ps (_mm512_loadu_si512 (tile + m * TILE_N )); 1178 1179__m512 vsum ; 1180if (is_acc ) { 1181vsum = _mm512_loadu_ps (C + m * ldc ); 1182 }else { 1183vsum = _mm512_set1_ps (0.f ); 1184 } 1185 1186const __m256i q8sums = _mm256_loadu_si256 ((const __m256i * )A [m * lda ].bsums ); 1187const __m128i q8s = _mm_hadd_epi16 (_mm256_extracti128_si256 (q8sums ,0 ),_mm256_extracti128_si256 (q8sums ,1 )); 1188 1189__m512i acc_m = _mm512_setzero_si512 (); 1190for (int k = 0 ;k < 4 ;++ k ) { 1191__m512i vmask = _mm512_set1_epi32 (k ); 1192__m512i va = _mm512_permutexvar_epi32 (vmask ,_mm512_castsi128_si512 (q8s )); 1193__m512i vb = _mm512_cvtepi8_epi16 (_mm256_loadu_si256 ((const __m256i * )(mins + k * 32 ))); 1194acc_m = _mm512_dpwssds_epi32 (acc_m ,va ,vb ); 1195 } 1196 1197vsum = _mm512_fmadd_ps (vtile ,vd ,vsum ); 1198vsum = _mm512_fmadd_ps (_mm512_cvtepi32_ps (acc_m ),vdm ,vsum ); 1199_mm512_storeu_ps (C + m * ldc ,vsum ); 1200 } 1201 } 1202}; 1203 1204template < bool is_acc > 1205struct acc_C < block_q8_K ,block_q6_K ,is_acc > { 1206static void apply (float * RESTRICT C ,int ldc ,const int32_t * RESTRICT tile ,const block_q8_K * A ,int lda ,const void * packed_B ,int nr ) { 1207const uint8_t * scales = reinterpret_cast < const uint8_t *> ((const char * )packed_B + (QK_K /2 )* TILE_N + (QK_K /4 )* TILE_N ); 1208const ggml_half * d0 = reinterpret_cast < const ggml_half *> (scales + 16 * TILE_N ); 1209 1210const __m512 vd0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )d0 )); 1211 1212for (int m = 0 ;m < nr ;++ m ) { 1213const float d1 = A [m * lda ].d ; 1214const __m512 vd = _mm512_mul_ps (_mm512_set1_ps (d1 ),vd0 ); 1215const __m512 vtile = _mm512_cvtepi32_ps (_mm512_loadu_si512 (tile + m * TILE_N )); 1216 1217__m512 vsum ; 1218if (is_acc ) { 1219vsum = _mm512_loadu_ps (C + m * ldc ); 1220 }else { 1221vsum = _mm512_set1_ps (0.f ); 1222 } 1223 1224vsum = _mm512_fmadd_ps (vtile ,vd ,vsum ); 1225_mm512_storeu_ps (C + m * ldc ,vsum ); 1226 } 1227 } 1228}; 1229 1230template < bool is_acc > 1231struct acc_C < block_q8_K ,block_iq4_xs ,is_acc > { 1232static void apply (float * RESTRICT C ,int ldc ,const int32_t * RESTRICT tile ,const block_q8_K * A ,int lda ,const void * packed_B ,int nr ) { 1233const int8_t * scales = reinterpret_cast < const int8_t *> ((const char * )packed_B + (QK_K /2 )* TILE_N ); 1234const ggml_half * d0 = reinterpret_cast < const ggml_half *> (scales + 8 * TILE_N ); 1235 1236const __m512 vd0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )d0 )); 1237 1238for (int m = 0 ;m < nr ;++ m ) { 1239const float d1 = A [m * lda ].d ; 1240const __m512 vd = _mm512_mul_ps (_mm512_set1_ps (d1 ),vd0 ); 1241const __m512 vtile = _mm512_cvtepi32_ps (_mm512_loadu_si512 (tile + m * TILE_N )); 1242 1243__m512 vsum ; 1244if (is_acc ) { 1245vsum = _mm512_loadu_ps (C + m * ldc ); 1246 }else { 1247vsum = _mm512_set1_ps (0.f ); 1248 } 1249 1250vsum = _mm512_fmadd_ps (vtile ,vd ,vsum ); 1251_mm512_storeu_ps (C + m * ldc ,vsum ); 1252 } 1253 } 1254}; 1255 1256template < typename TB > constexpr int get_quants_size (); 1257template <> constexpr int get_quants_size < block_q4_K > () {return (QK_K /2 )* TILE_N ; } 1258template <> constexpr int get_quants_size < block_q5_K > () {return (QK_K /2 )* TILE_N + (QK_K /8 )* TILE_N ; } 1259template <> constexpr int get_quants_size < block_q6_K > () {return (QK_K /2 )* TILE_N + (QK_K /4 )* TILE_N ; } 1260template <> constexpr int get_quants_size < block_iq4_xs > () {return (QK_K /2 )* TILE_N ; } 1261 1262// used for QKK format 1263template < typename TB ,bool is_acc , 1264typename std::enable_if < is_type_qkk < TB > ::value ,int > ::type = 0 > 1265inline void scale_C (const int32_t * RESTRICT tile ,int32_t * RESTRICT sumi ,const void * packed_B ,int k ,int nr ) { 1266const uint8_t * scales = reinterpret_cast < const uint8_t *> ((const char * )packed_B + get_quants_size < TB > ()); 1267const __m512i vscale = _mm512_cvtepi8_epi32 (_mm_loadu_si128 ((const __m128i * )(scales + k * TILE_N ))); 1268 1269for (int m = 0 ;m < nr ;++ m ) { 1270__m512i vsumi ; 1271if (is_acc ) { 1272vsumi = _mm512_loadu_si512 (sumi + m * TILE_N ); 1273 }else { 1274vsumi = _mm512_setzero_si512 (); 1275 } 1276__m512i vtile = _mm512_loadu_si512 (tile + m * TILE_N ); 1277vsumi = _mm512_add_epi32 (vsumi ,_mm512_mullo_epi32 (vtile ,vscale )); 1278_mm512_storeu_si512 ((__m512i * )(sumi + m * TILE_N ),vsumi ); 1279 } 1280} 1281 1282template < typename TA ,typename TB ,typename TC ,int BLOCK_M ,int BLOCK_N ,int BLOCK_K > 1283struct tinygemm_kernel_avx { 1284static void apply (int K ,const TA * RESTRICT A ,const TB * RESTRICT B ,TC * RESTRICT C ,int ldc ) { 1285GGML_UNUSED (K ); 1286GGML_UNUSED (A ); 1287GGML_UNUSED (B ); 1288GGML_UNUSED (C ); 1289GGML_UNUSED (ldc ); 1290 } 1291}; 1292 1293template < int BLOCK_M ,int BLOCK_N ,int BLOCK_K > 1294struct tinygemm_kernel_avx < float ,ggml_fp16_t ,float ,BLOCK_M ,BLOCK_N ,BLOCK_K > { 1295static void apply (int K ,const float * RESTRICT A ,const ggml_fp16_t * RESTRICT B ,float * RESTRICT C ,int ldc ) { 1296constexpr int ROWS = BLOCK_M ; 1297constexpr int COLS = BLOCK_N ; 1298assert (BLOCK_K == 16 ); 1299 1300__m512 va ; 1301__m512 vb [COLS ]; 1302__m512 vc [ROWS * COLS ]; 1303 1304auto loadc = [& ](auto idx ) { 1305vc [idx ]= _mm512_setzero_ps (); 1306 }; 1307Unroll < ROWS * COLS > {}(loadc ); 1308 1309auto compute = [& ](auto idx ,auto k ) { 1310constexpr int row = idx /COLS ; 1311constexpr int col = idx %COLS ; 1312 1313if constexpr (col == 0 ) { 1314va = _mm512_loadu_ps (A + row * K + k ); 1315 } 1316if constexpr (row == 0 ) { 1317vb [col ]= _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )(B + col * K + k ))); 1318 } 1319vc [idx ]= _mm512_fmadd_ps (va ,vb [col ],vc [idx ]); 1320 }; 1321 1322for (int k = 0 ;k < K ;k += 16 ) { 1323Unroll < ROWS * COLS > {}(compute ,k ); 1324 } 1325 1326auto storec = [& ](auto idx ) { 1327constexpr int row = idx /COLS ; 1328constexpr int col = idx %COLS ; 1329C [row * ldc + col ]= _mm512_reduce_add_ps (vc [idx ]); 1330 }; 1331Unroll < ROWS * COLS > {}(storec ); 1332 } 1333}; 1334 1335#define LAUNCH_TINYGEMM_KERNEL_AVX (MB_SIZE ,NB_SIZE ) \ 1336 tinygemm_kernel_avx<float, type, float, MB_SIZE, NB_SIZE, blck_size>::apply( \ 1337 K, (const float *)src1->data + src1_offset + mb_start * K, \ 1338 (const type *)src0->data + src0_offset + nb_start * K, \ 1339 (float *)dst->data + dst_offset + mb_start * ldc + nb_start, ldc) 1340 1341 1342// re-organize in the format {NB, KB, TILE_SIZE}: 1343#define PACKED_INDEX (n ,k ,KB ,tile_size ) (n * KB + k) * tile_size 1344 1345template < typename TB ,int BLOCK_K > 1346void convert_B_packed_format (void * RESTRICT packed_B ,const TB * RESTRICT B ,int N ,int K ) { 1347const int NB = N /TILE_N ; 1348const int KB = K /BLOCK_K ; 1349const int TILE_SIZE = get_tile_size < TB > (); 1350 1351// parallel on NB should be enough 1352parallel_for (NB , [& ](int begin ,int end ) { 1353for (int n = begin ;n < end ;++ n ) { 1354for (int k = 0 ;k < KB ;++ k ) { 1355int n0 = n * TILE_N ; 1356pack_B ((char * )packed_B + PACKED_INDEX (n ,k ,KB ,TILE_SIZE ),& B [n0 * KB + k ],KB ); 1357 } 1358 } 1359 }); 1360} 1361 1362template < typename TA ,typename TB ,typename TC ,int BLOCK_M ,int BLOCK_N ,int BLOCK_K > 1363struct tinygemm_kernel_vnni {}; 1364 1365template < int BLOCK_M ,int BLOCK_N ,int BLOCK_K > 1366struct tinygemm_kernel_vnni < block_q8_0 ,block_q4_0 ,float ,BLOCK_M ,BLOCK_N ,BLOCK_K > { 1367static void apply (int KB ,const void * RESTRICT _A ,const void * RESTRICT _B ,float * RESTRICT C ,int ldc ) { 1368 1369constexpr int COLS = BLOCK_N /16 ; 1370const int TILE_SIZE = TILE_N * sizeof (block_q4_0 ); 1371 1372const block_q8_0 * RESTRICT A = static_cast < const block_q8_0 *> (_A ); 1373const char * RESTRICT B = static_cast < const char *> (_B ); 1374 1375__m512i va [8 ]; 1376__m512 vc [COLS ]; 1377__m512 vd1 ; 1378 1379// sum of offsets, shared across COLS 1380// 1381// avx512-vnni does not have `_mm512_dpbssd_epi32`, 1382// need to transform ss to us: 1383// a * (b - 8) is equivalent to b * a - 8 * a 1384// s u u u s u s 1385// 1386__m512i vcomp ; 1387 1388const __m512i off = _mm512_set1_epi8 (8 ); 1389const __m512i lowMask = _mm512_set1_epi8 (0xF ); 1390 1391auto loadc = [& ](auto col ) { 1392vc [col ]= _mm512_setzero_ps (); 1393 }; 1394Unroll < COLS > {}(loadc ); 1395 1396auto compute = [& ](auto col ,auto i ) { 1397// load a and compute compensation 1398if constexpr (col == 0 ) { 1399const int32_t * a_ptr = reinterpret_cast < const int32_t *> (A [0 * KB + i ].qs ); 1400vcomp = _mm512_setzero_si512 (); 1401for (int k = 0 ;k < 8 ;++ k ) { 1402va [k ]= _mm512_set1_epi32 (a_ptr [k ]); 1403vcomp = _mm512_dpbusd_epi32 (vcomp ,off ,va [k ]); 1404 } 1405vd1 = _mm512_set1_ps (GGML_CPU_FP16_TO_FP32 (A [0 * KB + i ].d )); 1406 } 1407 1408// load b 1409__m512i vsum = _mm512_setzero_si512 (); 1410const char * b_ptr = B + PACKED_INDEX (col ,i ,KB ,TILE_SIZE ); 1411for (int k = 0 ;k < 8 ;k += 2 ) { 1412__m512i bytes = _mm512_loadu_si512 ((const __m512i * )(b_ptr + k * 32 )); 1413__m512i vb0 = _mm512_and_si512 (bytes ,lowMask ); 1414vsum = _mm512_dpbusd_epi32 (vsum ,vb0 ,va [k + 0 ]); 1415__m512i vb1 = _mm512_and_si512 (_mm512_srli_epi16 (bytes ,4 ),lowMask ); 1416vsum = _mm512_dpbusd_epi32 (vsum ,vb1 ,va [k + 1 ]); 1417 } 1418const int offset = TILE_N * TILE_K /2 ; 1419const __m512 vd0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )(b_ptr + offset ))); 1420vsum = _mm512_sub_epi32 (vsum ,vcomp ); 1421 1422vc [col ]= _mm512_fmadd_ps (_mm512_cvtepi32_ps (vsum ),_mm512_mul_ps (vd0 ,vd1 ),vc [col ]); 1423 }; 1424 1425for (int i = 0 ;i < KB ;++ i ) { 1426Unroll < COLS > {}(compute ,i ); 1427 } 1428 1429//store to C 1430auto storec = [& ](auto col ) { 1431_mm512_storeu_ps ((__m512i * )(C + 0 * ldc + col * 16 ),vc [col ]); 1432 }; 1433Unroll < COLS > {}(storec ); 1434 } 1435}; 1436 1437template < int BLOCK_N ,int BLOCK_K > 1438struct tinygemm_kernel_vnni < block_q8_1 ,block_q4_1 ,float ,1 ,BLOCK_N ,BLOCK_K > { 1439static void apply (int KB ,const void * RESTRICT _A ,const void * RESTRICT _B ,float * RESTRICT C ,int ldc ) { 1440 1441constexpr int COLS = BLOCK_N /16 ; 1442const int TILE_SIZE = TILE_N * sizeof (block_q4_1 ); 1443 1444const block_q8_1 * RESTRICT A = static_cast < const block_q8_1 *> (_A ); 1445const char * RESTRICT B = static_cast < const char *> (_B ); 1446 1447__m512i va [8 ]; 1448__m512i vb [8 ]; 1449__m512 vc [COLS ]; 1450__m512 vd1 ,vs1 ; 1451 1452const __m512i lowMask = _mm512_set1_epi8 (0xF ); 1453 1454auto loadc = [& ](auto col ) { 1455vc [col ]= _mm512_setzero_ps (); 1456 }; 1457Unroll < COLS > {}(loadc ); 1458 1459auto compute = [& ](auto col ,auto i ) { 1460// load a 1461if constexpr (col == 0 ) { 1462const int32_t * a_ptr = reinterpret_cast < const int32_t *> (A [0 * KB + i ].qs ); 1463for (int k = 0 ;k < 8 ;++ k ) { 1464va [k ]= _mm512_set1_epi32 (a_ptr [k ]); 1465 } 1466vd1 = _mm512_set1_ps (GGML_CPU_FP16_TO_FP32 (A [0 * KB + i ].d )); 1467vs1 = _mm512_set1_ps (GGML_CPU_FP16_TO_FP32 (A [0 * KB + i ].s )); 1468 } 1469 1470// load b 1471const char * b_ptr = B + PACKED_INDEX (col ,i ,KB ,TILE_SIZE ); 1472for (int k = 0 ;k < 8 ;k += 2 ) { 1473__m512i bytes = _mm512_loadu_si512 ((const __m512i * )(b_ptr + k * 32 )); 1474vb [k + 0 ]= _mm512_and_si512 (bytes ,lowMask ); 1475vb [k + 1 ]= _mm512_and_si512 (_mm512_srli_epi16 (bytes ,4 ),lowMask ); 1476 } 1477const int offset = TILE_N * TILE_K /2 ; 1478const __m512 vd0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )(b_ptr + offset ))); 1479const __m512 vm0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )(b_ptr + offset + TILE_N * sizeof (ggml_half )))); 1480 1481__m512i vsum = _mm512_setzero_si512 (); 1482for (int k = 0 ;k < 8 ;++ k ) { 1483vsum = _mm512_dpbusd_epi32 (vsum ,vb [k ],va [k ]); 1484 } 1485 1486vc [col ]= _mm512_fmadd_ps (_mm512_cvtepi32_ps (vsum ),_mm512_mul_ps (vd0 ,vd1 ),vc [col ]); 1487vc [col ]= _mm512_fmadd_ps (vm0 ,vs1 ,vc [col ]); 1488 }; 1489 1490for (int i = 0 ;i < KB ;++ i ) { 1491Unroll < COLS > {}(compute ,i ); 1492 } 1493 1494//store to C 1495auto storec = [& ](auto col ) { 1496_mm512_storeu_ps ((__m512i * )(C + 0 * ldc + col * 16 ),vc [col ]); 1497 }; 1498Unroll < COLS > {}(storec ); 1499 } 1500}; 1501 1502template < int BLOCK_M ,int BLOCK_N ,int BLOCK_K > 1503struct tinygemm_kernel_vnni < block_q8_0 ,block_q8_0 ,float ,BLOCK_M ,BLOCK_N ,BLOCK_K > { 1504static void apply (int KB ,const void * RESTRICT _A ,const void * RESTRICT _B ,float * RESTRICT C ,int ldc ) { 1505 1506constexpr int COLS = BLOCK_N /16 ; 1507const int TILE_SIZE = TILE_N * sizeof (block_q8_0 )+ TILE_N * sizeof (int32_t ); 1508 1509const block_q8_0 * RESTRICT A = static_cast < const block_q8_0 *> (_A ); 1510const char * RESTRICT B = static_cast < const char *> (_B ); 1511 1512__m512i va [8 ]; 1513__m512i vb [8 ]; 1514__m512 vc [COLS ]; 1515__m512 vd1 ; 1516 1517// Notes: s8s8 igemm compensation in avx512-vnni 1518// change s8s8 to u8s8 with compensate 1519// a * b = (a + 128) * b - 128 * b 1520// s s u s u s 1521// 1522// (128 * b is pre-computed when packing B to vnni formats) 1523// 1524const __m512i off = _mm512_set1_epi8 (static_cast < char > (0x80 )); 1525 1526auto loadc = [& ](auto col ) { 1527vc [col ]= _mm512_setzero_ps (); 1528 }; 1529Unroll < COLS > {}(loadc ); 1530 1531auto compute = [& ](auto col ,auto i ) { 1532// load a and add offset 128 1533if constexpr (col == 0 ) { 1534const int32_t * a_ptr = reinterpret_cast < const int32_t *> (A [0 * KB + i ].qs ); 1535for (int k = 0 ;k < 8 ;++ k ) { 1536va [k ]= _mm512_set1_epi32 (a_ptr [k ]); 1537va [k ]= _mm512_add_epi8 (va [k ],off ); 1538 } 1539vd1 = _mm512_set1_ps (GGML_CPU_FP16_TO_FP32 (A [0 * KB + i ].d )); 1540 } 1541 1542// load b 1543const char * b_ptr = B + PACKED_INDEX (col ,i ,KB ,TILE_SIZE ); 1544for (int k = 0 ;k < 8 ;++ k ) { 1545vb [k ]= _mm512_loadu_si512 ((const __m512i * )(b_ptr + k * 64 )); 1546 } 1547const int offset = TILE_N * TILE_K ; 1548const __m512 vd0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )(b_ptr + offset ))); 1549const int offset2 = TILE_N * TILE_K + TILE_N * sizeof (ggml_half ); 1550const __m512i vcomp = _mm512_loadu_si512 ((const __m512i * )(b_ptr + offset2 )); 1551 1552__m512i vsum = _mm512_setzero_si512 (); 1553for (int k = 0 ;k < 8 ;++ k ) { 1554vsum = _mm512_dpbusd_epi32 (vsum ,va [k ],vb [k ]); 1555 } 1556vsum = _mm512_sub_epi32 (vsum ,vcomp ); 1557 1558vc [col ]= _mm512_fmadd_ps (_mm512_cvtepi32_ps (vsum ),_mm512_mul_ps (vd0 ,vd1 ),vc [col ]); 1559 }; 1560 1561for (int i = 0 ;i < KB ;++ i ) { 1562Unroll < COLS > {}(compute ,i ); 1563 } 1564 1565//store to C 1566auto storec = [& ](auto col ) { 1567_mm512_storeu_ps ((__m512i * )(C + 0 * ldc + col * 16 ),vc [col ]); 1568 }; 1569Unroll < COLS > {}(storec ); 1570 } 1571}; 1572 1573template < int BLOCK_M ,int BLOCK_N ,int BLOCK_K > 1574struct tinygemm_kernel_vnni < block_q8_K ,block_q4_K ,float ,BLOCK_M ,BLOCK_N ,BLOCK_K > { 1575static void apply (int KB ,const void * RESTRICT _A ,const void * RESTRICT _B ,float * RESTRICT C ,int ldc ) { 1576 1577constexpr int COLS = BLOCK_N /16 ; 1578const int TILE_SIZE = TILE_N * sizeof (block_q4_K )+ TILE_N * 4 ; 1579 1580const block_q8_K * RESTRICT A = static_cast < const block_q8_K *> (_A ); 1581const char * RESTRICT B = static_cast < const char *> (_B ); 1582 1583// a.qs: 8 groups, 32 bytes each group (m256i) 1584__m512i va [8 ]; 1585// a.bsum: 8 groups, 2 bytes each group (m128i) 1586__m512i va_bsum ; 1587__m512 vc [COLS ]; 1588__m512 vd1 ; 1589 1590// packed_B: 1591const int offset_scales = (QK_K /2 )* TILE_N ; 1592const int offset_mins = (QK_K /2 )* TILE_N + 8 * TILE_N ; 1593const int offset_d0 = (QK_K /2 )* TILE_N + 16 * TILE_N ; 1594const int offset_dmin = (QK_K /2 )* TILE_N + 16 * TILE_N + TILE_N * sizeof (ggml_half ); 1595 1596const __m512i lowMask = _mm512_set1_epi8 (0xF ); 1597 1598auto loadc = [& ](auto col ) { 1599vc [col ]= _mm512_setzero_ps (); 1600 }; 1601Unroll < COLS > {}(loadc ); 1602 1603// Notes: vnni formats in QK_K 1604// a) quants vnni format 1605// int8 {k/4, n, 4}, viewed as 2d {k/4, 4n}, k = 32 1606// from {16, 32} to {8, 64} 1607// 1608// b) min vnni format 1609// int16 {k/2, n, 2}, viewed as 2d {k/2, 2n}, k = 8 1610// from {16, 8} to {4, 32} 1611// 1612auto compute = [& ](auto col ,auto i ) { 1613// load a 1614if constexpr (col == 0 ) { 1615for (int k_group = 0 ;k_group < QK_K /32 ;++ k_group ) { 1616va [k_group ]= _mm512_castsi256_si512 (_mm256_loadu_si256 ((const __m256i * )(A [0 * KB + i ].qs + k_group * 32 ))); 1617 } 1618const __m256i q8sums = _mm256_loadu_si256 ((const __m256i * )A [0 * KB + i ].bsums ); 1619const __m128i q8s = _mm_hadd_epi16 (_mm256_extracti128_si256 (q8sums ,0 ),_mm256_extracti128_si256 (q8sums ,1 )); 1620va_bsum = _mm512_castsi128_si512 (q8s ); 1621vd1 = _mm512_set1_ps (A [0 * KB + i ].d ); 1622 } 1623 1624// step 1: accumultate the quants 1625__m512i acc = _mm512_setzero_si512 (); 1626const char * b_ptr = B + PACKED_INDEX (col ,i ,KB ,TILE_SIZE ); 1627const char * b_qs = b_ptr ; 1628for (int k_group = 0 ;k_group < QK_K /32 ;++ k_group ) { 1629__m512i vsum = _mm512_setzero_si512 (); 1630for (int k = 0 ;k < 8 ;k += 2 ) { 1631__m512i va0 = _mm512_permutexvar_epi32 (_mm512_set1_epi32 (k + 0 ),va [k_group ]); 1632__m512i va1 = _mm512_permutexvar_epi32 (_mm512_set1_epi32 (k + 1 ),va [k_group ]); 1633 1634__m512i bytes = _mm512_loadu_si512 ((const __m512i * )b_qs ); 1635__m512i vb0 = _mm512_and_si512 (bytes ,lowMask ); 1636vsum = _mm512_dpbusd_epi32 (vsum ,vb0 ,va0 ); 1637__m512i vb1 = _mm512_and_si512 (_mm512_srli_epi16 (bytes ,4 ),lowMask ); 1638vsum = _mm512_dpbusd_epi32 (vsum ,vb1 ,va1 ); 1639 1640b_qs += 64 ; 1641 } 1642// vacc += scale * (q8 @ q4) 1643const __m512i vscale = _mm512_cvtepi8_epi32 (_mm_loadu_si128 ((const __m128i * )(b_ptr + offset_scales + k_group * TILE_N ))); 1644acc = _mm512_add_epi32 (acc ,_mm512_mullo_epi32 (vsum ,vscale )); 1645 } 1646const __m512 vd0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )(b_ptr + offset_d0 ))); 1647vc [col ]= _mm512_fmadd_ps (_mm512_cvtepi32_ps (acc ),_mm512_mul_ps (vd0 ,vd1 ),vc [col ]); 1648 1649// step 2: accumulate the mins 1650__m512i acc_m = _mm512_setzero_si512 (); 1651for (int k = 0 ;k < 4 ;++ k ) { 1652__m512i vmask = _mm512_set1_epi32 (k ); 1653__m512i va = _mm512_permutexvar_epi32 (vmask ,va_bsum ); 1654__m512i vb = _mm512_cvtepi8_epi16 (_mm256_loadu_si256 ((const __m256i * )(b_ptr + offset_mins + k * 32 ))); 1655acc_m = _mm512_dpwssds_epi32 (acc_m ,va ,vb ); 1656 } 1657const __m512 vdmin = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )(b_ptr + offset_dmin ))); 1658vc [col ]= _mm512_fnmadd_ps (_mm512_cvtepi32_ps (acc_m ),_mm512_mul_ps (vdmin ,vd1 ),vc [col ]); 1659 }; 1660 1661for (int i = 0 ;i < KB ;++ i ) { 1662Unroll < COLS > {}(compute ,i ); 1663 } 1664 1665//store to C 1666auto storec = [& ](auto col ) { 1667_mm512_storeu_ps ((__m512i * )(C + 0 * ldc + col * 16 ),vc [col ]); 1668 }; 1669Unroll < COLS > {}(storec ); 1670 } 1671}; 1672 1673template < int BLOCK_M ,int BLOCK_N ,int BLOCK_K > 1674struct tinygemm_kernel_vnni < block_q8_K ,block_q5_K ,float ,BLOCK_M ,BLOCK_N ,BLOCK_K > { 1675static void apply (int KB ,const void * RESTRICT _A ,const void * RESTRICT _B ,float * RESTRICT C ,int ldc ) { 1676 1677constexpr int COLS = BLOCK_N /16 ; 1678const int TILE_SIZE = TILE_N * sizeof (block_q5_K )+ TILE_N * 4 ; 1679 1680const block_q8_K * RESTRICT A = static_cast < const block_q8_K *> (_A ); 1681const char * RESTRICT B = static_cast < const char *> (_B ); 1682 1683// a.qs: 8 groups, 32 bytes each group (m256i) 1684__m512i va [8 ]; 1685// a.bsum: 8 groups, 2 bytes each group (m128i) 1686__m512i va_bsum ; 1687__m512 vc [COLS ]; 1688__m512 vd1 ; 1689 1690// packed_B: 1691const int offset_qh = (QK_K /2 )* TILE_N ; 1692const int offset_scales = (QK_K /2 )* TILE_N + (QK_K /8 )* TILE_N ; 1693const int offset_mins = (QK_K /2 )* TILE_N + (QK_K /8 )* TILE_N + 8 * TILE_N ; 1694const int offset_d0 = (QK_K /2 )* TILE_N + (QK_K /8 )* TILE_N + 16 * TILE_N ; 1695const int offset_dmin = (QK_K /2 )* TILE_N + (QK_K /8 )* TILE_N + 16 * TILE_N + TILE_N * sizeof (ggml_half ); 1696 1697const __m512i lowMask = _mm512_set1_epi8 (0xF ); 1698 1699auto loadc = [& ](auto col ) { 1700vc [col ]= _mm512_setzero_ps (); 1701 }; 1702Unroll < COLS > {}(loadc ); 1703 1704// Q5_K and Q4_K shares the same vnni formats, refer to notes above. 1705auto compute = [& ](auto col ,auto i ) { 1706// load a 1707if constexpr (col == 0 ) { 1708for (int k_group = 0 ;k_group < QK_K /32 ;++ k_group ) { 1709va [k_group ]= _mm512_castsi256_si512 (_mm256_loadu_si256 ((const __m256i * )(A [0 * KB + i ].qs + k_group * 32 ))); 1710 } 1711const __m256i q8sums = _mm256_loadu_si256 ((const __m256i * )A [0 * KB + i ].bsums ); 1712const __m128i q8s = _mm_hadd_epi16 (_mm256_extracti128_si256 (q8sums ,0 ),_mm256_extracti128_si256 (q8sums ,1 )); 1713va_bsum = _mm512_castsi128_si512 (q8s ); 1714vd1 = _mm512_set1_ps (A [0 * KB + i ].d ); 1715 } 1716 1717// step 1: accumultate the quants 1718__m512i acc = _mm512_setzero_si512 (); 1719const char * b_ptr = B + PACKED_INDEX (col ,i ,KB ,TILE_SIZE ); 1720const char * b_qs = b_ptr ; 1721const char * b_qh = b_ptr + offset_qh ; 1722for (int k_group = 0 ;k_group < QK_K /32 ;++ k_group ) { 1723__m512i vsum = _mm512_setzero_si512 (); 1724__m512i hmask0 = _mm512_set1_epi8 (0x1 ); 1725__m512i hmask1 = _mm512_set1_epi8 (0x2 ); 1726__m512i hbits = _mm512_loadu_si512 ((const __m512i * )(b_qh + k_group * 64 )); 1727for (int k = 0 ;k < 8 ;k += 2 ) { 1728__m512i va0 = _mm512_permutexvar_epi32 (_mm512_set1_epi32 (k + 0 ),va [k_group ]); 1729__m512i va1 = _mm512_permutexvar_epi32 (_mm512_set1_epi32 (k + 1 ),va [k_group ]); 1730 1731__m512i bytes = _mm512_loadu_si512 ((const __m512i * )b_qs ); 1732__m512i vb0 = _mm512_and_si512 (bytes ,lowMask ); 1733__m512i vb1 = _mm512_and_si512 (_mm512_srli_epi16 (bytes ,4 ),lowMask ); 1734 1735__m512i vh0 = _mm512_slli_epi16 (_mm512_srli_epi16 (_mm512_and_si512 (hbits ,hmask0 ),k ),4 ); 1736__m512i vh1 = _mm512_slli_epi16 (_mm512_srli_epi16 (_mm512_and_si512 (hbits ,hmask1 ),k + 1 ),4 ); 1737 1738hmask0 = _mm512_slli_epi16 (hmask0 ,2 ); 1739hmask1 = _mm512_slli_epi16 (hmask1 ,2 ); 1740vb0 = _mm512_add_epi8 (vb0 ,vh0 ); 1741vb1 = _mm512_add_epi8 (vb1 ,vh1 ); 1742 1743vsum = _mm512_dpbusd_epi32 (vsum ,vb0 ,va0 ); 1744vsum = _mm512_dpbusd_epi32 (vsum ,vb1 ,va1 ); 1745 1746b_qs += 64 ; 1747 } 1748// vacc += scale * (q8 @ q5) 1749const __m512i vscale = _mm512_cvtepi8_epi32 (_mm_loadu_si128 ((const __m128i * )(b_ptr + offset_scales + k_group * TILE_N ))); 1750acc = _mm512_add_epi32 (acc ,_mm512_mullo_epi32 (vsum ,vscale )); 1751 } 1752const __m512 vd0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )(b_ptr + offset_d0 ))); 1753vc [col ]= _mm512_fmadd_ps (_mm512_cvtepi32_ps (acc ),_mm512_mul_ps (vd0 ,vd1 ),vc [col ]); 1754 1755// step 2: accumulate the mins 1756__m512i acc_m = _mm512_setzero_si512 (); 1757for (int k = 0 ;k < 4 ;++ k ) { 1758__m512i vmask = _mm512_set1_epi32 (k ); 1759__m512i va = _mm512_permutexvar_epi32 (vmask ,va_bsum ); 1760__m512i vb = _mm512_cvtepi8_epi16 (_mm256_loadu_si256 ((const __m256i * )(b_ptr + offset_mins + k * 32 ))); 1761acc_m = _mm512_dpwssds_epi32 (acc_m ,va ,vb ); 1762 } 1763const __m512 vdmin = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )(b_ptr + offset_dmin ))); 1764vc [col ]= _mm512_fnmadd_ps (_mm512_cvtepi32_ps (acc_m ),_mm512_mul_ps (vdmin ,vd1 ),vc [col ]); 1765 }; 1766 1767for (int i = 0 ;i < KB ;++ i ) { 1768Unroll < COLS > {}(compute ,i ); 1769 } 1770 1771//store to C 1772auto storec = [& ](auto col ) { 1773_mm512_storeu_ps ((__m512i * )(C + 0 * ldc + col * 16 ),vc [col ]); 1774 }; 1775Unroll < COLS > {}(storec ); 1776 } 1777}; 1778 1779template < int BLOCK_M ,int BLOCK_N ,int BLOCK_K > 1780struct tinygemm_kernel_vnni < block_q8_K ,block_q6_K ,float ,BLOCK_M ,BLOCK_N ,BLOCK_K > { 1781static void apply (int KB ,const void * RESTRICT _A ,const void * RESTRICT _B ,float * RESTRICT C ,int ldc ) { 1782 1783constexpr int COLS = BLOCK_N /16 ; 1784const int TILE_SIZE = TILE_N * sizeof (block_q6_K ); 1785 1786const block_q8_K * RESTRICT A = static_cast < const block_q8_K *> (_A ); 1787const char * RESTRICT B = static_cast < const char *> (_B ); 1788 1789// load the 256 bytes from A to 4 avx512 vectors 1790__m512i va [4 ]; 1791__m512 vc [COLS ]; 1792__m512 vd1 ; 1793 1794// packed_B: 1795const int offset_qh = (QK_K /2 )* TILE_N ; 1796const int offset_scales = (QK_K /2 )* TILE_N + (QK_K /4 )* TILE_N ; 1797const int offset_d0 = (QK_K /2 )* TILE_N + (QK_K /4 )* TILE_N + 16 * TILE_N ; 1798 1799// compensation 1800__m512i vcomp ; 1801 1802const __m512i m32s = _mm512_set1_epi32 (32 ); 1803const __m512i lowMask = _mm512_set1_epi8 (0xF ); 1804 1805auto loadc = [& ](auto col ) { 1806vc [col ]= _mm512_setzero_ps (); 1807 }; 1808Unroll < COLS > {}(loadc ); 1809 1810auto compute = [& ](auto col ,auto i ) { 1811if constexpr (col == 0 ) { 1812// load a 1813va [0 ]= _mm512_loadu_si512 ((const __m512i * )(A [0 * KB + i ].qs + 0 )); 1814va [1 ]= _mm512_loadu_si512 ((const __m512i * )(A [0 * KB + i ].qs + 64 )); 1815va [2 ]= _mm512_loadu_si512 ((const __m512i * )(A [0 * KB + i ].qs + 128 )); 1816va [3 ]= _mm512_loadu_si512 ((const __m512i * )(A [0 * KB + i ].qs + 192 )); 1817 1818const __m256i q8sums = _mm256_loadu_si256 ((const __m256i * )A [0 * KB + i ].bsums ); 1819vcomp = _mm512_mullo_epi32 (_mm512_cvtepi16_epi32 (q8sums ),m32s ); 1820vd1 = _mm512_set1_ps (A [0 * KB + i ].d ); 1821 } 1822 1823// accmulate the quants 1824__m512i acc = _mm512_setzero_si512 (); 1825const char * b_ptr = B + PACKED_INDEX (col ,i ,KB ,TILE_SIZE ); 1826const char * b_qs = b_ptr ; 1827const char * b_qh = b_ptr + offset_qh ; 1828int mask = 0 ; 1829for (int k_group = 0 ;k_group < QK_K /16 ;++ k_group ) { 1830int r = k_group >>2 ; 1831__m512i va0 = _mm512_permutexvar_epi32 (_mm512_set1_epi32 (mask ++ ),va [r ]); 1832__m512i va1 = _mm512_permutexvar_epi32 (_mm512_set1_epi32 (mask ++ ),va [r ]); 1833 1834__m512i vsum = _mm512_setzero_si512 (); 1835__m512i hmask = _mm512_set1_epi8 (0x3 ); 1836 1837__m512i bytes = _mm512_loadu_si512 (b_qs ); 1838__m512i hbits = _mm512_loadu_si512 (b_qh ); 1839__m512i vb0 = _mm512_and_si512 (bytes ,lowMask ); 1840__m512i vb1 = _mm512_and_si512 (_mm512_srli_epi16 (bytes ,4 ),lowMask ); 1841__m512i vh0 = _mm512_slli_epi16 (_mm512_and_si512 (hbits ,hmask ),4 ); 1842__m512i vh1 = _mm512_slli_epi16 (_mm512_and_si512 (hbits ,_mm512_slli_epi16 (hmask ,2 )),2 ); 1843 1844vb0 = _mm512_add_epi8 (vb0 ,vh0 ); 1845vb1 = _mm512_add_epi8 (vb1 ,vh1 ); 1846vsum = _mm512_dpbusd_epi32 (vsum ,vb0 ,va0 ); 1847vsum = _mm512_dpbusd_epi32 (vsum ,vb1 ,va1 ); 1848b_qs += 64 ; 1849 1850va0 = _mm512_permutexvar_epi32 (_mm512_set1_epi32 (mask ++ ),va [r ]); 1851va1 = _mm512_permutexvar_epi32 (_mm512_set1_epi32 (mask ++ ),va [r ]); 1852 1853bytes = _mm512_loadu_si512 (b_qs ); 1854vb0 = _mm512_and_si512 (bytes ,lowMask ); 1855vb1 = _mm512_and_si512 (_mm512_srli_epi16 (bytes ,4 ),lowMask ); 1856vh0 = _mm512_and_si512 (hbits ,_mm512_slli_epi16 (hmask ,4 )); 1857vh1 = _mm512_srli_epi16 (_mm512_and_si512 (hbits ,_mm512_slli_epi16 (hmask ,6 )),2 ); 1858vb0 = _mm512_add_epi8 (vb0 ,vh0 ); 1859vb1 = _mm512_add_epi8 (vb1 ,vh1 ); 1860vsum = _mm512_dpbusd_epi32 (vsum ,vb0 ,va0 ); 1861vsum = _mm512_dpbusd_epi32 (vsum ,vb1 ,va1 ); 1862b_qs += 64 ; 1863b_qh += 64 ; 1864 1865// B * A - 32 * A 1866__m512i vmask = _mm512_set1_epi32 (k_group ); 1867vsum = _mm512_sub_epi32 (vsum ,_mm512_permutexvar_epi32 (vmask ,vcomp )); 1868 1869// vacc += scale * (q8 @ q6) 1870const __m512i vscale = _mm512_cvtepi8_epi32 (_mm_loadu_si128 ((const __m128i * )(b_ptr + offset_scales + k_group * TILE_N ))); 1871acc = _mm512_add_epi32 (acc ,_mm512_mullo_epi32 (vsum ,vscale )); 1872 } 1873const __m512 vd0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )(b_ptr + offset_d0 ))); 1874vc [col ]= _mm512_fmadd_ps (_mm512_cvtepi32_ps (acc ),_mm512_mul_ps (vd0 ,vd1 ),vc [col ]); 1875 }; 1876 1877for (int i = 0 ;i < KB ;++ i ) { 1878Unroll < COLS > {}(compute ,i ); 1879 } 1880 1881//store to C 1882auto storec = [& ](int col ) { 1883_mm512_storeu_ps ((__m512i * )(C + 0 * ldc + col * 16 ),vc [col ]); 1884 }; 1885Unroll < COLS > {}(storec ); 1886 } 1887}; 1888 1889template < int BLOCK_M ,int BLOCK_N ,int BLOCK_K > 1890struct tinygemm_kernel_vnni < block_q8_K ,block_iq4_xs ,float ,BLOCK_M ,BLOCK_N ,BLOCK_K > { 1891static void apply (int KB ,const void * RESTRICT _A ,const void * RESTRICT _B ,float * RESTRICT C ,int ldc ) { 1892 1893constexpr int COLS = BLOCK_N /16 ; 1894const int TILE_SIZE = TILE_N * sizeof (block_iq4_xs )+ TILE_N * 2 ; 1895 1896const block_q8_K * RESTRICT A = static_cast < const block_q8_K *> (_A ); 1897const char * RESTRICT B = static_cast < const char *> (_B ); 1898 1899// load the 256 bytes from A to 4 avx512 vectors 1900__m512i va [4 ]; 1901__m512 vc [COLS ]; 1902__m512 vd1 ; 1903 1904// packed_B: 1905const int offset_scales = (QK_K /2 )* TILE_N ; 1906const int offset_d0 = (QK_K /2 )* TILE_N + 8 * TILE_N ; 1907 1908// compensation 1909__m512i vcomp ; 1910 1911const __m256i m128s = _mm256_set1_epi16 (128 ); 1912const __m512i lowMask = _mm512_set1_epi8 (0xF ); 1913 1914const __m512i values128 = _mm512_set_epi8 ( 1915113 ,89 ,69 ,53 ,38 ,25 ,13 ,1 ,-10 ,-22 ,-35 ,-49 ,-65 ,-83 ,-104 ,-127 , 1916113 ,89 ,69 ,53 ,38 ,25 ,13 ,1 ,-10 ,-22 ,-35 ,-49 ,-65 ,-83 ,-104 ,-127 , 1917113 ,89 ,69 ,53 ,38 ,25 ,13 ,1 ,-10 ,-22 ,-35 ,-49 ,-65 ,-83 ,-104 ,-127 , 1918113 ,89 ,69 ,53 ,38 ,25 ,13 ,1 ,-10 ,-22 ,-35 ,-49 ,-65 ,-83 ,-104 ,-127 1919 ); 1920const __m512i off = _mm512_set1_epi8 (static_cast < char > (0x80 )); 1921const __m512i values256 = _mm512_add_epi8 (values128 ,off ); 1922 1923auto loadc = [& ](auto col ) { 1924vc [col ]= _mm512_setzero_ps (); 1925 }; 1926Unroll < COLS > {}(loadc ); 1927 1928auto compute = [& ](auto col ,auto i ) { 1929if constexpr (col == 0 ) { 1930// load a 1931va [0 ]= _mm512_loadu_si512 ((const __m512i * )(A [0 * KB + i ].qs + 0 )); 1932va [1 ]= _mm512_loadu_si512 ((const __m512i * )(A [0 * KB + i ].qs + 64 )); 1933va [2 ]= _mm512_loadu_si512 ((const __m512i * )(A [0 * KB + i ].qs + 128 )); 1934va [3 ]= _mm512_loadu_si512 ((const __m512i * )(A [0 * KB + i ].qs + 192 )); 1935 1936// compensation: 128 * A 1937const __m256i q8sums = _mm256_loadu_si256 ((const __m256i * )A [0 * KB + i ].bsums ); 1938vcomp = _mm512_castsi256_si512 (_mm256_madd_epi16 (q8sums ,m128s )); 1939vd1 = _mm512_set1_ps (A [0 * KB + i ].d ); 1940 } 1941 1942// accmulate the quants 1943__m512i acc = _mm512_setzero_si512 (); 1944const char * b_ptr = B + PACKED_INDEX (col ,i ,KB ,TILE_SIZE ); 1945const char * b_qs = b_ptr ; 1946int mask = 0 ; 1947for (int k_group = 0 ;k_group < QK_K /32 ;++ k_group ) { 1948int r = k_group >>1 ; 1949__m512i vmask = _mm512_set1_epi32 (k_group ); 1950__m512i vsum = _mm512_setzero_si512 (); 1951for (int k = 0 ;k < 8 ;k += 2 ) { 1952__m512i va0 = _mm512_permutexvar_epi32 (_mm512_set1_epi32 (mask ++ ),va [r ]); 1953__m512i va1 = _mm512_permutexvar_epi32 (_mm512_set1_epi32 (mask ++ ),va [r ]); 1954 1955__m512i bytes = _mm512_loadu_si512 (b_qs ); 1956__m512i vb0 = _mm512_shuffle_epi8 (values256 ,_mm512_and_si512 (bytes ,lowMask )); 1957__m512i vb1 = _mm512_shuffle_epi8 (values256 ,_mm512_and_si512 (_mm512_srli_epi16 (bytes ,4 ),lowMask )); 1958 1959vsum = _mm512_dpbusd_epi32 (vsum ,vb0 ,va0 ); 1960vsum = _mm512_dpbusd_epi32 (vsum ,vb1 ,va1 ); 1961b_qs += 64 ; 1962 } 1963// (B + 128) * A - 128 * A 1964vsum = _mm512_sub_epi32 (vsum ,_mm512_permutexvar_epi32 (vmask ,vcomp )); 1965 1966// vacc += scale * (q8 @ q4) 1967const __m512i vscale = _mm512_cvtepi8_epi32 (_mm_loadu_si128 ((const __m128i * )(b_ptr + offset_scales + k_group * TILE_N ))); 1968acc = _mm512_add_epi32 (acc ,_mm512_mullo_epi32 (vsum ,vscale )); 1969 } 1970const __m512 vd0 = _mm512_cvtph_ps (_mm256_loadu_si256 ((const __m256i * )(b_ptr + offset_d0 ))); 1971vc [col ]= _mm512_fmadd_ps (_mm512_cvtepi32_ps (acc ),_mm512_mul_ps (vd0 ,vd1 ),vc [col ]); 1972 }; 1973 1974for (int i = 0 ;i < KB ;++ i ) { 1975Unroll < COLS > {}(compute ,i ); 1976 } 1977 1978//store to C 1979auto storec = [& ](auto col ) { 1980_mm512_storeu_ps ((__m512i * )(C + 0 * ldc + col * 16 ),vc [col ]); 1981 }; 1982Unroll < COLS > {}(storec ); 1983 } 1984}; 1985 1986#define LAUNCH_TINYGEMM_KERNEL_VNNI (NB_SIZE ) \ 1987 tinygemm_kernel_vnni<vec_dot_type, type, float, 1, NB_SIZE, blck_size>::apply( \ 1988 KB, wdata_batch, \ 1989 (const char *)src0->data + src0_offset + PACKED_INDEX(nb * kTilesN, 0, KB, TILE_SIZE), \ 1990 (float *) dst->data + dst_offset + nb_start, ldc) 1991 1992template < typename TA ,typename TB ,typename TC ,int BLOCK_K , 1993typename std::enable_if < !is_type_qkk < TB > ::value ,int > ::type = 0 > 1994void tinygemm_kernel_amx (int M ,int N ,int KB ,const void * RESTRICT _A ,const void * RESTRICT _B ,TC * RESTRICT C ,int ldc ) { 1995using packed_B_t = packed_B_type < TB > ; 1996const int TILE_SIZE = get_tile_size < TB > (); 1997const bool need_unpack = do_unpack < TB > ::value ; 1998 1999GGML_ASSERT (M <=2 * TILE_M && N == 2 * TILE_N ); 2000const TA * RESTRICT A = static_cast < const TA *> (_A ); 2001const char * RESTRICT B = static_cast < const char *> (_B ); 2002 2003const int m0 = std::min (M ,TILE_M ); 2004const int m1 = std::max (M - TILE_M ,0 ); 2005const int lda = KB * sizeof (TA ); 2006//const int ldb = KB * sizeof(TB); 2007 2008 alignas(64 )static thread_localpacked_B_t Tile0 [TILE_N * TILE_K ]; 2009 alignas(64 )static thread_localpacked_B_t Tile1 [TILE_N * TILE_K ]; 2010 alignas(64 )static thread_localint8_t Tile23 [TILE_M * TILE_K ]; 2011 2012 alignas(64 )static thread_localint32_t TileC0 [TILE_M * TILE_N * 4 ]; 2013 alignas(64 )static thread_localint32_t TileC1 [TILE_M * TILE_N * 4 ]; 2014 2015// double buffering C to interleave avx512 and amx 2016int32_t * C_cur = TileC0 ; 2017int32_t * C_pre = TileC1 ; 2018 2019auto Tile4 = [& ](int32_t * base ) {return base ; }; 2020auto Tile5 = [& ](int32_t * base ) {return base + TILE_M * TILE_N ; }; 2021auto Tile6 = [& ](int32_t * base ) {return base + 2 * TILE_M * TILE_N ; }; 2022auto Tile7 = [& ](int32_t * base ) {return base + 3 * TILE_M * TILE_N ; }; 2023 2024if (M == 2 * TILE_M ) { 2025// i = 0 2026const char * B_blk0 = B + PACKED_INDEX (0 ,0 ,KB ,TILE_SIZE ); 2027const char * B_blk1 = B + PACKED_INDEX (1 ,0 ,KB ,TILE_SIZE ); 2028if (need_unpack ) { 2029unpack_B < TB > (Tile0 ,B_blk0 ); 2030_tile_loadd (TMM0 ,Tile0 ,TILE_N * VNNI_BLK ); 2031 }else { 2032_tile_loadd (TMM0 ,B_blk0 ,TILE_N * VNNI_BLK ); 2033 } 2034 2035_tile_zero (TMM4 ); 2036_tile_loadd (TMM2 ,A [0 ].qs ,lda ); 2037_tile_dpbssd (TMM4 ,TMM2 ,TMM0 ); 2038_tile_stored (TMM4 ,Tile4 (C_pre ),TILE_N * sizeof (int32_t )); 2039 2040_tile_zero (TMM5 ); 2041_tile_loadd (TMM3 ,A [TILE_M * KB + 0 ].qs ,lda ); 2042_tile_dpbssd (TMM5 ,TMM3 ,TMM0 ); 2043_tile_stored (TMM5 ,Tile5 (C_pre ),TILE_N * sizeof (int32_t )); 2044 2045if (need_unpack ) { 2046unpack_B < TB > (Tile1 ,B_blk1 ); 2047_tile_loadd (TMM1 ,Tile1 ,TILE_N * VNNI_BLK ); 2048 }else { 2049_tile_loadd (TMM1 ,B_blk1 ,TILE_N * VNNI_BLK ); 2050 } 2051 2052_tile_zero (TMM6 ); 2053_tile_dpbssd (TMM6 ,TMM2 ,TMM1 ); 2054_tile_stored (TMM6 ,Tile6 (C_pre ),TILE_N * sizeof (int32_t )); 2055 2056_tile_zero (TMM7 ); 2057_tile_dpbssd (TMM7 ,TMM3 ,TMM1 ); 2058_tile_stored (TMM7 ,Tile7 (C_pre ),TILE_N * sizeof (int32_t )); 2059 2060for (int i = 1 ;i < KB ;++ i ) { 2061// index of previous iter 2062const int ii = i - 1 ; 2063const char * B_blk0 = B + PACKED_INDEX (0 ,i ,KB ,TILE_SIZE ); 2064const char * B_blk1 = B + PACKED_INDEX (1 ,i ,KB ,TILE_SIZE ); 2065GGML_DISPATCH_BOOL (ii > 0 ,is_acc , [& ] { 2066if (need_unpack ) { 2067unpack_B < TB > (Tile0 ,B_blk0 ); 2068_tile_loadd (TMM0 ,Tile0 ,TILE_N * VNNI_BLK ); 2069 }else { 2070_tile_loadd (TMM0 ,B_blk0 ,TILE_N * VNNI_BLK ); 2071 } 2072_tile_zero (TMM4 ); 2073_tile_loadd (TMM2 ,A [i ].qs ,lda ); 2074acc_C < TA ,TB ,is_acc > ::apply (C ,ldc ,Tile4 (C_pre ),& A [ii ],KB ,B + PACKED_INDEX (0 ,ii ,KB ,TILE_SIZE ),TILE_M ); 2075 2076_tile_dpbssd (TMM4 ,TMM2 ,TMM0 ); 2077_tile_stored (TMM4 ,Tile4 (C_cur ),TILE_N * sizeof (int32_t )); 2078 2079_tile_zero (TMM5 ); 2080_tile_loadd (TMM3 ,A [TILE_M * KB + i ].qs ,lda ); 2081acc_C < TA ,TB ,is_acc > ::apply (C + TILE_M * ldc ,ldc ,Tile5 (C_pre ),& A [TILE_M * KB + ii ],KB ,B + PACKED_INDEX (0 ,ii ,KB ,TILE_SIZE ),TILE_M ); 2082 2083_tile_dpbssd (TMM5 ,TMM3 ,TMM0 ); 2084_tile_stored (TMM5 ,Tile5 (C_cur ),TILE_N * sizeof (int32_t )); 2085 2086if (need_unpack ) { 2087unpack_B < TB > (Tile1 ,B_blk1 ); 2088_tile_loadd (TMM1 ,Tile1 ,TILE_N * VNNI_BLK ); 2089 }else { 2090_tile_loadd (TMM1 ,B_blk1 ,TILE_N * VNNI_BLK ); 2091 } 2092_tile_zero (TMM6 ); 2093acc_C < TA ,TB ,is_acc > ::apply (C + TILE_N ,ldc ,Tile6 (C_pre ),& A [ii ],KB ,B + PACKED_INDEX (1 ,ii ,KB ,TILE_SIZE ),TILE_M ); 2094 2095_tile_dpbssd (TMM6 ,TMM2 ,TMM1 ); 2096_tile_stored (TMM6 ,Tile6 (C_cur ),TILE_N * sizeof (int32_t )); 2097 2098_tile_zero (TMM7 ); 2099acc_C < TA ,TB ,is_acc > ::apply (C + TILE_M * ldc + TILE_N ,ldc ,Tile7 (C_pre ),& A [TILE_M * KB + ii ],KB ,B + PACKED_INDEX (1 ,ii ,KB ,TILE_SIZE ),TILE_M ); 2100 2101_tile_dpbssd (TMM7 ,TMM3 ,TMM1 ); 2102_tile_stored (TMM7 ,Tile7 (C_cur ),TILE_N * sizeof (int32_t )); 2103 2104 std::swap (C_cur ,C_pre ); 2105 }); 2106 } 2107// final accumulation 2108 { 2109int ii = KB - 1 ; 2110acc_C < TA ,TB , true> ::apply (C ,ldc ,Tile4 (C_pre ),& A [ii ],KB ,B + PACKED_INDEX (0 ,ii ,KB ,TILE_SIZE ),TILE_M ); 2111acc_C < TA ,TB , true> ::apply (C + TILE_M * ldc ,ldc ,Tile5 (C_pre ),& A [TILE_M * KB + ii ],KB ,B + PACKED_INDEX (0 ,ii ,KB ,TILE_SIZE ),TILE_M ); 2112acc_C < TA ,TB , true> ::apply (C + TILE_N ,ldc ,Tile6 (C_pre ),& A [ii ],KB ,B + PACKED_INDEX (1 ,ii ,KB ,TILE_SIZE ),TILE_M ); 2113acc_C < TA ,TB , true> ::apply (C + TILE_M * ldc + TILE_N ,ldc ,Tile7 (C_pre ),& A [TILE_M * KB + ii ],KB ,B + PACKED_INDEX (1 ,ii ,KB ,TILE_SIZE ),TILE_M ); 2114 } 2115 }else { 2116for (int i = 0 ;i < KB ;++ i ) { 2117_tile_zero (TMM4 ); 2118_tile_zero (TMM6 ); 2119if (m1 != 0 ) { 2120_tile_zero (TMM5 ); 2121_tile_zero (TMM7 ); 2122 } 2123 2124const char * B_blk0 = B + PACKED_INDEX (0 ,i ,KB ,TILE_SIZE ); 2125const char * B_blk1 = B + PACKED_INDEX (1 ,i ,KB ,TILE_SIZE ); 2126if (need_unpack ) { 2127unpack_B < TB > (Tile0 ,B_blk0 ); 2128_tile_loadd (TMM0 ,Tile0 ,TILE_N * VNNI_BLK ); 2129 }else { 2130_tile_loadd (TMM0 ,B_blk0 ,TILE_N * VNNI_BLK ); 2131 } 2132 2133if (need_unpack ) { 2134unpack_B < TB > (Tile1 ,B_blk1 ); 2135_tile_loadd (TMM1 ,Tile1 ,TILE_N * VNNI_BLK ); 2136 }else { 2137_tile_loadd (TMM1 ,B_blk1 ,TILE_N * VNNI_BLK ); 2138 } 2139 2140if (m0 == TILE_M ) { 2141_tile_loadd (TMM2 ,A [i ].qs ,lda ); 2142 }else { 2143unpack_A (Tile23 ,& A [i ],KB ,m0 ); 2144_tile_loadd (TMM2 ,Tile23 ,TILE_K ); 2145 } 2146 2147_tile_dpbssd (TMM4 ,TMM2 ,TMM0 ); 2148_tile_dpbssd (TMM6 ,TMM2 ,TMM1 ); 2149 2150_tile_stored (TMM4 ,Tile4 (C_cur ),TILE_N * sizeof (int32_t )); 2151_tile_stored (TMM6 ,Tile6 (C_cur ),TILE_N * sizeof (int32_t )); 2152 2153GGML_DISPATCH_BOOL (i > 0 ,is_acc , [& ] { 2154acc_C < TA ,TB ,is_acc > ::apply (C ,ldc ,Tile4 (C_cur ),& A [i ],KB ,B + PACKED_INDEX (0 ,i ,KB ,TILE_SIZE ),m0 ); 2155acc_C < TA ,TB ,is_acc > ::apply (C + TILE_N ,ldc ,Tile6 (C_cur ),& A [i ],KB ,B + PACKED_INDEX (1 ,i ,KB ,TILE_SIZE ),m0 ); 2156 }); 2157 2158if (m1 != 0 ) { 2159unpack_A (Tile23 ,& A [TILE_M * KB + i ],KB ,m1 ); 2160_tile_loadd (TMM3 ,Tile23 ,TILE_K ); 2161 2162_tile_dpbssd (TMM5 ,TMM3 ,TMM0 ); 2163_tile_dpbssd (TMM7 ,TMM3 ,TMM1 ); 2164_tile_stored (TMM5 ,Tile5 (C_cur ),TILE_N * sizeof (int32_t )); 2165_tile_stored (TMM7 ,Tile7 (C_cur ),TILE_N * sizeof (int32_t )); 2166GGML_DISPATCH_BOOL (i > 0 ,is_acc , [& ] { 2167acc_C < TA ,TB ,is_acc > ::apply (C + TILE_M * ldc ,ldc ,Tile5 (C_cur ),& A [TILE_M * KB + i ],KB ,B + PACKED_INDEX (0 ,i ,KB ,TILE_SIZE ),m1 ); 2168acc_C < TA ,TB ,is_acc > ::apply (C + TILE_M * ldc + TILE_N ,ldc ,Tile7 (C_cur ),& A [TILE_M * KB + i ],KB ,B + PACKED_INDEX (1 ,i ,KB ,TILE_SIZE ),m1 ); 2169 }); 2170 } 2171 } 2172 } 2173return ; 2174} 2175 2176template < typename TA ,typename TB ,typename TC ,int BLOCK_K , 2177typename std::enable_if < is_type_qkk < TB > ::value ,int > ::type = 0 > 2178void tinygemm_kernel_amx (int M ,int N ,int KB ,const void * RESTRICT _A ,const void * RESTRICT _B ,float * RESTRICT C ,int ldc ) { 2179 static_assert(std::is_same < TA ,block_q8_K > ::value ); 2180const int TILE_SIZE = get_tile_size < TB > (); 2181 2182GGML_ASSERT (M <=2 * TILE_M && N == 2 * TILE_N ); 2183const TA * RESTRICT A = static_cast < const TA *> (_A ); 2184const char * RESTRICT B = static_cast < const char *> (_B ); 2185 2186const int m0 = std::min (M ,TILE_M ); 2187const int m1 = std::max (M - TILE_M ,0 ); 2188//const int lda = KB * sizeof(TA); 2189 2190 alignas(64 )static thread_localint8_t Tile0 [TILE_N * TILE_K ]; 2191 alignas(64 )static thread_localint8_t Tile1 [TILE_N * TILE_K ]; 2192 alignas(64 )static thread_localint8_t Tile23 [TILE_M * TILE_K ]; 2193 2194// mat mul result for each group 2195 alignas(64 )static thread_localint32_t Tile4 [TILE_M * TILE_N ]; 2196 alignas(64 )static thread_localint32_t Tile5 [TILE_M * TILE_N ]; 2197 alignas(64 )static thread_localint32_t Tile6 [TILE_M * TILE_N ]; 2198 alignas(64 )static thread_localint32_t Tile7 [TILE_M * TILE_N ]; 2199 2200// sum of each QK_K block, contains 8 groups, int32 2201 alignas(64 )static thread_localint32_t Sumi4 [TILE_M * TILE_N ]; 2202 alignas(64 )static thread_localint32_t Sumi5 [TILE_M * TILE_N ]; 2203 alignas(64 )static thread_localint32_t Sumi6 [TILE_M * TILE_N ]; 2204 alignas(64 )static thread_localint32_t Sumi7 [TILE_M * TILE_N ]; 2205 2206const int k_group_size = std::is_same < TB ,block_q6_K > ::value ?16 :32 ; 2207for (int i = 0 ;i < KB ;++ i ) { 2208// step 1: accumulate the quants across 8 groups, each group with 32 2209for (int k = 0 ;k < QK_K /k_group_size ;++ k ) { 2210GGML_DISPATCH_BOOL (k > 0 ,is_acc , [& ] { 2211_tile_zero (TMM4 ); 2212_tile_zero (TMM6 ); 2213 2214unpack_B < TB > (Tile0 ,B + PACKED_INDEX (0 ,i ,KB ,TILE_SIZE ),k ); 2215_tile_loadd (TMM0 ,Tile0 ,TILE_N * VNNI_BLK ); 2216 2217unpack_B < TB > (Tile1 ,B + PACKED_INDEX (1 ,i ,KB ,TILE_SIZE ),k ); 2218_tile_loadd (TMM1 ,Tile1 ,TILE_N * VNNI_BLK ); 2219 2220unpack_A < TB > (Tile23 ,& A [i ],KB ,k ,m0 ); 2221_tile_loadd (TMM2 ,Tile23 ,TILE_K ); 2222 2223_tile_dpbssd (TMM4 ,TMM2 ,TMM0 ); 2224_tile_dpbssd (TMM6 ,TMM2 ,TMM1 ); 2225 2226_tile_stored (TMM4 ,Tile4 ,TILE_N * sizeof (int32_t )); 2227_tile_stored (TMM6 ,Tile6 ,TILE_N * sizeof (int32_t )); 2228 2229scale_C < TB ,is_acc > (Tile4 ,Sumi4 ,B + PACKED_INDEX (0 ,i ,KB ,TILE_SIZE ),k ,m0 ); 2230scale_C < TB ,is_acc > (Tile6 ,Sumi6 ,B + PACKED_INDEX (1 ,i ,KB ,TILE_SIZE ),k ,m0 ); 2231 2232if (m1 != 0 ) { 2233_tile_zero (TMM5 ); 2234_tile_zero (TMM7 ); 2235 2236unpack_A < TB > (Tile23 ,& A [TILE_M * KB + i ],KB ,k ,m1 ); 2237_tile_loadd (TMM3 ,Tile23 ,TILE_K ); 2238 2239_tile_dpbssd (TMM5 ,TMM3 ,TMM0 ); 2240_tile_dpbssd (TMM7 ,TMM3 ,TMM1 ); 2241 2242_tile_stored (TMM5 ,Tile5 ,TILE_N * sizeof (int32_t )); 2243_tile_stored (TMM7 ,Tile7 ,TILE_N * sizeof (int32_t )); 2244 2245scale_C < TB ,is_acc > (Tile5 ,Sumi5 ,B + PACKED_INDEX (0 ,i ,KB ,TILE_SIZE ),k ,m1 ); 2246scale_C < TB ,is_acc > (Tile7 ,Sumi7 ,B + PACKED_INDEX (1 ,i ,KB ,TILE_SIZE ),k ,m1 ); 2247 } 2248 }); 2249 } 2250 2251// step 2: accmulate the mins 2252GGML_DISPATCH_BOOL (i > 0 ,is_acc , [& ] { 2253acc_C < TA ,TB ,is_acc > ::apply (C ,ldc ,Sumi4 ,& A [i ],KB ,B + PACKED_INDEX (0 ,i ,KB ,TILE_SIZE ),m0 ); 2254acc_C < TA ,TB ,is_acc > ::apply (C + TILE_N ,ldc ,Sumi6 ,& A [i ],KB ,B + PACKED_INDEX (1 ,i ,KB ,TILE_SIZE ),m0 ); 2255if (m1 != 0 ) { 2256acc_C < TA ,TB ,is_acc > ::apply (C + TILE_M * ldc ,ldc ,Sumi5 ,& A [TILE_M * KB + i ],KB ,B + PACKED_INDEX (0 ,i ,KB ,TILE_SIZE ),m1 ); 2257acc_C < TA ,TB ,is_acc > ::apply (C + TILE_M * ldc + TILE_N ,ldc ,Sumi7 ,& A [TILE_M * KB + i ],KB ,B + PACKED_INDEX (1 ,i ,KB ,TILE_SIZE ),m1 ); 2258 } 2259 }); 2260 } 2261return ; 2262} 2263 2264}// anonymous namespace 2265 2266// get the packed tensor size for quantized weights 2267size_t ggml_backend_amx_get_alloc_size (const struct ggml_tensor * tensor ) { 2268const enum ggml_type TYPE = tensor -> type ; 2269 2270const int K = tensor -> ne [0 ];// ne0: in_features 2271const int N = tensor -> ne [1 ];// ne1: out_features 2272 2273auto get_tensor_size = [& ] { 2274size_t row_size_B {0 }; 2275GGML_DISPATCH_QTYPES (TYPE , [& ] { 2276row_size_B = get_row_size < type ,blck_size > (K ); 2277 }); 2278return N * row_size_B ; 2279 }; 2280 2281if (qtype_has_amx_kernels (TYPE )) { 2282return get_tensor_size (); 2283 }else { 2284// for f16, bf16 we don't do packing 2285return ggml_nbytes (tensor ); 2286 } 2287} 2288 2289// pack weight to vnni format 2290void ggml_backend_amx_convert_weight (struct ggml_tensor * tensor ,const void * data ,size_t offset ,size_t size ) { 2291GGML_ASSERT (offset == 0 && size == ggml_nbytes (tensor ));// only full tensor conversion is supported for now 2292 2293const enum ggml_type TYPE = tensor -> type ; 2294 2295const int K = tensor -> ne [0 ];// ne0: in_features 2296const int N = tensor -> ne [1 ];// ne1: out_features 2297 2298GGML_DISPATCH_QTYPES (TYPE , [& ] { 2299convert_B_packed_format < type ,blck_size > ((void * )((char * )tensor -> data + offset ), (const type * )data ,N ,K ); 2300 }); 2301} 2302 2303// ne2 is passed explicitly to help compiler optimize repeated calls 2304inline int64_t ggml_batch_offset (const ggml_tensor * t ,int64_t batch_idx ,int64_t ne2 ) { 2305const int64_t i2 = batch_idx %ne2 ; 2306const int64_t i3 = batch_idx /ne2 ; 2307return i3 * t -> nb [3 ]+ i2 * t -> nb [2 ]; 2308} 2309 2310size_t ggml_backend_amx_desired_wsize (const struct ggml_tensor * dst ) { 2311struct ggml_tensor * src0 = dst -> src [0 ]; 2312 2313const enum ggml_type TYPE = src0 -> type ; 2314 2315const bool is_floating_type = TYPE == GGML_TYPE_F16 ; 2316if (is_floating_type ) { 2317return 0 ; 2318 } 2319 2320const int M = dst -> ne [1 ]; 2321const int K = src0 -> ne [0 ]; 2322const int64_t n_batch = dst -> ne [2 ]* dst -> ne [3 ]; 2323 2324size_t desired_wsize = 0 ; 2325 2326GGML_DISPATCH_QTYPES (TYPE , [& ] { 2327const size_t row_size_A = K /blck_size * sizeof (vec_dot_type ); 2328desired_wsize = n_batch * M * row_size_A ; 2329 }); 2330 2331return desired_wsize ; 2332} 2333 2334// NB: mixed dtype gemm with Advanced Matrix Extensions (Intel AMX) 2335// 2336// src0: weight in shape of {N, K}, quantized 2337// src1: input in shape of {M, K}, float32 2338// dst: output in shape of {M, N}, float32 2339// 2340// the function performs: dst = src1 @ src0.T for each batch 2341// 2342void ggml_backend_amx_mul_mat (const ggml_compute_params * params ,struct ggml_tensor * dst ) { 2343struct ggml_tensor * src0 = dst -> src [0 ]; 2344struct ggml_tensor * src1 = dst -> src [1 ]; 2345 2346const enum ggml_type TYPE = src0 -> type ; 2347 2348// f16 only has avx512 kernels for now, 2349// amx kernels will be added once 6th gen xeon is released. 2350const bool is_floating_type = TYPE == GGML_TYPE_F16 ; 2351 2352const int M = dst -> ne [1 ]; 2353const int N = dst -> ne [0 ]; 2354const int K = src0 -> ne [0 ]; 2355const int ldc = dst -> nb [1 ] /dst -> nb [0 ]; 2356 2357const int64_t ne2 = dst -> ne [2 ]; 2358const int64_t n_batch = ne2 * dst -> ne [3 ]; 2359 2360if (is_floating_type ) { 2361constexpr int BLOCK_M = 4 ; 2362constexpr int BLOCK_N = 6 ; 2363const int MB = div_up (M ,BLOCK_M ); 2364const int NB = div_up (N ,BLOCK_N ); 2365 2366parallel_for_ggml (params ,n_batch * MB * NB , [& ](int begin ,int end ) { 2367GGML_DISPATCH_FLOATING_TYPES (TYPE , [& ] { 2368for (int i = begin ;i < end ;++ i ) { 2369int batch_idx = i / (MB * NB ); 2370int remaining = i % (MB * NB ); 2371int mb = remaining /NB ; 2372int nb = remaining %NB ; 2373 2374int64_t src0_offset = ggml_batch_offset (src0 ,batch_idx ,ne2 ); 2375int64_t src1_offset = ggml_batch_offset (src1 ,batch_idx ,ne2 ); 2376int64_t dst_offset = ggml_batch_offset (dst ,batch_idx ,ne2 ); 2377 2378int mb_start = mb * BLOCK_M ; 2379int mb_size = std::min (BLOCK_M ,M - mb_start ); 2380int nb_start = nb * BLOCK_N ; 2381int nb_size = std::min (BLOCK_N ,N - nb_start ); 2382 2383switch (mb_size <<4 |nb_size ) { 2384case 0x12 :LAUNCH_TINYGEMM_KERNEL_AVX (1 ,2 );break ; 2385case 0x14 :LAUNCH_TINYGEMM_KERNEL_AVX (1 ,4 );break ; 2386case 0x16 :LAUNCH_TINYGEMM_KERNEL_AVX (1 ,6 );break ; 2387case 0x22 :LAUNCH_TINYGEMM_KERNEL_AVX (2 ,2 );break ; 2388case 0x24 :LAUNCH_TINYGEMM_KERNEL_AVX (2 ,4 );break ; 2389case 0x26 :LAUNCH_TINYGEMM_KERNEL_AVX (2 ,6 );break ; 2390case 0x32 :LAUNCH_TINYGEMM_KERNEL_AVX (3 ,2 );break ; 2391case 0x34 :LAUNCH_TINYGEMM_KERNEL_AVX (3 ,4 );break ; 2392case 0x36 :LAUNCH_TINYGEMM_KERNEL_AVX (3 ,6 );break ; 2393case 0x42 :LAUNCH_TINYGEMM_KERNEL_AVX (4 ,2 );break ; 2394case 0x44 :LAUNCH_TINYGEMM_KERNEL_AVX (4 ,4 );break ; 2395case 0x46 :LAUNCH_TINYGEMM_KERNEL_AVX (4 ,6 );break ; 2396default :fprintf (stderr ,"Unexpected block size!\n" ); 2397 } 2398 } 2399 }); 2400 }); 2401return ; 2402 } 2403 2404// pointer to work space, used convert A from float to quantized type 2405void * wdata = params -> wdata ; 2406 2407//TODO: performance improvement: merge quant A 2408// if (params->ith == 0) { 2409GGML_DISPATCH_QTYPES (TYPE , [& ] { 2410const size_t row_size_A = K /blck_size * sizeof (vec_dot_type ); 2411const size_t desired_wsize = n_batch * M * row_size_A ; 2412if (params -> wsize < desired_wsize ) { 2413GGML_ABORT ("insufficient work space size" ); 2414 } 2415 2416// Q4_0, Q4_1, Q8_0 handles 1 TILE_K per blck_size 2417// Q4_K, Q5_K, Q6_K, IQ4_XS handles 8 TILE_K per blck_size 2418GGML_ASSERT (TILE_K == blck_size || TILE_K * 8 == blck_size ); 2419 2420parallel_for_ggml (params ,n_batch * M , [& ](int begin ,int end ) { 2421for (int idx = begin ;idx < end ;++ idx ) { 2422int batch_idx = idx /M ; 2423int m = idx %M ; 2424int64_t src1_offset = ggml_batch_offset (src1 ,batch_idx ,ne2 ); 2425const float * A_data = (const float * )((const char * )src1 -> data + src1_offset ); 2426char * wdata_batch = (char * )wdata + batch_idx * M * row_size_A ; 2427from_float < vec_dot_type > (A_data + m * K ,wdata_batch + m * row_size_A ,K ); 2428 } 2429 }); 2430 }); 2431// } 2432 2433ggml_barrier (params -> threadpool ); 2434 2435if (M == 1 ) { 2436// MB = 1 and handle 8 tiles in each block 2437constexpr int kTilesN = 4 ; 2438constexpr int BLOCK_N = TILE_N * kTilesN ; 2439const int NB = div_up (N ,BLOCK_N ); 2440 2441parallel_for_ggml (params ,n_batch * NB , [& ](int begin ,int end ) { 2442GGML_DISPATCH_QTYPES (TYPE , [& ] { 2443const int KB = K /blck_size ; 2444const int TILE_SIZE = get_tile_size < type > (); 2445const int row_size_A = KB * sizeof (vec_dot_type ); 2446for (int i = begin ;i < end ;++ i ) { 2447int batch_idx = i /NB ; 2448int nb = i %NB ; 2449 2450int64_t src0_offset = ggml_batch_offset (src0 ,batch_idx ,ne2 ); 2451int64_t dst_offset = ggml_batch_offset (dst ,batch_idx ,ne2 ); 2452const char * wdata_batch = (const char * )wdata + batch_idx * row_size_A ; 2453 2454int nb_start = nb * BLOCK_N ; 2455int nb_size = std::min (BLOCK_N ,N - nb_start );// 32, 64, 96 2456 2457switch (nb_size ) { 2458//case 160: LAUNCH_TINYGEMM_KERNEL_VNNI(160); break; 2459case 128 :LAUNCH_TINYGEMM_KERNEL_VNNI (128 );break ; 2460case 96 :LAUNCH_TINYGEMM_KERNEL_VNNI (96 );break ; 2461case 64 :LAUNCH_TINYGEMM_KERNEL_VNNI (64 );break ; 2462case 32 :LAUNCH_TINYGEMM_KERNEL_VNNI (32 );break ; 2463default :fprintf (stderr ,"Unexpected n block size!\n" ); 2464 } 2465 } 2466 }); 2467 }); 2468return ; 2469 } 2470 2471// handle 4 tiles at a tile 2472constexpr int BLOCK_M = TILE_M * 2 ; 2473constexpr int BLOCK_N = TILE_N * 2 ; 2474const int MB = div_up (M ,BLOCK_M ); 2475const int NB = div_up (N ,BLOCK_N ); 2476 2477parallel_for_ggml (params ,n_batch * MB * NB , [& ](int begin ,int end ) { 2478// init tile config for each thread 2479ggml_tile_config_init (); 2480 2481GGML_DISPATCH_QTYPES (TYPE , [& ] { 2482const int KB = K /blck_size ; 2483const int TILE_SIZE = get_tile_size < type > (); 2484const int row_size_A = KB * sizeof (vec_dot_type ); 2485 2486for (int i = begin ;i < end ;++ i ) { 2487int batch_idx = i / (MB * NB ); 2488int remaining = i % (MB * NB ); 2489int mb = remaining /NB ; 2490int nb = remaining %NB ; 2491 2492int64_t src0_offset = ggml_batch_offset (src0 ,batch_idx ,ne2 ); 2493int64_t dst_offset = ggml_batch_offset (dst ,batch_idx ,ne2 ); 2494const char * wdata_batch = (const char * )wdata + batch_idx * M * row_size_A ; 2495 2496int mb_start = mb * BLOCK_M ; 2497int mb_size = std::min (BLOCK_M ,M - mb_start ); 2498int nb_start = nb * BLOCK_N ; 2499int nb_size = BLOCK_N ; 2500 2501tinygemm_kernel_amx < vec_dot_type ,type ,float ,blck_size > ( 2502mb_size ,nb_size ,KB , 2503wdata_batch + mb_start * row_size_A , 2504 (const char * )src0 -> data + src0_offset + PACKED_INDEX (nb * 2 ,0 ,KB ,TILE_SIZE ), 2505 (float * )dst -> data + dst_offset + mb_start * N + nb_start ,ldc ); 2506 } 2507 }); 2508 }); 2509} 2510 2511#endif // if defined(__AMX_INT8__) && defined(__AVX512VNNI__)