diff --git a/src/nouveau/compiler/nak_ir.rs b/src/nouveau/compiler/nak_ir.rs index 25bfc8cbbaf..9ebab49ffb9 100644 --- a/src/nouveau/compiler/nak_ir.rs +++ b/src/nouveau/compiler/nak_ir.rs @@ -357,6 +357,20 @@ impl SrcMod { } } + pub fn is_alu(&self) -> bool { + match self { + SrcMod::None | SrcMod::Abs | SrcMod::Neg | SrcMod::NegAbs => true, + SrcMod::Not => false, + } + } + + pub fn is_bitwise(&self) -> bool { + match self { + SrcMod::None | SrcMod::Not => true, + SrcMod::Abs | SrcMod::Neg | SrcMod::NegAbs => false, + } + } + pub fn has_neg(&self) -> bool { match self { SrcMod::None | SrcMod::Abs => false, diff --git a/src/nouveau/compiler/nak_opt_copy_prop.rs b/src/nouveau/compiler/nak_opt_copy_prop.rs index ed004e93c72..4713e79dc44 100644 --- a/src/nouveau/compiler/nak_opt_copy_prop.rs +++ b/src/nouveau/compiler/nak_opt_copy_prop.rs @@ -6,9 +6,33 @@ use crate::nak_ir::*; use std::collections::HashMap; +use std::slice; + +#[derive(Clone, Copy, Eq, PartialEq)] +enum CopyType { + Raw, + Bits, + F32, + I32, +} + +#[derive(Clone)] +struct CopyEntry { + typ: CopyType, + src: Src, +} + +impl CopyEntry { + pub fn supports_type(&self, typ: CopyType) -> bool { + match self.typ { + CopyType::Raw => true, + entry_typ => entry_typ == typ, + } + } +} struct CopyPropPass { - ssa_map: HashMap>, + ssa_map: HashMap>, } impl CopyPropPass { @@ -18,32 +42,147 @@ impl CopyPropPass { } } - fn add_copy(&mut self, dst: &SSAValue, src_vec: Vec) { - self.ssa_map.insert(*dst, src_vec); + fn add_copy(&mut self, dst: &SSAValue, typ: CopyType, src_vec: &[Src]) { + let entries = src_vec + .iter() + .map(|src| { + match typ { + CopyType::Raw => assert!(src.src_mod.is_none()), + CopyType::Bits => assert!(src.src_mod.is_bitwise()), + CopyType::F32 | CopyType::I32 => { + assert!(src.src_mod.is_alu()) + } + } + CopyEntry { + typ: match src.src_mod { + SrcMod::None => CopyType::Raw, + SrcMod::Abs | SrcMod::Neg | SrcMod::NegAbs => { + assert!( + typ != CopyType::Raw && typ != CopyType::Bits + ); + typ + } + SrcMod::Not => { + assert!(typ == CopyType::Bits); + typ + } + }, + src: *src, + } + }) + .collect(); + self.ssa_map.insert(*dst, entries); } - fn get_copy(&mut self, dst: &SSAValue) -> Option<&Vec> { + fn add_copy_entry(&mut self, dst: &SSAValue, entry: CopyEntry) { + self.ssa_map.insert(*dst, vec![entry]); + } + + fn get_copy(&mut self, dst: &SSAValue) -> Option<&Vec> { self.ssa_map.get(dst) } + fn prop_to_pred(&mut self, pred: &mut Pred, pred_inv: &mut bool) { + if let Pred::SSA(src_ssa) = pred { + if let Some(src_vec) = self.get_copy(&src_ssa) { + let entry = &src_vec[0]; + if !entry.supports_type(CopyType::Bits) { + return; + } + + *pred = Pred::SSA(*entry.src.src_ref.as_ssa().unwrap()); + if entry.src.src_mod.has_not() { + *pred_inv = !*pred_inv; + } + } + } + } + + fn prop_to_src(&mut self, src: &mut Src, src_typ: CopyType) -> bool { + if let SrcRef::SSA(src_ssa) = src.src_ref { + if src_ssa.comps() != 1 { + return false; /* TODO */ + } + + if let Some(src_vec) = self.get_copy(&src_ssa) { + let entry = &src_vec[0]; + if !entry.supports_type(src_typ) { + return false; + } + + let mut new_src = entry.src; + match src_typ { + CopyType::Raw => { + assert!(src.src_mod.is_none()); + } + CopyType::Bits => { + if src.src_mod.has_neg() { + new_src.src_mod = new_src.src_mod.neg(); + } + } + CopyType::F32 | CopyType::I32 => { + if src.src_mod.has_abs() { + new_src.src_mod = new_src.src_mod.abs(); + } + if src.src_mod.has_neg() { + new_src.src_mod = new_src.src_mod.neg(); + } + } + } + *src = new_src; + true + } else { + false + } + } else { + false + } + } + + fn prop_to_srcs(&mut self, srcs: &mut [Src], src_typ: CopyType) -> bool { + let mut progress = false; + for src in srcs { + progress |= self.prop_to_src(src, src_typ); + } + progress + } + pub fn run(&mut self, f: &mut Function) { for b in &mut f.blocks { for instr in &mut b.instrs { match &instr.op { + Op::FMov(mov) => { + if !mov.saturate { + self.add_copy( + mov.dst.as_ssa().unwrap(), + CopyType::F32, + slice::from_ref(&mov.src), + ); + } + } + Op::IMov(mov) => { + self.add_copy( + mov.dst.as_ssa().unwrap(), + CopyType::I32, + slice::from_ref(&mov.src), + ); + } Op::Vec(vec) => { self.add_copy( vec.dst.as_ssa().unwrap(), - vec.srcs.to_vec(), + CopyType::Raw, + &vec.srcs, ); } Op::Split(split) => { assert!(split.src.src_mod.is_none()); let src_ssa = split.src.src_ref.as_ssa().unwrap(); - if let Some(src_vec) = self.get_copy(src_ssa).cloned() { + if let Some(src_vec) = self.get_copy(src_ssa) { + let mut src_vec = src_vec.clone(); assert!(src_vec.len() == split.dsts.len()); - for (i, dst) in split.dsts.iter().enumerate() { - if let Dst::SSA(ssa) = dst { - self.add_copy(ssa, vec![src_vec[i]]); + for (i, entry) in src_vec.drain(..).enumerate() { + if let Dst::SSA(ssa) = &split.dsts[i] { + self.add_copy_entry(ssa, entry); } } } @@ -51,23 +190,49 @@ impl CopyPropPass { _ => (), } - if let Pred::SSA(src_ssa) = &instr.pred { - if let Some(src_vec) = self.get_copy(&src_ssa) { - assert!(src_vec[0].src_mod.is_none()); - if let SrcRef::SSA(ssa) = src_vec[0].src_ref { - instr.pred = Pred::SSA(ssa); + self.prop_to_pred(&mut instr.pred, &mut instr.pred_inv); + + match &mut instr.op { + Op::FAdd(_) | Op::FSet(_) => { + self.prop_to_srcs(instr.srcs_mut(), CopyType::F32); + } + Op::FSetP(op) => { + self.prop_to_srcs(&mut op.srcs, CopyType::F32); + /* TODO Other predicates */ + } + Op::IAdd3(op) => { + self.prop_to_srcs(&mut op.srcs, CopyType::I32); + /* Carry doesn't have a negate modifier */ + self.prop_to_src(&mut op.carry, CopyType::Raw); + } + Op::ISetP(op) => { + self.prop_to_srcs(&mut op.srcs, CopyType::I32); + /* TODO Other predicates */ + } + Op::Lop3(op) => { + if self.prop_to_srcs(&mut op.srcs, CopyType::Bits) { + op.op = LogicOp::new_lut(&|mut x, mut y, mut z| { + if op.srcs[0].src_mod.has_not() { + x = !x; + } + if op.srcs[1].src_mod.has_not() { + y = !y; + } + if op.srcs[2].src_mod.has_not() { + z = !z; + } + op.op.eval(x, y, z) + }); + op.srcs[0].src_mod = SrcMod::None; + op.srcs[1].src_mod = SrcMod::None; + op.srcs[2].src_mod = SrcMod::None; } } - } - - for src in instr.srcs_mut() { - if let SrcRef::SSA(src_ssa) = src.src_ref { - if src_ssa.comps() == 1 { - if let Some(src_vec) = self.get_copy(&src_ssa) { - assert!(src_vec[0].src_mod.is_none()); - *src = src_vec[0]; - } - } + Op::PLop3(op) => { + self.prop_to_srcs(&mut op.srcs, CopyType::Bits); + } + _ => { + self.prop_to_srcs(instr.srcs_mut(), CopyType::Raw); } } }