nak: Add a builder

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24998>
This commit is contained in:
Faith Ekstrand 2023-05-24 16:14:10 -05:00 committed by Marge Bot
parent 063c9f41fa
commit 2d69a2c1d7
6 changed files with 835 additions and 718 deletions

View file

@ -6,6 +6,7 @@
mod bitset;
mod bitview;
mod nak_assign_regs;
mod nak_builder;
mod nak_calc_instr_deps;
mod nak_encode_sm75;
mod nak_from_nir;

View file

@ -272,9 +272,8 @@ impl RegFileAllocation {
let reg = self.used.next_unset(next_reg.into());
/* Ensure we're properly aligned */
let reg = match u8::try_from(reg.next_multiple_of(align.into())) {
Ok(r) => r,
Err(_) => return None,
let Ok(reg) = u8::try_from(reg.next_multiple_of(align.into())) else {
return None;
};
if !self.is_reg_in_bounds(reg, comps) {

View file

@ -0,0 +1,281 @@
/*
* Copyright © 2022 Collabora, Ltd.
* SPDX-License-Identifier: MIT
*/
use crate::nak_ir::*;
pub trait Builder {
fn push_instr(&mut self, instr: Box<Instr>);
fn push_op(&mut self, op: impl Into<Op>) {
self.push_instr(Instr::new_boxed(op));
}
fn predicate<'a>(&'a mut self, pred: Pred) -> PredicatedBuilder<'a, Self>
where
Self: Sized,
{
PredicatedBuilder {
b: self,
pred: pred,
}
}
}
pub trait SSABuilder: Builder {
fn alloc_ssa(&mut self, file: RegFile, comps: u8) -> SSARef;
fn fadd(&mut self, x: Src, y: Src) -> SSARef {
let dst = self.alloc_ssa(RegFile::GPR, 1);
self.push_op(OpFAdd {
dst: dst.into(),
srcs: [x, y],
saturate: false,
rnd_mode: FRndMode::NearestEven,
});
dst
}
fn fmul(&mut self, x: Src, y: Src) -> SSARef {
let dst = self.alloc_ssa(RegFile::GPR, 1);
self.push_op(OpFMul {
dst: dst.into(),
srcs: [x, y],
saturate: false,
rnd_mode: FRndMode::NearestEven,
});
dst
}
fn fset(&mut self, cmp_op: FloatCmpOp, x: Src, y: Src) -> SSARef {
let dst = self.alloc_ssa(RegFile::GPR, 1);
self.push_op(OpFSet {
dst: dst.into(),
cmp_op: cmp_op,
srcs: [x, y],
});
dst
}
fn fsetp(&mut self, cmp_op: FloatCmpOp, x: Src, y: Src) -> SSARef {
let dst = self.alloc_ssa(RegFile::Pred, 1);
self.push_op(OpFSetP {
dst: dst.into(),
set_op: PredSetOp::And,
cmp_op: cmp_op,
srcs: [x, y],
accum: SrcRef::True.into(),
});
dst
}
fn iabs(&mut self, i: Src) -> SSARef {
let dst = self.alloc_ssa(RegFile::GPR, 1);
self.push_op(OpIAbs {
dst: dst.into(),
src: i,
});
dst
}
fn iadd(&mut self, x: Src, y: Src) -> SSARef {
let dst = self.alloc_ssa(RegFile::GPR, 1);
self.push_op(OpIAdd3 {
dst: dst.into(),
overflow: Dst::None,
srcs: [Src::new_zero(), x, y],
carry: Src::new_imm_bool(false),
});
dst
}
fn ineg(&mut self, i: Src) -> SSARef {
let dst = self.alloc_ssa(RegFile::GPR, 1);
self.push_op(OpINeg {
dst: dst.into(),
src: i,
});
dst
}
fn isetp(
&mut self,
cmp_type: IntCmpType,
cmp_op: IntCmpOp,
x: Src,
y: Src,
) -> SSARef {
let dst = self.alloc_ssa(RegFile::Pred, 1);
self.push_op(OpISetP {
dst: dst.into(),
set_op: PredSetOp::And,
cmp_op: cmp_op,
cmp_type: cmp_type,
srcs: [x, y],
accum: SrcRef::True.into(),
});
dst
}
fn lop2(&mut self, op: LogicOp, x: Src, y: Src) -> SSARef {
/* Only uses x and y */
assert!(op.eval(0x5, 0x3, 0x0) == op.eval(0x5, 0x3, 0xf));
assert!(x.is_predicate() == y.is_predicate());
if x.is_predicate() {
let dst = self.alloc_ssa(RegFile::Pred, 1);
self.push_op(OpPLop3 {
dsts: [dst.into(), Dst::None],
srcs: [x, y, Src::new_imm_bool(true)],
ops: [op, LogicOp::new_const(false)],
});
dst
} else {
let dst = self.alloc_ssa(RegFile::GPR, 1);
self.push_op(OpLop3 {
dst: dst.into(),
srcs: [x, y, Src::new_zero()],
op: op,
});
dst
}
}
fn mov(&mut self, src: Src) -> SSARef {
assert!(!src.is_predicate());
let dst = self.alloc_ssa(RegFile::GPR, 1);
self.push_op(OpMov {
dst: dst.into(),
src: src,
quad_lanes: 0xf,
});
dst
}
fn mufu(&mut self, op: MuFuOp, src: Src) -> SSARef {
let dst = self.alloc_ssa(RegFile::GPR, 1);
self.push_op(OpMuFu {
dst: dst.into(),
op: op,
src: src,
});
dst
}
fn sel(&mut self, cond: Src, x: Src, y: Src) -> SSARef {
assert!(cond.src_ref.is_predicate());
assert!(x.is_predicate() == y.is_predicate());
if x.is_predicate() {
let dst = self.alloc_ssa(RegFile::Pred, 1);
self.push_op(OpPLop3 {
dsts: [dst.into(), Dst::None],
srcs: [cond, x, y],
ops: [
LogicOp::new_lut(&|c, x, y| (c & x) | (!c & y)),
LogicOp::new_const(false),
],
});
dst
} else {
let dst = self.alloc_ssa(RegFile::GPR, 1);
self.push_op(OpSel {
dst: dst.into(),
cond: cond,
srcs: [x, y],
});
dst
}
}
}
pub struct InstrBuilder {
instrs: MappedInstrs,
}
impl InstrBuilder {
pub fn new() -> Self {
Self {
instrs: MappedInstrs::None,
}
}
pub fn as_vec(self) -> Vec<Box<Instr>> {
match self.instrs {
MappedInstrs::None => Vec::new(),
MappedInstrs::One(i) => vec![i],
MappedInstrs::Many(v) => v,
}
}
pub fn as_mapped_instrs(self) -> MappedInstrs {
self.instrs
}
}
impl Builder for InstrBuilder {
fn push_instr(&mut self, instr: Box<Instr>) {
self.instrs.push(instr);
}
}
pub struct SSAInstrBuilder<'a> {
b: InstrBuilder,
alloc: &'a mut SSAValueAllocator,
}
impl<'a> SSAInstrBuilder<'a> {
pub fn new(alloc: &'a mut SSAValueAllocator) -> Self {
Self {
b: InstrBuilder::new(),
alloc: alloc,
}
}
pub fn as_vec(self) -> Vec<Box<Instr>> {
self.b.as_vec()
}
pub fn as_mapped_instrs(self) -> MappedInstrs {
self.b.as_mapped_instrs()
}
}
impl<'a> Builder for SSAInstrBuilder<'a> {
fn push_instr(&mut self, instr: Box<Instr>) {
self.b.push_instr(instr);
}
}
impl<'a> SSABuilder for SSAInstrBuilder<'a> {
fn alloc_ssa(&mut self, file: RegFile, comps: u8) -> SSARef {
if comps == 1 {
self.alloc.alloc(file).into()
} else {
let mut vec = Vec::new();
for _ in 0..comps {
vec.push(self.alloc.alloc(file));
}
vec.try_into().unwrap()
}
}
}
pub struct PredicatedBuilder<'a, T: Builder> {
b: &'a mut T,
pred: Pred,
}
impl<'a, T: Builder> Builder for PredicatedBuilder<'a, T> {
fn push_instr(&mut self, instr: Box<Instr>) {
let mut instr = instr;
assert!(instr.pred.is_true());
instr.pred = self.pred;
self.b.push_instr(instr);
}
}
impl<'a, T: SSABuilder> SSABuilder for PredicatedBuilder<'a, T> {
fn alloc_ssa(&mut self, file: RegFile, comps: u8) -> SSARef {
self.b.alloc_ssa(file, comps)
}
}

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,9 @@
extern crate nak_ir_proc;
pub use crate::nak_builder::{
Builder, InstrBuilder, SSABuilder, SSAInstrBuilder,
};
use nak_ir_proc::*;
use std::fmt;
use std::iter::Zip;
@ -650,14 +653,6 @@ impl Src {
Src::from(if b { SrcRef::True } else { SrcRef::False })
}
pub fn new_cbuf(idx: u8, offset: u16) -> Src {
SrcRef::CBuf(CBufRef {
buf: CBuf::Binding(idx),
offset: offset,
})
.into()
}
pub fn fabs(&self) -> Src {
Src {
src_ref: self.src_ref,
@ -3046,6 +3041,7 @@ pub enum Op {
FSOut(OpFSOut),
}
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum PredRef {
None,
SSA(SSAValue),
@ -3099,6 +3095,7 @@ impl fmt::Display for PredRef {
}
}
#[derive(Clone, Copy)]
pub struct Pred {
pub pred_ref: PredRef,
pub pred_inv: bool,
@ -3245,87 +3242,6 @@ impl Instr {
Box::new(Instr::new(op))
}
pub fn new_fadd(dst: Dst, x: Src, y: Src) -> Instr {
OpFAdd {
dst: dst,
srcs: [x, y],
saturate: false,
rnd_mode: FRndMode::NearestEven,
}
.into()
}
pub fn new_fmul(dst: Dst, x: Src, y: Src) -> Instr {
OpFMul {
dst: dst,
srcs: [x, y],
saturate: false,
rnd_mode: FRndMode::NearestEven,
}
.into()
}
pub fn new_fset(dst: Dst, cmp_op: FloatCmpOp, x: Src, y: Src) -> Instr {
OpFSet {
dst: dst,
cmp_op: cmp_op,
srcs: [x, y],
}
.into()
}
pub fn new_fsetp(dst: Dst, cmp_op: FloatCmpOp, x: Src, y: Src) -> Instr {
OpFSetP {
dst: dst,
set_op: PredSetOp::And,
cmp_op: cmp_op,
srcs: [x, y],
accum: SrcRef::True.into(),
}
.into()
}
pub fn new_mufu(dst: Dst, op: MuFuOp, src: Src) -> Instr {
OpMuFu {
dst: dst,
op: op,
src: src,
}
.into()
}
pub fn new_iadd(dst: Dst, x: Src, y: Src) -> Instr {
OpIAdd3 {
dst: dst,
overflow: Dst::None,
srcs: [Src::new_zero(), x, y],
carry: Src::new_imm_bool(false),
}
.into()
}
pub fn new_i2f(dst: Dst, src: Src) -> Instr {
OpI2F {
dst: dst,
src: src,
dst_type: FloatType::F32,
src_type: IntType::I32,
rnd_mode: FRndMode::NearestEven,
}
.into()
}
pub fn new_u2f(dst: Dst, src: Src) -> Instr {
OpI2F {
dst: dst,
src: src,
dst_type: FloatType::F32,
src_type: IntType::U32,
rnd_mode: FRndMode::NearestEven,
}
.into()
}
pub fn new_isetp(
dst: Dst,
cmp_type: IntCmpType,
@ -3387,15 +3303,6 @@ impl Instr {
.into()
}
pub fn new_sel(dst: Dst, sel: Src, x: Src, y: Src) -> Instr {
OpSel {
dst: dst,
cond: sel,
srcs: [x, y],
}
.into()
}
pub fn new_plop3(dst: Dst, op: LogicOp, x: Src, y: Src, z: Src) -> Instr {
assert!(x.is_predicate() && y.is_predicate() && z.is_predicate());
OpPLop3 {
@ -3406,80 +3313,6 @@ impl Instr {
.into()
}
pub fn new_ld(
dst: Dst,
access: MemAccess,
addr: Src,
offset: i32,
) -> Instr {
OpLd {
dst: dst,
addr: addr,
offset: offset,
access: access,
}
.into()
}
pub fn new_st(
access: MemAccess,
addr: Src,
offset: i32,
data: Src,
) -> Instr {
OpSt {
addr: addr,
data: data,
offset: offset,
access: access,
}
.into()
}
pub fn new_ald(dst: Dst, attr_addr: u16, vtx: Src, offset: Src) -> Instr {
OpALd {
dst: dst,
vtx: vtx,
offset: offset,
access: AttrAccess {
addr: attr_addr,
comps: dst.as_ssa().unwrap().comps(),
patch: false,
out_load: false,
flags: 0,
},
}
.into()
}
pub fn new_ast(attr_addr: u16, data: Src, vtx: Src, offset: Src) -> Instr {
OpASt {
vtx: vtx,
offset: offset,
data: data,
access: AttrAccess {
addr: attr_addr,
comps: data.src_ref.as_ssa().unwrap().comps(),
patch: false,
out_load: false,
flags: 0,
},
}
.into()
}
pub fn new_bra(block: u32) -> Instr {
OpBra { target: block }.into()
}
pub fn new_exit() -> Instr {
OpExit {}.into()
}
pub fn new_s2r(dst: Dst, idx: u8) -> Instr {
OpS2R { dst: dst, idx: idx }.into()
}
pub fn new_swap(x: RegRef, y: RegRef) -> Instr {
assert!(x.file() == y.file());
OpSwap {
@ -3489,13 +3322,6 @@ impl Instr {
.into()
}
pub fn new_fs_out(srcs: &[Src]) -> Instr {
OpFSOut {
srcs: srcs.to_vec(),
}
.into()
}
pub fn dsts(&self) -> &[Dst] {
self.op.dsts_as_slice()
}
@ -3626,6 +3452,25 @@ pub enum MappedInstrs {
Many(Vec<Box<Instr>>),
}
impl MappedInstrs {
pub fn push(&mut self, i: Box<Instr>) {
match self {
MappedInstrs::None => {
*self = MappedInstrs::One(i);
}
MappedInstrs::One(_) => {
*self = match std::mem::replace(self, MappedInstrs::None) {
MappedInstrs::One(o) => MappedInstrs::Many(vec![o, i]),
_ => panic!("Not a One"),
};
}
MappedInstrs::Many(v) => {
v.push(i);
}
}
}
}
pub struct BasicBlock {
pub id: u32,
pub instrs: Vec<Box<Instr>>,

View file

@ -99,9 +99,8 @@ impl LopPass {
_ => return,
};
let entry = match self.ssa_lop.get(&ssa) {
Some(e) => e,
None => return,
let Some(entry) = self.ssa_lop.get(&ssa) else {
return;
};
let entry_use_count = *self.use_counts.get(&ssa).unwrap();