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:
parent
950db58132
commit
5b355ff25a
2 changed files with 42 additions and 47 deletions
|
|
@ -254,7 +254,7 @@ pub extern "C" fn nak_compile_shader(
|
||||||
|
|
||||||
s.opt_out();
|
s.opt_out();
|
||||||
if DEBUG.print() {
|
if DEBUG.print() {
|
||||||
eprintln!("NAK IR:\n{}", &s);
|
eprintln!("NAK IR after opt_out:\n{}", &s);
|
||||||
}
|
}
|
||||||
|
|
||||||
s.legalize();
|
s.legalize();
|
||||||
|
|
|
||||||
|
|
@ -5,61 +5,56 @@
|
||||||
|
|
||||||
use crate::nak_ir::*;
|
use crate::nak_ir::*;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
fn try_combine_outs(emit: &mut Instr, cut: &Instr) -> bool {
|
||||||
use std::slice;
|
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 {
|
impl Shader {
|
||||||
pub fn opt_out(&mut self) {
|
pub fn opt_out(&mut self) {
|
||||||
if let ShaderStageInfo::Geometry(_) = self.info.stage {
|
if !matches!(self.info.stage, ShaderStageInfo::Geometry(_)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for f in &mut self.functions {
|
for f in &mut self.functions {
|
||||||
for b in &mut f.blocks {
|
for b in &mut f.blocks {
|
||||||
let mut instrs = Vec::new();
|
let mut instrs: Vec<Box<Instr>> = Vec::new();
|
||||||
|
for instr in b.instrs.drain(..) {
|
||||||
{
|
if let Some(prev) = instrs.last_mut() {
|
||||||
let mut drain = b.instrs.drain(..);
|
if try_combine_outs(prev, &instr) {
|
||||||
|
continue;
|
||||||
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),
|
instrs.push(instr);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.instrs = instrs;
|
b.instrs = instrs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue