feat(decompress): move platform BMI2 init to Rust

The decoder context remains allocated and laid out by C because optional members
change with the active build configuration. Previously, the C adapter also
owned the platform leaf: its DYNAMIC_BMI2 branch queried CPU features and
assigned the private bmi2 member directly. That kept the policy in C and made
the Rust boundary depend on the context layout.

Move the leaf to Rust and give it an opaque scalar address plus the active
configuration value. The C adapter now only extracts the optional address when
that member exists and forwards it, while DYNAMIC_BMI2=0 passes NULL. Rust
performs the dynamic decision, queries CPU support, and writes the scalar. The
existing 68-word DCtx view is unchanged. Focused unit coverage verifies that
disabled dynamic dispatch leaves the scalar untouched and enabled dispatch
publishes the CPU feature result.

Test Plan:
- `cc -fsyntax-only -Werror -DDYNAMIC_BMI2=0 -Ilib -Ilib/common -Ilib/compress -Ilib/decompress -Ilib/dict -Ilib/legacy lib/decompress/zstd_decompress.c` -- passed
- `cc -fsyntax-only -Werror -DDYNAMIC_BMI2=1 -Ilib -Ilib/common -Ilib/compress -Ilib/decompress -Ilib/dict -Ilib/legacy lib/decompress/zstd_decompress.c` -- passed
- `rustfmt --edition 2021 --check rust/src/zstd_decompress.rs` -- passed
- `git diff --check -- lib/decompress/zstd_decompress.c rust/src/zstd_decompress.rs` -- passed
This commit is contained in:
2026-07-20 14:59:22 +02:00
parent 40137b28bf
commit c2bed1242c
2 changed files with 38 additions and 5 deletions
+33 -2
View File
@@ -344,7 +344,7 @@ unsafe extern "C" {
fn ZSTD_rust_dctx_view(dctx: *mut ZSTD_DCtx, out: *mut ZSTD_rustDctxView);
fn ZSTD_rust_dctx_trace_view(dctx: *mut ZSTD_DCtx, out: *mut ZSTD_rustDctxTraceView);
fn ZSTD_rust_dctx_sizeof() -> usize;
fn ZSTD_rust_dctx_init_platform(dctx: *mut ZSTD_DCtx);
fn ZSTD_dctx_init_platform(dctx: *mut ZSTD_DCtx);
fn ZSTD_rust_dctx_default_max_window_size() -> usize;
fn ZSTD_rust_no_forward_progress_max() -> c_int;
fn ZSTD_rust_heapmode() -> c_int;
@@ -378,6 +378,37 @@ unsafe extern "C" {
fn ZSTD_checkContinuity(dctx: *mut ZSTD_DCtx, dst: *const c_void, dst_size: usize);
}
#[no_mangle]
pub unsafe extern "C" fn ZSTD_rust_dctx_init_platform(bmi2: *mut c_void, dynamic_bmi2: c_int) {
if dynamic_bmi2 != 0 && !bmi2.is_null() {
unsafe {
bmi2.cast::<c_int>()
.write(c_int::from(crate::cpu::ZSTD_cpuSupportsBmi2()));
}
}
}
#[cfg(test)]
mod dctx_platform_tests {
use super::*;
#[test]
fn initializes_bmi2_only_when_dynamic_support_is_enabled() {
let mut bmi2 = c_int::MAX;
unsafe {
ZSTD_rust_dctx_init_platform((&mut bmi2 as *mut c_int).cast(), 0);
}
assert_eq!(bmi2, c_int::MAX);
let expected = c_int::from(crate::cpu::ZSTD_cpuSupportsBmi2());
bmi2 = c_int::MAX;
unsafe {
ZSTD_rust_dctx_init_platform((&mut bmi2 as *mut c_int).cast(), 1);
}
assert_eq!(bmi2, expected);
}
}
type ZstdDecompressDCtxFn =
unsafe extern "C" fn(*mut ZSTD_DCtx, *mut c_void, usize, *const c_void, usize) -> usize;
@@ -2576,7 +2607,7 @@ unsafe fn init_dctx_internal(view: &ZSTD_rustDctxView) {
if !view.fuzz_end.is_null() {
set_pointer(view.fuzz_end, ptr::null());
}
ZSTD_rust_dctx_init_platform(view.dctx.cast());
ZSTD_dctx_init_platform(view.dctx.cast());
}
}