diff --git a/src/nouveau/compiler/nak/hw_tests.rs b/src/nouveau/compiler/nak/hw_tests.rs index f5790361265..0b7853faa0e 100644 --- a/src/nouveau/compiler/nak/hw_tests.rs +++ b/src/nouveau/compiler/nak/hw_tests.rs @@ -566,6 +566,40 @@ fn test_op_iadd3x() { } } +#[test] +fn test_op_shf() { + let sm = &RunSingleton::get().sm; + + let types = [IntType::U32, IntType::I32, IntType::U64, IntType::I64]; + + for i in 0..32 { + let op = OpShf { + dst: Dst::None, + low: 0.into(), + high: 0.into(), + shift: 0.into(), + data_type: types[i & 0x3], + right: i & 0x4 != 0, + wrap: i & 0x8 != 0, + dst_high: i & 0x10 != 0, + }; + + if sm.sm() < 70 && !(op.dst_high || op.right) { + continue; + } + + let shift_idx = op.src_idx(&op.shift); + let mut a = Acorn::new(); + test_foldable_op_with(op, &mut |i| { + if i == shift_idx { + a.get_uint(6) as u32 + } else { + a.get_u32() + } + }); + } +} + #[test] fn test_op_prmt() { let op = OpPrmt { diff --git a/src/nouveau/compiler/nak/ir.rs b/src/nouveau/compiler/nak/ir.rs index d7729538f76..7e00da7106a 100644 --- a/src/nouveau/compiler/nak/ir.rs +++ b/src/nouveau/compiler/nak/ir.rs @@ -2071,7 +2071,7 @@ impl fmt::Display for ImageDim { } } -#[derive(Clone, Copy, Eq, Hash, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum IntType { U8, I8, @@ -3616,7 +3616,7 @@ impl fmt::Display for ShflOp { } #[repr(C)] -#[derive(SrcsAsSlice, DstsAsSlice)] +#[derive(Clone, SrcsAsSlice, DstsAsSlice)] pub struct OpShf { #[dst_type(GPR)] pub dst: Dst, @@ -3636,6 +3636,55 @@ pub struct OpShf { pub dst_high: bool, } +impl Foldable for OpShf { + fn fold(&self, sm: &dyn ShaderModel, f: &mut OpFoldData<'_>) { + let low = f.get_u32_src(self, &self.low); + let high = f.get_u32_src(self, &self.high); + let shift = f.get_u32_src(self, &self.shift); + + let bits: u32 = self.data_type.bits().try_into().unwrap(); + let shift = if self.wrap { + shift & (bits - 1) + } else { + min(shift, bits) + }; + + let x = u64::from(low) | (u64::from(high) << 32); + let shifted = if sm.sm() < 70 + && self.dst_high + && self.data_type != IntType::I64 + { + if self.right { + x.checked_shr(shift).unwrap_or(0) as u64 + } else { + x.checked_shl(shift).unwrap_or(0) as u64 + } + } else if self.data_type.is_signed() { + if self.right { + (x as i64).checked_shr(shift).unwrap_or(0) as u64 + } else { + (x as i64).checked_shl(shift).unwrap_or(0) as u64 + } + } else { + if self.right { + x.checked_shr(shift).unwrap_or(0) as u64 + } else { + x.checked_shl(shift).unwrap_or(0) as u64 + } + }; + + let dst = if sm.sm() < 70 && !self.right { + (shifted >> 32) as u32 + } else if self.dst_high { + (shifted >> 32) as u32 + } else { + shifted as u32 + }; + + f.set_u32_dst(self, &self.dst, dst); + } +} + impl DisplayOp for OpShf { fn fmt_op(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "shf")?;