Skip to main content

core/
hint.rs

1#![stable(feature = "core_hint", since = "1.27.0")]
2
3//! Hints to compiler that affects how code should be emitted or optimized.
4//!
5//! Hints may be compile time or runtime.
6
7use crate::marker::Destruct;
8use crate::mem::MaybeUninit;
9use crate::{intrinsics, ub_checks};
10
11/// Informs the compiler that the site which is calling this function is not
12/// reachable, possibly enabling further optimizations.
13///
14/// # Safety
15///
16/// Reaching this function is *Undefined Behavior*.
17///
18/// As the compiler assumes that all forms of Undefined Behavior can never
19/// happen, it will eliminate all branches in the surrounding code that it can
20/// determine will invariably lead to a call to `unreachable_unchecked()`.
21///
22/// If the assumptions embedded in using this function turn out to be wrong -
23/// that is, if the site which is calling `unreachable_unchecked()` is actually
24/// reachable at runtime - the compiler may have generated nonsensical machine
25/// instructions for this situation, including in seemingly unrelated code,
26/// causing difficult-to-debug problems.
27///
28/// Use this function sparingly. Consider using the [`unreachable!`] macro,
29/// which may prevent some optimizations but will safely panic in case it is
30/// actually reached at runtime. Benchmark your code to find out if using
31/// `unreachable_unchecked()` comes with a performance benefit.
32///
33/// # Examples
34///
35/// `unreachable_unchecked()` can be used in situations where the compiler
36/// can't prove invariants that were previously established. Such situations
37/// have a higher chance of occurring if those invariants are upheld by
38/// external code that the compiler can't analyze.
39/// ```
40/// fn prepare_inputs(divisors: &mut Vec<u32>) {
41///     // Note to future-self when making changes: The invariant established
42///     // here is NOT checked in `do_computation()`; if this changes, you HAVE
43///     // to change `do_computation()`.
44///     divisors.retain(|divisor| *divisor != 0)
45/// }
46///
47/// /// # Safety
48/// /// All elements of `divisor` must be non-zero.
49/// unsafe fn do_computation(i: u32, divisors: &[u32]) -> u32 {
50///     divisors.iter().fold(i, |acc, divisor| {
51///         // Convince the compiler that a division by zero can't happen here
52///         // and a check is not needed below.
53///         if *divisor == 0 {
54///             // Safety: `divisor` can't be zero because of `prepare_inputs`,
55///             // but the compiler does not know about this. We *promise*
56///             // that we always call `prepare_inputs`.
57///             unsafe { std::hint::unreachable_unchecked() }
58///         }
59///         // The compiler would normally introduce a check here that prevents
60///         // a division by zero. However, if `divisor` was zero, the branch
61///         // above would reach what we explicitly marked as unreachable.
62///         // The compiler concludes that `divisor` can't be zero at this point
63///         // and removes the - now proven useless - check.
64///         acc / divisor
65///     })
66/// }
67///
68/// let mut divisors = vec![2, 0, 4];
69/// prepare_inputs(&mut divisors);
70/// let result = unsafe {
71///     // Safety: prepare_inputs() guarantees that divisors is non-zero
72///     do_computation(100, &divisors)
73/// };
74/// assert_eq!(result, 12);
75///
76/// ```
77///
78/// While using `unreachable_unchecked()` is perfectly sound in the following
79/// example, as the compiler is able to prove that a division by zero is not
80/// possible, benchmarking reveals that `unreachable_unchecked()` provides
81/// no benefit over using [`unreachable!`], while the latter does not introduce
82/// the possibility of Undefined Behavior.
83///
84/// ```
85/// fn div_1(a: u32, b: u32) -> u32 {
86///     use std::hint::unreachable_unchecked;
87///
88///     // `b.saturating_add(1)` is always positive (not zero),
89///     // hence `checked_div` will never return `None`.
90///     // Therefore, the else branch is unreachable.
91///     a.checked_div(b.saturating_add(1))
92///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
93/// }
94///
95/// assert_eq!(div_1(7, 0), 7);
96/// assert_eq!(div_1(9, 1), 4);
97/// assert_eq!(div_1(11, u32::MAX), 0);
98/// ```
99#[inline]
100#[stable(feature = "unreachable", since = "1.27.0")]
101#[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")]
102#[track_caller]
103pub const unsafe fn unreachable_unchecked() -> ! {
104    ub_checks::assert_unsafe_precondition!(
105        check_language_ub,
106        "hint::unreachable_unchecked must never be reached",
107        () => false
108    );
109    // SAFETY: the safety contract for `intrinsics::unreachable` must
110    // be upheld by the caller.
111    unsafe { intrinsics::unreachable() }
112}
113
114/// Makes a *soundness* promise to the compiler that `cond` holds.
115///
116/// This may allow the optimizer to simplify things, but it might also make the generated code
117/// slower. Either way, calling it will most likely make compilation take longer.
118///
119/// You may know this from other places as
120/// [`llvm.assume`](https://llvm.org/docs/LangRef.html#llvm-assume-intrinsic) or, in C,
121/// [`__builtin_assume`](https://clang.llvm.org/docs/LanguageExtensions.html#builtin-assume).
122///
123/// This promotes a correctness requirement to a soundness requirement. Don't do that without
124/// very good reason.
125///
126/// # Usage
127///
128/// This is a situational tool for micro-optimization, and is allowed to do nothing. Any use
129/// should come with a repeatable benchmark to show the value, with the expectation to drop it
130/// later should the optimizer get smarter and no longer need it.
131///
132/// The more complicated the condition, the less likely this is to be useful. For example,
133/// `assert_unchecked(foo.is_sorted())` is a complex enough value that the compiler is unlikely
134/// to be able to take advantage of it.
135///
136/// There's also no need to `assert_unchecked` basic properties of things.  For example, the
137/// compiler already knows the range of `count_ones`, so there is no benefit to
138/// `let n = u32::count_ones(x); assert_unchecked(n <= u32::BITS);`.
139///
140/// `assert_unchecked` is logically equivalent to `if !cond { unreachable_unchecked(); }`. If
141/// ever you are tempted to write `assert_unchecked(false)`, you should instead use
142/// [`unreachable_unchecked()`] directly.
143///
144/// # Safety
145///
146/// `cond` must be `true`. It is immediate UB to call this with `false`.
147///
148/// # Example
149///
150/// ```
151/// use core::hint;
152///
153/// /// # Safety
154/// ///
155/// /// `p` must be nonnull and valid
156/// pub unsafe fn next_value(p: *const i32) -> i32 {
157///     // SAFETY: caller invariants guarantee that `p` is not null
158///     unsafe { hint::assert_unchecked(!p.is_null()) }
159///
160///     if p.is_null() {
161///         return -1;
162///     } else {
163///         // SAFETY: caller invariants guarantee that `p` is valid
164///         unsafe { *p + 1 }
165///     }
166/// }
167/// ```
168///
169/// Without the `assert_unchecked`, the above function produces the following with optimizations
170/// enabled:
171///
172/// ```asm
173/// next_value:
174///         test    rdi, rdi
175///         je      .LBB0_1
176///         mov     eax, dword ptr [rdi]
177///         inc     eax
178///         ret
179/// .LBB0_1:
180///         mov     eax, -1
181///         ret
182/// ```
183///
184/// Adding the assertion allows the optimizer to remove the extra check:
185///
186/// ```asm
187/// next_value:
188///         mov     eax, dword ptr [rdi]
189///         inc     eax
190///         ret
191/// ```
192///
193/// This example is quite unlike anything that would be used in the real world: it is redundant
194/// to put an assertion right next to code that checks the same thing, and dereferencing a
195/// pointer already has the builtin assumption that it is nonnull. However, it illustrates the
196/// kind of changes the optimizer can make even when the behavior is less obviously related.
197#[track_caller]
198#[inline(always)]
199#[doc(alias = "assume")]
200#[stable(feature = "hint_assert_unchecked", since = "1.81.0")]
201#[rustc_const_stable(feature = "hint_assert_unchecked", since = "1.81.0")]
202pub const unsafe fn assert_unchecked(cond: bool) {
203    // SAFETY: The caller promised `cond` is true.
204    unsafe {
205        ub_checks::assert_unsafe_precondition!(
206            check_language_ub,
207            "hint::assert_unchecked must never be called when the condition is false",
208            (cond: bool = cond) => cond,
209        );
210        crate::intrinsics::assume(cond);
211    }
212}
213
214/// Emits a machine instruction to signal the processor that it is running in
215/// a busy-wait spin-loop ("spin lock").
216///
217/// Upon receiving the spin-loop signal the processor can optimize its behavior by,
218/// for example, saving power or switching hyper-threads.
219///
220/// This function is different from [`thread::yield_now`] which directly
221/// yields to the system's scheduler, whereas `spin_loop` does not interact
222/// with the operating system.
223///
224/// A common use case for `spin_loop` is implementing bounded optimistic
225/// spinning in a CAS loop in synchronization primitives. To avoid problems
226/// like priority inversion, it is strongly recommended that the spin loop is
227/// terminated after a finite amount of iterations and an appropriate blocking
228/// syscall is made.
229///
230/// **Note**: On platforms that do not support receiving spin-loop hints this
231/// function does not do anything at all.
232///
233/// # Examples
234///