Skip to main content

a/math/numbers/
add.rs

1//! Addition of [`Number`]s: `+` and `+=`, with either operand owned or borrowed.
2//!
3//! A number is a sign and a magnitude, so a sum is one of two operations on the magnitudes.
4//! When the signs agree, or an operand is zero, the magnitudes add up and the sum has the sign
5//! of the nonzero operands. When they differ, the smaller magnitude is subtracted from the
6//! larger and the sum has the sign of the larger. A zero magnitude is zero whatever `negative`
7//! says, and zero bytes above the most significant one count for nothing. Subtraction (in
8//! `sub`) is the sum with the sign of its right operand turned over, and takes the same paths.
9//!
10//! Operands whose vectors both hold at most 16 bytes take a short path in registers. Their
11//! magnitudes are read into `u128`s, with loads that stay inside the bytes of each vector, and
12//! both their sum and their difference are computed: the one the signs ask for, the sign, and
13//! the length in the shortest form (17 bytes when the sum carries out of the sixteenth) are
14//! then chosen without a branch. The sum is stored in the byte order of the left operand, in
15//! the vector chosen as below, with no reversal and no other pass over its bytes. The stores are
16//! chosen by the length `k` of the longer operand's vector rather than by the length of the sum:
17//! a sum of magnitudes of `k` bytes is `k` or `k + 1` bytes long, a coin toss for random ones,
18//! and the two lengths take the same stores (see [`write_sum`]). Longer operands, and a new
19//! vector for a short sum, are handled out of line, so that the short path saves no registers.
20//!
21//! Operands whose vectors both hold at most 64 bytes, not both at most 16, take the medium path,
22//! out of line, also in registers, with code for each number `L` of limbs of eight bytes of the
23//! longer vector, from 3 to 8. The magnitudes are read as `L` limbs each, loaded where they are
24//! (the top one of a vector from the eight bytes that end it, shifted), and one chain of
25//! additions gives their sum, or `x - y` when the signs differ, while a second one gives `y - x`
26//! alongside, which is taken when the first borrowed: neither the signs nor which magnitude is the
27//! larger, a coin toss for random operands, are branched on. The length of the sum is found from
28//! its top three limbs, and the sum stored from the limbs below its top eight bytes, at their
29//! places, and then those eight bytes; a vector of `+=` is written only once both operands have
30//! been read. A sum shorter than `L - 1` limbs, of operands that nearly cancel or have zero bytes
31//! above their most significant ones, and a sum the vector has no room for, go to slower code
32//! (see [`medium_slow`]).
33//!
34//! For operands of more than 64 bytes, everything about the sum but its bytes is planned first,
35//! from the operands as they are: the operation, which magnitude is `x`, the one the other (`y`)
36//! is added to or subtracted from, the sign, and the exact length of the sum in its shortest
37//! form. A sum of magnitudes of `lx >= ly` significant bytes is `lx` bytes long, or one more
38//! when it carries out of the top, and whether it does is found from the top down: the first
39//! byte position at which the bytes add up to anything but `0xFF` decides. A difference reaches
40//! up to the highest position at which the magnitudes differ, unless that position differs by
41//! exactly 1 and a borrow from below cancels it. It then ends at the bottom of the run of
42//! positions under it at which `x` has `0x00` and `y` has `0xFF`, which pass the borrow on, or
43//! a byte lower when a borrow comes into that run too, as in `0x01_00_00 - 0xFF_FF = 1`. The
44//! planning of a difference is out of line, so that additions keep their registers. The scans
45//! take eight positions at a time, and for random operands they stop in the first eight; only
46//! long runs of carries or borrows, or of zero bytes above the most significant one, make them
47//! read further, each byte once.
48//!
49//! Only then is a vector chosen for the sum, as the operators promise: the vector of an
50//! operand taken by value, or of the target of `+=`, when it has room for the sum (the left
51//! operand's first), and otherwise one new vector of the sum's length. In it the sum is
52//! computed in one pass from the least significant byte up, and only its bytes: there are no
53//! zero bytes to trim afterwards and no temporary vectors, and reusing a vector allocates
54//! nothing. The sum is in the byte order of the left operand. A right operand in the other
55//! order is brought into it without allocating: an owned one is reversed in place; a borrowed
56//! one is copied into the new vector of the sum, or, when the sum is built in the left
57//! operand's vector, the left operand is reversed into the right operand's order and the sum
58//! reversed back.
59//!
60//! The magnitudes are added and subtracted in limbs of eight bytes by kernels chosen at
61//! compile time: inline assembly on `x86_64` (one carry chain through the carry flag) and on
62//! 64-bit little-endian `aarch64` (one chain below 32 limbs little-endian and 64 big-endian,
63//! several interleaved chains from there), and portable Rust elsewhere and under Miri, which
64//! cannot run assembly. A big-endian magnitude is handed to them by its least significant end,
65//! the address one past its last byte, and its limbs go towards lower addresses, so the limbs
66//! of either byte order are read where they are. A big-endian sum that grows in the vector of
67//! an operand ends further on in it than the operand did, as the vector grows at the end where
68//! the least significant byte belongs: the kernels allow an output that lies above an input
69//! like this, as they read each limb before they write over it. The bytes of the shorter
70//! operand above its last whole limb follow as one more limb, read from below their start and
71//! shifted, when there are at least three of them and a whole limb under them, and one at a
72//! time otherwise. Above the shorter operand, a carry or a borrow goes on through the longer
73//! one eight bytes at a time while it lasts, and the rest of it is copied (inline below 16
74//! bytes), or left where it is when the sum is written over it at the same place. The carries
75//! that are coin tosses for random operands, out of the shorter operand and out of the top of
76//! the sum, are taken without a branch, which would mispredict half of them.
77//!
78//! Which magnitude of a difference is the larger is a coin toss for random operands of the same
79//! length too, and `x` and `y` are chosen without a branch as well. But then the kernel waits for
80//! the plan to read and compare the top limbs of both operands before it can load anything,
81//! which costs a long difference 12 to 23 cycles once the operands are out of the first-level
82//! cache. So a difference built in an operand's vector from 256 bytes little-endian and 512
83//! big-endian, the lengths from which the kernels run several chains, takes them by branches
84//! instead: a predicted one lets the kernel start at once, and a mispredicted one costs about
85//! what the wait did.
86
87use super::{ByteOrder, Number};
88use core::hint::select_unpredictable;
89use core::ops::{Add, AddAssign};
90use core::{mem, ptr};
91
92// The kernels behind the computation, one set per target under the name `kernels`.
93//
94// The `aarch64` assembly is for the 64-bit little-endian targets only: the ILP32 ones
95// (`arm64_32-apple-watchos`, `aarch64-unknown-linux-gnu_ilp32`) would pass it 32-bit pointers
96// and sizes in registers whose upper halves are undefined. It is also for the operating
97// systems that let user code load and store at any address only: the assembly loads and
98// stores limbs wherever the bytes of a magnitude lie, and unlike the accesses of Rust code,
99// which LLVM splits on a target that requires alignment, those of assembly reach the memory
100// as they are written. The `aarch64` targets that require it (`+strict-align` in their target
101// specifications, for which rustc has no `cfg`) are bare-metal and embedded ones:
102// `aarch64-unknown-none` and `-none-softfloat`, `aarch64v8r-unknown-none`, `-hermit`, `-nuttx`,
103// `-hyperlight`, `-qtee` and `-teeos`. So the gate names the systems known to allow unaligned
104// accesses rather than those that do not: a new target gets the portable kernels until it is
105// added here.
106#[cfg(all(
107    target_arch = "aarch64",
108    target_endian = "little",
109    target_pointer_width = "64",
110    any(
111        target_vendor = "apple",
112        target_os = "linux",
113        target_os = "android",
114        target_os = "windows",
115        target_os = "freebsd",
116        target_os = "netbsd",
117        target_os = "openbsd",
118        target_os = "fuchsia"
119    ),
120    not(miri)
121))]
122#[path = "add/aarch64.rs"]
123mod kernels;
124#[cfg(all(target_arch = "x86_64", not(miri)))]
125#[path = "add/x86_64.rs"]
126mod kernels;
127#[cfg(not(any(
128    all(
129        target_arch = "aarch64",
130        target_endian = "little",
131        target_pointer_width = "64",
132        any(
133            target_vendor = "apple",
134            target_os = "linux",
135            target_os = "android",
136            target_os = "windows",
137            target_os = "freebsd",
138            target_os = "netbsd",
139            target_os = "openbsd",
140            target_os = "fuchsia"
141        ),
142        not(miri)
143    ),
144    all(target_arch = "x86_64", not(miri))
145)))]
146#[path = "add/portable.rs"]
147mod kernels;
148
149use kernels::{add_n_be, add_n_le, sub_n_be, sub_n_le};
150
151/// `r = a + b` over the `n` native limbs at the pointers, for the multiplication; returns the
152/// carry out. On a little-endian target native limbs are little-endian ones, and the kernels of
153/// the addition take them as they are; `r` may be `a` or `b`.
154///
155/// # Safety
156///
157/// As for the kernels: the `n` limbs at each pointer must be valid, and `r` equal to an input or
158/// apart from both.
159#[cfg(target_endian = "little")]
160#[inline]
161pub(super) unsafe fn add_limbs(r: *mut u64, a: *const u64, b: *const u64, n: usize) -> bool {
162    // SAFETY: as the caller guarantees; a native limb is a little-endian one here.
163    unsafe { add_n_le(r.cast(), a.cast(), b.cast(), n, false) }
164}
165
166/// `r = a - b` over the `n` native limbs at the pointers, as [`add_limbs`] adds them; returns the
167/// borrow out.
168///
169/// # Safety
170///
171/// As for [`add_limbs`].
172#[cfg(target_endian = "little")]
173#[inline]
174pub(super) unsafe fn sub_limbs(r: *mut u64, a: *const u64, b: *const u64, n: usize) -> bool {
175    // SAFETY: as for `add_limbs`.
176    unsafe { sub_n_le(r.cast(), a.cast(), b.cast(), n, false) }
177}
178
179impl Add<&Number> for &Number {
180    type Output = Number;
181
182    /// Returns `self + rhs`, in the byte order of `self`, in the shortest form.
183    ///
184    /// The sum is built in one new vector of exactly its length (one byte for zero), the only
185    /// allocation; both operands are left as they were. The operands may have any signs, byte
186    /// orders and lengths, and need not be in the shortest form.
187    ///
188    /// # Examples
189    ///
190    /// ```
191    /// use a::math::numbers::{ByteOrder, Number};
192    ///
193    /// // 0x01_00 + -0x01_01 = -1, in the byte order of the left operand.
194    /// let a = Number::new_from_i32(0x0100, ByteOrder::BigEndian);
195    /// let b = Number::new_from_i32(-0x0101, ByteOrder::LittleEndian);
196    /// let sum = &a + &b;
197    /// assert_eq!(sum.value, [1]);
198    /// assert!(sum.is_negative());
199    /// assert!(sum.byte_order() == ByteOrder::BigEndian);
200    ///
201    /// // A number plus its negation is zero, one zero byte and not negative.
202    /// let minus_a = Number::new_from_i32(-0x0100, ByteOrder::LittleEndian);
203    /// let zero = &a + &minus_a;
204    /// assert_eq!(zero.value, [0]);
205    /// assert!(!zero.is_negative());
206    /// ```
207    fn add(self, rhs: &Number) -> Number {
208        if small(self, rhs) {
209            return small_number_of(self, rhs, rhs.negative);
210        }
211        if medium(self, rhs) {
212            return medium_new(self, rhs, rhs.negative);
213        }
214        ref_plus_ref(self, rhs)
215    }
216}
217
218impl Add<&Number> for Number {
219    type Output = Number;
220
221    /// Returns `self + rhs`, in the byte order of `self`, in the shortest form, as `self += rhs`
222    /// does.
223    ///
224    /// The sum is built in the vector of `self` when its capacity has room for the sum, which
225    /// allocates nothing, and otherwise in one new vector of exactly its length. `rhs` is left
226    /// as it was.
227    ///
228    /// # Examples
229    ///
230    /// ```
231    /// use a::math::numbers::{ByteOrder, Number};
232    ///
233    /// let mut value = Vec::with_capacity(8);
234    /// value.extend([0xFF, 0xFF]);
235    /// let a = Number::new(value, ByteOrder::BigEndian);
236    /// let pointer = a.value.as_ptr();
237    /// let one = Number::new_from_u8(1, ByteOrder::BigEndian);
238    ///
239    /// // 0xFF_FF + 1 = 0x01_00_00, in the vector of `a`.
240    /// let sum = a + &one;
241    /// assert_eq!(sum.value, [1, 0, 0]);
242    /// assert_eq!(sum.value.as_ptr(), pointer);
243    /// ```
244    fn add(mut self, rhs: &Number) -> Number {
245        self += rhs;
246        self
247    }
248}
249
250impl Add<Number> for &Number {
251    type Output = Number;
252
253    /// Returns `self + rhs`, in the byte order of `self`, in the shortest form.
254    ///
255    /// The sum is built in the vector of `rhs` when its capacity has room for the sum, which
256    /// allocates nothing, also when `rhs` is in the other byte order; otherwise it gets one new
257    /// vector of exactly its length. `self` is left as it was.
258    ///
259    /// # Examples
260    ///
261    /// ```
262    /// use a::math::numbers::{ByteOrder, Number};
263    ///
264    /// let a = Number::new_from_u32(0x01_02_03, ByteOrder::BigEndian);
265    /// let mut value = Vec::with_capacity(3);
266    /// value.extend([0x10, 0x20]);
267    /// let b = Number::new(value, ByteOrder::LittleEndian);
268    /// let pointer = b.value.as_ptr();
269    ///
270    /// // 0x01_02_03 + 0x20_10 = 0x01_22_13, big-endian, in the vector of `b`.
271    /// let sum = &a + b;
272    /// assert_eq!(sum.value, [0x01, 0x22, 0x13]);
273    /// assert_eq!(sum.value.as_ptr(), pointer);
274    /// ```
275    fn add(self, mut rhs: Number) -> Number {
276        if small(self, &rhs) {
277            let sum = small_sum(self, &rhs, rhs.negative);
278            let order = self.byte_order;
279            // SAFETY: a small sum is from 1 to 17 bytes long, and the vector it is written in
280            // has room for it.
281            unsafe {
282                if rhs.value.capacity() >= sum.len {
283                    write_small_in(&mut rhs.value, order, &sum);
284                } else {
285                    replace_small(&mut rhs.value, order, sum.lo, sum.hi, sum.len, sum.k);
286                }
287            }
288            return Number {
289                value: rhs.value,
290                negative: sum.negative,
291                byte_order: order,
292            };
293        }
294        if medium(self, &rhs) {
295            let (b, negative): (*mut Number, bool) = (&mut rhs, rhs.negative);
296            // SAFETY: both operands are valid and take the medium path, and the sum goes to `b`.
297            unsafe { medium_into(self, b, negative, b, Fallback::New) };
298            return rhs;
299        }
300        // `rhs` is dropped on return, with the vector it holds then, if any.
301        ref_plus_value(self, &mut rhs)
302    }
303}
304
305impl Add<Number> for Number {
306    type Output = Number;
307
308    /// Returns `self + rhs`, in the byte order of `self`, in the shortest form, as `self += rhs`
309    /// does.
310    ///
311    /// The sum is built in the vector of `self` when its capacity has room for the sum, or else
312    /// in the vector of `rhs` when that has room, also when `rhs` is in the other byte order,
313    /// either of which allocates nothing; otherwise it gets one new vector of exactly its
314    /// length.
315    ///
316    /// # Examples
317    ///
318    /// ```
319    /// use a::math::numbers::{ByteOrder, Number};
320    ///
321    /// // 0x01_00 + -0x02_FF = -0x01_FF.
322    /// let a = Number::new_from_i32(0x0100, ByteOrder::LittleEndian);
323    /// let b = Number::new_from_i32(-0x02FF, ByteOrder::BigEndian);
324    /// let sum = a + b;
325    /// assert_eq!(sum.value, [0xFF, 0x01]);
326    /// assert!(sum.is_negative());
327    /// ```
328    fn add(mut self, rhs: Number) -> Number {
329        self += rhs;
330        self
331    }
332}
333
334impl AddAssign<&Number> for Number {
335    /// Adds `rhs` to `self`, keeping the byte order of `self`, in the shortest form.
336    ///
337    /// The sum is built in the vector of `self` when its capacity has room for the sum, which
338    /// allocates nothing, and otherwise in one new vector of exactly its length, which
339    /// replaces it. `rhs` is left as it was.
340    ///
341    /// # Examples
342    ///
343    /// ```
344    /// use a::math::numbers::{ByteOrder, Number};
345    ///
346    /// let mut n = Number::new_from_u8(0xFF, ByteOrder::LittleEndian);
347    /// n += &Number::new_from_u16(0x0101, ByteOrder::BigEndian);
348    /// assert_eq!(n.value, [0x00, 0x02]);
349    /// n += &Number::new_from_i16(-0x0201, ByteOrder::BigEndian);
350    /// assert_eq!(n.value, [1]);
351    /// assert!(n.is_negative());
352    /// ```
353    #[inline]
354    fn add_assign(&mut self, rhs: &Number) {
355        if small(self, rhs) {
356            small_add_to(self, rhs, rhs.negative);
357            return;
358        }
359        if medium(self, rhs) {
360            let (a, b) = (ptr::from_mut(self), ptr::from_ref(rhs).cast_mut());
361            // SAFETY: both operands are valid and take the medium path, the sum goes to `a`, and
362            // `b` is only read.
363            unsafe { medium_into(a, b, rhs.negative, a, Fallback::New) };
364            return;
365        }
366        add_assign_ref(self, rhs);
367    }
368}
369
370impl AddAssign<Number> for Number {
371    /// Adds `rhs` to `self`, keeping the byte order of `self`, in the shortest form.
372    ///
373    /// The sum is built in the vector of `self` when its capacity has room for the sum, or else
374    /// in the vector of `rhs` when that has room, also when `rhs` is in the other byte order,
375    /// either of which allocates nothing; otherwise it gets one new vector of exactly its
376    /// length.
377    ///
378    /// # Examples
379    ///
380    /// ```
381    /// use a::math::numbers::{ByteOrder, Number};
382    ///
383    /// // `n` has no room for 0x01_00, but the vector of the right operand has.
384    /// let mut n = Number::new_from_u8(0xFF, ByteOrder::BigEndian);
385    /// let mut value = Vec::with_capacity(2);
386    /// value.push(1);
387    /// let one = Number::new(value, ByteOrder::BigEndian);
388    /// let pointer = one.value.as_ptr();
389    /// n += one;
390    /// assert_eq!(n.value, [1, 0]);
391    /// assert_eq!(n.value.as_ptr(), pointer);
392    /// ```
393    #[inline]
394    fn add_assign(&mut self, mut rhs: Number) {
395        if small(self, &rhs) {
396            let sum = small_sum(self, &rhs, rhs.negative);
397            self.negative = sum.negative;
398            let order = self.byte_order;
399            // SAFETY: a small sum is from 1 to 17 bytes long, and the vector it is written in
400            // has room for it.
401            unsafe {
402                if self.value.capacity() >= sum.len {
403                    write_small_in(&mut self.value, order, &sum);
404                } else if rhs.value.capacity() >= sum.len {
405                    write_small_in(&mut rhs.value, order, &sum);
406                    // The vector of `self` goes to `rhs`, and is dropped with it.
407                    mem::swap(&mut self.value, &mut rhs.value);
408                } else {
409                    replace_small(&mut self.value, order, sum.lo, sum.hi, sum.len, sum.k);
410                }
411            }
412            return;
413        }
414        if medium(self, &rhs) {
415            let (a, negative) = (ptr::from_mut(self), rhs.negative);
416            // SAFETY: both operands are valid and take the medium path, the sum goes to `a`, and
417            // `rhs` is taken by value.
418            unsafe { medium_into(a, &mut rhs, negative, a, Fallback::Other) };
419            return;
420        }
421        // `rhs` is dropped on return, with the vector it holds then.
422        add_assign_value(self, &mut rhs);
423    }
424}
425
426// The general path: operands of more than 64 bytes, out of line, so that the paths in registers
427// save no registers for it.
428
429/// `a + b` for borrowed operands, of which at least one has more than 64 bytes.
430#[inline(never)]
431pub(super) fn ref_plus_ref(a: &Number, b: &Number) -> Number {
432    let plan = plan(a, b);
433    // SAFETY: the plan is that of `a` and `b`, in their own byte orders.
434    let value = unsafe { sum_new(a, b, &plan) };
435    Number {
436        value,
437        negative: plan.negative,
438        byte_order: a.byte_order,
439    }
440}
441
442/// `a + b` for a borrowed `a` and an owned `b`, of which at least one has more than 64 bytes.
443/// The sum takes the vector of `b` when it is built there, leaving `b` an empty one; the
444/// caller drops `b` either way.
445#[inline(never)]
446fn ref_plus_value(a: &Number, b: &mut Number) -> Number {
447    let plan = plan(a, b);
448    let order = a.byte_order;
449    let reverse = b.byte_order != order && plan.len > 0;
450    if reverse {
451        b.value.reverse();
452        b.byte_order = order;
453    }
454    let value = if plan.fits(b.value.capacity()) {
455        // SAFETY: the plan is that of `a` and `b`, which are both in `order` now unless the
456        // sum is zero, and the vector of `b` has room for the sum.
457        unsafe { sum_in(&mut b.value, order, true, &a.value, &plan, reverse) };
458        mem::take(&mut b.value)
459    } else {
460        // SAFETY: the plan is that of `a` and `b`, in their own byte orders.
461        unsafe { sum_new(a, b, &plan) }
462    };
463    Number {
464        value,
465        negative: plan.negative,
466        byte_order: order,
467    }
468}
469
470/// `a += b` for a borrowed `b`, where at least one of them has more than 64 bytes; returns `a`,
471/// for the subtraction.
472#[inline(never)]
473pub(super) fn add_assign_ref<'a>(a: &'a mut Number, b: &Number) -> &'a mut Number {
474    let plan = plan(a, b);
475    if !plan.fits(a.value.capacity()) {
476        replace_with_sum(a, b, &plan);
477        return a;
478    }
479    // A borrowed `b` cannot be reversed: when the byte orders differ, `a` is reversed into the
480    // byte order of `b` instead, and the sum reversed back. One call, so that the computation
481    // inlined into it is there once.
482    let reverse = b.byte_order != a.byte_order && plan.len > 0;
483    if reverse {
484        a.value.reverse();
485    }
486    // SAFETY: the plan is that of `a` and `b`, which are in the byte order of `b` now unless the
487    // sum is zero, and the vector of `a` has room for the sum.
488    unsafe { sum_in(&mut a.value, b.byte_order, false, &b.value, &plan, reverse) };
489    if reverse {
490        a.value.reverse();
491    }
492    a.negative = plan.negative;
493    a
494}
495
496/// `a += b` for an owned `b`, where at least one of them has more than 64 bytes. When the sum
497/// is built in the vector of `b`, the vector of `a` goes to `b`; the caller drops `b` either
498/// way.
499#[inline(never)]
500fn add_assign_value(a: &mut Number, b: &mut Number) {
501    let plan = plan(a, b);
502    let order = a.byte_order;
503    let reverse = b.byte_order != order && plan.len > 0;
504    if reverse {
505        b.value.reverse();
506        b.byte_order = order;
507    }
508    let in_a = plan.fits(a.value.capacity());
509    if !in_a && !plan.fits(b.value.capacity()) {
510        replace_with_sum(a, b, &plan);
511        return;
512    }
513    // One call, so that the computation inlined into it is there once.
514    let (v, other) = if in_a {
515        (&mut a.value, &b.value)
516    } else {
517        (&mut b.value, &a.value)
518    };
519    // SAFETY: the plan is that of `a` and `b`, which are both in `order` now unless the sum is
520    // zero, and the vector of `a`, or else that of `b`, has room for the sum.
521    unsafe { sum_in(v, order, !in_a, other, &plan, reverse) };
522    if !in_a {
523        mem::swap(&mut a.value, &mut b.value);
524    }
525    a.negative = plan.negative;
526}
527
528/// `a += b` for operands of which neither vector has room for the sum: its new vector replaces
529/// that of `a`. Out of line and cold, so that the sums built in place keep no registers for
530/// its allocation.
531#[cold]
532#[inline(never)]
533fn replace_with_sum(a: &mut Number, b: &Number, plan: &Plan) {
534    // SAFETY: the plan is that of `a` and `b`, in their own byte orders.
535    a.value = unsafe { sum_new(a, b, plan) };
536    a.negative = plan.negative;
537}
538
539// Small numbers
540
541/// The longest vector, in bytes, of the operands that take the small path: with both this
542/// short, their magnitudes are added or subtracted as `u128`s.
543pub(super) const SMALL: usize = 16;
544
545/// Whether `a + b` takes the small path: both vectors hold at most [`SMALL`] bytes.
546#[inline(always)]
547pub(super) fn small(a: &Number, b: &Number) -> bool {
548    a.value.len() <= SMALL && b.value.len() <= SMALL
549}
550
551// The small paths of the forms with a borrowed right operand, which subtraction shares: `b` is
552// taken with the sign `negative_b`, its own for a sum and the opposite one for a difference.
553// They are inlined, so that the sign is a value in a register either way.
554
555/// `a + b` for small borrowed operands, `b` taken with the sign `negative_b`, in one new
556/// vector.
557#[inline(always)]
558pub(super) fn small_number_of(a: &Number, b: &Number, negative_b: bool) -> Number {
559    let sum = small_sum(a, b, negative_b);
560    // SAFETY: a small sum is from 1 to 17 bytes long.
561    unsafe { small_number(a.byte_order, sum.lo, sum.hi, sum.len, sum.k, sum.negative) }
562}
563
564/// `a += b` for small operands and a borrowed `b`, taken with the sign `negative_b`.
565#[inline(always)]
566pub(super) fn small_add_to(a: &mut Number, b: &Number, negative_b: bool) {
567    let sum = small_sum(a, b, negative_b);
568    a.negative = sum.negative;
569    let order = a.byte_order;
570    // SAFETY: a small sum is from 1 to 17 bytes long, and the vector it is written in has room
571    // for it.
572    unsafe {
573        if a.value.capacity() >= sum.len {
574            write_small_in(&mut a.value, order, &sum);
575        } else {
576            replace_small(&mut a.value, order, sum.lo, sum.hi, sum.len, sum.k);
577        }
578    }
579}
580
581/// The sum of two small operands, as the small path computes it in registers.
582struct Small {
583    /// The low eight bytes of the magnitude.
584    lo: u64,
585    /// The next eight bytes of the magnitude.
586    hi: u64,
587    /// The length of the sum in the shortest form, from 1 to 17: one byte for zero, and 17
588    /// when it carries out of the sixteenth byte, whose seventeenth byte is then 1.
589    len: usize,
590    /// The length of the longer of the operands' vectors, up to 16, which the stores of the sum
591    /// are chosen by (see [`write_sum`]).
592    k: usize,
593    /// Whether the sum is negative; never for zero.
594    negative: bool,
595}
596
597/// The sum of the small operands `a` and `b`, `b` taken with the sign `negative_b`: the sum of
598/// their magnitudes and both differences are computed, and the one the signs ask for chosen
599/// without a branch, as is the difference of the larger magnitude and the smaller.
600#[inline(always)]
601fn small_sum(a: &Number, b: &Number, negative_b: bool) -> Small {
602    // SAFETY: both vectors hold at most 16 bytes, as `small` checked.
603    let (x, y) = unsafe {
604        (
605            read_small(&a.value, a.byte_order),
606            read_small(&b.value, b.byte_order),
607        )
608    };
609    // A zero magnitude with a sign is subtracted from the other one, or the other one from it,
610    // which gives the other one with its own sign, as adding it would; a zero sum is never
611    // negative.
612    let subtract = a.negative != negative_b;
613    let (sum, carry) = x.overflowing_add(y);
614    let (difference, borrow) = x.overflowing_sub(y);
615    let difference = select_unpredictable(borrow, y.wrapping_sub(x), difference);
616    let magnitude = select_unpredictable(subtract, difference, sum);
617    let carry = carry & !subtract;
618    // One byte for zero, and 17 with a carry, chosen without a branch: the carry of two
619    // magnitudes of 16 bytes is often a coin toss, also when the signs differ and it is not
620    // used.
621    let len = select_unpredictable(
622        carry,
623        SMALL + 1,
624        SMALL - (magnitude | 1).leading_zeros() as usize / 8,
625    );
626    Small {
627        lo: magnitude as u64,
628        hi: (magnitude >> 64) as u64,
629        len,
630        k: a.value.len().max(b.value.len()),
631        // The sign of the larger magnitude, which is that of `y` when it is subtracted from a
632        // smaller `x`; never for zero.
633        negative: a.negative != (subtract && borrow) && (magnitude != 0 || carry),
634    }
635}
636
637/// The magnitude in the at most 16 bytes of `v`, in the layout of `order`.
638///
639/// Only the bytes of `v` are read, never its spare capacity: from 8 bytes up, the eight
640/// least significant ones and the eight most significant ones, which overlap below 16 and
641/// agree where they do; from 4 up, the same with four, and from 2 with two.
642///
643/// # Safety
644///
645/// `v` must hold at most 16 bytes.
646#[inline(always)]
647pub(super) unsafe fn read_small(v: &[u8], order: ByteOrder) -> u128 {
648    let (p, n) = (v.as_ptr(), v.len());
649    let be = order == ByteOrder::BigEndian;
650    // SAFETY: every read lies inside the `n` bytes of `v`: `[0, k)` and `[n - k, n)` with
651    // `n >= k`, for `k` of 8, 4 and 2, and the byte `0` with `n = 1`.
652    unsafe {
653        if n >= 4 {
654            if n >= 8 {
655                let lo = if be {
656                    u64::from_be_bytes(read(p.add(n - 8)))
657                } else {
658                    u64::from_le_bytes(read(p))
659                };
660                let hi = if n > 8 {
661                    let top = if be {
662                        u64::from_be_bytes(read(p))
663                    } else {
664                        u64::from_le_bytes(read(p.add(n - 8)))
665                    };
666                    // `top` holds positions `n - 8..n`; those from 8 up are the high half, a
667                    // shift by `8 * (16 - n)` down, which is below 64 and so `-8n` modulo 64.
668                    top.wrapping_shr((n as u32).wrapping_neg().wrapping_mul(8))
669                } else {
670                    0
671                };
672                u128::from(lo) | (u128::from(hi) << 64)
673            } else {
674                let (lo, top) = if be {
675                    (
676                        u32::from_be_bytes(read(p.add(n - 4))),
677                        u32::from_be_bytes(read(p)),
678                    )
679                } else {
680                    (
681                        u32::from_le_bytes(read(p)),
682                        u32::from_le_bytes(read(p.add(n - 4))),
683                    )
684                };
685                // `top` holds positions `n - 4..n`, which agree with `lo` where they overlap.
686                u128::from(u64::from(lo) | (u64::from(top) << (8 * (n - 4))))
687            }
688        } else if n >= 2 {
689            let (lo, top) = if be {
690                (
691                    u16::from_be_bytes(read(p.add(n - 2))),
692                    u16::from_be_bytes(read(p)),
693                )
694            } else {
695                (
696                    u16::from_le_bytes(read(p)),
697                    u16::from_le_bytes(read(p.add(n - 2))),
698                )
699            };
700            u128::from(u32::from(lo) | (u32::from(top) << (8 * (n - 2))))
701        } else if n == 1 {
702            u128::from(*p)
703        } else {
704            0
705        }
706    }
707}
708
709/// Writes the small sum of magnitude `hi:lo` and length `len` over the first `len` bytes at
710/// `p`, in the layout of `order`.
711///
712/// From 8 bytes up, two stores of eight, the most significant ones first, then the eight least
713/// significant ones over the bytes they overlap; 17 bytes are 16 and the top one. From 4 up, the
714/// same with four. Below 4, the least significant, the middle and the most significant byte. A
715/// sum of two operands of `k` bytes is `k` or `k + 1` bytes long, and for `k` of 1, 2, 4 and 8
716/// both lengths take the same stores.
717///
718/// The bytes are the sum's when `len` is its length as [`Small::len`] gives it.
719///
720/// # Safety
721///
722/// `len` must be from 1 to 17, and `p` valid for writing `len` bytes.
723#[inline(always)]
724pub(super) unsafe fn write_small(p: *mut u8, order: ByteOrder, lo: u64, hi: u64, len: usize) {
725    let be = order == ByteOrder::BigEndian;
726    // The shift that puts the high bytes of the class from 4 or 8 bytes at the top of their
727    // store, `8 * (2k - len)` for stores of `k` bytes, modulo `8k`.
728    let shift = (len as u32).wrapping_neg().wrapping_mul(8);
729    // SAFETY: every write lies inside the `len` bytes at `p`: `[0, 17)` for 17, `[0, k)` and
730    // `[len - k, len)` for `k` of 8 and 4 with `len >= k`, and the bytes `0`, `len / 2` and
731    // `len - 1` below 4. Of two writes that overlap, the later one puts the sum's bytes there.
732    unsafe {
733        if len >= 8 {
734            if len > SMALL {
735                if be {
736                    *p = 1;
737                    write(p.add(1), hi.to_be_bytes());
738                    write(p.add(9), lo.to_be_bytes());
739                } else {
740                    write(p, lo.to_le_bytes());
741                    write(p.add(8), hi.to_le_bytes());
742                    *p.add(16) = 1;
743                }
744            } else {
745                // The high bytes at the top of their eight; the bytes below them do not
746                // matter, as the low eight are written over them. For 8 bytes, `hi` and the
747                // shift are 0.
748                let top = hi.wrapping_shl(shift);
749                if be {
750                    write(p, top.to_be_bytes());
751                    write(p.add(len - 8), lo.to_be_bytes());
752                } else {
753                    write(p.add(len - 8), top.to_le_bytes());
754                    write(p, lo.to_le_bytes());
755                }
756            }
757        } else if len >= 4 {
758            let top = ((lo >> 32) as u32).wrapping_shl(shift);
759            if be {
760                write(p, top.to_be_bytes());
761                write(p.add(len - 4), (lo as u32).to_be_bytes());
762            } else {
763                write(p.add(len - 4), top.to_le_bytes());
764                write(p, (lo as u32).to_le_bytes());
765            }
766        } else {
767            let (mid, last) = (len / 2, len - 1);
768            let (b0, b1, b2) = (lo as u8, (lo >> (8 * mid)) as u8, (lo >> (8 * last)) as u8);
769            if be {
770                *p.add(last) = b0;
771                *p.add(last - mid) = b1;
772                *p = b2;
773            } else {
774                *p = b0;
775                *p.add(mid) = b1;
776                *p.add(last) = b2;
777            }
778        }
779    }
780}
781
782/// Writes the small sum of magnitude `hi:lo` and length `len` over the first `len` bytes at
783/// `p`, in the layout of `order`, for operands whose longer vector holds `k` bytes.
784///
785/// The stores are chosen by `k`, not by `len`: a sum of two magnitudes of `k` bytes is `k` or
786/// `k + 1` bytes long, a coin toss for random ones, and a branch on the length would mispredict
787/// half of them where the two lengths take different stores in [`write_small`] (`k` of 3, 7
788/// and 16). So for `k` of 16, two stores of eight bytes and one of the seventeenth or sixteenth
789/// byte; from 8, two of eight that overlap; from 4, two of four, which also store 8 bytes; for 3,
790/// two of two, which also store 4; below, three of a byte. A shorter sum, of operands that nearly
791/// cancel or have zero bytes above their most significant ones, takes the stores of its length.
792///
793/// # Safety
794///
795/// `len` must be from 1 to 17 and at most `k + 1`, and `p` valid for writing `len` bytes.
796#[inline(always)]
797unsafe fn write_sum(p: *mut u8, order: ByteOrder, lo: u64, hi: u64, len: usize, k: usize) {
798    let be = order == ByteOrder::BigEndian;
799    // SAFETY: every write lies inside the `len` bytes at `p`: from 16, `[0, 16)` and the byte
800    // `min(16, len - 1)`; from 8, `[0, 8)` and `[len - 8, len)`; from 4, `[0, 4)` and
801    // `[len - 4, len)`; from 2, `[0, 2)` and `[len - 2, len)`; below, the bytes `0`, `len / 2` and
802    // `len - 1`. Of two writes that overlap, the later one puts the sum's bytes there.
803    unsafe {
804        if k >= 8 {
805            if len < 8 {
806                // A sum much shorter than the operands' vectors.
807                write_small(p, order, lo, hi, len);
808            } else if k == SMALL && len >= SMALL {
809                // The seventeenth byte, 1, with a carry, and otherwise the sixteenth again.
810                let top = select_unpredictable(len > SMALL, 1, (hi >> 56) as u8);
811                if be {
812                    write(p.add(len - 8), lo.to_be_bytes());
813                    write(p.add(len - 16), hi.to_be_bytes());
814                    *p = top;
815                } else {
816                    write(p, lo.to_le_bytes());
817                    write(p.add(8), hi.to_le_bytes());
818                    *p.add(len - 1) = top;
819                }
820            } else {
821                // As `write_small` writes 8 to 16 bytes.
822                let top = hi.wrapping_shl((len as u32).wrapping_neg().wrapping_mul(8));
823                if be {
824                    write(p, top.to_be_bytes());
825                    write(p.add(len - 8), lo.to_be_bytes());
826                } else {
827                    write(p.add(len - 8), top.to_le_bytes());
828                    write(p, lo.to_le_bytes());
829                }
830            }
831        } else if k >= 4 && len >= 4 {
832            // As `write_small` writes 4 to 7 bytes, and also 8: the high four bytes of the eight,
833            // shifted by `8 (8 - len)` modulo 32, at the top.
834            let shift = (len as u32).wrapping_neg().wrapping_mul(8);
835            let top = ((lo >> 32) as u32).wrapping_shl(shift);
836            if be {
837                write(p, top.to_be_bytes());
838                write(p.add(len - 4), (lo as u32).to_be_bytes());
839            } else {
840                write(p.add(len - 4), top.to_le_bytes());
841                write(p, (lo as u32).to_le_bytes());
842            }
843        } else if k == 3 && len >= 2 {
844            // Two to four bytes: the high two of the four, shifted by `8 (4 - len)` modulo 16,
845            // at the top.
846            let shift = (len as u32).wrapping_neg().wrapping_mul(8) % 16;
847            let top = ((lo >> 16) as u16) << shift;
848            if be {
849                write(p, top.to_be_bytes());
850                write(p.add(len - 2), (lo as u16).to_be_bytes());
851            } else {
852                write(p.add(len - 2), top.to_le_bytes());
853                write(p, (lo as u16).to_le_bytes());
854            }
855        } else {
856            // One to three bytes, as `write_small` writes them.
857            let (mid, last) = (len / 2, len - 1);
858            let (b0, b1, b2) = (lo as u8, (lo >> (8 * mid)) as u8, (lo >> (8 * last)) as u8);
859            if be {
860                *p.add(last) = b0;
861                *p.add(last - mid) = b1;
862                *p = b2;
863            } else {
864                *p = b0;
865                *p.add(mid) = b1;
866                *p.add(last) = b2;
867            }
868        }
869    }
870}
871
872/// Writes the small sum `sum` over `v`, in the layout of `order`, as its whole value.
873///
874/// # Safety
875///
876/// The capacity of `v` must be at least the length of the sum.
877#[inline(always)]
878unsafe fn write_small_in(v: &mut Vec<u8>, order: ByteOrder, sum: &Small) {
879    // SAFETY: as the caller guarantees; `write_sum` writes all of the first `len` bytes, so
880    // they are initialised when the length is set.
881    unsafe {
882        write_sum(v.as_mut_ptr(), order, sum.lo, sum.hi, sum.len, sum.k);
883        v.set_len(sum.len);
884    }
885}
886
887/// The small sum of magnitude `hi:lo` and length `len`, of operands whose longer vector holds
888/// `k` bytes, in one new vector of exactly its length, in the layout of `order`.
889///
890/// # Safety
891///
892/// `len` must be from 1 to 17 and at most `k + 1`.
893#[inline(always)]
894unsafe fn new_small(order: ByteOrder, lo: u64, hi: u64, len: usize, k: usize) -> Vec<u8> {
895    let mut v = Vec::with_capacity(len);
896    // SAFETY: as the caller guarantees, and the new vector has room for the `len` bytes, all of
897    // which `write_sum` writes.
898    unsafe {
899        write_sum(v.as_mut_ptr(), order, lo, hi, len, k);
900        v.set_len(len);
901    }
902    v
903}
904
905/// The small sum of magnitude `hi:lo`, length `len` and sign `negative`, of operands whose
906/// longer vector holds `k` bytes, as a number in one new vector of exactly its length, in the
907/// byte order `order`. Out of line, and given the sum in registers, so that the small path of
908/// `&a + &b` saves no registers for the allocation.
909///
910/// # Safety
911///
912/// `len` must be from 1 to 17 and at most `k + 1`.
913#[inline(never)]
914unsafe fn small_number(
915    order: ByteOrder,
916    lo: u64,
917    hi: u64,
918    len: usize,
919    k: usize,
920    negative: bool,
921) -> Number {
922    // SAFETY: as the caller guarantees: told so, the compiler checks neither the size of the
923    // allocation nor a zero length.
924    unsafe {
925        core::hint::assert_unchecked(len != 0);
926        core::hint::assert_unchecked(len <= SMALL + 1);
927        Number {
928            value: new_small(order, lo, hi, len, k),
929            negative,
930            byte_order: order,
931        }
932    }
933}
934
935/// Replaces `v` with one new vector of exactly the small sum's length, holding the sum of
936/// magnitude `hi:lo` and length `len`, of operands whose longer vector holds `k` bytes, in the
937/// layout of `order`. Out of line and cold, and given the sum in registers, so that the small
938/// path saves no registers for it.
939///
940/// # Safety
941///
942/// `len` must be from 1 to 17 and at most `k + 1`.
943#[cold]
944#[inline(never)]
945unsafe fn replace_small(v: &mut Vec<u8>, order: ByteOrder, lo: u64, hi: u64, len: usize, k: usize) {
946    // SAFETY: as the caller guarantees.
947    *v = unsafe { new_small(order, lo, hi, len, k) };
948}
949
950// Operands of up to 64 bytes
951
952/// The longest vector, in bytes, of the operands that the medium path adds in registers.
953pub(super) const MEDIUM: usize = 64;
954
955/// Whether `a + b` takes the medium path, when it does not take the small one: both vectors
956/// hold at most [`MEDIUM`] bytes.
957#[inline(always)]
958pub(super) fn medium(a: &Number, b: &Number) -> bool {
959    a.value.len() <= MEDIUM && b.value.len() <= MEDIUM
960}
961
962/// A sum computed in registers by the medium path.
963struct Medium {
964    /// The limbs of the magnitude, the least significant first: those of the operands, then
965    /// the carry out of the top one, then zeros.
966    limbs: [u64; 9],
967    /// Whether the sum is negative, unless it is zero.
968    negative: bool,
969}
970
971/// Calls `$f::<L>($args)` for the number of limbs `L` of the longer of the vectors `$a` and `$b`,
972/// from 3 (for at most 24 bytes) to 8.
973macro_rules! by_limbs {
974    ($a:expr, $b:expr, $f:ident($($arg:expr),*)) => {
975        match $a.len().max($b.len()).div_ceil(8) {
976            ..=3 => $f::<3>($($arg),*),
977            4 => $f::<4>($($arg),*),
978            5 => $f::<5>($($arg),*),
979            6 => $f::<6>($($arg),*),
980            7 => $f::<7>($($arg),*),
981            _ => $f::<8>($($arg),*),
982        }
983    };
984}
985
986/// Where the medium path builds a sum when the vector of the operand it goes to has no room for
987/// it, as the operators promise.
988#[derive(Clone, Copy, PartialEq, Eq)]
989pub(super) enum Fallback {
990    /// In one new vector of exactly its length.
991    New,
992    /// In the vector of `b`, an operand taken by value, when that has room, and otherwise in one
993    /// new vector of exactly its length.
994    Other,
995}
996
997/// Writes `a + b`, `b` taken with the sign `negative_b`, over `out`, one of the operands: its
998/// vector, in the byte order of `a`, its sign and its byte order. The sum is built in the vector
999/// of `out` when that has room for it, and otherwise as `fallback` says; the vector of `out`
1000/// then goes to `b`, or is dropped. For operands of at most 64 bytes, not both of at most 16.
1001///
1002/// The code for the number `L` of limbs of the longer vector computes the sum, and hands a sum
1003/// shorter than `8 (L - 1)` bytes, or one the vector of `out` has no room for, to
1004/// [`medium_slow`]. Each call is the last step of its caller, so that none saves registers.
1005///
1006/// # Safety
1007///
1008/// `a` and `b` must be valid for reading, both their vectors hold at most 64 bytes and one more
1009/// than 16, and `out` must be `a` or `b`, valid for writing. With [`Fallback::Other`], `out` must
1010/// be `a`, and `b` an operand taken by value, valid for writing.
1011#[inline(never)]
1012pub(super) unsafe fn medium_into(
1013    a: *const Number,
1014    b: *mut Number,
1015    negative_b: bool,
1016    out: *mut Number,
1017    fallback: Fallback,
1018) {
1019    // SAFETY: as the caller guarantees; the vectors hold at most `8 L` bytes for the `L` chosen.
1020    unsafe {
1021        let (x, y) = (&(*a).value, &(*b).value);
1022        by_limbs!(x, y, medium_into_in(a, b, negative_b, out, fallback))
1023    }
1024}
1025
1026/// [`medium_into`] for vectors of at most `L` limbs, out of line, so that each length saves only
1027/// the registers it needs, and the call is the dispatch's last step.
1028///
1029/// # Safety
1030///
1031/// As for [`medium_into`], with vectors of at most `8 L` bytes.
1032#[inline(never)]
1033unsafe fn medium_into_in<const L: usize>(
1034    a: *const Number,
1035    b: *mut Number,
1036    negative_b: bool,
1037    out: *mut Number,
1038    fallback: Fallback,
1039) {
1040    // SAFETY: as the caller guarantees. Both operands are read before `out` is written, and
1041    // the references to them end before it is.
1042    unsafe {
1043        let order = (*a).byte_order;
1044        let m = medium_sum::<L>(
1045            read_limbs::<L>(&(*a).value, order),
1046            read_limbs::<L>(&(*b).value, (*b).byte_order),
1047            (*a).negative,
1048            negative_b,
1049        );
1050        let r = &m.limbs;
1051        let (len, top) = top_of::<L>(r);
1052        let v = &mut (*out).value;
1053        if !long::<L>(r) || v.capacity() < len {
1054            return medium_slow(a, b, negative_b, out, fallback);
1055        }
1056        write_long::<L>(v.as_mut_ptr(), order, r, len, top);
1057        v.set_len(len);
1058        (*out).negative = m.negative;
1059        (*out).byte_order = order;
1060    }
1061}
1062
1063/// `a + b`, `b` taken with the sign `negative_b`, in one new vector of exactly its length, for
1064/// operands of at most 64 bytes, not both of at most 16.
1065#[inline(never)]
1066pub(super) fn medium_new(a: &Number, b: &Number, negative_b: bool) -> Number {
1067    // SAFETY: the vectors hold at most `8 L` bytes for the `L` chosen.
1068    unsafe { by_limbs!(a.value, b.value, medium_new_in(a, b, negative_b)) }
1069}
1070
1071/// [`medium_new`] for vectors of at most `L` limbs.
1072///
1073/// # Safety
1074///
1075/// Both vectors must hold at most `8 L` bytes, and one more than 16.
1076#[inline(never)]
1077unsafe fn medium_new_in<const L: usize>(a: &Number, b: &Number, negative_b: bool) -> Number {
1078    let order = a.byte_order;
1079    // SAFETY: as the caller guarantees.
1080    let m = unsafe {
1081        medium_sum::<L>(
1082            read_limbs::<L>(&a.value, order),
1083            read_limbs::<L>(&b.value, b.byte_order),
1084            a.negative,
1085            negative_b,
1086        )
1087    };
1088    let r = &m.limbs;
1089    if !long::<L>(r) {
1090        return medium_new_slow(a, b, negative_b);
1091    }
1092    let (len, top) = top_of::<L>(r);
1093    let mut v = Vec::with_capacity(len);
1094    // SAFETY: the new vector has room for the sum, all of whose bytes are written before the
1095    // length is set.
1096    unsafe {
1097        write_long::<L>(v.as_mut_ptr(), order, r, len, top);
1098        v.set_len(len);
1099    }
1100    Number {
1101        value: v,
1102        negative: m.negative,
1103        byte_order: order,
1104    }
1105}
1106
1107// The cases the medium path leaves to slower code: a sum much shorter than the longer operand's
1108// vector, and no room in the vector it would be built in. The sum is computed as above and
1109// written to a buffer, whose bytes then go where the operator promises.
1110
1111/// A sum of the medium path in a buffer.
1112struct Bytes {
1113    /// The bytes of the magnitude, least significant first.
1114    bytes: [u8; 72],
1115    /// The length of the sum in the shortest form: one byte for zero.
1116    len: usize,
1117    /// Whether the sum is negative; never for zero.
1118    negative: bool,
1119}
1120
1121impl Bytes {
1122    /// `a + b`, `b` taken with the sign `negative_b`, for operands of at most 64 bytes.
1123    fn of(a: &Number, b: &Number, negative_b: bool) -> Self {
1124        // The limbs of a magnitude of at most 64 bytes, a byte at a time: this code is rare, and
1125        // kept short.
1126        let limbs = |n: &Number| {
1127            let mut x = [0u64; 9];
1128            let len = n.value.len();
1129            for (i, &byte) in n.value.iter().enumerate() {
1130                let p = if n.byte_order == ByteOrder::BigEndian {
1131                    len - 1 - i
1132                } else {
1133                    i
1134                };
1135                x[p / 8] |= u64::from(byte) << (8 * (p % 8));
1136            }
1137            x
1138        };
1139        let m = medium_sum::<8>(limbs(a), limbs(b), a.negative, negative_b);
1140        let mut bytes = [0; 72];
1141        for (chunk, limb) in bytes.as_chunks_mut::<8>().0.iter_mut().zip(m.limbs) {
1142            *chunk = limb.to_le_bytes();
1143        }
1144        let top = bytes.iter().rposition(|&b| b != 0);
1145        Bytes {
1146            bytes,
1147            len: top.map_or(1, |p| p + 1),
1148            negative: m.negative && top.is_some(),
1149        }
1150    }
1151
1152    /// Writes the sum over `v`, in the layout of `order`, as its whole value.
1153    ///
1154    /// # Safety
1155    ///
1156    /// The capacity of `v` must be at least the length of the sum.
1157    unsafe fn put(&self, v: &mut Vec<u8>, order: ByteOrder) {
1158        let (p, len) = (v.as_mut_ptr(), self.len);
1159        // SAFETY: as the caller guarantees; every one of the `len` bytes is written before the
1160        // length is set.
1161        unsafe {
1162            if order == ByteOrder::BigEndian {
1163                for (i, &byte) in self.bytes[..len].iter().enumerate() {
1164                    *p.add(len - 1 - i) = byte;
1165                }
1166            } else {
1167                ptr::copy_nonoverlapping(self.bytes.as_ptr(), p, len);
1168            }
1169            v.set_len(len);
1170        }
1171    }
1172
1173    /// The sum as a number in one new vector of exactly its length, in the byte order `order`.
1174    fn into_new(self, order: ByteOrder) -> Number {
1175        let mut value = Vec::with_capacity(self.len);
1176        // SAFETY: the new vector has room for the sum.
1177        unsafe { self.put(&mut value, order) };
1178        Number {
1179            value,
1180            negative: self.negative,
1181            byte_order: order,
1182        }
1183    }
1184}
1185
1186/// [`medium_into`] for a sum much shorter than the longer operand's vector, or that the vector of
1187/// `out` has no room for: out of line and cold.
1188///
1189/// # Safety
1190///
1191/// As for [`medium_into`].
1192#[cold]
1193#[inline(never)]
1194unsafe fn medium_slow(
1195    a: *const Number,
1196    b: *mut Number,
1197    negative_b: bool,
1198    out: *mut Number,
1199    fallback: Fallback,
1200) {
1201    // SAFETY: as the caller guarantees; the sum is computed before anything is written, and the
1202    // references to the operands end before it is.
1203    unsafe {
1204        let sum = Bytes::of(&*a, &*b, negative_b);
1205        let order = (*a).byte_order;
1206        let v = &mut (*out).value;
1207        if v.capacity() < sum.len {
1208            if fallback == Fallback::Other && (*b).value.capacity() >= sum.len {
1209                mem::swap(v, &mut (*b).value);
1210            } else {
1211                *v = Vec::with_capacity(sum.len);
1212            }
1213        }
1214        sum.put(v, order);
1215        (*out).negative = sum.negative;
1216        (*out).byte_order = order;
1217    }
1218}
1219
1220/// [`medium_new`] for a sum much shorter than the longer operand's vector.
1221#[cold]
1222#[inline(never)]
1223fn medium_new_slow(a: &Number, b: &Number, negative_b: bool) -> Number {
1224    Bytes::of(a, b, negative_b).into_new(a.byte_order)
1225}
1226
1227/// `x + y + carry`, and the carry out.
1228#[inline(always)]
1229fn adc(x: u64, y: u64, carry: bool) -> (u64, bool) {
1230    let (s, c1) = x.overflowing_add(y);
1231    let (s, c2) = s.overflowing_add(u64::from(carry));
1232    (s, c1 | c2)
1233}
1234
1235/// The magnitude in `v`, of at most `8 L` bytes, as limbs, those above it zero.
1236///
1237/// # Safety
1238///
1239/// `v` must hold at most `8 L` bytes.
1240#[inline(always)]
1241pub(super) unsafe fn read_limbs<const L: usize>(v: &[u8], order: ByteOrder) -> [u64; 9] {
1242    let n = v.len();
1243    // SAFETY: as the caller guarantees.
1244    unsafe {
1245        if n > 8 * (L - 1) {
1246            if order == ByteOrder::BigEndian {
1247                exact_limbs::<true, L>(v.as_ptr(), n)
1248            } else {
1249                exact_limbs::<false, L>(v.as_ptr(), n)
1250            }
1251        } else if n <= SMALL {
1252            let s = read_small(v, order);
1253            let mut x = [0; 9];
1254            x[0] = s as u64;
1255            x[1] = (s >> 64) as u64;
1256            x
1257        } else if order == ByteOrder::BigEndian {
1258            clamped_limbs::<true, L>(v.as_ptr(), n)
1259        } else {
1260            clamped_limbs::<false, L>(v.as_ptr(), n)
1261        }
1262    }
1263}
1264
1265/// The eight positions from `p` of the `n` bytes at `v` in the layout `BE`, as a `u64`.
1266///
1267/// # Safety
1268///
1269/// `p + 8 <= n`, and the `n` bytes must be valid for reading.
1270#[inline(always)]
1271unsafe fn limb_at<const BE: bool>(v: *const u8, n: usize, p: usize) -> u64 {
1272    // SAFETY: as the caller guarantees.
1273    unsafe {
1274        if BE {
1275            u64::from_be_bytes(read(v.add(n - 8 - p)))
1276        } else {
1277            u64::from_le_bytes(read(v.add(p)))
1278        }
1279    }
1280}
1281
1282/// The `n` bytes at `v` in the layout `BE`, `8 (L - 1) < n <= 8 L`, as `L` limbs.
1283///
1284/// # Safety
1285///
1286/// The `n` bytes must be valid for reading.
1287#[inline(always)]
1288unsafe fn exact_limbs<const BE: bool, const L: usize>(v: *const u8, n: usize) -> [u64; 9] {
1289    let mut x = [0; 9];
1290    // SAFETY: limbs `0..L - 1` lie below `8 (L - 1) < n`, and the top one is read from the eight
1291    // positions that end at `n`, `n >= 8`, and shifted down by `8 L - n` of them.
1292    unsafe {
1293        for (i, limb) in x.iter_mut().enumerate().take(L - 1) {
1294            *limb = limb_at::<BE>(v, n, 8 * i);
1295        }
1296        // `8 (8 L - n)` bits, which is `-8 n` modulo 64.
1297        let shift = (n as u32).wrapping_mul(8).wrapping_neg();
1298        x[L - 1] = limb_at::<BE>(v, n, n - 8).wrapping_shr(shift);
1299    }
1300    x
1301}
1302
1303/// The `n` bytes at `v` in the layout `BE`, `16 < n <= 8 (L - 1)`, as `L` limbs, the top ones
1304/// zero.
1305///
1306/// # Safety
1307///
1308/// The `n` bytes must be valid for reading.
1309#[inline(always)]
1310unsafe fn clamped_limbs<const BE: bool, const L: usize>(v: *const u8, n: usize) -> [u64; 9] {
1311    let mut x = [0; 9];
1312    // SAFETY: the limb at position `8 i` is read at the position `c = min(8 i, n - 8)`, inside
1313    // the `n` bytes, and shifted down by the positions from `c` up to `8 i`, fewer than eight
1314    // unless the limb is above the magnitude.
1315    unsafe {
1316        for (i, limb) in x.iter_mut().enumerate().take(L) {
1317            let c = (8 * i).min(n - 8);
1318            let w = limb_at::<BE>(v, n, c);
1319            *limb = if 8 * i < n { w >> (8 * (8 * i - c)) } else { 0 };
1320        }
1321    }
1322    x
1323}
1324
1325/// `x + y` over `L` limbs, `x` with the sign `negative_x` and `y` with `negative_y`.
1326///
1327/// One chain of additions gives the sum, or, when the signs differ, `x - y` as `x + !y + 1`.
1328/// Alongside it a second one gives `y - x`, which is taken instead when the first one borrowed,
1329/// without a branch: which magnitude is the larger is a coin toss for random operands of the same
1330/// length, and so, for random signs, is whether they are subtracted at all. The second chain
1331/// subtracts whatever the signs are, its low limbs as such and the others as the addition of the
1332/// complement with the carry, `y + !x + c`: for these LLVM makes one chain of `subs` and `adcs`,
1333/// while the carry of a first `y + !x + 1` would be worked out apart.
1334#[inline(always)]
1335fn medium_sum<const L: usize>(
1336    x: [u64; 9],
1337    y: [u64; 9],
1338    negative_x: bool,
1339    negative_y: bool,
1340) -> Medium {
1341    let subtract = negative_x != negative_y;
1342    let m = u64::from(subtract).wrapping_neg();
1343    let (mut s, mut d) = ([0u64; 9], [0u64; 9]);
1344    let (d0, borrow_d) = y[0].overflowing_sub(x[0]);
1345    let (mut carry, mut carry_d) = (subtract, !borrow_d);
1346    d[0] = d0;
1347    (s[0], carry) = adc(x[0], y[0] ^ m, carry);
1348    for i in 1..L {
1349        (s[i], carry) = adc(x[i], y[i] ^ m, carry);
1350        (d[i], carry_d) = adc(y[i], !x[i], carry_d);
1351    }
1352    let borrow = subtract & !carry;
1353    let mut r = [0u64; 9];
1354    for i in 0..L {
1355        r[i] = select_unpredictable(borrow, d[i], s[i]);
1356    }
1357    r[L] = u64::from(carry & !subtract);
1358    Medium {
1359        limbs: r,
1360        negative: negative_x != borrow,
1361    }
1362}
1363
1364/// Whether the sum `r` of operands of at most `L` limbs is at least `8 (L - 1)` bytes long.
1365#[inline(always)]
1366pub(super) fn long<const L: usize>(r: &[u64; 9]) -> bool {
1367    (r[L] | r[L - 1]) != 0 || r[L - 2] >> 56 != 0
1368}
1369
1370/// The length of the sum `r` of operands of at most `L` limbs, at least `8 (L - 1)` bytes long,
1371/// and its eight most significant positions.
1372#[inline(always)]
1373pub(super) fn top_of<const L: usize>(r: &[u64; 9]) -> (usize, u64) {
1374    let below = select_unpredictable(
1375        r[L - 1] != 0,
1376        (L - 1, r[L - 1], r[L - 2]),
1377        (L - 2, r[L - 2], r[L - 3]),
1378    );
1379    let (t, high, low) = select_unpredictable(r[L] != 0, (L, r[L], r[L - 1]), below);
1380    let z = high.leading_zeros();
1381    let shift = z & 56;
1382    (
1383        8 * t + 8 - z as usize / 8,
1384        (high << shift) | ((low >> 1) >> (63 - shift)),
1385    )
1386}
1387
1388/// Writes the sum `r` of operands of at most `L` limbs, of `len >= 8 (L - 1)` bytes whose top
1389/// eight are `top`, over the `len` bytes at `p` in the layout of `order`.
1390///
1391/// Limbs `0..L - 1` lie below the top eight positions of the sum or reach up to them; limb
1392/// `L - 1` is written below the top eight positions when the sum carried out of it, and at them
1393/// otherwise; then `top` over the top eight positions.
1394///
1395/// # Safety
1396///
1397/// `p` must be valid for writing `len` bytes.
1398#[inline(always)]
1399unsafe fn write_long<const L: usize>(
1400    p: *mut u8,
1401    order: ByteOrder,
1402    r: &[u64; 9],
1403    len: usize,
1404    top: u64,
1405) {
1406    let c = (8 * (L - 1)).min(len - 8);
1407    // SAFETY: every write lies inside the `len >= 8 (L - 1)` bytes.
1408    unsafe {
1409        if order == ByteOrder::BigEndian {
1410            for (i, limb) in r.iter().enumerate().take(L - 1) {
1411                write(p.add(len - 8 - 8 * i), limb.to_be_bytes());
1412            }
1413            write(p.add(len - 8 - c), r[L - 1].to_be_bytes());
1414            write(p, top.to_be_bytes());
1415        } else {
1416            for (i, limb) in r.iter().enumerate().take(L - 1) {
1417                write(p.add(8 * i), limb.to_le_bytes());
1418            }
1419            write(p.add(c), r[L - 1].to_le_bytes());
1420            write(p.add(len - 8), top.to_le_bytes());
1421        }
1422    }
1423}
1424
1425// Planning
1426
1427/// The sum `a + b` as planned from the untouched operands, before a vector is chosen for it.
1428///
1429/// The magnitude the other one is added to or subtracted from is `x`, the other one `y`: for
1430/// an addition `x` has at least as many significant bytes as `y`, for a subtraction it is the
1431/// larger magnitude. The significant length of a magnitude counts its bytes up to the most
1432/// significant nonzero one, and is 0 for zero.
1433struct Plan {
1434    /// Whether `y` is subtracted from `x` (the signs differ) rather than added to it.
1435    sub: bool,
1436    /// Whether `x` is `b` rather than `a`.
1437    x_is_b: bool,
1438    /// The significant length of `a`.
1439    la: usize,
1440    /// The significant length of `b`.
1441    lb: usize,
1442    /// The significant length of the sum: 0 for zero.
1443    len: usize,
1444    /// Whether the sum is negative; never for zero.
1445    negative: bool,
1446}
1447
1448impl Plan {
1449    /// The significant length of `x`.
1450    fn lx(&self) -> usize {
1451        if self.x_is_b { self.lb } else { self.la }
1452    }
1453
1454    /// The significant length of `y`.
1455    fn ly(&self) -> usize {
1456        if self.x_is_b { self.la } else { self.lb }
1457    }
1458
1459    /// Whether a vector of capacity `capacity` has room for the sum in the shortest form, one
1460    /// byte for zero.
1461    fn fits(&self, capacity: usize) -> bool {
1462        capacity >= self.len.max(1)
1463    }
1464
1465    /// Whether the operand whose vector holds the sum, `b` if `alias_is_b` and `a` otherwise,
1466    /// is `x`.
1467    fn alias_is_x(&self, alias_is_b: bool) -> bool {
1468        alias_is_b == self.x_is_b
1469    }
1470}
1471
1472/// Plans `a + b`.
1473fn plan(a: &Number, b: &Number) -> Plan {
1474    match (a.byte_order, b.byte_order) {
1475        (ByteOrder::BigEndian, ByteOrder::BigEndian) => plan_in::<true, true>(a, b),
1476        (ByteOrder::BigEndian, ByteOrder::LittleEndian) => plan_in::<true, false>(a, b),
1477        (ByteOrder::LittleEndian, ByteOrder::BigEndian) => plan_in::<false, true>(a, b),
1478        (ByteOrder::LittleEndian, ByteOrder::LittleEndian) => plan_in::<false, false>(a, b),
1479    }
1480}
1481
1482/// Plans `a + b` for `a` in the layout `A` and `b` in the layout `B` (`true` for big-endian).
1483///
1484/// An addition is planned here, a subtraction by [`plan_sub`], out of line: it needs more
1485/// registers, which an addition then does not have to save.
1486fn plan_in<const A: bool, const B: bool>(a: &Number, b: &Number) -> Plan {
1487    let la = significant_len::<A>(&a.value);
1488    let lb = significant_len::<B>(&b.value);
1489    let (pa, pb) = (end::<A>(&a.value), end::<B>(&b.value));
1490    let negative_a = a.negative && la > 0;
1491    let negative_b = b.negative && lb > 0;
1492    if negative_a == negative_b || la == 0 || lb == 0 {
1493        let x_is_b = lb > la;
1494        // SAFETY: the significant bytes of `a` and `b` are inside their vectors, and `x` is
1495        // the one with more of them.
1496        let carry = unsafe {
1497            if x_is_b {
1498                carries::<B, A>(pb, pa, lb, la)
1499            } else {
1500                carries::<A, B>(pa, pb, la, lb)
1501            }
1502        };
1503        return Plan {
1504            sub: false,
1505            x_is_b,
1506            la,
1507            lb,
1508            len: la.max(lb) + usize::from(carry),
1509            // The sign of the operands that are not zero.
1510            negative: negative_a || negative_b,
1511        };
1512    }
1513    // SAFETY: `pa` and `pb` are the least significant ends of the magnitudes of `a` and `b`,
1514    // of `la` and `lb` significant bytes, neither zero.
1515    unsafe { plan_sub::<A, B>(pa, pb, la, lb, negative_a) }
1516}
1517
1518/// Plans the difference of the magnitudes at the least significant ends `pa` and `pb` in the
1519/// layouts `A` and `B`, of `la` and `lb` significant bytes, for `a + b` with the signs of `a`
1520/// and `b` different: the sum has the sign of the larger magnitude, which `negative_a` gives
1521/// for `a`.
1522///
1523/// # Safety
1524///
1525/// The `la` significant bytes at `pa` and the `lb` at `pb` must be valid for reading, and
1526/// neither `la` nor `lb` may be 0.
1527#[inline(never)]
1528unsafe fn plan_sub<const A: bool, const B: bool>(
1529    pa: *const u8,
1530    pb: *const u8,
1531    la: usize,
1532    lb: usize,
1533    negative_a: bool,
1534) -> Plan {
1535    // The longer magnitude is the larger, and of two as long, the one with the larger byte
1536    // where they first differ from the top.
1537    let (x_is_b, top) = if la != lb {
1538        (lb > la, la.max(lb) - 1)
1539    } else {
1540        // SAFETY: both have `la` significant bytes.
1541        match unsafe { highest_difference::<A, B>(pa, pb, lb, la) } {
1542            // SAFETY: position `k` is below the significant length of both.
1543            Some(k) => (unsafe { get::<B>(pb, k) > get::<A>(pa, k) }, k),
1544            None => {
1545                return Plan {
1546                    sub: true,
1547                    x_is_b: false,
1548                    la,
1549                    lb,
1550                    len: 0,
1551                    negative: false,
1552                };
1553            }
1554        }
1555    };
1556    // SAFETY: `x` is the larger magnitude, and `top` the highest position at which `x` and
1557    // `y` differ, below the significant length of `x`.
1558    let len = unsafe {
1559        if A == B {
1560            // Which magnitude is the larger depends on their bytes: one copy of the scan, on
1561            // operands chosen without a branch.
1562            let (x, y, ly) = select_unpredictable(x_is_b, (pb, pa, la), (pa, pb, lb));
1563            difference_len::<A, B>(x, y, ly, top)
1564        } else if x_is_b {
1565            difference_len::<B, A>(pb, pa, la, top)
1566        } else {
1567            difference_len::<A, B>(pa, pb, lb, top)
1568        }
1569    };
1570    Plan {
1571        sub: true,
1572        x_is_b,
1573        la,
1574        lb,
1575        len,
1576        // The signs differ: `b` is negative exactly when `a` is not.
1577        negative: negative_a != x_is_b,
1578    }
1579}
1580
1581/// The significant length of the magnitude `v` in the layout `BE`: its length without the
1582/// zero bytes above its most significant nonzero byte, the leading ones big-endian and the
1583/// trailing ones little-endian. The bytes are read eight at a time while they are zero, so
1584/// a number in the shortest form costs one read, and a long run of zeros little more.
1585#[inline]
1586pub(super) fn significant_len<const BE: bool>(v: &[u8]) -> usize {
1587    let (p, len) = (v.as_ptr(), v.len());
1588    // SAFETY: every read lies inside `v`: big-endian `[i, i + 8)` with `i + 8 <= len` and `i`
1589    // with `i < len`; little-endian `[end - 8, end)` with `end >= 8` and `end - 1` with
1590    // `end > 0`, where `end <= len`.
1591    unsafe {
1592        if BE {
1593            let mut i = 0;
1594            while len - i >= 8 && p.add(i).cast::<[u8; 8]>().read() == [0; 8] {
1595                i += 8;
1596            }
1597            while i < len && *p.add(i) == 0 {
1598                i += 1;
1599            }
1600            len - i
1601        } else {
1602            let mut end = len;
1603            while end >= 8 && p.add(end - 8).cast::<[u8; 8]>().read() == [0; 8] {
1604                end -= 8;
1605            }
1606            while end > 0 && *p.add(end - 1) == 0 {
1607                end -= 1;
1608            }
1609            end
1610        }
1611    }
1612}
1613
1614/// Whether `x + y` carries out of the top position of `x`, for magnitudes of `lx >= ly`
1615/// significant bytes at the least significant ends `x` and `y`, in the layouts `X` and `Y`.
1616///
1617/// It is found from the top down, without computing the sum: the highest position whose
1618/// bytes do not add up to `0xFF` decides, with a carry if they add up to more. Above `ly`
1619/// only `x` has bytes, which can pass a carry on but not start one. The positions go eight at
1620/// a time, as `u64`s, while that many are left: such a group starts a carry if its two
1621/// values overflow, passes one on if they add up to `u64::MAX`, and stops one otherwise.
1622///
1623/// # Safety
1624///
1625/// The `lx` significant bytes of `x` and the `ly` of `y` must be valid for reading.
1626#[inline]
1627unsafe fn carries<const X: bool, const Y: bool>(
1628    x: *const u8,
1629    y: *const u8,
1630    lx: usize,
1631    ly: usize,
1632) -> bool {
1633    let mut p = lx;
1634    // SAFETY: every position read is below `p`, which is at most `lx`, and those of `y` are
1635    // below `ly` as well.
1636    unsafe {
1637        while p >= ly + 8 {
1638            if load::<X>(x, p - 8) != u64::MAX {
1639                return false;
1640            }
1641            p -= 8;
1642        }
1643        while p > ly {
1644            if get::<X>(x, p - 1) != 0xFF {
1645                return false;
1646            }
1647            p -= 1;
1648        }
1649        while p >= 8 {
1650            let (sum, overflow) = load::<X>(x, p - 8).overflowing_add(load::<Y>(y, p - 8));
1651            if overflow || sum != u64::MAX {
1652                return overflow;
1653            }
1654            p -= 8;
1655        }
1656        while p > 0 {
1657            let sum = u16::from(get::<X>(x, p - 1)) + u16::from(get::<Y>(y, p - 1));
1658            if sum != 0xFF {
1659                return sum > 0xFF;
1660            }
1661            p -= 1;
1662        }
1663    }
1664    false
1665}
1666
1667/// The highest position below `p` at which the magnitudes at the least significant ends `x`
1668/// and `y`, in the layouts `X` and `Y`, differ, the positions of `y` from `ly` up counting as
1669/// zeros; `None` if they agree on every position below `p`.
1670///
1671/// The positions go eight at a time while that many are left, as `u64`s whose most
1672/// significant byte is the highest position: the leading zeros of their difference (their
1673/// XOR) tell how far down from it the first difference lies.
1674///
1675/// # Safety
1676///
1677/// The positions of `x` below `p`, and those of `y` below `p` and `ly`, must be valid for
1678/// reading.
1679#[inline]
1680unsafe fn highest_difference<const X: bool, const Y: bool>(
1681    x: *const u8,
1682    y: *const u8,
1683    ly: usize,
1684    mut p: usize,
1685) -> Option<usize> {
1686    // SAFETY: every position read is below `p`, and those of `y` below `ly` as well.
1687    unsafe {
1688        // Above `ly`, the nonzero bytes of `x`.
1689        while p >= ly + 8 {
1690            let v = load::<X>(x, p - 8);
1691            if v != 0 {
1692                return Some(p - 1 - (v.leading_zeros() / 8) as usize);
1693            }
1694            p -= 8;
1695        }
1696        while p > ly {
1697            if get::<X>(x, p - 1) != 0 {
1698                return Some(p - 1);
1699            }
1700            p -= 1;
1701        }
1702        while p >= 8 {
1703            let v = load::<X>(x, p - 8) ^ load::<Y>(y, p - 8);
1704            if v != 0 {
1705                return Some(p - 1 - (v.leading_zeros() / 8) as usize);
1706            }
1707            p -= 8;
1708        }
1709        while p > 0 {
1710            if get::<X>(x, p - 1) != get::<Y>(y, p - 1) {
1711                return Some(p - 1);
1712            }
1713            p -= 1;
1714        }
1715    }
1716    None
1717}
1718
1719/// The significant length of `x - y` for magnitudes at the least significant ends `x` and
1720/// `y`, in the layouts `X` and `Y`, `x` the larger, `y` of `ly` significant bytes, and `k`
1721/// the highest position at which they differ.
1722///
1723/// Position `p` of the difference holds `x_p - y_p - b_p` modulo 256, where the borrow `b_p`
1724/// into it is 1 exactly when `x` has the smaller byte at the highest position below `p` at
1725/// which the two differ. Above `k` the difference is zero, and at `k`, where `x` has the
1726/// larger byte, it is not unless `x_k - y_k = 1`: the length is then `k + 1`.
1727///
1728/// Otherwise take the run of positions below `k` at which `x` has `0x00` and `y` has `0xFF`,
1729/// down to `p`, its lowest (`p = k` for an empty run). Such a position borrows whatever the
1730/// borrow into it is, and holds `1 - b` for a borrow `b` into it. So the positions of the run
1731/// above `p`, and `k` itself, hold 0 when the run is not empty, and position `p` holds
1732/// `1 - b_p`, as `k` does when it is empty. With `b_p = 0` the length is `p + 1`. With
1733/// `b_p = 1` it is `p`: `x` has the smaller byte at the highest position `q` below `p` at
1734/// which the two differ, and position `p - 1` is not zero, either because `q = p - 1`, where
1735/// `x_q - y_q` is between -254 and -1 (the pair there is not `(0x00, 0xFF)`), so that the
1736/// byte is between 1 and 255 whatever the borrow into it, or because the bytes agree from
1737/// `q + 1` to `p - 1` and the borrow out of `q` makes them `0xFF`. In both cases the length is
1738/// `p + 1 - b_p`.
1739///
1740/// The run is found eight positions at a time, and `b_p` by [`highest_difference`] from `p`
1741/// down: a run is read once however long it is (`256^n - (256^n - 1)` has one of `n`
1742/// positions), and only the eight positions at which it ends may be read twice.
1743///
1744/// # Safety
1745///
1746/// The significant bytes of `x` and the `ly` of `y` must be valid for reading, and `k` must be
1747/// below the significant length of `x`.
1748#[inline]
1749unsafe fn difference_len<const X: bool, const Y: bool>(
1750    x: *const u8,
1751    y: *const u8,
1752    ly: usize,
1753    k: usize,
1754) -> usize {
1755    // SAFETY: every position read is at most `k`, below the significant length of `x`; those
1756    // of `y` are read below `ly` only, as the run is looked for only when `k <= ly`.
1757    unsafe {
1758        if get::<X>(x, k).wrapping_sub(get_or_zero::<Y>(y, ly, k)) != 1 {
1759            return k + 1;
1760        }
1761        // Above `ly` the bytes of `y` are zeros, and no run starts.
1762        let mut p = k;
1763        if p <= ly {
1764            while p >= 8 {
1765                // Zero exactly where `x` has 0x00 and `y` has 0xFF.
1766                let v = load::<X>(x, p - 8) | !load::<Y>(y, p - 8);
1767                if v != 0 {
1768                    p -= (v.leading_zeros() / 8) as usize;
1769                    break;
1770                }
1771                p -= 8;
1772            }
1773            while p > 0 && get::<X>(x, p - 1) == 0 && get::<Y>(y, p - 1) == 0xFF {
1774                p -= 1;
1775            }
1776        }
1777        let borrow = match highest_difference::<X, Y>(x, y, ly, p) {
1778            Some(q) => get::<X>(x, q) < get_or_zero::<Y>(y, ly, q),
1779            None => false,
1780        };
1781        p + 1 - usize::from(borrow)
1782    }
1783}
1784
1785// Building the sum
1786
1787/// Builds the planned sum of `a` and `b` in one new vector, of exactly its length, in the
1788/// byte order of `a`.
1789///
1790/// When `b` is in the other byte order, its low bytes, those the sum needs, are first copied
1791/// into the new vector, in the byte order of the sum and where they belong in it, and the sum
1792/// is then computed over that copy in place.
1793///
1794/// # Safety
1795///
1796/// `plan` must be the plan of `a + b`.
1797unsafe fn sum_new(a: &Number, b: &Number, plan: &Plan) -> Vec<u8> {
1798    if plan.len == 0 {
1799        return vec![0];
1800    }
1801    // SAFETY: as the caller guarantees; the operands are each read in their own layout.
1802    unsafe {
1803        match (a.byte_order, b.byte_order) {
1804            (ByteOrder::BigEndian, ByteOrder::BigEndian) => {
1805                new_from::<true>(end::<true>(&a.value), end::<true>(&b.value), plan)
1806            }
1807            (ByteOrder::LittleEndian, ByteOrder::LittleEndian) => {
1808                new_from::<false>(end::<false>(&a.value), end::<false>(&b.value), plan)
1809            }
1810            (ByteOrder::BigEndian, ByteOrder::LittleEndian) => {
1811                new_with_copy::<true>(end::<true>(&a.value), &b.value, plan)
1812            }
1813            (ByteOrder::LittleEndian, ByteOrder::BigEndian) => {
1814                new_with_copy::<false>(end::<false>(&a.value), &b.value, plan)
1815            }
1816        }
1817    }
1818}
1819
1820/// Builds the planned sum in a new vector in the layout `BE`, from the operands at the least
1821/// significant ends `a` and `b` in that layout.
1822///
1823/// # Safety
1824///
1825/// `plan` must be the plan of the sum of `a` and `b`, and not zero.
1826unsafe fn new_from<const BE: bool>(a: *const u8, b: *const u8, plan: &Plan) -> Vec<u8> {
1827    let len = plan.len;
1828    let mut v = Vec::<u8>::with_capacity(len);
1829    let base = v.as_mut_ptr();
1830    // SAFETY: the vector has room for the `len` bytes of the sum, and as it is apart from the
1831    // operands, `compute` writes every one of them. The end of the sum, `base + len`
1832    // big-endian, is inside or one past the allocation.
1833    unsafe {
1834        let r = if BE { base.add(len) } else { base };
1835        let (x, y) = select_unpredictable(plan.x_is_b, (b, a), (a, b));
1836        compute_new::<BE>(r, x, y, plan);
1837        v.set_len(len);
1838    }
1839    v
1840}
1841
1842/// Builds the planned sum in a new vector in the layout `BE`, from `a` at its least
1843/// significant end in that layout and `b` in the other byte order: the low positions of `b`
1844/// that the sum needs are copied into the vector, where they belong in the sum, and the sum is
1845/// computed over the copy in place.
1846///
1847/// # Safety
1848///
1849/// `plan` must be the plan of the sum of `a` and `b`, and not zero.
1850unsafe fn new_with_copy<const BE: bool>(a: *const u8, b: &[u8], plan: &Plan) -> Vec<u8> {
1851    let len = plan.len;
1852    // No position of `b` at or above the length of the sum changes the sum.
1853    let m = plan.lb.min(len);
1854    let mut v = Vec::<u8>::with_capacity(len);
1855    let base = v.as_mut_ptr();
1856    let copy_is_x = plan.alias_is_x(true);
1857    // The copy is `x` only when `b` has at least as many significant bytes as `a`, so that it
1858    // holds all of `x` that is kept: `lx` bytes for a sum, `len` for a difference.
1859    debug_assert!(!copy_is_x || m == if plan.sub { len } else { plan.lx() });
1860    // SAFETY: the vector has room for the `len` bytes of the sum. `b` holds its `m <= lb`
1861    // lowest positions at its start if it is little-endian and at its end otherwise, and they
1862    // go to positions `0..m` of the sum: `[len - m, len)` big-endian, `[0, m)` little-endian.
1863    // `compute` then reads the copy as an operand that is the output exactly, and writes the
1864    // positions of the sum that differ from it: all of them when the copy is `y`; when it is
1865    // `x`, those below the position at which the carry (borrow) out of `y` stops, the copy
1866    // keeping the rest, which it holds as `m` is all of `x` that the sum needs. So every byte
1867    // below `len` is written before the length is set.
1868    unsafe {
1869        if BE {
1870            copy_reversed(base.add(len - m), b.as_ptr(), m);
1871        } else {
1872            copy_reversed(base, b.as_ptr().add(b.len() - m), m);
1873        }
1874        let r = if BE { base.add(len) } else { base };
1875        let copy = r.cast_const();
1876        let (x, y) = select_unpredictable(copy_is_x, (copy, a), (a, copy));
1877        compute_new::<BE>(r, x, y, plan);
1878        v.set_len(len);
1879    }
1880    v
1881}
1882
1883/// Builds the planned sum in `v`, the vector of one of the operands (`b` if `alias_is_b`, `a`
1884/// otherwise), in the layout of `order`; `other` is the other operand. `reversed` says whether
1885/// one of them was reversed into `order` after the plan was made.
1886///
1887/// It is inlined into the operators' general paths, with everything under it but the kernels
1888/// for many limbs: below a few hundred bytes the calls cost such a sum a sixth of its time. A
1889/// long difference goes out of line instead, to [`long_in_vector`], unless an operand was
1890/// reversed: the reversal takes longer than the plan, which is then done before the kernel
1891/// could start, and the branches of a long difference would only add their mispredictions (3 to
1892/// 4 % from 512 bytes, measured).
1893///
1894/// # Safety
1895///
1896/// `plan` must be the plan of the sum, both operands must be in `order` (unless the sum is
1897/// zero), and the capacity of `v` must have room for the sum.
1898#[inline(always)]
1899unsafe fn sum_in(
1900    v: &mut Vec<u8>,
1901    order: ByteOrder,
1902    alias_is_b: bool,
1903    other: &[u8],
1904    plan: &Plan,
1905    reversed: bool,
1906) {
1907    // SAFETY: as the caller guarantees: for a zero sum, the capacity of `v` holds one byte.
1908    unsafe {
1909        if plan.len == 0 {
1910            *v.as_mut_ptr() = 0;
1911            v.set_len(1);
1912            return;
1913        }
1914        match order {
1915            ByteOrder::BigEndian if !reversed && long_difference(plan, LONG_DIFFERENCE_BE) => {
1916                long_in_vector::<true>(v, alias_is_b, end::<true>(other), plan)
1917            }
1918            ByteOrder::LittleEndian if !reversed && long_difference(plan, LONG_DIFFERENCE_LE) => {
1919                long_in_vector::<false>(v, alias_is_b, end::<false>(other), plan)
1920            }
1921            ByteOrder::BigEndian => {
1922                in_vector::<true, false>(v, alias_is_b, end::<true>(other), plan)
1923            }
1924            ByteOrder::LittleEndian => {
1925                in_vector::<false, false>(v, alias_is_b, end::<false>(other), plan)
1926            }
1927        }
1928    }
1929}
1930
1931/// [`sum_in`] in the layout `BE`, with `other` the least significant end of the other operand,
1932/// for a sum that is not zero; with `LONG`, for a long difference, whose operands are taken by
1933/// [`difference_in`].
1934///
1935/// Little-endian the positions of the sum are those of the operand in `v`, from its start;
1936/// the bytes from its length up are its spare capacity, written and never read. Big-endian
1937/// the sum ends at its own length: a longer sum lies above the operand, which the kernels
1938/// allow, and a shorter one (a difference, or an operand with zero bytes above its most
1939/// significant one) is first given the low bytes it needs from the operand, moved down to end
1940/// where the sum ends. A byte of a sum or a difference depends only on the bytes at or below
1941/// its position, so the bytes of the operand from the length of the sum up are never needed.
1942///
1943/// # Safety
1944///
1945/// As for [`sum_in`], with `other` valid for reading the significant bytes of the other
1946/// operand, and the sum not zero.
1947#[inline(always)]
1948unsafe fn in_vector<const BE: bool, const LONG: bool>(
1949    v: &mut Vec<u8>,
1950    alias_is_b: bool,
1951    other: *const u8,
1952    plan: &Plan,
1953) {
1954    let (old_len, len) = (v.len(), plan.len);
1955    // Every pointer into the vector comes from this one call.
1956    let base = v.as_mut_ptr();
1957    // SAFETY: the capacity of `v` is at least `len`, and its first `old_len` bytes hold the
1958    // operand, so `base + len` and `base + old_len` are inside the allocation or one past it.
1959    // A shorter big-endian sum moves the `m` low bytes of the operand from the end of its
1960    // bytes to the end of the sum, within them. `compute` reads the operand where it now is,
1961    // as the output exactly, or below it big-endian, and writes the positions of the sum that
1962    // differ from it, keeping the operand's own bytes above them when it is `x` and the output
1963    // exactly: those below `old_len`, or among the `m` moved, which are all of `x` that the sum
1964    // needs (`lx` bytes for a sum, `len` for a difference). So every byte below `len` holds the
1965    // sum before the length is set.
1966    unsafe {
1967        let (r, alias) = if !BE {
1968            (base, base)
1969        } else if len >= old_len {
1970            (base.add(len), base.add(old_len))
1971        } else {
1972            let m = if alias_is_b { plan.lb } else { plan.la }.min(len);
1973            move_down(base.add(old_len), base.add(len), m);
1974            (base.add(len), base.add(len))
1975        };
1976        let alias = alias.cast_const();
1977        let alias_is_x = plan.alias_is_x(alias_is_b);
1978        if LONG {
1979            // The significant lengths of the operand in `v` and of the other one.
1980            let (l_alias, l_other) = if alias_is_b {
1981                (plan.lb, plan.la)
1982            } else {
1983                (plan.la, plan.lb)
1984            };
1985            if alias_is_x {
1986                difference_in::<BE, false>(r, alias, other, l_other, len);
1987            } else {
1988                difference_in::<BE, true>(r, alias, other, l_alias, len);
1989            }
1990        } else {
1991            let (x, y) = select_unpredictable(alias_is_x, (alias, other), (other, alias));
1992            compute::<BE>(r, x, y, plan);
1993        }
1994        v.set_len(len);
1995    }
1996}
1997
1998/// Whether the planned sum is a long difference: a subtraction of magnitudes of at least `long`
1999/// significant bytes each.
2000#[inline(always)]
2001fn long_difference(plan: &Plan, long: usize) -> bool {
2002    plan.sub && plan.la.min(plan.lb) >= long
2003}
2004
2005/// [`in_vector`] for a long difference, out of line, so that the code of the other sums is as it
2006/// would be without it.
2007///
2008/// # Safety
2009///
2010/// As for [`in_vector`], with the plan that of a long difference.
2011#[inline(never)]
2012unsafe fn long_in_vector<const BE: bool>(
2013    v: &mut Vec<u8>,
2014    alias_is_b: bool,
2015    other: *const u8,
2016    plan: &Plan,
2017) {
2018    // SAFETY: as the caller guarantees.
2019    unsafe { in_vector::<BE, true>(v, alias_is_b, other, plan) }
2020}
2021
2022/// Moves the `m` bytes that end at `from` down to end at `to`, for the big-endian sum that is
2023/// shorter than its operand's vector. Out of line and cold, so that the call does not cost
2024/// the other sums the registers it needs.
2025///
2026/// # Safety
2027///
2028/// Both ranges of `m` bytes must lie in one allocation, `to <= from`.
2029#[cold]
2030#[inline(never)]
2031unsafe fn move_down(from: *mut u8, to: *mut u8, m: usize) {
2032    // SAFETY: as the caller guarantees; `ptr::copy` allows the ranges to overlap.
2033    unsafe { ptr::copy(from.sub(m), to.sub(m), m) }
2034}
2035
2036// Computing the sum
2037
2038/// Writes the planned sum of `x` and `y`, magnitudes at their least significant ends in the
2039/// layout `BE`, to the output whose least significant end is `r`: positions `0..plan.len`, of
2040/// which, when the output is `x` itself (`r == x`), it keeps those above the position at which
2041/// the carry (borrow) out of `y` stops as they are, the bytes of `x`.
2042///
2043/// # Safety
2044///
2045/// `x` and `y` must be valid for reading their significant bytes, and `r` for writing the
2046/// `plan.len` bytes of the sum. The output must be apart from both, equal to one or both
2047/// (`r == x` or `r == y`), or, big-endian, end `s >= 1` bytes above one of them (`r = x + s` or
2048/// `r = y + s`), as a sum that grows in the vector of its operand does. When `r == x`, the
2049/// output must hold `x` initialised up to its significant length for a sum, and up to
2050/// `plan.len` for a difference.
2051#[inline(always)]
2052unsafe fn compute<const BE: bool>(r: *mut u8, x: *const u8, y: *const u8, plan: &Plan) {
2053    // SAFETY: as the caller guarantees.
2054    unsafe {
2055        if plan.sub {
2056            sub_into::<BE>(r, x, y, plan.ly(), plan.len);
2057        } else {
2058            add_into::<BE>(r, x, y, plan.lx(), plan.ly(), plan.len);
2059        }
2060    }
2061}
2062
2063/// [`compute`] for a sum in a new vector, out of line: there the allocation costs more than the
2064/// call, and one copy of the computation serves both ways to build a new vector.
2065///
2066/// # Safety
2067///
2068/// As for [`compute`].
2069#[inline(never)]
2070unsafe fn compute_new<const BE: bool>(r: *mut u8, x: *const u8, y: *const u8, plan: &Plan) {
2071    // SAFETY: as the caller guarantees.
2072    unsafe { compute::<BE>(r, x, y, plan) }
2073}
2074
2075/// Writes the `len` bytes of `x + y` to `r`, all least significant ends in the layout `BE`,
2076/// for magnitudes of `lx >= ly` significant bytes whose sum is `len` bytes long, `lx` or
2077/// `lx + 1`.
2078///
2079/// The whole limbs of `y` go to the kernel, and the bytes of `y` above them follow, as one
2080/// partial limb when there are at least three and a whole limb below them, and one at a time
2081/// otherwise. Above `y`, the carry goes on through `x` a limb at a time while it lasts, and
2082/// the rest of `x` is copied, unless the output is `x` itself. Each position is read before
2083/// it is written, from the least significant one up. The top byte, 1 when the sum carries out
2084/// of `x`, is written without a branch.
2085///
2086/// # Safety
2087///
2088/// As for [`compute`].
2089#[inline(always)]
2090unsafe fn add_into<const BE: bool>(
2091    r: *mut u8,
2092    x: *const u8,
2093    y: *const u8,
2094    lx: usize,
2095    ly: usize,
2096    len: usize,
2097) {
2098    let n = ly / 8;
2099    // SAFETY: the positions of `x` read are below `lx`, those of `y` below `ly`, and those of
2100    // `r` written below `len`; each position of the inputs is read before the same position of
2101    // the output is written, so an output equal to an input, or above it, overwrites only
2102    // what has been read.
2103    unsafe {
2104        let carry = add_n::<BE>(r, x, y, n, false);
2105        let mut carry = rest_of_y::<BE, false>(r, x, y, n, ly, carry);
2106        // With as many bytes as `y`, `x` has no more positions, and only the carry out of the
2107        // top is looked at.
2108        if ly < lx {
2109            let p;
2110            (p, carry) = carry_on::<BE, false>(r, x, ly, lx, carry);
2111            if !carry {
2112                copy_rest::<BE>(r, x, p, lx);
2113            }
2114        }
2115        debug_assert_eq!(len, lx + usize::from(carry), "the planned length is wrong");
2116        // A carry out of the top is a coin toss for random operands of the same length. The
2117        // top byte is chosen by the planned length rather than by `carry`: LLVM turns a select
2118        // on `carry` back into a branch, merged with the branches of `carry_on` on it. Without
2119        // a carry the byte under it is written again.
2120        let top = get::<BE>(r.cast_const(), lx - 1);
2121        set::<BE>(r, len - 1, select_unpredictable(len > lx, 1, top));
2122    }
2123}
2124
2125/// Writes the `len` bytes of `x - y` to `r`, all least significant ends in the layout `BE`,
2126/// for a larger magnitude `x`, `y` of `ly` significant bytes, and a difference of `len`
2127/// significant bytes.
2128///
2129/// As [`add_into`] does, over the positions below `len` only: those of `y` above it do not
2130/// change the difference, and the borrow out of the top position, if any, is cancelled by the
2131/// positions of `x` above it.
2132///
2133/// # Safety
2134///
2135/// As for [`compute`].
2136#[inline(always)]
2137unsafe fn sub_into<const BE: bool>(r: *mut u8, x: *const u8, y: *const u8, ly: usize, len: usize) {
2138    // SAFETY: as the caller guarantees.
2139    unsafe { sub_below::<BE>(r, x, y, ly.min(len), len) }
2140}
2141
2142/// The significant length from which a little-endian difference built in the vector of one of
2143/// its operands, both at least this long, is long (see [`difference_in`]): the length from which
2144/// the kernels run several carry chains.
2145const LONG_DIFFERENCE_LE: usize = 256;
2146
2147/// [`LONG_DIFFERENCE_LE`] for big-endian operands.
2148const LONG_DIFFERENCE_BE: usize = 512;
2149
2150/// [`sub_into`] for a long difference built in the vector of an operand, at the least
2151/// significant end `alias` in the layout `BE`, from the other operand at `other`: `x` is `alias`
2152/// and `y` is `other`, or the other way round with `SWAPPED`. `ly` is the significant length of
2153/// `y`, and `len` that of the difference.
2154///
2155/// The other sums take `x` and `y` without a branch, as which magnitude is the larger is a coin
2156/// toss for random operands of the same length. The kernel then cannot load a limb before the
2157/// plan has read and compared the top limbs of both operands: its addresses come from that
2158/// choice, and the number of limbs it takes from the length of the difference (`ly` is cut to
2159/// `len`), which the plan finds from those limbs too. Here both come from branches instead: `x`
2160/// from which of the two copies of this function is called, which LLVM cannot merge into one
2161/// call with chosen arguments as it can calls of one function, and the number of limbs from the
2162/// branch on `ly <= len`, a difference shorter than `y` taking the cold path. A predicted branch
2163/// lets the kernel start while the plan is still reading; a mispredicted one costs about what
2164/// the wait would have.
2165///
2166/// Measured in place on an Apple M4 Max as `a += &b` with opposite signs, over 512 pairs of
2167/// operands in the second-level cache: with a predictable larger operand, 12 cycles fewer at 256
2168/// bytes little-endian and 19 to 23 fewer from 320 up, and 7 to 23 fewer big-endian from 512;
2169/// with a random one, which the branch mispredicts half the time, 10 more at 256 bytes and 3 more
2170/// at 320 little-endian, but 11 to 13 fewer from 512, and 3 to 19 fewer big-endian from 512.
2171/// With the operands in the first-level cache, 1 to 24 cycles fewer from 256 bytes. Shorter, a
2172/// random larger operand cost 17 to 23 cycles more (64 to 192 bytes), and big-endian, whose
2173/// loop is bound by how many instructions the core issues, saved nothing at 256 and 320 bytes.
2174///
2175/// # Safety
2176///
2177/// As for [`compute`], with the operands of `x` and `y` as said.
2178#[inline(never)]
2179unsafe fn difference_in<const BE: bool, const SWAPPED: bool>(
2180    r: *mut u8,
2181    alias: *const u8,
2182    other: *const u8,
2183    ly: usize,
2184    len: usize,
2185) {
2186    let (x, y) = if SWAPPED {
2187        (other, alias)
2188    } else {
2189        (alias, other)
2190    };
2191    // SAFETY: as the caller guarantees; `sub_below` takes the positions of `y` below `len`.
2192    unsafe {
2193        if ly <= len {
2194            sub_below::<BE>(r, x, y, ly, len);
2195        } else {
2196            short_difference::<BE>(r, x, y, len);
2197        }
2198    }
2199}
2200
2201/// [`sub_below`] for a long difference shorter than `y`, out of line and cold, so that the
2202/// common case takes the length of `y`, not one that depends on the bytes of the operands.
2203///
2204/// # Safety
2205///
2206/// As for [`sub_into`].
2207#[cold]
2208#[inline(never)]
2209unsafe fn short_difference<const BE: bool>(r: *mut u8, x: *const u8, y: *const u8, len: usize) {
2210    // SAFETY: as the caller guarantees.
2211    unsafe { sub_below::<BE>(r, x, y, len, len) }
2212}
2213
2214/// [`sub_into`] for `ly <= len`: every position of `y` it takes is below the length of the
2215/// difference.
2216///
2217/// # Safety
2218///
2219/// As for [`sub_into`], with `ly <= len`.
2220#[inline(always)]
2221unsafe fn sub_below<const BE: bool>(r: *mut u8, x: *const u8, y: *const u8, ly: usize, len: usize) {
2222    let n = ly / 8;
2223    // SAFETY: as in `add_into`, with every position below `len`, which is at most the
2224    // significant length of `x`.
2225    unsafe {
2226        let borrow = sub_n::<BE>(r, x, y, n, false);
2227        let borrow = rest_of_y::<BE, true>(r, x, y, n, ly, borrow);
2228        if ly < len {
2229            let (p, _) = carry_on::<BE, true>(r, x, ly, len, borrow);
2230            copy_rest::<BE>(r, x, p, len);
2231        }
2232        debug_assert!(
2233            get::<BE>(r.cast_const(), len - 1) != 0,
2234            "the planned length is wrong"
2235        );
2236    }
2237}
2238
2239/// Adds (subtracts, with `SUB`) the positions of `y` from `8 * n` up to `ly`, above the `n`
2240/// whole limbs the kernel took, with the carry (borrow) `carry` out of them; returns the
2241/// carry (borrow) out of position `ly - 1`.
2242///
2243/// From three of them, and with a whole limb below, they go as one partial limb: the eight
2244/// positions that end at `ly` are read from `x` and `y` and shifted down to the new ones,
2245/// and written back over the output's last whole limb, whose top bytes the kernel wrote and
2246/// which are read back for that. Below three, one at a time.
2247///
2248/// # Safety
2249///
2250/// As for [`add_into`] (for [`sub_into`] with `SUB`), with `n = ly / 8` and the kernel's
2251/// limbs written.
2252#[inline(always)]
2253unsafe fn rest_of_y<const BE: bool, const SUB: bool>(
2254    r: *mut u8,
2255    x: *const u8,
2256    y: *const u8,
2257    n: usize,
2258    ly: usize,
2259    mut carry: bool,
2260) -> bool {
2261    let mut p = 8 * n;
2262    let rem = ly - p;
2263    if rem == 0 {
2264        return carry;
2265    }
2266    // SAFETY: positions `ly - 8..ly` are below `ly` and, with `n > 0`, at or above 0; those of
2267    // the output below `p` are the kernel's, written and so initialised. Every other position
2268    // is below `ly`.
2269    unsafe {
2270        if rem >= 3 && n > 0 {
2271            let shift = 8 * (8 - rem) as u32;
2272            let (xs, ys) = (
2273                load::<BE>(x, ly - 8) >> shift,
2274                load::<BE>(y, ly - 8) >> shift,
2275            );
2276            let c = u64::from(carry);
2277            let s = if SUB {
2278                xs.wrapping_sub(ys).wrapping_sub(c)
2279            } else {
2280                xs + ys + c
2281            };
2282            carry = (s >> (8 * rem)) & 1 != 0;
2283            let below = load::<BE>(r.cast_const(), p - 8) >> (8 * rem);
2284            store::<BE>(r, ly - 8, below | (s << shift));
2285        } else {
2286            while p < ly {
2287                let (xb, yb, c) = (get::<BE>(x, p), get::<BE>(y, p), u16::from(carry));
2288                let s = if SUB {
2289                    u16::from(xb).wrapping_sub(u16::from(yb)).wrapping_sub(c)
2290                } else {
2291                    u16::from(xb) + u16::from(yb) + c
2292                };
2293                set::<BE>(r, p, s as u8);
2294                carry = s >> 8 != 0;
2295                p += 1;
2296            }
2297        }
2298    }
2299    carry
2300}
2301
2302/// Takes the carry (borrow, with `SUB`) `carry` on from position `p` through the positions of
2303/// `x` below `top` that pass it on, `0xFF` (`0x00`), writing them to `r`: a limb at a time,
2304/// then a byte at a time. Returns the position at which it stopped, `top` if it did not, and
2305/// whether a carry is left.
2306///
2307/// The carry out of `y` is a coin toss for random operands, so the first step takes it without
2308/// a branch: the limb at `p`, plus or minus the carry, or, with fewer than eight positions left
2309/// and a whole limb under `p`, those positions as one partial limb, read from below their start
2310/// and shifted, and written back over the output's limb under `p`, which is read back for that,
2311/// as in [`rest_of_y`]. Only a carry that gets through that step, whose limb passed it on,
2312/// goes further.
2313///
2314/// # Safety
2315///
2316/// As for [`add_into`] (for [`sub_into`] with `SUB`), with `p <= top` and the positions of the
2317/// output below `p` written.
2318#[inline(always)]
2319unsafe fn carry_on<const BE: bool, const SUB: bool>(
2320    r: *mut u8,
2321    x: *const u8,
2322    mut p: usize,
2323    top: usize,
2324    mut carry: bool,
2325) -> (usize, bool) {
2326    let passes = if SUB { 0 } else { u64::MAX };
2327    // SAFETY: every position read and written is below `top`; the partial limb reads positions
2328    // `top - 8..top` of `x`, at or above 0 as `top > p >= 8`, and `p - 8..p` of the output,
2329    // which are written.
2330    unsafe {
2331        let c = u64::from(carry);
2332        if top - p >= 8 {
2333            let v = load::<BE>(x, p);
2334            store::<BE>(
2335                r,
2336                p,
2337                if SUB {
2338                    v.wrapping_sub(c)
2339                } else {
2340                    v.wrapping_add(c)
2341                },
2342            );
2343            carry &= v == passes;
2344            p += 8;
2345        } else if p < top && p >= 8 {
2346            let m = top - p;
2347            let shift = 8 * (8 - m) as u32;
2348            let v = load::<BE>(x, top - 8) >> shift;
2349            let s = if SUB { v.wrapping_sub(c) } else { v + c };
2350            let below = load::<BE>(r.cast_const(), p - 8) >> (8 * m);
2351            store::<BE>(r, top - 8, below | (s << shift));
2352            return (top, (s >> (8 * m)) & 1 != 0);
2353        }
2354        while carry && top - p >= 8 {
2355            let v = load::<BE>(x, p);
2356            store::<BE>(
2357                r,
2358                p,
2359                if SUB {
2360                    v.wrapping_sub(1)
2361                } else {
2362                    v.wrapping_add(1)
2363                },
2364            );
2365            carry = v == passes;
2366            p += 8;
2367        }
2368        while carry && p < top {
2369            let v = get::<BE>(x, p);
2370            set::<BE>(
2371                r,
2372                p,
2373                if SUB {
2374                    v.wrapping_sub(1)
2375                } else {
2376                    v.wrapping_add(1)
2377                },
2378            );
2379            carry = v == passes as u8;
2380            p += 1;
2381        }
2382    }
2383    (p, carry)
2384}
2385
2386/// Copies positions `p..top` of `x` to the output `r`, unless the output is `x` itself: from
2387/// 16 bytes with `ptr::copy`, and below that inline, with two loads and two stores of 8, 4 or
2388/// 2 bytes that overlap, or one of a byte, the loads first.
2389///
2390/// # Safety
2391///
2392/// The positions of `x` below `top` must be valid for reading, and those of `r` for writing;
2393/// the two may overlap.
2394#[inline(always)]
2395unsafe fn copy_rest<const BE: bool>(r: *mut u8, x: *const u8, p: usize, top: usize) {
2396    if p < top && !ptr::eq(r.cast_const(), x) {
2397        let m = top - p;
2398        // SAFETY: the `m` bytes from `src` and `dst` are positions `p..top` of `x` and `r`;
2399        // each load and store below lies within them, and the loads come first.
2400        unsafe {
2401            let (src, dst) = if BE {
2402                (x.sub(top), r.sub(top))
2403            } else {
2404                (x.add(p), r.add(p))
2405            };
2406            if m >= 16 {
2407                ptr::copy(src, dst, m);
2408            } else if m >= 8 {
2409                let (u, v) = (read::<8>(src), read::<8>(src.add(m - 8)));
2410                write::<8>(dst, u);
2411                write::<8>(dst.add(m - 8), v);
2412            } else if m >= 4 {
2413                let (u, v) = (read::<4>(src), read::<4>(src.add(m - 4)));
2414                write::<4>(dst, u);
2415                write::<4>(dst.add(m - 4), v);
2416            } else if m >= 2 {
2417                let (u, v) = (read::<2>(src), read::<2>(src.add(m - 2)));
2418                write::<2>(dst, u);
2419                write::<2>(dst.add(m - 2), v);
2420            } else {
2421                *dst = *src;
2422            }
2423        }
2424    }
2425}
2426
2427/// The kernel `r = x + y + carry` over `n` limbs in the layout `BE`; returns the carry out.
2428///
2429/// # Safety
2430///
2431/// As for the kernels: `x` and `y` valid for reading and `r` for writing `n` limbs from their
2432/// least significant ends, the output apart from the inputs, equal to them, or, big-endian,
2433/// above them.
2434#[inline(always)]
2435unsafe fn add_n<const BE: bool>(
2436    r: *mut u8,
2437    x: *const u8,
2438    y: *const u8,
2439    n: usize,
2440    carry: bool,
2441) -> bool {
2442    // SAFETY: as the caller guarantees.
2443    unsafe {
2444        if BE {
2445            add_n_be(r, x, y, n, carry)
2446        } else {
2447            add_n_le(r, x, y, n, carry)
2448        }
2449    }
2450}
2451
2452/// The kernel `r = x - y - borrow` over `n` limbs in the layout `BE`; returns the borrow out.
2453///
2454/// # Safety
2455///
2456/// As for [`add_n`].
2457#[inline(always)]
2458unsafe fn sub_n<const BE: bool>(
2459    r: *mut u8,
2460    x: *const u8,
2461    y: *const u8,
2462    n: usize,
2463    borrow: bool,
2464) -> bool {
2465    // SAFETY: as the caller guarantees.
2466    unsafe {
2467        if BE {
2468            sub_n_be(r, x, y, n, borrow)
2469        } else {
2470            sub_n_le(r, x, y, n, borrow)
2471        }
2472    }
2473}
2474
2475// Positions
2476
2477/// The least significant end of the magnitude in `v` in the layout `BE`: the address of its
2478/// first byte little-endian, and the address one past its last byte big-endian.
2479#[inline(always)]
2480fn end<const BE: bool>(v: &[u8]) -> *const u8 {
2481    if BE { v.as_ptr_range().end } else { v.as_ptr() }
2482}
2483
2484/// Reads position `p` of the magnitude at the least significant end `end` in the layout `BE`:
2485/// the byte at `end + p` little-endian, at `end - 1 - p` big-endian.
2486///
2487/// # Safety
2488///
2489/// The byte must be valid for reading.
2490#[inline(always)]
2491unsafe fn get<const BE: bool>(end: *const u8, p: usize) -> u8 {
2492    // SAFETY: as the caller guarantees.
2493    unsafe { if BE { *end.sub(p + 1) } else { *end.add(p) } }
2494}
2495
2496/// Reads position `p` of the magnitude of `len` significant bytes at the least significant end
2497/// `end` in the layout `BE`, as [`get`] does, or 0 from `len` up.
2498///
2499/// # Safety
2500///
2501/// The significant bytes must be valid for reading.
2502#[inline(always)]
2503unsafe fn get_or_zero<const BE: bool>(end: *const u8, len: usize, p: usize) -> u8 {
2504    if p < len {
2505        // SAFETY: as the caller guarantees, with `p < len`.
2506        unsafe { get::<BE>(end, p) }
2507    } else {
2508        0
2509    }
2510}
2511
2512/// Writes position `p` of the magnitude at the least significant end `end` in the layout
2513/// `BE`, as [`get`] reads it.
2514///
2515/// # Safety
2516///
2517/// The byte must be valid for writing.
2518#[inline(always)]
2519unsafe fn set<const BE: bool>(end: *mut u8, p: usize, v: u8) {
2520    // SAFETY: as the caller guarantees.
2521    unsafe {
2522        if BE {
2523            *end.sub(p + 1) = v;
2524        } else {
2525            *end.add(p) = v;
2526        }
2527    }
2528}
2529
2530/// Reads positions `p..p + 8` of the magnitude at the least significant end `end` in the
2531/// layout `BE` as a `u64` whose least significant byte is position `p`: the eight bytes from
2532/// `end + p` as a little-endian `u64`, or the eight bytes up to `end - p` as a big-endian one.
2533///
2534/// # Safety
2535///
2536/// The eight bytes must be valid for reading; they need no alignment.
2537#[inline(always)]
2538unsafe fn load<const BE: bool>(end: *const u8, p: usize) -> u64 {
2539    // SAFETY: as the caller guarantees; `[u8; 8]` is aligned at any address.
2540    unsafe {
2541        if BE {
2542            u64::from_be_bytes(end.sub(p + 8).cast::<[u8; 8]>().read())
2543        } else {
2544            u64::from_le_bytes(end.add(p).cast::<[u8; 8]>().read())
2545        }
2546    }
2547}
2548
2549/// Writes positions `p..p + 8` of the magnitude at the least significant end `end` in the
2550/// layout `BE`, as [`load`] reads them.
2551///
2552/// # Safety
2553///
2554/// The eight bytes must be valid for writing; they need no alignment.
2555#[inline(always)]
2556unsafe fn store<const BE: bool>(end: *mut u8, p: usize, v: u64) {
2557    // SAFETY: as the caller guarantees; `[u8; 8]` is aligned at any address.
2558    unsafe {
2559        if BE {
2560            end.sub(p + 8).cast::<[u8; 8]>().write(v.to_be_bytes());
2561        } else {
2562            end.add(p).cast::<[u8; 8]>().write(v.to_le_bytes());
2563        }
2564    }
2565}
2566
2567/// Copies the `m` bytes at `src` to `dst` in the reverse order, `dst[i] = src[m - 1 - i]`,
2568/// eight at a time while that many are left.
2569///
2570/// # Safety
2571///
2572/// `src` must be valid for reading and `dst` for writing `m` bytes, and they must not overlap.
2573#[inline(always)]
2574unsafe fn copy_reversed(dst: *mut u8, src: *const u8, m: usize) {
2575    let mut i = 0;
2576    // SAFETY: every byte read is below `src + m` and every byte written below `dst + m`.
2577    unsafe {
2578        while m - i >= 8 {
2579            let bytes = src.add(m - i - 8).cast::<[u8; 8]>().read();
2580            dst.add(i)
2581                .cast::<[u8; 8]>()
2582                .write(u64::from_be_bytes(bytes).to_le_bytes());
2583            i += 8;
2584        }
2585        while i < m {
2586            *dst.add(i) = *src.add(m - 1 - i);
2587            i += 1;
2588        }
2589    }
2590}
2591
2592/// Reads the `N` bytes at `p`.
2593///
2594/// # Safety
2595///
2596/// The bytes must be valid for reading; they need no alignment.
2597#[inline(always)]
2598pub(super) unsafe fn read<const N: usize>(p: *const u8) -> [u8; N] {
2599    // SAFETY: as the caller guarantees; `[u8; N]` is aligned at any address.
2600    unsafe { p.cast::<[u8; N]>().read() }
2601}
2602
2603/// Writes the `N` bytes `v` at `p`.
2604///
2605/// # Safety
2606///
2607/// The bytes must be valid for writing; they need no alignment.
2608#[inline(always)]
2609pub(super) unsafe fn write<const N: usize>(p: *mut u8, v: [u8; N]) {
2610    // SAFETY: as the caller guarantees; `[u8; N]` is aligned at any address.
2611    unsafe { p.cast::<[u8; N]>().write(v) }
2612}