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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
//! x86 / `x86_64` SIMD kernels.
//!
//! One submodule per field family, plus `bytes` for the field-independent
//! byte kernels. This module-named file
//! keeps only what the families share:
//! the non-temporal store threshold and its alignment helpers, and the two
//! width-parameterized store primitives every `mul_into` kernel calls.
//!
//! Selected entries use [`archmage`] capability tokens and reference-based
//! intrinsics. Unsafe remains only where the borrow checker cannot express
//! offset-addressed rows, uninitialized scratch, or non-temporal stores;
//! each residue item carries a per-item `#[allow(unsafe_code)]` and local
//! SINCE–THUS proofs.
//!
//! Two multiply strategies:
//!
//! - **GFNI.** `GF2P8MULB` multiplies bytes in `GF(2)[x] / 0x11B` across
//! 32 lanes; other byte polynomials use affine coefficient maps or conjugate
//! elementwise multiplication through their isomorphism onto that field.
//! - **Nibble shuffle.** Without GFNI, `PSHUFB` performs a 16-entry lookup
//! per lane, so `c * x` becomes two shuffles and an XOR against the
//! precomputed [`ScaleTable`](crate::kernel::tables::ScaleTable).
pub use ;
use *;
use *;
///
/// `mul_into` writes a destination it never reads, so an ordinary store pays
/// a read-for-ownership fetch of every line it is about to overwrite
/// completely. `vmovntdq` skips that fetch and the allocation, at the price
/// of evicting the destination from cache.
///
/// Non-temporal stores evict the written destination from cache, so a
/// subsequent read pays to fetch it again. `mul_add` and `mul_assign` read
/// their destination and keep ordinary stores.
pub const NT_STORE_MIN: usize = 2 << 20;
/// Smallest destination a fused overwrite prefetches for.
///
/// Below this the destination and its source both sit in L1 and the
/// prefetches are pure overhead; above it the ordinary stores are waiting on
/// the read-for-ownership fetch of a line the loop is about to replace
/// whole.
pub const PREFETCH_MIN: usize = 24 << 10;
/// Bytes ahead of the cursor at which a fused overwrite pulls its
/// destination in.
pub const PREFETCH_AHEAD: usize = 512;
/// Whether a fused overwrite of `dst` should prefetch its destination.
///
/// Non-temporal stores fetch nothing, so a body storing them has nothing to
/// hide and prefetching only competes for bandwidth.
pub
/// Pull one 64-byte line into cache.
///
/// The hint is `T0` rather than the write-intent form, which measured no
/// better than the unprefetched loop even where the instruction is
/// available. A body must name every line it is about to store:
/// prefetching every second one measures worse than prefetching none.
///
/// No unsafe block: a prefetch names a cache line rather than accessing
/// memory, so the intrinsic is safe inside a feature-enabled context.
pub >;
}
/// Pull both lines of the 128-byte tile starting at `target`.
pub
/// Whether a fused overwrite of `len` bytes should take the streaming
/// path: the same threshold [`nt_split`] applies, without committing to a
/// peel. Lets a wider entry defer to the AVX2 streaming body past the point
/// where eviction pays.
pub
/// Shortest 32-byte-lane destination that peels a 16-byte half-lane head.
///
/// A 256-bit store starting 16 bytes into a cache line splits it, and a
/// body of split stores increases line traffic; one narrow head puts every
/// remaining lane on a boundary.
pub const HALF_LANE_PEEL_MIN: usize = 512;
/// Head bytes to store normally so that a non-temporal body starts on a
/// 32-byte boundary, or `None` when this destination should stay temporal.
///
/// `None` covers a destination too small to repay the eviction, and the case
/// where the alignment peel would not be a whole number of `elem_bytes`
/// elements — a kernel may only split a buffer on an element boundary.
pub
/// Bytes of lead-in that put a row group's vector accesses on a 32-byte
/// boundary, or `0` when the row is too short to repay it.
///
/// A 32-byte `vmovdqu` at an odd multiple of 32 straddles two cache lines,
/// and a multi-row body issues one load and one store per row per vector: a
/// misaligned destination therefore doubles the line traffic of every access
/// but the shared source load. Peeling at most 31 bytes per row group buys
/// the aligned body for the rest of the pass.
/// Rows of a group sit `row_len` apart, so aligning one aligns them all
/// whenever `row_len` is a multiple of 32 — the usual case. The source is
/// left where it falls: it is one access against many, and only the
/// destination is ours to choose.
///
/// The peel is rounded up to a whole number of `elem_bytes` elements, because
/// a kernel may only split a buffer on an element boundary. For an odd
/// destination pointer in a 2-byte field that is unreachable, and the peel is
/// skipped.
pub
/// Store 32 bytes, non-temporally when `NT`.
///
/// # Safety
/// `ptr` must be writable for 32 bytes, and when `NT` it must additionally be
/// 32-byte aligned. A `NT` caller must `_mm_sfence()` before any other thread
/// observes the stores.
pub unsafe
/// Store 16 bytes, non-temporally when `NT`.
///
/// # Safety
/// As [`store_avx2`], for 16 bytes and 16-byte alignment.
pub unsafe