1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Software prefetch: one per-architecture implementation shared by every backend.
//!
//! Prefetch is an ISA-level *memory* hint rather than a lane operation -- the
//! same instruction is issued whether the surrounding code is running scalar,
//! SSE2 or AVX2 kernels -- so every [`NativeIsa::prefetch`] impl routes here
//! instead of re-deriving it per tier. The x86 path is re-exported through
//! `backend::x86::sse` and the aarch64 path through the NEON polyfills, so
//! backend code can reach it as `arch::prefetch` like any other primitive.
//!
//! # Parameterization
//!
//! The knobs follow the LLVM / `__builtin_prefetch` convention rather than any
//! one ISA's encoding, because it is the only one every target can express:
//!
//! * `LOCALITY` -- how long the line should be kept: `0` = none (streaming,
//! evict as soon as possible), `1` = low, `2` = moderate, `3` = high (keep it
//! in every cache level). Outside `0..=3` is a compile error.
//! * `WRITE` -- `true` when the line is about to be *written*, letting the
//! hardware fetch it in an exclusive/owned state and skip the later
//! read-for-ownership. Targets with no write form fall back to the read form;
//! it is only ever a hint.
//!
//! | `LOCALITY` | x86 (read / write) | aarch64 (read / write) |
//! |---|---|---|
//! | 3 | `prefetcht0` / `prefetchw` | `prfm pldl1keep` / `prfm pstl1keep` |
//! | 2 | `prefetcht1` / `prefetchw`(t1) | `prfm pldl2keep` / `prfm pstl2keep` |
//! | 1 | `prefetcht2` / `prefetchw`(t1) | `prfm pldl3keep` / `prfm pstl3keep` |
//! | 0 | `prefetchnta` | `prfm pldl1strm` / `prfm pstl1strm` |
//!
//! The x86 write forms need `prfchw` (or `prefetchwt1`) to be enabled at compile
//! time; without them LLVM quietly lowers the write hints back to `prefetcht0` /
//! `prefetcht1`, which is exactly the right degradation for a hint. Verified in
//! emitted assembly at every `LOCALITY`, both directions, on x86-64 (with and
//! without `+prfchw`) and aarch64.
//!
//! # Safety
//!
//! A prefetch is architecturally invisible: the address is never dereferenced,
//! never faults and never traps, so [`prefetch`] is a **safe** function that
//! accepts any pointer -- dangling, null, unaligned or wildly out of bounds.
//! That is what makes the branchless `base.wrapping_add(i)` idiom (compute the
//! address of the *next* iteration's data without bounds-checking it first)
//! usable in a hot loop, and it keeps Miri quiet because no provenance is ever
//! used.
//!
//! [`NativeIsa::prefetch`]: crate::simd::NativeIsa::prefetch
/// `true` when [`prefetch`] lowers to a real instruction on the target being
/// compiled for, `false` when it compiles away to nothing (wasm, SPIR-V, and
/// any architecture without a software-prefetch hint). Mirrored by
/// [`NativeIsa::HAS_PREFETCH`](crate::simd::NativeIsa::HAS_PREFETCH).
pub const HAS_PREFETCH: bool = cfg!;
/// Hint that the cache line containing `ptr` should be fetched now, ahead of
/// the access that actually needs it. See the [module docs](self) for the
/// meaning of `LOCALITY`/`WRITE` and the per-target lowering.
///
/// Safe for *any* pointer value: nothing is read, so nothing can fault.