nak: Implement phis

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24998>
This commit is contained in:
Faith Ekstrand 2023-04-10 17:23:23 -05:00 committed by Marge Bot
parent 520ad0f4a7
commit 020a7ba8f5
4 changed files with 157 additions and 11 deletions

View file

@ -16,6 +16,7 @@ struct TrivialRegAlloc {
next_pred: u8,
next_upred: u8,
reg_map: HashMap<SSAValue, RegRef>,
phi_map: HashMap<u32, RegRef>,
}
impl TrivialRegAlloc {
@ -26,6 +27,7 @@ impl TrivialRegAlloc {
next_pred: 0,
next_upred: 0,
reg_map: HashMap::new(),
phi_map: HashMap::new(),
}
}
@ -56,7 +58,17 @@ impl TrivialRegAlloc {
RegRef::new(file, idx, comps)
}
pub fn rewrite_ssa(&mut self, ssa: SSAValue) -> RegRef {
fn get_phi_reg(&mut self, phi_id: u32, file: RegFile, comps: u8) -> RegRef {
if let Some(reg) = self.phi_map.get(&phi_id) {
*reg
} else {
let reg = self.alloc_reg(file, comps);
self.phi_map.insert(phi_id, reg);
reg
}
}
pub fn get_ssa_reg(&mut self, ssa: SSAValue) -> RegRef {
if let Some(reg) = self.reg_map.get(&ssa) {
*reg
} else {
@ -70,17 +82,49 @@ impl TrivialRegAlloc {
for f in &mut s.functions {
for b in &mut f.blocks {
for instr in &mut b.instrs {
if let Pred::SSA(ssa) = instr.pred {
instr.pred = Pred::Reg(self.rewrite_ssa(ssa));
}
for dst in instr.dsts_mut() {
if let Dst::SSA(ssa) = dst {
*dst = self.rewrite_ssa(*ssa).into();
match &instr.op {
Op::PhiSrc(op) => {
let src_ssa = op.src.as_ssa().unwrap();
let src = self.get_ssa_reg(*src_ssa);
let dst = self.get_phi_reg(
op.phi_id,
src_ssa.file(),
src_ssa.comps(),
);
instr.op = Op::Mov(OpMov {
dst: dst.into(),
src: src.into(),
quad_lanes: 0xf,
});
}
}
for src in instr.srcs_mut() {
if let SrcRef::SSA(ssa) = src.src_ref {
src.src_ref = self.rewrite_ssa(ssa).into();
Op::PhiDst(op) => {
let dst_ssa = op.dst.as_ssa().unwrap();
let src = self.get_phi_reg(
op.phi_id,
dst_ssa.file(),
dst_ssa.comps(),
);
let dst = self.get_ssa_reg(*dst_ssa);
instr.op = Op::Mov(OpMov {
dst: dst.into(),
src: src.into(),
quad_lanes: 0xf,
});
}
_ => {
if let Pred::SSA(ssa) = instr.pred {
instr.pred = self.get_ssa_reg(ssa).into();
}
for dst in instr.dsts_mut() {
if let Dst::SSA(ssa) = dst {
*dst = self.get_ssa_reg(*ssa).into();
}
}
for src in instr.srcs_mut() {
if let SrcRef::SSA(ssa) = src.src_ref {
src.src_ref = self.get_ssa_reg(ssa).into();
}
}
}
}
}

View file

@ -10,6 +10,8 @@ use crate::nir::*;
use nak_bindings::*;
use std::collections::HashMap;
struct ShaderFromNir<'a> {
nir: &'a nir_shader,
func: Option<Function>,
@ -17,6 +19,8 @@ struct ShaderFromNir<'a> {
instrs: Vec<Instr>,
fs_out_regs: Vec<Src>,
end_block_id: u32,
num_phis: u32,
phis: HashMap<u32, u32>,
}
impl<'a> ShaderFromNir<'a> {
@ -34,6 +38,8 @@ impl<'a> ShaderFromNir<'a> {
instrs: Vec::new(),
fs_out_regs: fs_out_regs,
end_block_id: 0,
num_phis: 0,
phis: HashMap::new(),
}
}
@ -81,6 +87,18 @@ impl<'a> ShaderFromNir<'a> {
}
}
fn get_phi_id(&mut self, phi: &nir_phi_instr) -> u32 {
match self.phis.get(&phi.def.index) {
Some(id) => *id,
None => {
let id = self.num_phis;
self.num_phis += 1;
self.phis.insert(phi.def.index, id);
id
}
}
}
fn split64(&mut self, ssa: SSAValue) -> [SSAValue; 2] {
assert!(ssa.comps() == 2);
let split =
@ -509,11 +527,39 @@ impl<'a> ShaderFromNir<'a> {
nir_instr_type_undef => {
self.parse_undef(ni.as_undef().unwrap())
}
nir_instr_type_phi => {
let phi = ni.as_phi().unwrap();
let dst = self.get_dst(&phi.def);
let phi_id = self.get_phi_id(phi);
self.instrs.push(Instr::new_phi_dst(phi_id, dst));
}
_ => panic!("Unsupported instruction type"),
}
}
let succ = nb.successors();
for sb in succ {
let sb = match sb {
Some(b) => b,
None => continue,
};
for i in sb.iter_instr_list() {
let phi = match i.as_phi() {
Some(phi) => phi,
None => break,
};
let phi_id = self.get_phi_id(phi);
for ps in phi.iter_srcs() {
if ps.pred().index == nb.index {
let src = self.get_src(&ps.src);
self.instrs.push(Instr::new_phi_src(phi_id, src));
}
}
}
}
let s0 = succ[0].unwrap();
if let Some(s1) = succ[1] {
/* Jump to the else. We'll come back and fix up the predicate as

View file

@ -1322,6 +1322,32 @@ impl fmt::Display for OpSplit {
}
}
#[repr(C)]
#[derive(SrcsAsSlice, DstsAsSlice)]
pub struct OpPhiSrc {
pub src: Src,
pub phi_id: u32,
}
impl fmt::Display for OpPhiSrc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "PHI_SRC({}) {}", self.phi_id, self.src)
}
}
#[repr(C)]
#[derive(SrcsAsSlice, DstsAsSlice)]
pub struct OpPhiDst {
pub dst: Dst,
pub phi_id: u32,
}
impl fmt::Display for OpPhiDst {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "PHI_DST({}) {}", self.phi_id, self.dst)
}
}
#[repr(C)]
#[derive(DstsAsSlice)]
pub struct OpFSOut {
@ -1370,6 +1396,8 @@ pub enum Op {
S2R(OpS2R),
FMov(OpFMov),
IMov(OpIMov),
PhiSrc(OpPhiSrc),
PhiDst(OpPhiDst),
Vec(OpVec),
Split(OpSplit),
FSOut(OpFSOut),
@ -1701,6 +1729,20 @@ impl Instr {
Instr::new(Op::S2R(OpS2R { dst: dst, idx: idx }))
}
pub fn new_phi_src(phi_id: u32, src: Src) -> Instr {
Instr::new(Op::PhiSrc(OpPhiSrc {
phi_id: phi_id,
src: src,
}))
}
pub fn new_phi_dst(phi_id: u32, dst: Dst) -> Instr {
Instr::new(Op::PhiDst(OpPhiDst {
phi_id: phi_id,
dst: dst,
}))
}
pub fn new_vec(dst: Dst, srcs: &[Src]) -> Instr {
Instr::new(Op::Vec(OpVec {
dst: dst,
@ -1775,6 +1817,8 @@ impl Instr {
Op::Bra(_) | Op::Exit(_) => Some(15),
Op::FMov(_)
| Op::IMov(_)
| Op::PhiSrc(_)
| Op::PhiDst(_)
| Op::Vec(_)
| Op::Split(_)
| Op::FSOut(_) => {

View file

@ -9,12 +9,14 @@ use std::collections::HashSet;
struct DeadCodePass {
live_ssa: HashSet<SSAValue>,
live_phi: HashSet<u32>,
}
impl DeadCodePass {
pub fn new() -> DeadCodePass {
DeadCodePass {
live_ssa: HashSet::new(),
live_phi: HashSet::new(),
}
}
@ -23,6 +25,10 @@ impl DeadCodePass {
}
fn mark_instr_live(&mut self, instr: &Instr) {
if let Op::PhiDst(op) = &instr.op {
self.live_phi.insert(op.phi_id);
}
if let Pred::SSA(ssa) = &instr.pred {
self.mark_ssa_live(ssa);
}
@ -47,6 +53,12 @@ impl DeadCodePass {
return true;
}
if let Op::PhiSrc(op) = &instr.op {
if self.live_phi.get(&op.phi_id).is_some() {
return true;
}
}
for dst in instr.dsts() {
if self.is_dst_live(dst) {
return true;