diff options
Diffstat (limited to 'library/core/src/hint.rs')
| -rw-r--r-- | library/core/src/hint.rs | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs new file mode 100644 index 00000000000..3116815f5d6 --- /dev/null +++ b/library/core/src/hint.rs @@ -0,0 +1,127 @@ +#![stable(feature = "core_hint", since = "1.27.0")] + +//! Hints to compiler that affects how code should be emitted or optimized. + +use crate::intrinsics; + +/// Informs the compiler that this point in the code is not reachable, enabling +/// further optimizations. +/// +/// # Safety +/// +/// Reaching this function is completely *undefined behavior* (UB). In +/// particular, the compiler assumes that all UB must never happen, and +/// therefore will eliminate all branches that reach to a call to +/// `unreachable_unchecked()`. +/// +/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the +/// `unreachable_unchecked()` call is actually reachable among all possible +/// control flow, the compiler will apply the wrong optimization strategy, and +/// may sometimes even corrupt seemingly unrelated code, causing +/// difficult-to-debug problems. +/// +/// Use this function only when you can prove that the code will never call it. +/// Otherwise, consider using the [`unreachable!`] macro, which does not allow +/// optimizations but will panic when executed. +/// +/// [`unreachable!`]: ../macro.unreachable.html +/// +/// # Example +/// +/// ``` +/// fn div_1(a: u32, b: u32) -> u32 { +/// use std::hint::unreachable_unchecked; +/// +/// // `b.saturating_add(1)` is always positive (not zero), +/// // hence `checked_div` will never return `None`. +/// // Therefore, the else branch is unreachable. +/// a.checked_div(b.saturating_add(1)) +/// .unwrap_or_else(|| unsafe { unreachable_unchecked() }) +/// } +/// +/// assert_eq!(div_1(7, 0), 7); +/// assert_eq!(div_1(9, 1), 4); +/// assert_eq!(div_1(11, u32::MAX), 0); +/// ``` +#[inline] +#[stable(feature = "unreachable", since = "1.27.0")] +#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")] +pub const unsafe fn unreachable_unchecked() -> ! { + // SAFETY: the safety contract for `intrinsics::unreachable` must + // be upheld by the caller. + unsafe { intrinsics::unreachable() } +} + +/// Emits a machine instruction hinting to the processor that it is running in busy-wait +/// spin-loop ("spin lock"). +/// +/// For a discussion of different locking strategies and their trade-offs, see +/// [`core::sync::atomic::spin_loop_hint`]. +/// +/// **Note**: On platforms that do not support receiving spin-loop hints this function does not +/// do anything at all. +/// +/// [`core::sync::atomic::spin_loop_hint`]: ../sync/atomic/fn.spin_loop_hint.html +#[inline] +#[unstable(feature = "renamed_spin_loop", issue = "55002")] +pub fn spin_loop() { + #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))] + { + #[cfg(target_arch = "x86")] + { + // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets. + unsafe { crate::arch::x86::_mm_pause() }; + } + + #[cfg(target_arch = "x86_64")] + { + // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets. + unsafe { crate::arch::x86_64::_mm_pause() }; + } + } + + #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))] + { + #[cfg(target_arch = "aarch64")] + { + // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets. + unsafe { crate::arch::aarch64::__yield() }; + } + #[cfg(target_arch = "arm")] + { + // SAFETY: the `cfg` attr ensures that we only execute this on arm targets + // with support for the v6 feature. + unsafe { crate::arch::arm::__yield() }; + } + } +} + +/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what +/// `black_box` could do. +/// +/// [`std::convert::identity`]: https://doc.rust-lang.org/core/convert/fn.identity.html +/// +/// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can +/// use `x` in any possible valid way that Rust code is allowed to without introducing undefined +/// behavior in the calling code. This property makes `black_box` useful for writing code in which +/// certain optimizations are not desired, such as benchmarks. +/// +/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The +/// extent to which it can block optimisations may vary depending upon the platform and code-gen +/// backend used. Programs cannot rely on `black_box` for *correctness* in any way. +#[inline] +#[unstable(feature = "test", issue = "50297")] +#[allow(unreachable_code)] // this makes #[cfg] a bit easier below. +pub fn black_box<T>(dummy: T) -> T { + // We need to "use" the argument in some way LLVM can't introspect, and on + // targets that support it we can typically leverage inline assembly to do + // this. LLVM's interpretation of inline assembly is that it's, well, a black + // box. This isn't the greatest implementation since it probably deoptimizes + // more than we want, but it's so far good enough. + + // SAFETY: the inline assembly is a no-op. + unsafe { + llvm_asm!("" : : "r"(&dummy)); + dummy + } +} |
