diff --git a/src/ctx.rs b/src/ctx.rs index be22f7e27..a0605a3e8 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -99,6 +99,32 @@ impl CaseSetter(&mut *buf, val); } + + /// # Safety + /// + /// `buf` must be correctly aligned and dereferencable (but need not be + /// initialized). + #[inline] + pub unsafe fn set_raw(&self, buf: *mut [T], val: T) { + assert!(buf.len() >= self.offset + self.len); + let buf = (buf as *mut T).add(self.offset); + match self.len { + 01 if UP_TO >= 01 => unsafe { *(buf as *mut [T; 01]) = [val; 01] }, + 02 if UP_TO >= 02 => unsafe { *(buf as *mut [T; 02]) = [val; 02] }, + 04 if UP_TO >= 04 => unsafe { *(buf as *mut [T; 04]) = [val; 04] }, + 08 if UP_TO >= 08 => unsafe { *(buf as *mut [T; 08]) = [val; 08] }, + 16 if UP_TO >= 16 => unsafe { *(buf as *mut [T; 16]) = [val; 16] }, + 32 if UP_TO >= 32 => unsafe { *(buf as *mut [T; 32]) = [val; 32] }, + 64 if UP_TO >= 64 => unsafe { *(buf as *mut [T; 64]) = [val; 64] }, + _ => { + if WITH_DEFAULT { + for i in 0..self.len { + unsafe { buf.add(i).write(val) }; + } + } + } + } + } } /// The entrypoint to the [`CaseSet`] API. diff --git a/src/lf_mask.rs b/src/lf_mask.rs index 8ec7ea3a4..c4fc34043 100644 --- a/src/lf_mask.rs +++ b/src/lf_mask.rs @@ -18,6 +18,9 @@ use libc::ptrdiff_t; use parking_lot::RwLock; use std::cmp; use std::ffi::c_int; +use std::mem; +use std::mem::MaybeUninit; +use std::ptr; #[repr(C)] pub struct Av1FilterLUT { @@ -93,7 +96,7 @@ pub struct Av1Restoration { /// Instead of offsetting `txa`, the offsets are calculated from /// the existing `y_off` and `x_off` args and applied at each use site of `txa. fn decomp_tx( - txa: &mut [[[[u8; 32]; 32]; 2]; 2], + txa: &mut [[[[MaybeUninit; 32]; 32]; 2]; 2], from: TxfmSize, depth: usize, y_off: u8, @@ -130,13 +133,15 @@ fn decomp_tx( CaseSet::<16, false>::one((), t_dim.w as usize, x0, |case, ()| { for y in 0..t_dim.h as usize { - case.set(&mut txa[0][0][y0 + y], lw); - case.set(&mut txa[1][0][y0 + y], lh); - txa[0][1][y0 + y][x0] = t_dim.w; + unsafe { + case.set_raw(ptr::from_mut(&mut txa[0][0][y0 + y]) as *mut [u8; 32], lw); + case.set_raw(ptr::from_mut(&mut txa[1][0][y0 + y]) as *mut [u8; 32], lh); + txa[0][1][y0 + y][x0].write(t_dim.w); + } } }); - CaseSet::<16, false>::one((), t_dim.w as usize, x0, |case, ()| { - case.set(&mut txa[1][1][y0], t_dim.h); + CaseSet::<16, false>::one((), t_dim.w as usize, x0, |case, ()| unsafe { + case.set_raw(ptr::from_mut(&mut txa[1][1][y0]) as *mut [u8; 32], t_dim.h); }); }; } @@ -157,7 +162,11 @@ fn mask_edges_inter( let t_dim = &dav1d_txfm_dimensions[max_tx as usize]; // See [`decomp_tx`]'s docs for the `txa` arg. - let mut txa = Align16([[[[0; 32]; 32]; 2]; 2]); + + // SAFETY: We are building an array of uninitialized MaybeUninit values, + // which do not require initialization, so this `assume_init` is safe + let mut txa: Align16<[[[[MaybeUninit; 32]; 32]; 2]; 2]> = + unsafe { MaybeUninit::uninit().assume_init() }; for (y_off, _) in (0..h4).step_by(t_dim.h as usize).enumerate() { for (x_off, _) in (0..w4).step_by(t_dim.w as usize).enumerate() { @@ -165,6 +174,11 @@ fn mask_edges_inter( } } + // SAFETY: Calls to `decomp_tx` above fully initialize the `txa` array. We + // can't call `array_assume_init` because it is unstable, but transmute from + // fully initialized `MaybeUninit` to the same inner type is safe. + let txa: [[[[u8; 32]; 32]; 2]; 2] = unsafe { mem::transmute(txa) }; + // left block edge for y in 0..h4 { let mask = 1u32 << (by4 + y);