]>
Commit | Line | Data |
---|---|---|
83c7162d XL |
1 | #![stable(feature = "core_hint", since = "1.27.0")] |
2 | ||
3 | //! Hints to compiler that affects how code should be emitted or optimized. | |
4 | ||
60c5eb7d XL |
5 | // ignore-tidy-undocumented-unsafe |
6 | ||
48663c56 | 7 | use crate::intrinsics; |
83c7162d XL |
8 | |
9 | /// Informs the compiler that this point in the code is not reachable, enabling | |
10 | /// further optimizations. | |
11 | /// | |
12 | /// # Safety | |
13 | /// | |
14 | /// Reaching this function is completely *undefined behavior* (UB). In | |
15 | /// particular, the compiler assumes that all UB must never happen, and | |
16 | /// therefore will eliminate all branches that reach to a call to | |
17 | /// `unreachable_unchecked()`. | |
18 | /// | |
0731742a | 19 | /// Like all instances of UB, if this assumption turns out to be wrong, i.e., the |
83c7162d XL |
20 | /// `unreachable_unchecked()` call is actually reachable among all possible |
21 | /// control flow, the compiler will apply the wrong optimization strategy, and | |
22 | /// may sometimes even corrupt seemingly unrelated code, causing | |
23 | /// difficult-to-debug problems. | |
24 | /// | |
25 | /// Use this function only when you can prove that the code will never call it. | |
48663c56 XL |
26 | /// Otherwise, consider using the [`unreachable!`] macro, which does not allow |
27 | /// optimizations but will panic when executed. | |
83c7162d | 28 | /// |
48663c56 | 29 | /// [`unreachable!`]: ../macro.unreachable.html |
83c7162d XL |
30 | /// |
31 | /// # Example | |
32 | /// | |
33 | /// ``` | |
34 | /// fn div_1(a: u32, b: u32) -> u32 { | |
35 | /// use std::hint::unreachable_unchecked; | |
36 | /// | |
37 | /// // `b.saturating_add(1)` is always positive (not zero), | |
9fa01778 | 38 | /// // hence `checked_div` will never return `None`. |
83c7162d XL |
39 | /// // Therefore, the else branch is unreachable. |
40 | /// a.checked_div(b.saturating_add(1)) | |
41 | /// .unwrap_or_else(|| unsafe { unreachable_unchecked() }) | |
42 | /// } | |
43 | /// | |
44 | /// assert_eq!(div_1(7, 0), 7); | |
45 | /// assert_eq!(div_1(9, 1), 4); | |
46 | /// assert_eq!(div_1(11, std::u32::MAX), 0); | |
47 | /// ``` | |
48 | #[inline] | |
49 | #[stable(feature = "unreachable", since = "1.27.0")] | |
50 | pub unsafe fn unreachable_unchecked() -> ! { | |
51 | intrinsics::unreachable() | |
52 | } | |
9fa01778 | 53 | |
e1599b0c XL |
54 | /// Emits a machine instruction hinting to the processor that it is running in busy-wait |
55 | /// spin-loop ("spin lock"). | |
9fa01778 | 56 | /// |
e1599b0c XL |
57 | /// For a discussion of different locking strategies and their trade-offs, see |
58 | /// [`core::sync::atomic::spin_loop_hint`]. | |
532ac7d7 XL |
59 | /// |
60 | /// **Note**: On platforms that do not support receiving spin-loop hints this function does not | |
61 | /// do anything at all. | |
62 | /// | |
e1599b0c | 63 | /// [`core::sync::atomic::spin_loop_hint`]: ../sync/atomic/fn.spin_loop_hint.html |
9fa01778 XL |
64 | #[inline] |
65 | #[unstable(feature = "renamed_spin_loop", issue = "55002")] | |
66 | pub fn spin_loop() { | |
60c5eb7d XL |
67 | #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))] |
68 | { | |
69 | #[cfg(target_arch = "x86")] | |
70 | { | |
532ac7d7 XL |
71 | unsafe { crate::arch::x86::_mm_pause() }; |
72 | } | |
73 | ||
60c5eb7d XL |
74 | #[cfg(target_arch = "x86_64")] |
75 | { | |
532ac7d7 XL |
76 | unsafe { crate::arch::x86_64::_mm_pause() }; |
77 | } | |
9fa01778 XL |
78 | } |
79 | ||
60c5eb7d XL |
80 | #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))] |
81 | { | |
82 | #[cfg(target_arch = "aarch64")] | |
83 | { | |
532ac7d7 XL |
84 | unsafe { crate::arch::aarch64::__yield() }; |
85 | } | |
60c5eb7d XL |
86 | #[cfg(target_arch = "arm")] |
87 | { | |
532ac7d7 XL |
88 | unsafe { crate::arch::arm::__yield() }; |
89 | } | |
90 | } | |
91 | } | |
92 | ||
e1599b0c XL |
93 | /// An identity function that *__hints__* to the compiler to be maximally pessimistic about what |
94 | /// `black_box` could do. | |
95 | /// | |
96 | /// [`std::convert::identity`]: https://doc.rust-lang.org/core/convert/fn.identity.html | |
97 | /// | |
98 | /// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can | |
99 | /// use `x` in any possible valid way that Rust code is allowed to without introducing undefined | |
100 | /// behavior in the calling code. This property makes `black_box` useful for writing code in which | |
101 | /// certain optimizations are not desired, such as benchmarks. | |
532ac7d7 | 102 | /// |
e1599b0c XL |
103 | /// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The |
104 | /// extent to which it can block optimisations may vary depending upon the platform and code-gen | |
105 | /// backend used. Programs cannot rely on `black_box` for *correctness* in any way. | |
532ac7d7 | 106 | #[inline] |
416331ca | 107 | #[unstable(feature = "test", issue = "50297")] |
dc9dc135 | 108 | #[allow(unreachable_code)] // this makes #[cfg] a bit easier below. |
532ac7d7 | 109 | pub fn black_box<T>(dummy: T) -> T { |
dc9dc135 XL |
110 | // We need to "use" the argument in some way LLVM can't introspect, and on |
111 | // targets that support it we can typically leverage inline assembly to do | |
60c5eb7d | 112 | // this. LLVM's interpretation of inline assembly is that it's, well, a black |
dc9dc135 XL |
113 | // box. This isn't the greatest implementation since it probably deoptimizes |
114 | // more than we want, but it's so far good enough. | |
dc9dc135 XL |
115 | unsafe { |
116 | asm!("" : : "r"(&dummy)); | |
117 | return dummy; | |
118 | } | |
9fa01778 | 119 | } |