]> git.lizzy.rs Git - rust.git/blob - src/libcore/hint.rs
Remove derives `Encodable`/`Decodable` and unstabilize attribute `#[bench]`
[rust.git] / src / libcore / 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 use crate::intrinsics;
6
7 /// Informs the compiler that this point in the code is not reachable, enabling
8 /// further optimizations.
9 ///
10 /// # Safety
11 ///
12 /// Reaching this function is completely *undefined behavior* (UB). In
13 /// particular, the compiler assumes that all UB must never happen, and
14 /// therefore will eliminate all branches that reach to a call to
15 /// `unreachable_unchecked()`.
16 ///
17 /// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
18 /// `unreachable_unchecked()` call is actually reachable among all possible
19 /// control flow, the compiler will apply the wrong optimization strategy, and
20 /// may sometimes even corrupt seemingly unrelated code, causing
21 /// difficult-to-debug problems.
22 ///
23 /// Use this function only when you can prove that the code will never call it.
24 /// Otherwise, consider using the [`unreachable!`] macro, which does not allow
25 /// optimizations but will panic when executed.
26 ///
27 /// [`unreachable!`]: ../macro.unreachable.html
28 ///
29 /// # Example
30 ///
31 /// ```
32 /// fn div_1(a: u32, b: u32) -> u32 {
33 ///     use std::hint::unreachable_unchecked;
34 ///
35 ///     // `b.saturating_add(1)` is always positive (not zero),
36 ///     // hence `checked_div` will never return `None`.
37 ///     // Therefore, the else branch is unreachable.
38 ///     a.checked_div(b.saturating_add(1))
39 ///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
40 /// }
41 ///
42 /// assert_eq!(div_1(7, 0), 7);
43 /// assert_eq!(div_1(9, 1), 4);
44 /// assert_eq!(div_1(11, std::u32::MAX), 0);
45 /// ```
46 #[inline]
47 #[stable(feature = "unreachable", since = "1.27.0")]
48 pub unsafe fn unreachable_unchecked() -> ! {
49     intrinsics::unreachable()
50 }
51
52 /// Signals the processor that it is entering a busy-wait spin-loop.
53 ///
54 /// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving
55 /// power or switching hyper-threads.
56 ///
57 /// This function is different than [`std::thread::yield_now`] which directly yields to the
58 /// system's scheduler, whereas `spin_loop` only signals the processor that it is entering a
59 /// busy-wait spin-loop without yielding control to the system's scheduler.
60 ///
61 /// Using a busy-wait spin-loop with `spin_loop` is ideally used in situations where a
62 /// contended lock is held by another thread executed on a different CPU and where the waiting
63 /// times are relatively small. Because entering busy-wait spin-loop does not trigger the system's
64 /// scheduler, no overhead for switching threads occurs. However, if the thread holding the
65 /// contended lock is running on the same CPU, the spin-loop is likely to occupy an entire CPU slice
66 /// before switching to the thread that holds the lock. If the contending lock is held by a thread
67 /// on the same CPU or if the waiting times for acquiring the lock are longer, it is often better to
68 /// use [`std::thread::yield_now`].
69 ///
70 /// **Note**: On platforms that do not support receiving spin-loop hints this function does not
71 /// do anything at all.
72 ///
73 /// [`std::thread::yield_now`]: ../../std/thread/fn.yield_now.html
74 #[inline]
75 #[unstable(feature = "renamed_spin_loop", issue = "55002")]
76 pub fn spin_loop() {
77     #[cfg(
78         all(
79             any(target_arch = "x86", target_arch = "x86_64"),
80             target_feature = "sse2"
81         )
82     )] {
83         #[cfg(target_arch = "x86")] {
84             unsafe { crate::arch::x86::_mm_pause() };
85         }
86
87         #[cfg(target_arch = "x86_64")] {
88             unsafe { crate::arch::x86_64::_mm_pause() };
89         }
90     }
91
92     #[cfg(
93         any(
94             target_arch = "aarch64",
95             all(target_arch = "arm", target_feature = "v6")
96         )
97     )] {
98         #[cfg(target_arch = "aarch64")] {
99             unsafe { crate::arch::aarch64::__yield() };
100         }
101         #[cfg(target_arch = "arm")] {
102             unsafe { crate::arch::arm::__yield() };
103         }
104     }
105 }
106
107 /// A function that is opaque to the optimizer, to allow benchmarks to
108 /// pretend to use outputs to assist in avoiding dead-code
109 /// elimination.
110 ///
111 /// This function is a no-op, and does not even read from `dummy`.
112 #[inline]
113 #[unstable(feature = "test", issue = "50297")]
114 #[allow(unreachable_code)] // this makes #[cfg] a bit easier below.
115 pub fn black_box<T>(dummy: T) -> T {
116     // We need to "use" the argument in some way LLVM can't introspect, and on
117     // targets that support it we can typically leverage inline assembly to do
118     // this. LLVM's intepretation of inline assembly is that it's, well, a black
119     // box. This isn't the greatest implementation since it probably deoptimizes
120     // more than we want, but it's so far good enough.
121     #[cfg(not(any(
122         target_arch = "asmjs",
123         all(
124             target_arch = "wasm32",
125             target_os = "emscripten"
126         )
127     )))]
128     unsafe {
129         asm!("" : : "r"(&dummy));
130         return dummy;
131     }
132
133     // Not all platforms support inline assembly so try to do something without
134     // inline assembly which in theory still hinders at least some optimizations
135     // on those targets. This is the "best effort" scenario.
136     unsafe {
137         let ret = crate::ptr::read_volatile(&dummy);
138         crate::mem::forget(dummy);
139         ret
140     }
141 }