diff --git a/src/nouveau/compiler/nak/hw_tests.rs b/src/nouveau/compiler/nak/hw_tests.rs index 2e179e2c9b5..5330ed408c1 100644 --- a/src/nouveau/compiler/nak/hw_tests.rs +++ b/src/nouveau/compiler/nak/hw_tests.rs @@ -566,6 +566,61 @@ fn test_op_iadd3x() { } } +#[test] +fn test_op_isetp() { + let set_ops = [PredSetOp::And, PredSetOp::Or, PredSetOp::Xor]; + let cmp_ops = [ + IntCmpOp::Eq, + IntCmpOp::Ne, + IntCmpOp::Lt, + IntCmpOp::Le, + IntCmpOp::Gt, + IntCmpOp::Ge, + ]; + let cmp_types = [IntCmpType::U32, IntCmpType::I32]; + + for mut i in 0..(set_ops.len() * cmp_ops.len() * cmp_types.len() * 2) { + let set_op = set_ops[i % set_ops.len()]; + i /= set_ops.len(); + + let cmp_op = cmp_ops[i % cmp_ops.len()]; + i /= cmp_ops.len(); + + let cmp_type = cmp_types[i % cmp_types.len()]; + i /= cmp_types.len(); + + let ex = i != 0; + + let op = OpISetP { + dst: Dst::None, + set_op, + cmp_op, + cmp_type, + ex, + srcs: [0.into(), 0.into()], + accum: 0.into(), + low_cmp: 0.into(), + }; + + let src0_idx = op.src_idx(&op.srcs[0]); + let mut a = Acorn::new(); + let mut src0 = 0_u32; + test_foldable_op_with(op, &mut |i| { + let x = a.get_u32(); + if i == src0_idx { + src0 = x; + } + + // Make src0 and src1 + if i == src0_idx + 1 && a.get_bool() { + src0 + } else { + x + } + }); + } +} + #[test] fn test_op_shf() { let sm = &RunSingleton::get().sm; diff --git a/src/nouveau/compiler/nak/ir.rs b/src/nouveau/compiler/nak/ir.rs index d873908d65d..20d77d13783 100644 --- a/src/nouveau/compiler/nak/ir.rs +++ b/src/nouveau/compiler/nak/ir.rs @@ -3541,7 +3541,7 @@ impl DisplayOp for OpIMnMx { impl_display_for_op!(OpIMnMx); #[repr(C)] -#[derive(SrcsAsSlice, DstsAsSlice)] +#[derive(Clone, SrcsAsSlice, DstsAsSlice)] pub struct OpISetP { #[dst_type(Pred)] pub dst: Dst, @@ -3561,6 +3561,73 @@ pub struct OpISetP { pub low_cmp: Src, } +impl Foldable for OpISetP { + fn fold(&self, sm: &dyn ShaderModel, f: &mut OpFoldData<'_>) { + let x = f.get_u32_src(self, &self.srcs[0]); + let y = f.get_u32_src(self, &self.srcs[1]); + let accum = f.get_pred_src(self, &self.accum); + let low_cmp = f.get_pred_src(self, &self.low_cmp); + + let cmp = if self.cmp_type.is_signed() { + let x = x as i32; + let y = y as i32; + match &self.cmp_op { + IntCmpOp::Eq => x == y, + IntCmpOp::Ne => x != y, + IntCmpOp::Lt => x < y, + IntCmpOp::Le => x <= y, + IntCmpOp::Gt => x > y, + IntCmpOp::Ge => x >= y, + } + } else { + match &self.cmp_op { + IntCmpOp::Eq => x == y, + IntCmpOp::Ne => x != y, + IntCmpOp::Lt => x < y, + IntCmpOp::Le => x <= y, + IntCmpOp::Gt => x > y, + IntCmpOp::Ge => x >= y, + } + }; + + let dst = if sm.sm() >= 70 { + let cmp = if self.ex && x == y { low_cmp } else { cmp }; + match &self.set_op { + PredSetOp::And => cmp & accum, + PredSetOp::Or => cmp | accum, + PredSetOp::Xor => cmp ^ accum, + } + } else { + if self.ex && x == y { + match self.cmp_op { + IntCmpOp::Eq | IntCmpOp::Gt | IntCmpOp::Ge => { + match &self.set_op { + PredSetOp::And => false, + PredSetOp::Or => accum, + PredSetOp::Xor => accum, + } + } + IntCmpOp::Ne | IntCmpOp::Lt | IntCmpOp::Le => { + match &self.set_op { + PredSetOp::And => accum, + PredSetOp::Or => true, + PredSetOp::Xor => !accum, + } + } + } + } else { + match &self.set_op { + PredSetOp::And => cmp & accum, + PredSetOp::Or => cmp | accum, + PredSetOp::Xor => cmp ^ accum, + } + } + }; + + f.set_pred_dst(self, &self.dst, dst); + } +} + impl DisplayOp for OpISetP { fn fmt_op(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "isetp{}{}", self.cmp_op, self.cmp_type)?;