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(unstable, feature(core_intrinsics))]
5#![cfg_attr(unstable, 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(not(unstable))]
11#[inline(always)]
12#[cold]
13fn 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(not(unstable))]
31    {
32        #[cfg(not(feature = "std"))]
33        unreachable!();
34        #[cfg(feature = "std")]
35        std::process::abort();
36    }
37    #[cfg(unstable)]
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(not(unstable))]
58    if !b {
59        core::hint::unreachable_unchecked();
60    }
61    #[cfg(unstable)]
62    core::intrinsics::assume(b)
63}
64
65/// Hints to the compiler that the branch condition is likely to be true.
66/// Returns the value passed to it.
67///
68/// This intrinsic is primarily used with `if` statements.
69/// Using it in other contexts may not have any effect.
70///
71/// Unlike most intrinsics, this function is safe to call and doesn't require an `unsafe` block.
72/// Therefore, implementations must not require the user to uphold any safety invariants.
73#[inline(always)]
74pub fn likely(b: bool) -> bool {
75    #[cfg(not(unstable))]
76    {
77        if !b {
78            cold_and_empty();
79        }
80        b
81    }
82    #[cfg(unstable)]
83    core::intrinsics::likely(b)
84}
85
86/// Hints to the compiler that the branch condition is unlikely to be true.
87/// Returns the value passed to it.
88///
89/// This intrinsic is primarily used with `if` statements.
90/// Using it in other contexts may not have any effect.
91///
92/// Unlike most intrinsics, this function is safe to call and doesn't require an `unsafe` block.
93/// Therefore, implementations must not require the user to uphold any safety invariants.
94#[inline(always)]
95pub fn unlikely(b: bool) -> bool {
96    #[cfg(not(unstable))]
97    {
98        if b {
99            cold_and_empty();
100        }
101        b
102    }
103    #[cfg(unstable)]
104    core::intrinsics::unlikely(b)
105}
106
107/// Prefetches data for reading into the cache.
108///
109/// This function hints to the CPU that the data at the given address
110/// will be read soon, allowing the CPU to load the data into the cache
111/// in advance. This can improve performance by reducing cache misses.
112///
113/// # Arguments
114///
115/// * `addr` - A pointer to the data to prefetch.
116/// * `LOCALITY` - The cache locality to prefetch into.
117#[inline(always)]
118pub fn prefetch_read_data<T, const LOCALITY: i32>(addr: *const T) {
119    #[cfg(not(unstable))]
120    {
121        #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
122        unsafe {
123            match LOCALITY {
124                0 => core::arch::asm!(
125                    "prefetcht0 [{}]",
126                    in(reg) addr,
127                    options(nostack, readonly, preserves_flags)
128                ), // L1 cache
129                1 => core::arch::asm!(
130                    "prefetcht1 [{}]",
131                    in(reg) addr,
132                    options(nostack, readonly, preserves_flags)
133                ), // L2 cache
134                2 => core::arch::asm!(
135                    "prefetcht2 [{}]",
136                    in(reg) addr,
137                    options(nostack, readonly, preserves_flags)
138                ), // L3 cache
139                _ => core::arch::asm!(
140                    "prefetchnta [{}]",
141                    in(reg) addr,
142                    options(nostack, readonly, preserves_flags)
143                ), // Non-temporal
144            }
145        }
146
147        #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
148        unsafe {
149            match LOCALITY {
150                0 => core::arch::asm!(
151                    "prfm pldl1keep, [{}]",
152                    in(reg) addr,
153                    options(nostack, readonly, preserves_flags)
154                ), // L1 cache
155                1 => core::arch::asm!(
156                    "prfm pldl2keep, [{}]",
157                    in(reg) addr,
158                    options(nostack, readonly, preserves_flags)
159                ), // L2 cache
160                _ => core::arch::asm!(
161                    "prfm pldl3keep, [{}]",
162                    in(reg) addr,
163                    options(nostack, readonly, preserves_flags)
164                ), // L3 or non-temporal
165            }
166        }
167
168        #[cfg(target_arch = "riscv64")]
169        unsafe {
170            core::arch::asm!(
171                "prefetch [{}]",
172                in(reg) addr,
173                options(nostack, readonly, preserves_flags)
174            );
175        }
176
177        #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
178        unsafe {
179            core::arch::asm!(
180                "dcbt 0, {}",
181                in(reg) addr,
182                options(nostack, readonly, preserves_flags)
183            );
184        }
185    }
186    #[cfg(unstable)]
187    core::intrinsics::prefetch_read_data::<_, LOCALITY>(addr)
188}
189
190/// Prefetches data for writing into the cache.
191///
192/// This function hints to the CPU that the data at the given address
193/// will be written soon, allowing the CPU to load the data into the cache
194/// in advance. This can improve performance by reducing cache misses.
195///
196/// # Arguments
197///
198/// * `addr` - A pointer to the data to prefetch.
199/// * `LOCALITY` - The cache locality to prefetch into.
200#[inline(always)]
201pub fn prefetch_write_data<T, const LOCALITY: i32>(addr: *const T) {
202    #[cfg(not(unstable))]
203    {
204        #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
205        unsafe {
206            core::arch::asm!(
207                "prefetchw [{}]",
208                in(reg) addr,
209                options(nostack, readonly, preserves_flags)
210            ) // Write-prefetch for L1/L2/L3 cache
211        }
212
213        #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
214        unsafe {
215            core::arch::asm!(
216                "prfm pstl1keep, [{}]",
217                in(reg) addr,
218                options(nostack, readonly, preserves_flags)
219            ); // Write-prefetch for L1 cache
220        }
221
222        #[cfg(target_arch = "riscv64")]
223        unsafe {
224            core::arch::asm!(
225                "prefetchw [{}]",
226                in(reg) addr,
227                options(nostack, readonly, preserves_flags)
228            );
229        }
230
231        #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
232        unsafe {
233            core::arch::asm!(
234                "dcbtst 0, {}",
235                in(reg) addr,
236                options(nostack, readonly, preserves_flags)
237            ); // Write-prefetch
238        }
239    }
240    #[cfg(unstable)]
241    core::intrinsics::prefetch_write_data::<_, LOCALITY>(addr)
242}
243
244// tests
245#[cfg(test)]
246mod test;