Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
21b3ea1
perf(decoding): hold a streamed frame to one window plus a block
polaz Sep 15, 2026
984c3a3
perf(decoding): allocate a declared-size stream frame's buffer once
polaz Sep 15, 2026
8099096
perf(decoding): decode a frame of unknown size straight into the call…
polaz Sep 15, 2026
d3ecc38
fix(decoding): hold direct-path blocks to the block maximum, reserve …
polaz Sep 15, 2026
09b20b6
perf(decoding): fold the block ceiling into the slice bound, keep a b…
polaz Sep 15, 2026
026dc01
fix(decoding): bound block literals, size small rings
polaz Sep 15, 2026
ac4953f
fix(decoding): hold a block to its frame's block maximum
polaz Sep 16, 2026
c347e57
fix(decoding): report short targets on literal-only blocks
polaz Sep 16, 2026
7c336b2
perf(decoding): keep the literal-only write off the per-block body
polaz Sep 16, 2026
58d840e
perf(decoding): keep the infallible literal write for growable backends
polaz Sep 16, 2026
bf45e99
perf(decoding): hand the literal-only write over as a tail call
polaz Sep 16, 2026
193e2f9
perf(decoding): arm the block ceiling where the block maximum is known
polaz Sep 16, 2026
7df1aa4
fix(decoding): stop a full target from pulling in another block
polaz Sep 16, 2026
e5e57b6
refactor(decoding): resolve the kernel once, drop the side detects
polaz Sep 16, 2026
7673672
refactor(decoding): drop the pext side-branch from the sequence readers
polaz Sep 16, 2026
97de827
test(decoding): compare the kernels instead of the removed pext policy
polaz Sep 16, 2026
e5d093c
fix(decoding): give 32-bit x86 its BMI2 tier back
polaz Sep 16, 2026
da99e65
fix(decoding): let the aarch64 tiers reach the literals monomorph
polaz Sep 16, 2026
a7ecf1a
fix(decoding): reserve no more than the frame has left to give
polaz Sep 16, 2026
00997e9
perf(decoding): keep the block-reservation arithmetic off the block body
polaz Sep 16, 2026
a98fd0b
perf(decoding): keep the declared-size field off the hot field layout
polaz Sep 16, 2026
70ba71b
perf(decoding): take the low-bit mask from a table, not a guarded shift
polaz Sep 16, 2026
f3d68e0
perf(decoding): take pext back as a kernel operation
polaz Sep 16, 2026
6a03bea
perf(decoding): keep the mask form of the three-field extract
polaz Sep 16, 2026
3aa5eb2
fix(decoding): finish an empty frame, and cap the ring at what a fram…
polaz Sep 16, 2026
c70fc81
perf(decoding): bzhi for the precomputed HUF mask on Avx2 and Vbmi2
polaz Sep 16, 2026
b09746b
perf(decoding): advance the HUF state by the table's mask on every ke…
polaz Sep 16, 2026
88fba73
fix(decoding): cap the ring's reservation at the declared size, not i…
polaz Sep 16, 2026
ca1963b
test(decoding): gate the VBMI2 kernel tests on the selector's full pr…
polaz Sep 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 8 additions & 175 deletions zstd/src/bit_io/bit_reader_reverse.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
use crate::cpu_kernel::{CpuKernel, ScalarKernel};
use core::convert::TryInto;
use core::marker::PhantomData;
#[cfg(all(feature = "std", target_arch = "x86_64", feature = "kernel-bmi2"))]
use std::sync::OnceLock;

/// Pre-computed mask table: `BIT_MASK[n]` equals the lower `n` bits set,
/// i.e. `(1u64 << n) - 1` for `n` in `0..=64`.
///
/// `mask_lower_bits` no longer reads this table — it computes the mask
/// via `u64::MAX >> (64 - n)` to save a load. The table is still used
/// by the BMI2 PEXT triple-extract path on x86-64 (where the mask is
/// constructed once per call and then fed to `_pext_u64`), and by the
/// tests that verify mask values directly.
#[cfg(any(test, all(target_arch = "x86_64", feature = "kernel-bmi2")))]
/// i.e. `(1u64 << n) - 1` for `n` in `0..=64`. Kept for the tests that verify
/// mask values directly; `mask_lower_bits` computes the mask instead of
/// loading it.
#[cfg(test)]
const BIT_MASK: [u64; 65] = {
let mut table = [0u64; 65];
let mut i: u32 = 1;
Expand All @@ -24,72 +18,6 @@ const BIT_MASK: [u64; 65] = {
table
};

#[cfg(all(feature = "std", target_arch = "x86_64", feature = "kernel-bmi2"))]
#[derive(Copy, Clone)]
struct TripleExtractDispatch {
use_pext: bool,
}

#[cfg(all(feature = "std", target_arch = "x86_64", feature = "kernel-bmi2"))]
static TRIPLE_EXTRACT_DISPATCH: OnceLock<TripleExtractDispatch> = OnceLock::new();

#[cfg(all(feature = "std", target_arch = "x86_64", feature = "kernel-bmi2"))]
#[inline(always)]
fn should_use_pext(vendor: [u8; 12], family: u32) -> bool {
vendor != *b"AuthenticAMD" || family != 0x17
}

#[cfg(all(feature = "std", target_arch = "x86_64", feature = "kernel-bmi2"))]
#[inline(always)]
fn triple_extract_dispatch() -> &'static TripleExtractDispatch {
TRIPLE_EXTRACT_DISPATCH.get_or_init(detect_triple_extract_dispatch)
}

#[cfg(all(feature = "std", target_arch = "x86_64", feature = "kernel-bmi2"))]
fn detect_triple_extract_dispatch() -> TripleExtractDispatch {
use core::arch::x86_64::__cpuid;
use std::arch::is_x86_feature_detected;

if !is_x86_feature_detected!("bmi2") {
return TripleExtractDispatch { use_pext: false };
}

// AMD Zen1/Zen2 execute PEXT/PDEP through a slow microcode path.
// Keep scalar extraction there and enable PEXT on Intel and newer AMD.
let leaf0 = __cpuid(0);
let mut vendor = [0u8; 12];
vendor[0..4].copy_from_slice(&leaf0.ebx.to_le_bytes());
vendor[4..8].copy_from_slice(&leaf0.edx.to_le_bytes());
vendor[8..12].copy_from_slice(&leaf0.ecx.to_le_bytes());
let eax = __cpuid(1).eax;
let base_family = (eax >> 8) & 0xF;
let ext_family = (eax >> 20) & 0xFF;
let family = if base_family == 0xF {
base_family + ext_family
} else {
base_family
};

TripleExtractDispatch {
use_pext: should_use_pext(vendor, family),
}
}

#[cfg(all(target_arch = "x86_64", feature = "kernel-bmi2"))]
#[target_feature(enable = "bmi2")]
unsafe fn extract_triple_pext(all_three: u64, n1: u8, n2: u8, n3: u8) -> (u64, u64, u64) {
use core::arch::x86_64::_pext_u64;

let mask3 = BIT_MASK[n3 as usize];
let mask2 = BIT_MASK[n2 as usize].wrapping_shl(u32::from(n3));
let mask1 = BIT_MASK[n1 as usize].wrapping_shl(u32::from(n2) + u32::from(n3));

let val1 = _pext_u64(all_three, mask1);
let val2 = _pext_u64(all_three, mask2);
let val3 = _pext_u64(all_three, mask3);
(val1, val2, val3)
}

/// Zstandard encodes some types of data in a way that the data must be read
/// back to front to decode it properly. `BitReaderReversed` provides a
/// convenient interface to do that.
Expand Down Expand Up @@ -144,16 +72,6 @@ pub struct BitReaderReversed<'s, K: CpuKernel = ScalarKernel> {
/// drives monomorphisation of methods that route through `K::mask_lower_bits`
/// without forcing the struct itself to carry runtime kernel state.
_kernel: PhantomData<K>,

/// Cached `triple_extract_dispatch().use_pext` snapshot, populated
/// once in `new()`. `peek_bits_triple` reads this field instead of
/// re-checking the global `OnceLock` on every sequence — the
/// per-call atomic load + dispatch-branch was paying ~3 cycles on
/// every sequence decode (thousands per block × many blocks per
/// frame). One bool per `BitReaderReversed` lifetime, amortised
/// across every `peek_bits_triple` in the same decode pass.
#[cfg(all(feature = "std", target_arch = "x86_64", feature = "kernel-bmi2"))]
pub(crate) use_pext_triple: bool,
}

impl<'s, K: CpuKernel> BitReaderReversed<'s, K> {
Expand All @@ -162,32 +80,6 @@ impl<'s, K: CpuKernel> BitReaderReversed<'s, K> {
self.index as isize * 8 + (64 - self.bits_consumed as isize) - self.extra_bits as isize
}

/// Returns `true` when the cached vendor policy says PEXT is fast
/// on the running CPU (Intel + AMD Zen3+) and the bmi2-direct
/// triple-extract path should be used. AMD Zen1/Zen2 microcode
/// PEXT is slower than the scalar 3× shift+mask path, so
/// [`should_use_pext`] caches `false` for those vendors.
///
/// `no_std` x86_64 builds lack the runtime detection (`use_pext_triple`
/// is std-gated), so this falls back to `true`: callers on
/// `no_std` rely on compile-time `target_feature = "bmi2"` and
/// implicitly trust that the chosen target CPU advertises fast
/// PEXT. Vendor-specific microcode regression remains a
/// build-time concern there — pin a known-good target with
/// `RUSTFLAGS="-C target-cpu=..."`.
#[cfg(all(target_arch = "x86_64", feature = "kernel-bmi2"))]
#[inline(always)]
pub(crate) fn use_pext_triple_fast(&self) -> bool {
#[cfg(all(feature = "std", target_arch = "x86_64", feature = "kernel-bmi2"))]
{
self.use_pext_triple
}
#[cfg(not(all(feature = "std", target_arch = "x86_64")))]
{
true
}
}

pub fn new(source: &'s [u8]) -> BitReaderReversed<'s, K> {
BitReaderReversed {
index: source.len(),
Expand All @@ -196,8 +88,6 @@ impl<'s, K: CpuKernel> BitReaderReversed<'s, K> {
bit_container: 0,
extra_bits: 0,
_kernel: PhantomData,
#[cfg(all(feature = "std", target_arch = "x86_64", feature = "kernel-bmi2"))]
use_pext_triple: triple_extract_dispatch().use_pext,
}
}

Expand Down Expand Up @@ -366,21 +256,10 @@ impl<'s, K: CpuKernel> BitReaderReversed<'s, K> {
let shift_by = (64u8 - self.bits_consumed).wrapping_sub(sum);
let all_three = self.bit_container.wrapping_shr(shift_by as u32);

#[cfg(all(feature = "std", target_arch = "x86_64", feature = "kernel-bmi2"))]
if self.use_pext_triple {
// SAFETY: `use_pext_triple` was set in `new()` from
// `triple_extract_dispatch().use_pext`, which only returns
// `true` when BMI2 is runtime-detected; the unsafe call is
// gated on the same runtime check that the inline-form
// `try_extract_triple_with_pext` used to perform per-call.
return unsafe { extract_triple_pext(all_three, n1, n2, n3) };
}

let val1 = K::mask_lower_bits(all_three.wrapping_shr(u32::from(n3) + u32::from(n2)), n1);
let val2 = K::mask_lower_bits(all_three.wrapping_shr(u32::from(n3)), n2);
let val3 = K::mask_lower_bits(all_three, n3);

(val1, val2, val3)
// The kernel was chosen where this decode was dispatched, so the split
// is the monomorph's own instruction sequence. The reader used to carry
// the choice as a flag and branch on it here, once per sequence.
K::extract_triple(all_three, n1, n2, n3)
}

/// BMI2-scoped variant of [`peek_bits`]. The whole body executes
Expand Down Expand Up @@ -411,52 +290,6 @@ impl<'s, K: CpuKernel> BitReaderReversed<'s, K> {
core::arch::x86_64::_bzhi_u64(self.bit_container.wrapping_shr(shift_by as u32), n as u32)
}

/// BMI2-scoped variant of [`peek_bits_triple`]. Mirrors the
/// scalar/K-trait variant but inlines `_pext_u64` directly instead
/// of crossing the `extract_triple_pext` CALL boundary.
///
/// On AMD Zen1/Zen2 (vendor=AuthenticAMD family=0x17) `_pext_u64`
/// goes through slow microcode; callers should still consult
/// `self.use_pext_triple` (populated at construction from the
/// global dispatch cache) and route to the scalar variant on
/// those CPUs. This method assumes the caller already gated on
/// `use_pext_triple == true`.
///
/// # Safety
/// Caller MUST ensure BMI2 is available AND the running CPU
/// benefits from `_pext_u64` (i.e. not Zen1/Zen2).
#[cfg(all(target_arch = "x86_64", feature = "kernel-bmi2"))]
#[target_feature(enable = "bmi2")]
#[inline]
pub(crate) unsafe fn peek_bits_triple_bmi2(
&mut self,
sum: u8,
n1: u8,
n2: u8,
n3: u8,
) -> (u64, u64, u64) {
debug_assert_eq!(
u16::from(sum),
u16::from(n1) + u16::from(n2) + u16::from(n3),
"peek_bits_triple_bmi2: sum ({}) must equal n1+n2+n3 ({}+{}+{})",
sum,
n1,
n2,
n3
);
debug_assert!(
sum == 0 || self.bits_consumed + sum <= 64,
"peek_bits_triple_bmi2: not enough bits (consumed={}, requested={})",
self.bits_consumed,
sum
);
let shift_by = (64u8 - self.bits_consumed).wrapping_sub(sum);
let all_three = self.bit_container.wrapping_shr(shift_by as u32);
// SAFETY: caller's target_feature includes BMI2 per `# Safety`
// contract; same scope as the enclosing fn.
unsafe { extract_triple_pext(all_three, n1, n2, n3) }
}

/// Consume `n` bits from the source.
#[inline(always)]
pub fn consume(&mut self, n: u8) {
Expand Down
Loading