@@ -20,9 +20,12 @@ pub trait BitPacking: FastLanes {
2020 /// - The input slice must be of exactly length 1024.
2121 /// - The output slice must be of length `1024 * W / T`, where `T` is the (unpacked) bit-width
2222 /// of `Self` and `W` is the packed bit-width.
23- /// - The `width` must be less than or equal to the (unpacked) bit-width of `Self`.
2423 ///
2524 /// These lengths are checked only with `debug_assert` (i.e., not checked on release builds).
25+ ///
26+ /// # Panics
27+ ///
28+ /// Panics if `width` is greater than the (unpacked) bit-width of `Self`.
2629 unsafe fn unchecked_pack ( width : usize , input : & [ Self ] , output : & mut [ Self ] ) ;
2730
2831 /// Unpacks 1024 elements from `W` bits each.
@@ -36,12 +39,19 @@ pub trait BitPacking: FastLanes {
3639 /// - The input slice must be of length `1024 * W / T`, where `T` is the (unpacked) bit-width
3740 /// of `Self` and `W` is the packed bit-width.
3841 /// - The output slice must be of exactly length 1024.
39- /// - The `width` must be less than or equal to the (unpacked) bit-width of `Self`.
4042 ///
4143 /// These lengths are checked only with `debug_assert` (i.e., not checked on release builds).
44+ ///
45+ /// # Panics
46+ ///
47+ /// Panics if `width` is greater than the (unpacked) bit-width of `Self`.
4248 unsafe fn unchecked_unpack ( width : usize , input : & [ Self ] , output : & mut [ Self ] ) ;
4349
4450 /// Unpacks a single element at the provided index from a packed array of 1024 `W` bit elements.
51+ ///
52+ /// # Panics
53+ ///
54+ /// Panics if `W` is not zero and `index` is not less than 1024.
4555 fn unpack_single < const W : usize , const B : usize > ( packed : & [ Self ; B ] , index : usize ) -> Self ;
4656
4757 /// Unpacks a single element at the provided index from a packed array of 1024 `W` bit elements,
@@ -51,9 +61,13 @@ pub trait BitPacking: FastLanes {
5161 ///
5262 /// - The input slice must be of length `1024 * W / T`, where `T` is the (unpacked) bit-width
5363 /// of `Self` and `W` is the packed bit-width.
54- /// - The `width` must be less than or equal to the (unpacked) bit-width of `Self`.
5564 ///
56- /// These lengths are checked only with `debug_assert` (i.e., not checked on release builds).
65+ /// This length is checked only with `debug_assert` (i.e., not checked on release builds).
66+ ///
67+ /// # Panics
68+ ///
69+ /// Panics if `width` is greater than the (unpacked) bit-width of `Self` or, when `width` is
70+ /// not zero, `index` is not less than 1024.
5771 unsafe fn unchecked_unpack_single ( width : usize , input : & [ Self ] , index : usize ) -> Self ;
5872
5973 /// Unpacks selected elements from a packed array of 1024 `W` bit elements.
@@ -76,14 +90,13 @@ pub trait BitPacking: FastLanes {
7690 ///
7791 /// - The input slice must contain exactly `1024 * W / T` elements, where `T` is the unpacked bit
7892 /// width of `Self` and `W` is `width`.
79- /// - The `width` must be less than or equal to the unpacked bit width of `Self`.
8093 ///
81- /// These conditions are checked only with `debug_assert`.
94+ /// This length is checked only with `debug_assert` (i.e., not checked on release builds) .
8295 ///
8396 /// # Panics
8497 ///
85- /// Panics if the output length differs from the index length or, when `width` is not zero, an
86- /// index is not less than 1024.
98+ /// Panics if `width` is greater than the unpacked bit width of `Self`, if the output length
99+ /// differs from the index length or, when `width` is not zero, an index is not less than 1024.
87100 unsafe fn unchecked_unpack_indices (
88101 width : usize ,
89102 input : & [ Self ] ,
@@ -215,16 +228,25 @@ macro_rules! impl_packing {
215228 // decompression can be fused efficiently with encodings like delta and RLE.
216229 //
217230 // First step, we need to get the lane and row for interpretation #1 above.
218- assert!( index < 1024 , "Index must be less than 1024, got {}" , index) ;
231+ // Indexing the 1024-entry tables is the `index < 1024` bounds check; a separate
232+ // assert would only add a second panic path that captures `index` for formatting.
219233 let ( lane, row) : ( usize , usize ) = {
220234 const LANES : [ u8 ; 1024 ] = lanes_by_index:: <$T>( ) ;
221235 const ROWS : [ u8 ; 1024 ] = rows_by_index:: <$T>( ) ;
222236 ( LANES [ index] as usize , ROWS [ index] as usize )
223237 } ;
224238
239+ // The table lookups above bound `lane < LANES` and `row < T`, and the `const`
240+ // block bounds `B == LANES * W`. Every `packed` read below is therefore in-bounds
241+ // by construction, so it is `get_unchecked` rather than a checked index whose
242+ // bounds LLVM cannot prove away through the table loads.
243+
225244 if W == <$T>:: T {
226- // Special case for W==T, we can just read the value directly
227- return packed[ <$T>:: LANES * row + lane] ;
245+ // Special case for W==T, we can just read the value directly.
246+ // SAFETY: `LANES * row + lane <= LANES * (T - 1) + LANES - 1 = 1024 - 1 < B`.
247+ let word = <$T>:: LANES * row + lane;
248+ debug_assert!( word < B ) ;
249+ return unsafe { * packed. get_unchecked( word) } ;
228250 }
229251
230252 let mask: $T = ( 1 << ( W % <$T>:: T ) ) - 1 ;
@@ -233,13 +255,22 @@ macro_rules! impl_packing {
233255 let lo_shift = start_bit % <$T>:: T ;
234256 let remaining_bits = <$T>:: T - lo_shift;
235257
236- let lo = packed[ <$T>:: LANES * start_word + lane] >> lo_shift;
258+ // SAFETY: `start_word = row * W / T <= (T - 1) * W / T < W`, so
259+ // `LANES * start_word + lane < LANES * W == B`.
260+ let lo_word = <$T>:: LANES * start_word + lane;
261+ debug_assert!( lo_word < B ) ;
262+ let lo = unsafe { * packed. get_unchecked( lo_word) } >> lo_shift;
237263 return if remaining_bits >= W {
238264 // in this case we will mask out all bits of hi word
239265 lo & mask
240266 } else {
241267 // guaranteed that lo_shift > 0 and thus remaining_bits < T
242- let hi = packed[ <$T>:: LANES * ( start_word + 1 ) + lane] << remaining_bits;
268+ // SAFETY: the element straddles `start_word` and `start_word + 1`, so its last
269+ // bit `row * W + W - 1 <= T * W - 1` lies in word `start_word + 1 <= W - 1`,
270+ // hence `LANES * (start_word + 1) + lane < LANES * W == B`.
271+ let hi_word = <$T>:: LANES * ( start_word + 1 ) + lane;
272+ debug_assert!( hi_word < B ) ;
273+ let hi = unsafe { * packed. get_unchecked( hi_word) } << remaining_bits;
243274 ( lo | hi) & mask
244275 } ;
245276 }
@@ -285,7 +316,7 @@ macro_rules! impl_packing {
285316 assert!( B == 1024 * W / Self :: T ) ;
286317 }
287318
288- assert_eq !( indices. len( ) , output. len( ) , "Output length must equal index length" ) ;
319+ assert !( indices. len( ) == output. len( ) , "Output length must equal index length" ) ;
289320 if W == 0 {
290321 for value in output {
291322 value. write( 0 as Self ) ;
0 commit comments