nak: Fix opt_out
It was converting instructions to/from Op which throws away predicates. This meant that any instruction immediately after an OUT.EMIT would loose its predicate (if any). If an OUT.EMIT comes right before a BRA, this results in the branch always getting taken. While reworking things, I also totally reformatted the pass to make it more readable IMO. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24998>
This commit is contained in:

committed by
Marge Bot

parent
950db58132
commit
5b355ff25a
@@ -254,7 +254,7 @@ pub extern "C" fn nak_compile_shader(
|
||||
|
||||
s.opt_out();
|
||||
if DEBUG.print() {
|
||||
eprintln!("NAK IR:\n{}", &s);
|
||||
eprintln!("NAK IR after opt_out:\n{}", &s);
|
||||
}
|
||||
|
||||
s.legalize();
|
||||
|
@@ -5,60 +5,55 @@
|
||||
|
||||
use crate::nak_ir::*;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::slice;
|
||||
fn try_combine_outs(emit: &mut Instr, cut: &Instr) -> bool {
|
||||
let Op::Out(emit) = &mut emit.op else {
|
||||
return false;
|
||||
};
|
||||
|
||||
struct OutPass;
|
||||
let Op::Out(cut) = &cut.op else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if emit.out_type != OutType::Emit || cut.out_type != OutType::Cut {
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(handle) = emit.dst.as_ssa() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if cut.handle.as_ssa() != Some(handle) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if emit.stream != emit.stream {
|
||||
return false;
|
||||
}
|
||||
|
||||
emit.dst = cut.dst;
|
||||
emit.out_type = OutType::EmitThenCut;
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
impl Shader {
|
||||
pub fn opt_out(&mut self) {
|
||||
if let ShaderStageInfo::Geometry(_) = self.info.stage {
|
||||
for f in &mut self.functions {
|
||||
for b in &mut f.blocks {
|
||||
let mut instrs = Vec::new();
|
||||
if !matches!(self.info.stage, ShaderStageInfo::Geometry(_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
let mut drain = b.instrs.drain(..);
|
||||
|
||||
while let Some(instr) = drain.next() {
|
||||
match instr.op {
|
||||
Op::Out(op) if op.out_type == OutType::Emit => {
|
||||
let next_op_opt =
|
||||
drain.next().map(|x| x.op);
|
||||
|
||||
match next_op_opt {
|
||||
Some(Op::Out(next_op))
|
||||
if next_op.out_type
|
||||
== OutType::Cut
|
||||
&& op.stream
|
||||
== next_op.stream =>
|
||||
{
|
||||
instrs.push(Instr::new_boxed(
|
||||
OpOut {
|
||||
dst: next_op.dst.clone(),
|
||||
handle: op.handle,
|
||||
stream: op.stream,
|
||||
out_type:
|
||||
OutType::EmitThenCut,
|
||||
},
|
||||
));
|
||||
}
|
||||
Some(next_op) => {
|
||||
instrs.push(Instr::new_boxed(op));
|
||||
instrs.push(Instr::new_boxed(
|
||||
next_op,
|
||||
));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
_ => instrs.push(instr),
|
||||
}
|
||||
for f in &mut self.functions {
|
||||
for b in &mut f.blocks {
|
||||
let mut instrs: Vec<Box<Instr>> = Vec::new();
|
||||
for instr in b.instrs.drain(..) {
|
||||
if let Some(prev) = instrs.last_mut() {
|
||||
if try_combine_outs(prev, &instr) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
b.instrs = instrs;
|
||||
instrs.push(instr);
|
||||
}
|
||||
b.instrs = instrs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user