1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//! Duplicate-value detection across lanes.
//!
//! [`count_conflicts_default`] answers, per lane, *how many earlier lanes hold
//! my value* - `out[i] == |{ j < i : v[j] == v[i] }|`, i.e. AVX-512CD's
//! `conflict(v).count_ones()`. Two things fall out of it:
//!
//! - `count_conflicts(v) == 0` is the **first-occurrence** mask.
//! - The count is the round number for a conflicting read-modify-write. A lane
//! of rank `r` is safe to process in round `r`, since every earlier duplicate
//! has a strictly smaller rank and goes first. That is what makes a vectorized
//! histogram or SAH-bin increment correct where a plain scatter silently drops
//! duplicate writes.
//!
//! # The ladder
//!
//! Step `j` compares each lane against the one `LANES - j` positions earlier -
//! [`align::<j>(v, v)`](crate::register::Register::align) is exactly that rotate - and
//! `suffix_mask(j)` is the set of lanes where the rotate did not wrap. Running
//! `j` over `1..LANES` visits every ordered pair `(i, j < i)` exactly once.
//!
//! Indexing by `j` rather than by the distance is what keeps every offset a
//! *literal*: `align`'s offset is a const-generic argument and stable Rust has
//! no const arithmetic in that position. So one `if const` chain serves every
//! width, including non-powers-of-two, with no per-width offset table - unlike
//! the forward prefix-scan ladder, which needs `LANES - j` and therefore a
//! match on the lane count.
//!
//! `LANES - 1` steps of ~4 vector ops: more than the single instruction
//! AVX-512CD needs, hence a *default* on [`IntegerRegister::count_conflicts`]
//! rather than the only implementation, but far under a scalar pass at
//! `LANES * (LANES - 1) / 2` compares over a spilled register.
use Unsigned;
use crate::;
/// Portable rotate-ladder body behind
/// [`crate::register::IntegerRegister::count_conflicts`].
///
/// Free-standing so blanket impls can reach it without `Self::count_conflicts`
/// recursion, matching [`compress_default`](super::compress::compress_default).