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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
// Most or all contents generated by AI (model glm-5.3)
//! Lightweight generic fixed-array vector types.
//!
//! This crate provides [`Simd`], a fixed-lane vector type `Simd<T, N>` over
//! `[T; N]`, with lane-wise arithmetic (vector/vector and vector/scalar),
//! multiply-add (fused where the target has hardware FMA; see below), float
//! functions, comparisons producing masks, mask selection, horizontal
//! reductions, and slice load/store — all implemented without intrinsics and
//! without runtime instruction dispatch.
//!
//! Performance relies on the compiler auto-vectorizing this portable code;
//! build with `-C target-cpu=native` (or a similar `target-cpu` setting) to
//! obtain SIMD-level efficiency. Correctness does not depend on it.
//!
//! Element categories are expressed by trait bounds rather than by distinct
//! types: arithmetic requires [`num_traits::Num`], the float functions require
//! [`num_traits::Float`], multiply-add requires [`num_traits::MulAdd`] where
//! the target has hardware FMA and [`core::ops::Mul`] with [`core::ops::Add`]
//! otherwise, and bitwise operations require the element's own
//! [`core::ops`] implementations. `bool` is a valid element, and
//! `Simd<bool, N>` doubles as the mask type. The lane count `N` is an
//! arbitrary const generic.
//!
//! A full one-file map of the API surface — written for users and AI coding
//! agents — lives in the [`guide`] module (kept as `src/guide.md` in the
//! repository).
//!
//! Concrete aliases such as `f64x8` are enforced-alignment types
//! ([`Aligned64<f64, 8>`](Aligned64)): array-backed siblings of [`Simd`] that
//! share one implementation — every operation is defined once for `Simd` and
//! the five aligned types together. The alignment is the vector's byte size
//! rounded up to a power of two, capped at 64 bytes; conversions between plain
//! and aligned vectors are `From`/`.0`/`to_simd`. Masks (`Simd<bool, N>` and
//! the `maskN` aliases) carry no enforced alignment; per-lane selection is
//! [`mask_select`](Simd::mask_select) on the value (available on every vector
//! type), or [`Simd::select`] on the mask for plain vectors.
//!
//! # Multiply-add semantics
//!
//! [`mul_add`](Simd::mul_add) and [`fma_from`](Simd::fma_from) follow the
//! compilation target (see `docs/adr/0005` in the repository for the
//! measured trade-off):
//!
//! - **targets with hardware FMA** — x86 built with `-C target-cpu` of `x86-64-v3` or higher
//! (including `native`), and all aarch64: the element's fused [`num_traits::MulAdd`], a single
//! rounding per lane, one FMA instruction per register, no extra flags.
//! - **targets without** — generic x86-64, `x86-64-v2`, and architectures the predicate does not
//! know: a separated multiply and add (two roundings per lane) that never degrades into the slow
//! software-fused libm `fma` calls (~4.6x slower than separated there). Under `-C
//! llvm-args=-fp-contract=fast` this form still fuses into a hardware FMA instruction on capable
//! targets.
//! - the non-default cargo feature **`use_libm_fma`** pins the fused form on *every* target,
//! accepting the libm software `fma` where hardware is absent — use it when results must be
//! bit-identical across build targets.
//!
//! # Example
//!
//! Same example as the README; kept as a doctest so it is verified by CI.
//!
//! ```
//! use lightweight_simd::{f64x8, Simd};
//!
//! // typed aliases (enforced alignment) or the generic Simd<T, N>
//! let a = f64x8::from([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);
//! let b = f64x8::splat(2.0);
//!
//! let c = a.mul_add(b, f64x8::one()); // a*b + 1, fused on FMA targets
//! assert_eq!(c.reduce_sum(), 80.0);
//!
//! let mask = a.simd_gt(f64x8::splat(4.0)); // comparisons -> masks
//! assert_eq!(a.mask_select(mask, b).to_array(), [2.0, 2.0, 2.0, 2.0, 5.0, 6.0, 7.0, 8.0]);
//!
//! let mut buf = [0.0; 8];
//! a.store_slice(&mut buf); // slice load/store
//!
//! // any element type and lane count
//! let u = Simd::from([10u32, 20, 30]);
//! assert_eq!((u * 3).to_array(), [30, 60, 90]);
//! ```
use ;
use ;
/// Dummy doc-only module: renders `src/guide.md` (the one-file API overview,
/// also linked from the README) into the rustdoc output.
pub use *;
pub use ;
/// A fixed-length vector of `N` lanes of element type `T`.
///
/// All operations are lane-wise and implemented as plain loops over the
/// underlying `[T; N]`, so the compiler can auto-vectorize them for any
/// element type and lane count. The lane count `N` is arbitrary (powers of two
/// that fill whole SIMD registers are the sweet spot, but not required).
///
/// The type carries no enforced alignment beyond the element's natural
/// alignment; for enforced alignment use the [`aligned`] sibling types, which
/// share this type's full operation surface. The field is public for
/// zero-friction interoperability with array code.
;