]> git.lizzy.rs Git - rust.git/blob - src/libcore/hint.rs
Auto merge of #59619 - alexcrichton:wasi-fs, r=fitzgen
[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 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 ///
25 /// The [`unreachable!()`] macro is the safe counterpart of this function, which
26 /// will panic instead when executed.
27 ///
28 /// [`unreachable!()`]: ../macro.unreachable.html
29 ///
30 /// # Example
31 ///
32 /// ```
33 /// fn div_1(a: u32, b: u32) -> u32 {
34 ///     use std::hint::unreachable_unchecked;
35 ///
36 ///     // `b.saturating_add(1)` is always positive (not zero),
37 ///     // hence `checked_div` will never return `None`.
38 ///     // Therefore, the else branch is unreachable.
39 ///     a.checked_div(b.saturating_add(1))
40 ///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
41 /// }
42 ///
43 /// assert_eq!(div_1(7, 0), 7);
44 /// assert_eq!(div_1(9, 1), 4);
45 /// assert_eq!(div_1(11, std::u32::MAX), 0);
46 /// ```
47 #[inline]
48 #[stable(feature = "unreachable", since = "1.27.0")]
49 pub unsafe fn unreachable_unchecked() -> ! {
50     intrinsics::unreachable()
51 }
52
53 /// Signals the processor that it is entering a busy-wait spin-loop.
54 ///
55 /// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving
56 /// power or switching hyper-threads.
57 ///
58 /// This function is different than [`std::thread::yield_now`] which directly yields to the
59 /// system's scheduler, whereas `spin_loop` only signals the processor that it is entering a
60 /// busy-wait spin-loop without yielding control to the system's scheduler.
61 ///
62 /// Using a busy-wait spin-loop with `spin_loop` is ideally used in situations where a
63 /// contended lock is held by another thread executed on a different CPU and where the waiting
64 /// times are relatively small. Because entering busy-wait spin-loop does not trigger the system's
65 /// scheduler, no overhead for switching threads occurs. However, if the thread holding the
66 /// contended lock is running on the same CPU, the spin-loop is likely to occupy an entire CPU slice
67 /// before switching to the thread that holds the lock. If the contending lock is held by a thread
68 /// on the same CPU or if the waiting times for acquiring the lock are longer, it is often better to
69 /// use [`std::thread::yield_now`].
70 ///
71 /// **Note**: On platforms that do not support receiving spin-loop hints this function does not
72 /// do anything at all.
73 ///
74 /// [`std::thread::yield_now`]: ../../std/thread/fn.yield_now.html
75 #[inline]
76 #[unstable(feature = "renamed_spin_loop", issue = "55002")]
77 pub fn spin_loop() {
78     #[cfg(
79         all(
80             any(target_arch = "x86", target_arch = "x86_64"),
81             target_feature = "sse2"
82         )
83     )] {
84         #[cfg(target_arch = "x86")] {
85             unsafe { crate::arch::x86::_mm_pause() };
86         }
87
88         #[cfg(target_arch = "x86_64")] {
89             unsafe { crate::arch::x86_64::_mm_pause() };
90         }
91     }
92
93     #[cfg(
94         any(
95             target_arch = "aarch64",
96             all(target_arch = "arm", target_feature = "v6")
97         )
98     )] {
99         #[cfg(target_arch = "aarch64")] {
100             unsafe { crate::arch::aarch64::__yield() };
101         }
102         #[cfg(target_arch = "arm")] {
103             unsafe { crate::arch::arm::__yield() };
104         }
105     }
106 }
107
108 /// A function that is opaque to the optimizer, to allow benchmarks to
109 /// pretend to use outputs to assist in avoiding dead-code
110 /// elimination.
111 ///
112 /// This function is a no-op, and does not even read from `dummy`.
113 #[inline]
114 #[unstable(feature = "test", issue = "27812")]
115 pub fn black_box<T>(dummy: T) -> T {
116     cfg_if! {
117         if #[cfg(any(
118             target_arch = "asmjs",
119             all(
120                 target_arch = "wasm32",
121                 target_os = "emscripten"
122             )
123         ))] {
124             #[inline]
125             unsafe fn black_box_impl<T>(d: T) -> T {
126                 // these targets do not support inline assembly
127                 let ret = crate::ptr::read_volatile(&d);
128                 crate::mem::forget(d);
129                 ret
130             }
131         } else {
132             #[inline]
133             unsafe fn black_box_impl<T>(d: T) -> T {
134                 // we need to "use" the argument in some way LLVM can't
135                 // introspect.
136                 asm!("" : : "r"(&d));
137                 d
138             }
139         }
140     }
141     unsafe { black_box_impl(dummy) }
142 }