stable_intrinsics/
lib.rs

1#![cfg_attr(nightly, feature(core_intrinsics))]
2#![cfg_attr(not(feature = "std"), no_std)]
3#![allow(internal_features)]
4
5#![doc = include_str!("../README.md")]
6
7mod disjoint_bitor;
8mod test;
9
10pub use disjoint_bitor::*;
11
12/// Same as [`std::intrinsics::abort`] on nightly. On stable and beta, the exact behavior depends
13/// on whether or not that `std` is avalible.
14///
15/// If `std` feature is enabled, use [`std::process::abort`].
16/// If `std` feature is not enabled, use `panic!()`.
17#[inline(always)]
18pub fn abort() -> ! {
19    #[cfg(nightly)]
20    core::intrinsics::abort();
21
22    #[cfg(not(nightly))] {
23        // use system abort as fallback on std
24        #[cfg(feature = "std")]
25        std::process::abort();
26
27        // panic on non-std
28        #[cfg(not(feature = "std"))]
29        panic!();
30    }
31}
32
33/// Same as [`std::intrinsics::breakpoint`] on nightly. On stable and beta, the implementation
34/// depends on the target architecture.
35///
36/// # Notes
37/// On stable and beta, the exact behavior is not stable across crate versions and may change.
38///
39/// Currently it is implemented as followed:
40///     - On x86 and x86-64, an `int3` instruction is emitted.
41///     - On ARM, an `bkpt` instruction is emitted.
42///     - On AArch64, an `brk #0xf000` instruction is emitted, like the nightly counterpart.
43///     - On RISCV, an `ebreak` instruction is emitted.
44///     - On MIPS, an `break` instruction is emitted.
45///     - Otherwise, it is a no-op.
46#[inline(always)]
47pub fn breakpoint() {
48    #[cfg(nightly)]
49    core::intrinsics::breakpoint();
50
51    #[cfg(not(nightly))] {
52        #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
53        unsafe { core::arch::asm!("int3", options(nomem, nostack)) };
54
55        #[cfg(target_arch = "arm")]
56        unsafe { core::arch::asm!("bkpt", options(nomem, nostack)) };
57
58        #[cfg(target_arch = "aarch64")]
59        unsafe { core::arch::asm!("brk #0xf000", options(nomem, nostack)) };
60
61        #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
62        unsafe { core::arch::asm!("ebreak", options(nomem, nostack)) };
63
64        #[cfg(any(target_arch = "mips", target_arch = "mips64"))]
65        unsafe { core::arch::asm!("break", options(nomem, nostack)) };
66    }
67}
68
69/// Same as [`core::intrinsics::cold_path`] on nightly. On stable and beta, it is a no-op.
70#[inline(always)]
71pub const fn cold_path() {
72    #[cfg(nightly)]
73    core::intrinsics::cold_path();
74}
75
76/// Same as [`core::intrinsics::likely`] on nightly. On stable and beta, it is an identity
77/// function.
78#[inline(always)]
79pub const fn likely(b: bool) -> bool {
80    #[cfg(nightly)]
81    return core::intrinsics::likely(b);
82
83    #[cfg(not(nightly))]
84    return b;
85}
86
87/// Same as [`core::intrinsics::unlikely`] on nightly. On stable and beta, it is an identity
88/// function.
89#[inline(always)]
90pub const fn unlikely(b: bool) -> bool {
91    #[cfg(nightly)]
92    return core::intrinsics::unlikely(b);
93
94    #[cfg(not(nightly))]
95    return b;
96}
97
98/// Same as [`core::intrinsics::prefetch_read_data`] on nightly. On stable and beta, it is a no-op.
99///
100/// # Safety
101/// Marked as unsafe like the standard library.
102#[inline(always)]
103pub unsafe fn prefetch_read_data<T>(_data: *const T, _locality: i32) {
104    #[cfg(nightly)]
105    unsafe {
106        core::intrinsics::prefetch_read_data(_data, _locality);
107    }
108}
109
110/// Same as [`core::intrinsics::prefetch_read_instruction`] on nightly. On stable and beta, it is a no-op.
111///
112/// # Safety
113/// Marked as unsafe like the standard library.
114#[inline(always)]
115pub unsafe fn prefetch_read_instruction<T>(_data: *const T, _locality: i32) {
116    #[cfg(nightly)]
117    unsafe {
118        core::intrinsics::prefetch_read_instruction(_data, _locality);
119    }
120}
121
122/// Same as [`core::intrinsics::prefetch_write_data`] on nightly. On stable and beta, it is a no-op.
123///
124/// # Safety
125/// Marked as unsafe like the standard library.
126#[inline(always)]
127pub unsafe fn prefetch_write_data<T>(_data: *const T, _locality: i32) {
128    #[cfg(nightly)]
129    unsafe {
130        core::intrinsics::prefetch_write_data(_data, _locality);
131    }
132}
133
134/// Same as [`core::intrinsics::prefetch_write_instruction`] on nightly. On stable and beta, it is a no-op.
135///
136/// # Safety
137/// Marked as unsafe like the standard library.
138#[inline(always)]
139pub unsafe fn prefetch_write_instruction<T>(_data: *const T, _locality: i32) {
140    #[cfg(nightly)]
141    unsafe {
142        core::intrinsics::prefetch_write_instruction(_data, _locality);
143    }
144}
145
146/// Same as [`core::intrinsics::select_unpredictable`] on nightly. On stable and beta, use an
147/// if-else to determine the output.
148#[inline(always)]
149pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
150    #[cfg(nightly)]
151    return core::intrinsics::select_unpredictable(b, true_val, false_val);
152
153    #[cfg(not(nightly))]
154    return if b { true_val } else { false_val };
155}
156
157/// Same as [`core::intrinsics::disjoint_bitor`] on nightly except the `const`-ness. On stable and beta, it is
158/// implemented with [`core::hint::assert_unchecked`].
159///
160/// # Panics
161/// This function panics if it is about to be unsafe on builds with debug assertions enabled.
162///
163/// # Safety
164/// Requires that `(a & b) == 0`, or equivalently that `(a | b) == (a + b)`.
165#[inline(always)]
166pub unsafe fn disjoint_bitor<T: DisjointBitOr>(a: T, b: T) -> T {
167    unsafe { a.disjoint_bitor(b) }
168}
169
170/// Same as [`core::intrinsics::transmute_unchecked`].
171///
172/// # Safety
173/// Same as [`core::intrinsics::transmute_unchecked`].
174#[inline(always)]
175pub const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst {
176    #[cfg(nightly)]
177    return unsafe { core::intrinsics::transmute_unchecked(src) };
178
179    #[cfg(not(nightly))]
180    unsafe {
181        let dst = core::mem::transmute::<*const Src, *const Dst>(&src as *const Src);
182        core::mem::forget(src);
183        dst.read()
184    }
185}
186
187/// Same as [`core::intrinsics::raw_eq`] on nightly. On stable and beta, `a` and `b` are converted
188/// into `[u8]` before comparason.
189///
190/// # Safety
191/// Same as [`core::intrinsics::raw_eq`].
192#[inline(always)]
193pub const unsafe fn raw_eq<T>(a: &T, b: &T) -> bool {
194    #[cfg(nightly)]
195    return unsafe { core::intrinsics::raw_eq(a, b) };
196
197    #[cfg(not(nightly))]
198    unsafe {
199        let a = core::slice::from_raw_parts(a as *const T as *const u8, size_of::<T>());
200        let b = core::slice::from_raw_parts(b as *const T as *const u8, size_of::<T>());
201
202        // NOTE: using `while` instead of `for` or `==` because const-evaluation
203        let mut i = 0;
204        while i < size_of::<T>() {
205            if a[i] != b[i] {
206                return false;
207            }
208
209            i += 1;
210        }
211
212        true
213    }
214}
215
216/// Same as [`core::intrinsics::nontemporal_store`] on nightly. On stable and beta, it is simply a
217/// pointer store.
218///
219/// # Safety
220/// [`core::ptr::write`] must be safe.
221pub unsafe fn nontemporal_store<T>(ptr: *mut T, val: T) {
222    unsafe {
223        #[cfg(nightly)]
224        core::intrinsics::nontemporal_store(ptr, val);
225
226        #[cfg(not(nightly))]
227        ptr.write(val);
228    }
229}