pub struct MaskShiftSpec(/* private fields */);Expand description
A BlockSizeSpec that packs the alignment mask in the upper 32 bits and the power-of-two bit
shift in the lower 32 bits: (mask << 32) | shift.
This representation is an extremely efficient way to store a runtime power-of-two block size on modern 64-bit architectures (AArch64 and x86_64).
§Why this representation was chosen:
-
Zero Dynamic Bit-Scanning Latency: Representations that only store the size or the mask must dynamically compute
shiftvia trailing-zero counting (trailing_zerosortrailing_ones).- On ARM64, computing trailing ones requires a dependent instruction chain:
mvn+rbit+clz. On in-order efficiency cores, this 3-instruction dependency stalls the pipeline, making operations likeshift,div, andmulmore than 2x slower.
- On ARM64, computing trailing ones requires a dependent instruction chain:
-
The 6-Bit Shift Rule (Zero-Instruction Unpacking for Shifts): Variable shift instructions on both AArch64 (
lsr xd, xn, xm/lsl xd, xn, xm) and x86_64 (shrx r64, r64, r64) only inspect the lowest 6 bits of the register operand (shift_amount mod 64). Becauseshift(which is between 0 and 32) is placed in the low 32 bits ([31..0]), the lowest 6 bits of the rawu64are literally the shift amount. Consequently, compilers do not need to mask, clear, or moveshiftinto a temporary register before shifting. The raw 64-bitMaskShiftSpecregister can be passed directly as the shift operand, executing in a single instruction and single cycle (lsr x_val, x_val, x_bs). -
ARM64 Fused Barrel Shifter (
adds ..., lsr #32): ARM64 ALU instructions feature a hardware barrel shifter that can shift an input operand at zero extra cycle cost. To add the mask to an offset (such as duringalign_uporalign_up_to_blocks), the compiler emits:adds x_res, x_val, x_bs, lsr #32This shifts out the low 32 bits and adds the high 32-bit mask in a single cycle. In
align_up_to_blocks, the compiler follows this immediately withlsr x_res, x_res, x_bs, performing the combined align-and-divide in just two back-to-back single-cycle instructions. -
Packed
u64vs. Two Separateu32Fields: Storing a single packedu64is superior to a struct with twou32s ({ shift: u32, mask: u32 }):- Register Pressure & ABI: Under Rust’s internal calling convention, small multi-field
structs are scalarized across multiple registers when passed by value. A packed
u64always consumes a single argument register, avoiding register pressure and spills in functions with many arguments. - Register Reuse on ARM64: With a single
u64, the exact same register can be fed directly into both the barrel-shifted mask operation (adds ..., x0, lsr #32) and the shift (lsr ..., x0). Separate fields force values into different registers and require moving or zero-extending them.
- Register Pressure & ABI: Under Rust’s internal calling convention, small multi-field
structs are scalarized across multiple registers when passed by value. A packed
Trait Implementations§
Source§impl BlockSizeSpec for MaskShiftSpec
impl BlockSizeSpec for MaskShiftSpec
Source§impl Clone for MaskShiftSpec
impl Clone for MaskShiftSpec
Source§fn clone(&self) -> MaskShiftSpec
fn clone(&self) -> MaskShiftSpec
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more