#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(
rustc_ge_1_54_0,
cfg_attr(all(), doc = include_str!("../README.md"))
)]
#![cfg_attr(
not(rustc_ge_1_54_0),
doc = "Branch prediction hints (`likely`, `unlikely`, `mark_unlikely`), control-flow \
assumptions (`assume`), `abort`, and CPU cache prefetch helpers for stable Rust. \
See the project README for the full documentation."
)]
#![warn(missing_docs, missing_debug_implementations)]
#![cfg_attr(branches_nightly, feature(core_intrinsics))]
#![cfg_attr(branches_nightly, allow(internal_features))]
#[cfg(all(branches_stable, not(rustc_ge_1_95_0)))]
#[cfg_attr(not(branches_cold_weights), inline(never))]
#[cold]
const fn cold_and_empty() {}
#[cfg(all(branches_stable, rustc_ge_1_95_0))]
use core::hint::cold_path as cold_and_empty;
#[cold]
pub extern "C" fn abort() -> ! {
#[cfg(feature = "std")]
std::process::abort();
#[cfg(all(not(feature = "std"), branches_nightly))]
core::intrinsics::abort();
#[cfg(all(not(feature = "std"), branches_stable))]
panic!("branches::abort() called");
}
#[inline(always)]
pub const unsafe fn assume(b: bool) {
let _ = b;
#[cfg(all(branches_stable, rustc_ge_1_81_0))]
#[allow(clippy::incompatible_msrv)]
{
core::hint::assert_unchecked(b)
}
#[cfg(all(branches_stable, rustc_ge_1_57_0, not(rustc_ge_1_81_0)))]
{
if !b {
core::hint::unreachable_unchecked()
}
}
#[cfg(all(branches_nightly, rustc_ge_1_57_0))]
core::intrinsics::assume(b)
}
#[must_use = "the hint only takes effect when the returned value is used as a branch condition"]
#[inline(always)]
pub fn likely(b: bool) -> bool {
#[cfg(branches_stable)]
#[allow(clippy::incompatible_msrv)]
{
if !b {
cold_and_empty();
}
b
}
#[cfg(branches_nightly)]
core::intrinsics::likely(b)
}
#[cfg(not(rustc_ge_1_95_0))]
#[cold]
#[cfg_attr(not(branches_cold_weights), inline(never))]
pub const fn mark_unlikely() {}
#[cfg(rustc_ge_1_95_0)]
pub use core::hint::cold_path as mark_unlikely;
#[must_use = "the hint only takes effect when the returned value is used as a branch condition"]
#[inline(always)]
pub fn unlikely(b: bool) -> bool {
#[cfg(branches_stable)]
#[allow(clippy::incompatible_msrv)]
{
if b {
cold_and_empty();
}
b
}
#[cfg(branches_nightly)]
core::intrinsics::unlikely(b)
}
#[inline(always)]
#[cfg(feature = "prefetch")]
pub fn prefetch_read_data<T, const LOCALITY: i32>(addr: *const T) {
let _ = addr;
#[cfg(branches_stable)]
{
#[cfg(all(
rustc_ge_1_59_0,
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "sse"
))]
unsafe {
match LOCALITY {
0 => core::arch::asm!(
"prefetcht0 [{}]",
in(reg) addr,
options(nostack, readonly, preserves_flags)
), 1 => core::arch::asm!(
"prefetcht1 [{}]",
in(reg) addr,
options(nostack, readonly, preserves_flags)
), 2 => core::arch::asm!(
"prefetcht2 [{}]",
in(reg) addr,
options(nostack, readonly, preserves_flags)
), _ => core::arch::asm!(
"prefetchnta [{}]",
in(reg) addr,
options(nostack, readonly, preserves_flags)
), }
}
#[cfg(all(rustc_ge_1_59_0, target_arch = "aarch64"))]
unsafe {
match LOCALITY {
0 => core::arch::asm!(
"prfm pldl1keep, [{}]",
in(reg) addr,
options(nostack, readonly, preserves_flags)
), 1 => core::arch::asm!(
"prfm pldl2keep, [{}]",
in(reg) addr,
options(nostack, readonly, preserves_flags)
), 2 => core::arch::asm!(
"prfm pldl3keep, [{}]",
in(reg) addr,
options(nostack, readonly, preserves_flags)
), _ => core::arch::asm!(
"prfm pldl1strm, [{}]",
in(reg) addr,
options(nostack, readonly, preserves_flags)
), }
}
#[cfg(all(rustc_ge_1_59_0, target_arch = "riscv64", target_feature = "zicbop"))]
unsafe {
core::arch::asm!(
"prefetch.r 0({})",
in(reg) addr,
options(nostack, readonly, preserves_flags)
);
}
#[cfg(all(rustc_ge_1_84_0, target_arch = "s390x"))]
unsafe {
core::arch::asm!(
"pfd 1, 0({})",
in(reg_addr) addr,
options(nostack, readonly, preserves_flags)
); }
#[cfg(all(
rustc_ge_1_95_0,
any(target_arch = "powerpc", target_arch = "powerpc64")
))]
unsafe {
core::arch::asm!(
"dcbt 0, {}",
in(reg) addr,
options(nostack, readonly, preserves_flags)
);
}
}
#[cfg(branches_nightly)]
{
match LOCALITY {
0 => core::intrinsics::prefetch_read_data::<_, 3>(addr),
1 => core::intrinsics::prefetch_read_data::<_, 2>(addr),
2 => core::intrinsics::prefetch_read_data::<_, 1>(addr),
_ => core::intrinsics::prefetch_read_data::<_, 0>(addr),
}
}
}
#[inline(always)]
#[cfg(feature = "prefetch")]
pub fn prefetch_write_data<T, const LOCALITY: i32>(addr: *const T) {
let _ = addr;
#[cfg(branches_stable)]
{
#[cfg(all(rustc_ge_1_59_0, target_arch = "x86_64"))]
unsafe {
core::arch::asm!(
"prefetchw [{}]",
in(reg) addr,
options(nostack, readonly, preserves_flags)
) }
#[cfg(all(rustc_ge_1_59_0, target_arch = "x86", target_feature = "sse"))]
unsafe {
core::arch::asm!(
"prefetcht0 [{}]",
in(reg) addr,
options(nostack, readonly, preserves_flags)
)
}
#[cfg(all(rustc_ge_1_59_0, target_arch = "aarch64"))]
unsafe {
match LOCALITY {
0 => core::arch::asm!(
"prfm pstl1keep, [{}]",
in(reg) addr,
options(nostack, readonly, preserves_flags)
), 1 => core::arch::asm!(
"prfm pstl2keep, [{}]",
in(reg) addr,
options(nostack, readonly, preserves_flags)
), 2 => core::arch::asm!(
"prfm pstl3keep, [{}]",
in(reg) addr,
options(nostack, readonly, preserves_flags)
), _ => core::arch::asm!(
"prfm pstl1strm, [{}]",
in(reg) addr,
options(nostack, readonly, preserves_flags)
), }
}
#[cfg(all(rustc_ge_1_59_0, target_arch = "riscv64", target_feature = "zicbop"))]
unsafe {
core::arch::asm!(
"prefetch.w 0({})",
in(reg) addr,
options(nostack, readonly, preserves_flags)
);
}
#[cfg(all(rustc_ge_1_84_0, target_arch = "s390x"))]
unsafe {
core::arch::asm!(
"pfd 2, 0({})",
in(reg_addr) addr,
options(nostack, readonly, preserves_flags)
); }
#[cfg(all(
rustc_ge_1_95_0,
any(target_arch = "powerpc", target_arch = "powerpc64")
))]
unsafe {
core::arch::asm!(
"dcbtst 0, {}",
in(reg) addr,
options(nostack, readonly, preserves_flags)
); }
}
#[cfg(branches_nightly)]
{
match LOCALITY {
0 => core::intrinsics::prefetch_write_data::<_, 3>(addr),
1 => core::intrinsics::prefetch_write_data::<_, 2>(addr),
2 => core::intrinsics::prefetch_write_data::<_, 1>(addr),
_ => core::intrinsics::prefetch_write_data::<_, 0>(addr),
}
}
}
#[cfg(branches_check_asm)]
#[doc(hidden)]
pub fn __branches_check_asm(addr: *const u8, cond: bool) -> bool {
let _ = addr;
#[cfg(feature = "prefetch")]
{
prefetch_read_data::<_, 0>(addr);
prefetch_read_data::<_, 1>(addr);
prefetch_read_data::<_, 2>(addr);
prefetch_read_data::<_, 3>(addr);
prefetch_read_data::<_, { -1 }>(addr);
prefetch_write_data::<_, 0>(addr);
prefetch_write_data::<_, 1>(addr);
prefetch_write_data::<_, 2>(addr);
prefetch_write_data::<_, 3>(addr);
prefetch_write_data::<_, { -1 }>(addr);
}
if unlikely(!cond) {
mark_unlikely();
}
likely(cond)
}