nak: Add modifier propagation

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24998>
This commit is contained in:
Faith Ekstrand
2023-01-30 20:53:19 -06:00
committed by Marge Bot
parent 495b64be2b
commit 1b3382b861
2 changed files with 203 additions and 24 deletions

View File

@@ -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 { pub fn has_neg(&self) -> bool {
match self { match self {
SrcMod::None | SrcMod::Abs => false, SrcMod::None | SrcMod::Abs => false,

View File

@@ -6,9 +6,33 @@
use crate::nak_ir::*; use crate::nak_ir::*;
use std::collections::HashMap; 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 { struct CopyPropPass {
ssa_map: HashMap<SSAValue, Vec<Src>>, ssa_map: HashMap<SSAValue, Vec<CopyEntry>>,
} }
impl CopyPropPass { impl CopyPropPass {
@@ -18,32 +42,147 @@ impl CopyPropPass {
} }
} }
fn add_copy(&mut self, dst: &SSAValue, src_vec: Vec<Src>) { fn add_copy(&mut self, dst: &SSAValue, typ: CopyType, src_vec: &[Src]) {
self.ssa_map.insert(*dst, src_vec); 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<Src>> { 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<CopyEntry>> {
self.ssa_map.get(dst) 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) { pub fn run(&mut self, f: &mut Function) {
for b in &mut f.blocks { for b in &mut f.blocks {
for instr in &mut b.instrs { for instr in &mut b.instrs {
match &instr.op { 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) => { Op::Vec(vec) => {
self.add_copy( self.add_copy(
vec.dst.as_ssa().unwrap(), vec.dst.as_ssa().unwrap(),
vec.srcs.to_vec(), CopyType::Raw,
&vec.srcs,
); );
} }
Op::Split(split) => { Op::Split(split) => {
assert!(split.src.src_mod.is_none()); assert!(split.src.src_mod.is_none());
let src_ssa = split.src.src_ref.as_ssa().unwrap(); 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()); assert!(src_vec.len() == split.dsts.len());
for (i, dst) in split.dsts.iter().enumerate() { for (i, entry) in src_vec.drain(..).enumerate() {
if let Dst::SSA(ssa) = dst { if let Dst::SSA(ssa) = &split.dsts[i] {
self.add_copy(ssa, vec![src_vec[i]]); self.add_copy_entry(ssa, entry);
} }
} }
} }
@@ -51,23 +190,49 @@ impl CopyPropPass {
_ => (), _ => (),
} }
if let Pred::SSA(src_ssa) = &instr.pred { self.prop_to_pred(&mut instr.pred, &mut instr.pred_inv);
if let Some(src_vec) = self.get_copy(&src_ssa) {
assert!(src_vec[0].src_mod.is_none()); match &mut instr.op {
if let SrcRef::SSA(ssa) = src_vec[0].src_ref { Op::FAdd(_) | Op::FSet(_) => {
instr.pred = Pred::SSA(ssa); 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;
} }
} }
} Op::PLop3(op) => {
self.prop_to_srcs(&mut op.srcs, CopyType::Bits);
for src in instr.srcs_mut() { }
if let SrcRef::SSA(src_ssa) = src.src_ref { _ => {
if src_ssa.comps() == 1 { self.prop_to_srcs(instr.srcs_mut(), CopyType::Raw);
if let Some(src_vec) = self.get_copy(&src_ssa) {
assert!(src_vec[0].src_mod.is_none());
*src = src_vec[0];
}
}
} }
} }
} }