mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 22:38:05 +02:00
nak: Rework phis
Have a single phi src/dest instruction per block which handles all the phis at one go. This makes phis very similar to parallel copies. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24998>
This commit is contained in:
parent
15a4b620b9
commit
8004416e38
4 changed files with 196 additions and 91 deletions
|
|
@ -58,14 +58,22 @@ impl TrivialRegAlloc {
|
|||
RegRef::new(file, idx, comps)
|
||||
}
|
||||
|
||||
fn get_ssa_reg(&mut self, ssa: SSAValue) -> RegRef {
|
||||
if let Some(reg) = self.reg_map.get(&ssa) {
|
||||
*reg
|
||||
} else {
|
||||
let reg = self.alloc_reg(ssa.file(), ssa.comps());
|
||||
self.reg_map.insert(ssa, reg);
|
||||
reg
|
||||
fn alloc_ssa(&mut self, ssa: SSAValue) -> RegRef {
|
||||
let reg = self.alloc_reg(ssa.file(), ssa.comps());
|
||||
let old = self.reg_map.insert(ssa, reg);
|
||||
assert!(old.is_none());
|
||||
reg
|
||||
}
|
||||
|
||||
fn get_ssa_reg(&self, ssa: SSAValue) -> RegRef {
|
||||
*self.reg_map.get(&ssa).unwrap()
|
||||
}
|
||||
|
||||
fn map_src(&self, mut src: Src) -> Src {
|
||||
if let SrcRef::SSA(ssa) = src.src_ref {
|
||||
src.src_ref = self.get_ssa_reg(ssa).into();
|
||||
}
|
||||
src
|
||||
}
|
||||
|
||||
pub fn do_alloc(&mut self, s: &mut Shader) {
|
||||
|
|
@ -73,18 +81,21 @@ impl TrivialRegAlloc {
|
|||
for b in &mut f.blocks {
|
||||
for instr in &mut b.instrs {
|
||||
match &instr.op {
|
||||
Op::PhiDst(op) => {
|
||||
let dst_ssa = op.dst.as_ssa().unwrap();
|
||||
let reg =
|
||||
self.alloc_reg(dst_ssa.file(), dst_ssa.comps());
|
||||
self.phi_map.insert(op.phi_id, reg);
|
||||
Op::PhiDsts(phi) => {
|
||||
let mut pcopy = OpParCopy::new();
|
||||
|
||||
let dst = self.get_ssa_reg(*dst_ssa);
|
||||
instr.op = Op::Mov(OpMov {
|
||||
dst: dst.into(),
|
||||
src: reg.into(),
|
||||
quad_lanes: 0xf,
|
||||
});
|
||||
assert!(phi.ids.len() == phi.dsts.len());
|
||||
for (id, dst) in phi.iter() {
|
||||
let dst_ssa = dst.as_ssa().unwrap();
|
||||
let dst_reg = self.alloc_ssa(*dst_ssa);
|
||||
let src_reg = self
|
||||
.alloc_reg(dst_ssa.file(), dst_ssa.comps());
|
||||
self.phi_map.insert(*id, src_reg);
|
||||
pcopy.srcs.push(src_reg.into());
|
||||
pcopy.dsts.push(dst_reg.into());
|
||||
}
|
||||
|
||||
instr.op = Op::ParCopy(pcopy);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
|
@ -96,18 +107,21 @@ impl TrivialRegAlloc {
|
|||
for b in &mut f.blocks {
|
||||
for instr in &mut b.instrs {
|
||||
match &instr.op {
|
||||
Op::PhiSrc(op) => {
|
||||
assert!(op.src.src_mod.is_none());
|
||||
let reg = *self.phi_map.get(&op.phi_id).unwrap();
|
||||
let src = if let SrcRef::SSA(ssa) = op.src.src_ref {
|
||||
Src::from(self.get_ssa_reg(ssa))
|
||||
} else {
|
||||
op.src
|
||||
};
|
||||
instr.op = Op::Mov(OpMov {
|
||||
dst: reg.into(),
|
||||
src: src.into(),
|
||||
quad_lanes: 0xf,
|
||||
Op::PhiSrcs(phi) => {
|
||||
assert!(phi.ids.len() == phi.srcs.len());
|
||||
instr.op = Op::ParCopy(OpParCopy {
|
||||
srcs: phi
|
||||
.srcs
|
||||
.iter()
|
||||
.map(|src| self.map_src(*src))
|
||||
.collect(),
|
||||
dsts: phi
|
||||
.ids
|
||||
.iter()
|
||||
.map(|id| {
|
||||
(*self.phi_map.get(id).unwrap()).into()
|
||||
})
|
||||
.collect(),
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -116,13 +130,11 @@ impl TrivialRegAlloc {
|
|||
}
|
||||
for dst in instr.dsts_mut() {
|
||||
if let Dst::SSA(ssa) = dst {
|
||||
*dst = self.get_ssa_reg(*ssa).into();
|
||||
*dst = self.alloc_ssa(*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();
|
||||
}
|
||||
*src = self.map_src(*src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -529,6 +529,25 @@ impl<'a> ShaderFromNir<'a> {
|
|||
}
|
||||
|
||||
fn parse_block(&mut self, nb: &nir_block) {
|
||||
let mut phi = OpPhiDsts {
|
||||
ids: Vec::new(),
|
||||
dsts: Vec::new(),
|
||||
};
|
||||
|
||||
for ni in nb.iter_instr_list() {
|
||||
if ni.type_ == nir_instr_type_phi {
|
||||
let np = ni.as_phi().unwrap();
|
||||
phi.ids.push(self.get_phi_id(np));
|
||||
phi.dsts.push(self.get_dst(&np.def));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !phi.ids.is_empty() {
|
||||
self.instrs.push(Instr::new(Op::PhiDsts(phi)));
|
||||
}
|
||||
|
||||
for ni in nb.iter_instr_list() {
|
||||
match ni.type_ {
|
||||
nir_instr_type_alu => self.parse_alu(ni.as_alu().unwrap()),
|
||||
|
|
@ -543,12 +562,7 @@ 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));
|
||||
}
|
||||
nir_instr_type_phi => (),
|
||||
_ => panic!("Unsupported instruction type"),
|
||||
}
|
||||
}
|
||||
|
|
@ -560,20 +574,29 @@ impl<'a> ShaderFromNir<'a> {
|
|||
None => continue,
|
||||
};
|
||||
|
||||
let mut phi = OpPhiSrcs {
|
||||
srcs: Vec::new(),
|
||||
ids: Vec::new(),
|
||||
};
|
||||
|
||||
for i in sb.iter_instr_list() {
|
||||
let phi = match i.as_phi() {
|
||||
let np = match i.as_phi() {
|
||||
Some(phi) => phi,
|
||||
None => break,
|
||||
};
|
||||
|
||||
let phi_id = self.get_phi_id(phi);
|
||||
for ps in phi.iter_srcs() {
|
||||
for ps in np.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));
|
||||
phi.srcs.push(self.get_src(&ps.src));
|
||||
phi.ids.push(self.get_phi_id(np));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !phi.ids.is_empty() {
|
||||
self.instrs.push(Instr::new(Op::PhiSrcs(phi)));
|
||||
}
|
||||
}
|
||||
|
||||
let s0 = succ[0].unwrap();
|
||||
|
|
|
|||
|
|
@ -1419,28 +1419,88 @@ impl fmt::Display for OpSplit {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(SrcsAsSlice, DstsAsSlice)]
|
||||
pub struct OpPhiSrc {
|
||||
pub src: Src,
|
||||
pub phi_id: u32,
|
||||
#[derive(DstsAsSlice)]
|
||||
pub struct OpPhiSrcs {
|
||||
pub srcs: Vec<Src>,
|
||||
pub ids: Vec<u32>,
|
||||
}
|
||||
|
||||
impl fmt::Display for OpPhiSrc {
|
||||
impl OpPhiSrcs {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
assert!(self.ids.len() == self.srcs.len());
|
||||
self.ids.is_empty()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Zip<slice::Iter<'_, u32>, slice::Iter<'_, Src>> {
|
||||
assert!(self.ids.len() == self.srcs.len());
|
||||
self.ids.iter().zip(self.srcs.iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl SrcsAsSlice for OpPhiSrcs {
|
||||
fn srcs_as_slice(&self) -> &[Src] {
|
||||
&self.srcs
|
||||
}
|
||||
|
||||
fn srcs_as_mut_slice(&mut self) -> &mut [Src] {
|
||||
&mut self.srcs
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for OpPhiSrcs {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "PHI_SRC({}) {}", self.phi_id, self.src)
|
||||
write!(f, "PHI_SRC {{")?;
|
||||
assert!(self.ids.len() == self.srcs.len());
|
||||
for i in 0..self.ids.len() {
|
||||
if i > 0 {
|
||||
write!(f, ",")?;
|
||||
}
|
||||
write!(f, " {} <- {}", self.ids[i], self.srcs[i])?;
|
||||
}
|
||||
write!(f, " }}")
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(SrcsAsSlice, DstsAsSlice)]
|
||||
pub struct OpPhiDst {
|
||||
pub dst: Dst,
|
||||
pub phi_id: u32,
|
||||
#[derive(SrcsAsSlice)]
|
||||
pub struct OpPhiDsts {
|
||||
pub ids: Vec<u32>,
|
||||
pub dsts: Vec<Dst>,
|
||||
}
|
||||
|
||||
impl fmt::Display for OpPhiDst {
|
||||
impl OpPhiDsts {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
assert!(self.ids.len() == self.dsts.len());
|
||||
self.ids.is_empty()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Zip<slice::Iter<'_, u32>, slice::Iter<'_, Dst>> {
|
||||
assert!(self.ids.len() == self.dsts.len());
|
||||
self.ids.iter().zip(self.dsts.iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl DstsAsSlice for OpPhiDsts {
|
||||
fn dsts_as_slice(&self) -> &[Dst] {
|
||||
&self.dsts
|
||||
}
|
||||
|
||||
fn dsts_as_mut_slice(&mut self) -> &mut [Dst] {
|
||||
&mut self.dsts
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for OpPhiDsts {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "PHI_DST({}) {}", self.phi_id, self.dst)
|
||||
write!(f, "PHI_DST {{")?;
|
||||
assert!(self.ids.len() == self.dsts.len());
|
||||
for i in 0..self.ids.len() {
|
||||
if i > 0 {
|
||||
write!(f, ",")?;
|
||||
}
|
||||
write!(f, " {} <- {}", self.dsts[i], self.ids[i])?;
|
||||
}
|
||||
write!(f, " }}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1568,8 +1628,8 @@ pub enum Op {
|
|||
S2R(OpS2R),
|
||||
FMov(OpFMov),
|
||||
IMov(OpIMov),
|
||||
PhiSrc(OpPhiSrc),
|
||||
PhiDst(OpPhiDst),
|
||||
PhiSrcs(OpPhiSrcs),
|
||||
PhiDsts(OpPhiDsts),
|
||||
Vec(OpVec),
|
||||
Split(OpSplit),
|
||||
Swap(OpSwap),
|
||||
|
|
@ -1909,20 +1969,6 @@ 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,
|
||||
|
|
@ -2005,8 +2051,8 @@ impl Instr {
|
|||
Op::Bra(_) | Op::Exit(_) => Some(15),
|
||||
Op::FMov(_)
|
||||
| Op::IMov(_)
|
||||
| Op::PhiSrc(_)
|
||||
| Op::PhiDst(_)
|
||||
| Op::PhiSrcs(_)
|
||||
| Op::PhiDsts(_)
|
||||
| Op::Vec(_)
|
||||
| Op::Split(_)
|
||||
| Op::Swap(_)
|
||||
|
|
|
|||
|
|
@ -55,12 +55,6 @@ 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;
|
||||
|
|
@ -72,20 +66,24 @@ impl DeadCodePass {
|
|||
|
||||
fn mark_instr(&mut self, instr: &Instr) {
|
||||
match &instr.op {
|
||||
Op::PhiSrc(phi) => {
|
||||
Op::PhiSrcs(phi) => {
|
||||
assert!(instr.pred.is_none());
|
||||
if self.is_phi_live(phi.phi_id) {
|
||||
self.mark_src_live(&phi.src);
|
||||
} else {
|
||||
self.any_dead = true;
|
||||
for (id, src) in phi.iter() {
|
||||
if self.is_phi_live(*id) {
|
||||
self.mark_src_live(src);
|
||||
} else {
|
||||
self.any_dead = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Op::PhiDst(phi) => {
|
||||
Op::PhiDsts(phi) => {
|
||||
assert!(instr.pred.is_none());
|
||||
if self.is_dst_live(&phi.dst) {
|
||||
self.mark_phi_live(phi.phi_id);
|
||||
} else {
|
||||
self.any_dead = true;
|
||||
for (id, dst) in phi.iter() {
|
||||
if self.is_dst_live(dst) {
|
||||
self.mark_phi_live(*id);
|
||||
} else {
|
||||
self.any_dead = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Op::ParCopy(pcopy) => {
|
||||
|
|
@ -116,6 +114,32 @@ impl DeadCodePass {
|
|||
|
||||
fn map_instr(&self, mut instr: Instr) -> Vec<Instr> {
|
||||
let is_live = match &mut instr.op {
|
||||
Op::PhiSrcs(phi) => {
|
||||
assert!(phi.ids.len() == phi.srcs.len());
|
||||
let mut i = 0;
|
||||
while i < phi.ids.len() {
|
||||
if self.is_phi_live(phi.ids[i]) {
|
||||
i += 1;
|
||||
} else {
|
||||
phi.srcs.remove(i);
|
||||
phi.ids.remove(i);
|
||||
}
|
||||
}
|
||||
i > 0
|
||||
}
|
||||
Op::PhiDsts(phi) => {
|
||||
assert!(phi.ids.len() == phi.dsts.len());
|
||||
let mut i = 0;
|
||||
while i < phi.ids.len() {
|
||||
if self.is_dst_live(&phi.dsts[i]) {
|
||||
i += 1;
|
||||
} else {
|
||||
phi.ids.remove(i);
|
||||
phi.dsts.remove(i);
|
||||
}
|
||||
}
|
||||
i > 0
|
||||
}
|
||||
Op::ParCopy(pcopy) => {
|
||||
assert!(pcopy.srcs.len() == pcopy.dsts.len());
|
||||
let mut i = 0;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue