From 50b1deefa728e94be33cdd99fa32ec7c53708ba0 Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Mon, 30 Jan 2023 20:53:17 -0600 Subject: [PATCH] nak: Add encoding for a few instructions Part-of: --- src/nouveau/compiler/nak.rs | 41 +++- src/nouveau/compiler/nak_encode_tu102.rs | 256 +++++++++++++++++++++++ src/nouveau/compiler/nak_ir.rs | 21 +- 3 files changed, 313 insertions(+), 5 deletions(-) create mode 100644 src/nouveau/compiler/nak_encode_tu102.rs diff --git a/src/nouveau/compiler/nak.rs b/src/nouveau/compiler/nak.rs index 987781d2652..4c828ad5420 100644 --- a/src/nouveau/compiler/nak.rs +++ b/src/nouveau/compiler/nak.rs @@ -5,6 +5,7 @@ mod bitset; mod nak_assign_regs; +mod nak_encode_tu102; mod nak_from_nir; mod nak_ir; mod nak_opt_copy_prop; @@ -14,11 +15,26 @@ mod util; use nak_bindings::*; use nak_from_nir::*; +use std::os::raw::c_void; #[repr(C)] struct ShaderBin { bin: nak_shader_bin, - instrs: Vec, + code: Vec, +} + +impl ShaderBin { + pub fn new(info: nak_shader_info, code: Vec) -> ShaderBin { + let bin = nak_shader_bin { + info: info, + code_size: (code.len() * 4).try_into().unwrap(), + code: code.as_ptr() as *const c_void, + }; + ShaderBin { + bin: bin, + code: code, + } + } } #[no_mangle] @@ -54,5 +70,26 @@ pub extern "C" fn nak_compile_shader( println!("NAK IR:\n{}", &s); - std::ptr::null_mut() + let info = nak_shader_info { + num_gprs: 255, + tls_size: 0, + cs: nak_shader_info__bindgen_ty_1 { + local_size: [0; 3], + smem_size: 0, + }, + hdr: [0; 32], + }; + + let code = nak_encode_tu102::encode_shader(&s); + + print!("Encoded shader:"); + for i in 0..code.len() { + if (i % 8) == 0 { + print!("\n "); + } + print!(" {:#x}", code[i]); + } + print!("\n\n"); + + Box::into_raw(Box::new(ShaderBin::new(info, code))) as *mut nak_shader_bin } diff --git a/src/nouveau/compiler/nak_encode_tu102.rs b/src/nouveau/compiler/nak_encode_tu102.rs new file mode 100644 index 00000000000..2b6c01efd9c --- /dev/null +++ b/src/nouveau/compiler/nak_encode_tu102.rs @@ -0,0 +1,256 @@ +/* + * Copyright © 2022 Collabora, Ltd. + * SPDX-License-Identifier: MIT + */ + +use crate::bitset::*; +use crate::nak_ir::*; + +use std::ops::Range; + +trait SrcMod { + fn src_mod(&self, idx: usize) -> u8; +} + +impl SrcMod for Instr { + fn src_mod(&self, idx: usize) -> u8 { + 0 /* TODO */ + } +} + +fn encode_imm(bs: &mut impl BitSetMut, range: Range, imm: &Immediate) { + assert!(range.len() == 32); + bs.set_field(range, imm.u); +} + +fn encode_reg(bs: &mut impl BitSetMut, range: Range, reg: RegRef) { + assert!(range.len() == 8); + assert!(reg.file() == RegFile::GPR); + bs.set_field(range, reg.base_idx()); +} + +fn encode_ureg(bs: &mut impl BitSetMut, range: Range, reg: RegRef) { + assert!(range.len() == 8); + assert!(reg.file() == RegFile::UGPR); + assert!(reg.base_idx() <= 63); + bs.set_field(range, reg.base_idx()); +} + +fn encode_mod(bs: &mut impl BitSetMut, range: Range, src_mod: u8) { + assert!(range.len() == 2); + bs.set_field(range, src_mod); +} + +fn encode_cb(bs: &mut impl BitSetMut, range: Range, cb: &CBufRef) { + let mut v = bs.subset_mut(range); + v.set_field(0..16, cb.offset); + if let CBuf::Binding(idx) = cb.buf { + v.set_field(16..21, idx); + } else { + panic!("Must be a bound constant buffer"); + } +} + +fn encode_cx(bs: &mut impl BitSetMut, range: Range, cb: &CBufRef) { + let mut v = bs.subset_mut(range); + if let CBuf::BindlessGPR(gpr) = cb.buf { + encode_ureg(&mut v, 0..8, gpr); + } else { + panic!("Must be a bound constant buffer"); + } + assert!(cb.offset % 4 == 0); + v.set_field(8..22, cb.offset / 4); +} + +fn encode_instr_base(bs: &mut impl BitSetMut, instr: &Instr, opcode: u16) { + bs.set_field(0..12, opcode); + bs.set_field(12..16, 0x7_u8); /* TODO: Predicate */ + if instr.num_dsts() > 0 { + assert!(instr.num_dsts() == 1); + encode_reg(bs, 16..24, *instr.dst(0).as_reg().unwrap()); + } + + bs.set_field(105..109, instr.deps.delay); + bs.set_bit(109, instr.deps.yld); + bs.set_field(110..113, instr.deps.wr_bar().unwrap_or(7)); + bs.set_field(113..116, instr.deps.rd_bar().unwrap_or(7)); + bs.set_field(116..122, instr.deps.wt_bar_mask); + bs.set_field(122..126, instr.deps.reuse_mask); +} + +enum ALUSrc { + Imm(Immediate), + Reg(RegRef), + UReg(RegRef), + CBuf(CBufRef), +} + +impl ALUSrc { + pub fn from_src(src: &Src, comps: u8) -> ALUSrc { + match src { + Src::Reg(reg) => { + assert!(reg.comps() == comps); + match reg.file() { + RegFile::GPR => ALUSrc::Reg(*reg), + RegFile::UGPR => ALUSrc::UReg(*reg), + _ => panic!("Invalid ALU register file"), + } + } + Src::Imm(i) => ALUSrc::Imm(*i), + Src::CBuf(cb) => ALUSrc::CBuf(*cb), + _ => panic!("Invalid ALU source"), + } + } +} + +fn encode_alu(bs: &mut impl BitSetMut, instr: &Instr, opcode: u16) { + encode_instr_base(bs, instr, opcode); + + encode_reg(bs, 24..32, *instr.src(0).as_reg().unwrap()); + bs.set_field(32..72, 0u64); /* Pad */ + + let mut form = 0_u8; + if instr.num_srcs() > 1 { + match ALUSrc::from_src(instr.src(1), 1) { + ALUSrc::Reg(reg1) => { + if instr.num_srcs() == 2 { + form = 1; + encode_reg(bs, 32..40, reg1); + encode_mod(bs, 62..64, instr.src_mod(1)); + } else { + assert!(instr.num_srcs() == 3); + match ALUSrc::from_src(instr.src(2), 1) { + ALUSrc::Reg(reg2) => { + form = 1; + encode_reg(bs, 32..40, reg1); + encode_mod(bs, 62..64, instr.src_mod(1)); + encode_reg(bs, 64..72, reg2); + encode_mod(bs, 74..76, instr.src_mod(2)); + } + ALUSrc::UReg(reg2) => { + form = 7; + encode_ureg(bs, 32..40, reg2); + encode_mod(bs, 62..64, instr.src_mod(2)); + encode_reg(bs, 64..72, reg1); + encode_mod(bs, 74..76, instr.src_mod(1)); + } + ALUSrc::Imm(imm) => { + form = 2; + encode_imm(bs, 32..64, &imm); + encode_reg(bs, 64..72, reg1); + encode_mod(bs, 74..76, instr.src_mod(1)); + } + ALUSrc::CBuf(cb) => { + form = 3; + /* TODO encode_cx */ + encode_cb(bs, 38..59, &cb); + encode_mod(bs, 62..64, instr.src_mod(2)); + encode_reg(bs, 64..72, reg1); + encode_mod(bs, 74..76, instr.src_mod(1)); + } + _ => panic!("Invalid instruction form"), + } + } + } + ALUSrc::Reg(reg1) => { + form = 6; + encode_ureg(bs, 32..40, reg1); + encode_mod(bs, 62..64, instr.src_mod(1)); + if instr.num_srcs() > 2 { + assert!(instr.num_srcs() == 3); + encode_reg(bs, 64..72, *instr.src(2).as_reg().unwrap()); + encode_mod(bs, 74..76, instr.src_mod(2)); + } + } + ALUSrc::Imm(imm) => { + form = 4; + encode_imm(bs, 32..64, &imm); + if instr.num_srcs() > 2 { + encode_reg(bs, 64..72, *instr.src(2).as_reg().unwrap()); + encode_mod(bs, 74..76, instr.src_mod(2)); + } + } + ALUSrc::CBuf(cb) => { + form = 5; + /* TODO encode_cx */ + encode_cb(bs, 38..59, &cb); + encode_mod(bs, 62..64, instr.src_mod(1)); + if instr.num_srcs() > 2 { + encode_reg(bs, 64..72, *instr.src(2).as_reg().unwrap()); + encode_mod(bs, 74..76, instr.src_mod(2)); + } + } + _ => panic!("Invalid instruction form"), + } + } + + bs.set_field(9..12, form); +} + +fn encode_mov(bs: &mut impl BitSetMut, instr: &Instr) { + encode_alu(bs, instr, 0x002); + bs.set_field(72..76, 0xf_u32 /* TODO: Quad lanes */); +} + +fn encode_ald(bs: &mut impl BitSetMut, instr: &Instr, attr: &AttrAccess) { + encode_instr_base(bs, &instr, 0x321); + + encode_reg(bs, 24..32, *instr.src(0).as_reg().unwrap()); + encode_reg(bs, 32..40, *instr.src(1).as_reg().unwrap()); + + bs.set_field(40..50, attr.addr); + bs.set_field(74..76, attr.comps - 1); + bs.set_field(76..77, attr.patch); + bs.set_field(77..78, attr.flags); + bs.set_field(79..80, attr.out_load); +} + +fn encode_ast(bs: &mut impl BitSetMut, instr: &Instr, attr: &AttrAccess) { + encode_instr_base(bs, &instr, 0x322); + assert!(instr.num_dsts() == 0); + + encode_reg(bs, 32..40, *instr.src(0).as_reg().unwrap()); + encode_reg(bs, 24..32, *instr.src(1).as_reg().unwrap()); + encode_reg(bs, 64..72, *instr.src(2).as_reg().unwrap()); + + bs.set_field(40..50, attr.addr); + bs.set_field(74..76, attr.comps - 1); + bs.set_field(76..77, attr.patch); + bs.set_field(77..78, attr.flags); + assert!(!attr.out_load); +} + +fn encode_exit(bs: &mut impl BitSetMut, instr: &Instr) { + encode_instr_base(bs, instr, 0x94d); + + bs.set_field(84..85, false); /* ./.KEEPREFCOUNT/.PREEMPTED/.INVALID3 */ + bs.set_field(85..86, false); /* .NO_ATEXIT */ + bs.set_field(87..90, 0x7_u8); /* TODO: Predicate */ + bs.set_field(90..91, false); /* NOT */ +} + +pub fn encode_instr(instr: &Instr) -> [u32; 4] { + let mut enc = [0_u32; 4]; + let mut bs = BitSetMutView::new(&mut enc); + match &instr.op { + Opcode::MOV => encode_mov(&mut bs, instr), + Opcode::ALD(a) => encode_ald(&mut bs, instr, &a), + Opcode::AST(a) => encode_ast(&mut bs, instr, &a), + Opcode::EXIT => encode_exit(&mut bs, instr), + _ => panic!("Unhandled instruction"), + } + enc +} + +pub fn encode_shader(shader: &Shader) -> Vec { + let mut encoded = Vec::new(); + assert!(shader.functions.len() == 1); + let func = &shader.functions[0]; + for b in &func.blocks { + for instr in &b.instrs { + let e = encode_instr(&instr); + encoded.extend_from_slice(&e[..]); + } + } + encoded +} diff --git a/src/nouveau/compiler/nak_ir.rs b/src/nouveau/compiler/nak_ir.rs index be981f4bdf7..f736cb97eb5 100644 --- a/src/nouveau/compiler/nak_ir.rs +++ b/src/nouveau/compiler/nak_ir.rs @@ -534,7 +534,13 @@ impl Instr { out_load: false, flags: 0, }; - Instr::new(Opcode::ALD(attr), slice::from_ref(&dst), &[vtx, offset]) + let mut instr = Instr::new( + Opcode::ALD(attr), + slice::from_ref(&dst), + &[vtx, offset], + ); + instr.deps.set_wr_bar(0); + instr } pub fn new_ast(attr_addr: u16, data: Src, vtx: Src, offset: Src) -> Instr { @@ -545,7 +551,12 @@ impl Instr { out_load: false, flags: 0, }; - Instr::new(Opcode::AST(attr), &[], &[data, vtx, offset]) + let mut instr = + Instr::new(Opcode::AST(attr), &[], &[data, vtx, offset]); + instr.deps.set_delay(2); + instr.deps.set_rd_bar(0); + instr.deps.add_wt_bar(0); + instr } pub fn new_fs_out(srcs: &[Src]) -> Instr { @@ -553,7 +564,11 @@ impl Instr { } pub fn new_exit() -> Instr { - Instr::new(Opcode::EXIT, &[], &[]) + let mut instr = Instr::new(Opcode::EXIT, &[], &[]); + for i in 0..6 { + instr.deps.add_wt_bar(i); + } + instr } pub fn dst(&self, idx: usize) -> &Dst {