1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! x86_64 AVX2 kernels for the interleaved repack tier, one file per
//! kind family. The dispatchers in `super::*` call these as
//! `avx2::<fn>`, which the re-exports below keep true after the split.
//!
//! # The lane mapping, once
//!
//! Every packed layout here stores one row's `blocklen`-element run
//! contiguously, `ncols_interleaved` rows in a row, so at `blocklen = 8`
//! a 32-byte load holds four consecutive rows. That single fact decides
//! the whole register plan, and it is llama.cpp's plan too
//! (`ggml/src/ggml-cpu/arch/x86/repack.cpp`):
//!
//! 1. [`bcast8`] puts one activation's 8-byte run opposite all four.
//! 2. `_mm256_maddubs_epi16` folds each row's run into four `i16` pair
//! sums: lanes `4t..4t+3` belong to row `t`. The weight side is the
//! *unsigned* operand, which is why the K-quant kernels below dot the
//! raw `0..2^b-1` quant and subtract the bias term separately rather
//! than sign-extending first.
//! 3. `_mm256_madd_epi16` against the row's scale folds those into two
//! `i32` per row (lanes `2t`, `2t+1`) — llama.cpp does the same fold
//! at `repack.cpp:2757`, `iacc_mat_00_0 = _mm512_madd_epi16(iacc_mat_00_0,
//! scale_014589CD_0)`.
//! 4. [`rows4_from_pairs`] / [`rows8_from_pairs`] collapse those pairs
//! into one `i32` per row, in row order.
//!
//! The `i16` stage is the one that can overflow, so each kernel states
//! its bound where it accumulates.
// Every range loop in this module is a coordinate — `a` is the quad row,
// `half` the 4-row half of a 32-byte load, `k` the 8-element run — and
// each body indexes two or three arrays plus a raw pointer with it.
// Rewriting those as zipped iterators moves the coordinate out of the
// code and into the zip order, which is where a lane bug would hide.
// `lib.rs` already carries this allow at one such site; the boundary
// here is the kernels, and it is deliberate rather than inherited.
use f16;
use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
/// Broadcast the 8 bytes at `p` into all four 64-bit lanes: one
/// activation run opposite four interleaved weight rows.
///
/// # Safety
/// `p` must be readable for 8 bytes.
unsafe
/// Read `n` f16 at `p` into an f32 array, lane `j` = row `j`.
///
/// Scalar on purpose: F16C is a separate CPUID bit from AVX2 and this
/// runs once per super-block, not once per dot.
///
/// # Safety
/// `p` must be readable for `2 * n` bytes and `n <= 8`.
unsafe
/// Eight f16 at `p` as an `f32x8`, lane `j` = row `j`.
///
/// # Safety
/// `p` must be readable for 16 bytes.
unsafe
/// Four f16 at `p` as an `f32x4`, lane `j` = row `j`.
///
/// # Safety
/// `p` must be readable for 8 bytes.
unsafe
/// Collapse an `i32x8` holding two lanes per row for four rows
/// (`2t`, `2t+1` are row `t`) into one `i32` per row, in row order.
unsafe
/// Collapse two `i32x8` pair accumulators — `lo` for rows 0..4, `hi` for
/// rows 4..8 — into one `i32x8`, lane `j` = row `j`.
unsafe
/// Widen eight per-row `u8` scales to the `i16` lane layout
/// `_mm256_maddubs_epi16` leaves behind: four copies of row `base + t` at
/// lanes `4t..4t+3`, for `t` in `0..4`.
unsafe
/// [`scale_lanes_u8`] for the signed per-16 scales Q6_K carries.
///
/// # Safety
/// `p` must be readable for `base + 4` bytes.
unsafe