branches/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]
2#![doc = include_str!("../README.md")]
3#![warn(missing_docs, missing_debug_implementations)]
4#![cfg_attr(branches_nightly, feature(core_intrinsics))]
5#![cfg_attr(branches_nightly, allow(internal_features))]
6/// Provides branch detection functions for Rust, using built-in Rust features
7/// on stable and core::intrinsics on nightly.
8
9// No one likes to visit this function.
10#[cfg(branches_stable)]
11#[inline(always)]
12#[cold]
13const fn cold_and_empty() {}
14
15/// Aborts the execution of the process immediately and without any cleanup.
16///
17/// This function is used to indicate a critical and unrecoverable error in the program.
18/// It terminates the process immediately without performing any cleanup or running destructors.
19///
20/// This function is safe to call, so it does not require an unsafe block.
21/// Therefore, implementations must not require the user to uphold any safety invariants.
22///
23/// If the std feature is enabled, this function calls std::process::abort()
24/// which is a more user-friendly and stable way of aborting the process.
25///
26/// If the std feature is disabled, this function panics by calling panic!().
27/// In this case, by using `extern "C"` this function is guaranteed to not unwind.
28#[cold]
29pub extern "C" fn abort() -> ! {
30 #[cfg(branches_stable)]
31 {
32 #[cfg(not(feature = "std"))]
33 unreachable!();
34 #[cfg(feature = "std")]
35 std::process::abort();
36 }
37 #[cfg(branches_nightly)]
38 core::intrinsics::abort()
39}
40
41/// Informs the optimizer that a condition is always true.
42///
43/// If the condition is actually false, the behavior is undefined.
44///
45/// This intrinsic doesn't generate any code. Instead, it tells the optimizer
46/// to preserve the condition for optimization passes. This can interfere with
47/// optimization of surrounding code and reduce performance, so avoid using it
48/// if the optimizer can already discover the invariant on its own or if it
49/// doesn't enable any significant optimizations.
50///
51/// # Safety
52///
53/// This intrinsic is marked unsafe because it can result in undefined behavior
54/// if the condition passed to it is false.
55#[inline(always)]
56pub unsafe fn assume(b: bool) {
57 #[cfg(branches_stable)]
58 {
59 // Rust >= 1.81.0: use the newer `assert_unchecked` hint.
60 #[cfg(rustc_ge_1_81_0)]
61 {
62 core::hint::assert_unchecked(b)
63 }
64 // Rust < 1.81.0: fall back to the older `unreachable_unchecked`.
65 #[cfg(not(rustc_ge_1_81_0))]
66 {
67 if !b {
68 core::hint::unreachable_unchecked()
69 }
70 }
71 }
72 #[cfg(branches_nightly)]
73 core::intrinsics::assume(b)
74}
75
76/// Hints to the compiler that the branch condition is likely to be true.
77/// Returns the value passed to it.
78///
79/// This intrinsic is primarily used with `if` statements.
80/// Using it in other contexts may not have any effect.
81///
82/// Unlike most intrinsics, this function is safe to call and doesn't require an `unsafe` block.
83/// Therefore, implementations must not require the user to uphold any safety invariants.
84#[inline(always)]
85pub fn likely(b: bool) -> bool {
86 #[cfg(branches_stable)]
87 {
88 if !b {
89 cold_and_empty();
90 }
91 b
92 }
93 #[cfg(branches_nightly)]
94 core::intrinsics::likely(b)
95}
96
97/// Marks a code block as cold, indicating to the compiler that it is unlikely to be called.
98/// This can help the compiler optimize for the common case.
99///
100/// This function does not take any arguments and does not return any value.
101/// It is primarily used to mark functions or code paths that are rarely executed,
102/// such as error handling or panic paths.
103
104/// Example: marking the `None` variant of an `Option` as unlikely.
105///
106/// In many hot paths an `Option<T>` is expected to be `Some`.
107/// By marking the `None` arm using `mark_unlikely` we give the optimizer a hint
108/// that this branch is rarely taken.
109///
110/// ```rust
111/// use branches::{mark_unlikely};
112///
113/// #[derive(Debug)]
114/// enum Status {
115/// Ok(i32),
116/// Err(String),
117/// }
118///
119/// fn get_value(status: Status) -> i32 {
120/// match status {
121/// Status::Ok(v) => v,
122/// // The error case is rare, hint the compiler accordingly.
123/// Status::Err(err) => {
124/// mark_unlikely();
125/// eprintln!("unexpected error: {:?}", err);
126/// -1
127/// }
128/// }
129/// }
130/// ```
131#[cold]
132#[inline(always)]
133pub const fn mark_unlikely() {}
134
135/// Hints to the compiler that the branch condition is unlikely to be true.
136/// Returns the value passed to it.
137///
138/// This intrinsic is primarily used with `if` statements.
139/// Using it in other contexts may not have any effect.
140///
141/// Unlike most intrinsics, this function is safe to call and doesn't require an `unsafe` block.
142/// Therefore, implementations must not require the user to uphold any safety invariants.
143#[inline(always)]
144pub fn unlikely(b: bool) -> bool {
145 #[cfg(branches_stable)]
146 {
147 if b {
148 cold_and_empty();
149 }
150 b
151 }
152 #[cfg(branches_nightly)]
153 core::intrinsics::unlikely(b)
154}
155
156/// Prefetches data for reading into the cache.
157///
158/// This function hints to the CPU that the data at the given address
159/// will be read soon, allowing the CPU to load the data into the cache
160/// in advance. This can improve performance by reducing cache misses.
161///
162/// # Arguments
163///
164/// * `addr` - A pointer to the data to prefetch.
165/// * `LOCALITY` - The cache locality to prefetch into.
166#[inline(always)]
167#[cfg(feature = "prefetch")]
168pub fn prefetch_read_data<T, const LOCALITY: i32>(addr: *const T) {
169 #[cfg(branches_stable)]
170 {
171 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
172 unsafe {
173 match LOCALITY {
174 0 => core::arch::asm!(
175 "prefetcht0 [{}]",
176 in(reg) addr,
177 options(nostack, readonly, preserves_flags)
178 ), // L1 cache
179 1 => core::arch::asm!(
180 "prefetcht1 [{}]",
181 in(reg) addr,
182 options(nostack, readonly, preserves_flags)
183 ), // L2 cache
184 2 => core::arch::asm!(
185 "prefetcht2 [{}]",
186 in(reg) addr,
187 options(nostack, readonly, preserves_flags)
188 ), // L3 cache
189 _ => core::arch::asm!(
190 "prefetchnta [{}]",
191 in(reg) addr,
192 options(nostack, readonly, preserves_flags)
193 ), // Non-temporal
194 }
195 }
196
197 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
198 unsafe {
199 match LOCALITY {
200 0 => core::arch::asm!(
201 "prfm pldl1keep, [{}]",
202 in(reg) addr,
203 options(nostack, readonly, preserves_flags)
204 ), // L1 cache
205 1 => core::arch::asm!(
206 "prfm pldl2keep, [{}]",
207 in(reg) addr,
208 options(nostack, readonly, preserves_flags)
209 ), // L2 cache
210 _ => core::arch::asm!(
211 "prfm pldl3keep, [{}]",
212 in(reg) addr,
213 options(nostack, readonly, preserves_flags)
214 ), // L3 or non-temporal
215 }
216 }
217
218 #[cfg(target_arch = "riscv64")]
219 unsafe {
220 core::arch::asm!(
221 "prefetch [{}]",
222 in(reg) addr,
223 options(nostack, readonly, preserves_flags)
224 );
225 }
226
227 // this requires unstable asm feature, uncomment when stabilized
228 //#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
229 //unsafe {
230 // core::arch::asm!(
231 // "dcbt 0, {}",
232 // in(reg) addr,
233 // options(nostack, readonly, preserves_flags)
234 // );
235 //}
236 }
237 #[cfg(branches_nightly)]
238 core::intrinsics::prefetch_read_data::<_, LOCALITY>(addr)
239}
240
241/// Prefetches data for writing into the cache.
242///
243/// This function hints to the CPU that the data at the given address
244/// will be written soon, allowing the CPU to load the data into the cache
245/// in advance. This can improve performance by reducing cache misses.
246///
247/// # Arguments
248///
249/// * `addr` - A pointer to the data to prefetch.
250/// * `LOCALITY` - The cache locality to prefetch into.
251#[inline(always)]
252#[cfg(feature = "prefetch")]
253pub fn prefetch_write_data<T, const LOCALITY: i32>(addr: *const T) {
254 #[cfg(branches_stable)]
255 {
256 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
257 unsafe {
258 core::arch::asm!(
259 "prefetchw [{}]",
260 in(reg) addr,
261 options(nostack, readonly, preserves_flags)
262 ) // Write-prefetch for L1/L2/L3 cache
263 }
264
265 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
266 unsafe {
267 core::arch::asm!(
268 "prfm pstl1keep, [{}]",
269 in(reg) addr,
270 options(nostack, readonly, preserves_flags)
271 ); // Write-prefetch for L1 cache
272 }
273
274 #[cfg(target_arch = "riscv64")]
275 unsafe {
276 core::arch::asm!(
277 "prefetchw [{}]",
278 in(reg) addr,
279 options(nostack, readonly, preserves_flags)
280 );
281 }
282
283 // this requires unstable asm feature, uncomment when stabilized
284 //#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
285 //unsafe {
286 // core::arch::asm!(
287 // "dcbtst 0, {}",
288 // in(reg) addr,
289 // options(nostack, readonly, preserves_flags)
290 // ); // Write-prefetch
291 // }
292 }
293 #[cfg(branches_nightly)]
294 core::intrinsics::prefetch_write_data::<_, LOCALITY>(addr)
295}