nak: Properly handle OpFSOut in RA and liveness

That one's a bit magic because it exists to ensure that each output GPR
ends up in the right register at the end of the shader.  We tried to
handle it as a simple lowering before but it's easier and safer to
handle it directly in RA and liveness.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24998>
This commit is contained in:
Faith Ekstrand
2023-09-11 22:41:19 -05:00
committed by Marge Bot
parent c47488341e
commit ecf5c4c13b
3 changed files with 37 additions and 9 deletions
+28
View File
@@ -177,6 +177,10 @@ impl RegAllocator {
self.file
}
pub fn num_regs_used(&self) -> u32 {
self.ssa_reg.len().try_into().unwrap()
}
pub fn reg_is_used(&self, reg: u32) -> bool {
self.used.get(reg.try_into().unwrap())
}
@@ -992,6 +996,30 @@ impl AssignRegsBlock {
Some(instr)
}
}
Op::FSOut(out) => {
for src in out.srcs.iter_mut() {
if let SrcRef::SSA(src_vec) = src.src_ref {
debug_assert!(src_vec.comps() == 1);
let src_ssa = &src_vec[0];
src.src_ref = self.get_scalar(*src_ssa).into();
}
}
self.ra.free_killed(srcs_killed);
assert!(dsts_killed.is_empty());
// This should be the last instruction and its sources should
// be the last free GPRs.
debug_assert!(self.ra[RegFile::GPR].num_regs_used() == 0);
for (i, src) in out.srcs.iter().enumerate() {
let reg = u32::try_from(i).unwrap();
let dst = RegRef::new(RegFile::GPR, reg, 1);
pcopy.push(dst.into(), *src);
}
None
}
_ => {
for file in self.ra.values_mut() {
instr_assign_regs_file(
-9
View File
@@ -4314,15 +4314,6 @@ impl Shader {
dst: neg.dst,
srcs: [Src::new_zero(), neg.src.ineg(), Src::new_zero()],
})),
Op::FSOut(out) => {
let mut pcopy = OpParCopy::new();
for (i, src) in out.srcs.iter().enumerate() {
let dst =
RegRef::new(RegFile::GPR, i.try_into().unwrap(), 1);
pcopy.push(dst.into(), *src);
}
MappedInstrs::One(Instr::new_boxed(pcopy))
}
_ => MappedInstrs::One(instr),
}
})
+9
View File
@@ -209,6 +209,15 @@ pub trait Liveness {
max_live = PerRegFile::new_with(|file| {
max(max_live[file], live_at_instr[file])
});
if let Op::FSOut(fs_out) = &instr.op {
// This should be the last instruction. Everything should
// be dead once we've processed it.
debug_assert!(live.count(RegFile::GPR) == 0);
let num_gprs_out = fs_out.srcs.len().try_into().unwrap();
max_live[RegFile::GPR] =
max(max_live[RegFile::GPR], num_gprs_out);
}
}
assert!(block_live_out.len() == bb_idx);