From c8116679c30bdf622a585d440f16f2ae8bb8f9a7 Mon Sep 17 00:00:00 2001 From: Mel Henning Date: Thu, 25 Sep 2025 18:36:13 -0400 Subject: [PATCH] nak: Add OpSgxt Reviewed-by: Karol Herbst Part-of: --- src/nouveau/compiler/nak/hw_tests.rs | 27 ++++++++++ src/nouveau/compiler/nak/ir.rs | 49 ++++++++++++++++++- src/nouveau/compiler/nak/nvdisasm_tests.rs | 27 ++++++++++ .../compiler/nak/opt_instr_sched_common.rs | 2 +- .../compiler/nak/sm120_instr_latencies.rs | 4 +- src/nouveau/compiler/nak/sm70.rs | 1 + src/nouveau/compiler/nak/sm70_encode.rs | 30 ++++++++++++ .../compiler/nak/sm75_instr_latencies.rs | 4 +- .../compiler/nak/sm80_instr_latencies.rs | 4 +- 9 files changed, 140 insertions(+), 8 deletions(-) diff --git a/src/nouveau/compiler/nak/hw_tests.rs b/src/nouveau/compiler/nak/hw_tests.rs index c562da68019..e8a428c4a5a 100644 --- a/src/nouveau/compiler/nak/hw_tests.rs +++ b/src/nouveau/compiler/nak/hw_tests.rs @@ -1924,3 +1924,30 @@ fn test_render_enable() -> io::Result<()> { Ok(()) } + +#[test] +fn test_op_sgxt() { + let sm = &RunSingleton::get().sm; + if sm.sm() < 70 { + return; + } + + for signed in [false, true] { + let op = OpSgxt { + dst: Dst::None, + a: 0.into(), + bits: 0.into(), + signed, + }; + + let bits_idx = op.src_idx(&op.bits); + let mut a = Acorn::new(); + test_foldable_op_with(op, &mut |i| { + if i == bits_idx && a.get_bool() { + a.get_uint(5) as u32 + } else { + a.get_u32() + } + }); + } +} diff --git a/src/nouveau/compiler/nak/ir.rs b/src/nouveau/compiler/nak/ir.rs index 5f98a3d6634..13857b8bae9 100644 --- a/src/nouveau/compiler/nak/ir.rs +++ b/src/nouveau/compiler/nak/ir.rs @@ -5112,6 +5112,52 @@ impl DisplayOp for OpSel { } impl_display_for_op!(OpSel); +#[repr(C)] +#[derive(Clone, SrcsAsSlice, DstsAsSlice)] +pub struct OpSgxt { + #[dst_type(GPR)] + pub dst: Dst, + + #[src_type(ALU)] + pub a: Src, + + #[src_type(ALU)] + pub bits: Src, + + pub signed: bool, +} + +impl DisplayOp for OpSgxt { + fn fmt_op(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let modifier = if self.signed { "" } else { ".u32" }; + write!(f, "sgxt{} {} {}", modifier, self.a, self.bits) + } +} +impl_display_for_op!(OpSgxt); + +impl Foldable for OpSgxt { + fn fold(&self, _sm: &dyn ShaderModel, f: &mut OpFoldData<'_>) { + let a = f.get_u32_src(self, &self.a); + let bits = f.get_u32_src(self, &self.bits); + + let dst = if bits >= 32 { + a + } else if bits == 0 { + 0 + } else { + let shift = 32 - bits; + let a = a << shift; + if self.signed { + let a = a as i32; + (a >> shift) as u32 + } else { + a >> shift + } + }; + f.set_u32_dst(self, &self.dst, dst); + } +} + #[repr(C)] #[derive(SrcsAsSlice, DstsAsSlice)] pub struct OpShfl { @@ -7895,6 +7941,7 @@ pub enum Op { Mov(Box), Prmt(Box), Sel(Box), + Sgxt(Box), Shfl(Box), PLop3(Box), PSetP(Box), @@ -8068,7 +8115,7 @@ impl Op { } // Move ops - Op::Mov(_) | Op::Prmt(_) | Op::Sel(_) => true, + Op::Mov(_) | Op::Prmt(_) | Op::Sel(_) | Op::Sgxt(_) => true, Op::Shfl(_) => false, // Predicate ops diff --git a/src/nouveau/compiler/nak/nvdisasm_tests.rs b/src/nouveau/compiler/nak/nvdisasm_tests.rs index 62a1c143ef5..7864db03bc3 100644 --- a/src/nouveau/compiler/nak/nvdisasm_tests.rs +++ b/src/nouveau/compiler/nak/nvdisasm_tests.rs @@ -750,3 +750,30 @@ pub fn test_match() { c.check(sm); } } + +#[test] +pub fn test_sgxt() { + let r0 = RegRef::new(RegFile::GPR, 0, 1); + let r1 = RegRef::new(RegFile::GPR, 1, 1); + let r2 = RegRef::new(RegFile::GPR, 2, 1); + + for sm in SM_LIST { + let mut c = DisasmCheck::new(); + for signed in [false, true] { + let instr = OpSgxt { + dst: Dst::Reg(r0), + a: SrcRef::Reg(r1).into(), + bits: SrcRef::Reg(r2).into(), + signed, + }; + + let disasm = if signed { + "sgxt r0, r1, r2;" + } else { + "sgxt.u32 r0, r1, r2;" + }; + c.push(instr, disasm); + } + c.check(sm); + } +} diff --git a/src/nouveau/compiler/nak/opt_instr_sched_common.rs b/src/nouveau/compiler/nak/opt_instr_sched_common.rs index 90e5cc08ade..9cd3da5f956 100644 --- a/src/nouveau/compiler/nak/opt_instr_sched_common.rs +++ b/src/nouveau/compiler/nak/opt_instr_sched_common.rs @@ -145,7 +145,7 @@ pub fn side_effect_type(op: &Op) -> SideEffect { } // Move ops - Op::Mov(_) | Op::Prmt(_) | Op::Sel(_) => SideEffect::None, + Op::Mov(_) | Op::Prmt(_) | Op::Sel(_) | Op::Sgxt(_) => SideEffect::None, Op::Shfl(_) => SideEffect::None, // Predicate ops diff --git a/src/nouveau/compiler/nak/sm120_instr_latencies.rs b/src/nouveau/compiler/nak/sm120_instr_latencies.rs index bf31edf70c9..e5710d014f7 100644 --- a/src/nouveau/compiler/nak/sm120_instr_latencies.rs +++ b/src/nouveau/compiler/nak/sm120_instr_latencies.rs @@ -42,7 +42,7 @@ fn op_reg_latency(op: &Op, reader: bool, op_reg_idx: usize) -> RegLatencySM100 { Op::IAdd3(_) | Op::IAdd3X(_) => Alu, Op::BMsk(_) => Alu, - // Sgxt => Alu, + Op::Sgxt(_) => Alu, Op::Lop3(_) => Alu, Op::Flo(_) => Decoupled, Op::ISetP(_) => Dualalu, @@ -282,7 +282,7 @@ fn op_ureg_latency( Op::PSetP(_) => coupled, // UR2UP Op::Sel(_) => coupled, - // SGXT + Op::Sgxt(_) => coupled, Op::Shf(_) => coupled, Op::Shfl(_) => decoupled, diff --git a/src/nouveau/compiler/nak/sm70.rs b/src/nouveau/compiler/nak/sm70.rs index e03b116ef1a..309657caea6 100644 --- a/src/nouveau/compiler/nak/sm70.rs +++ b/src/nouveau/compiler/nak/sm70.rs @@ -136,6 +136,7 @@ impl ShaderModel for ShaderModel70 { | Op::Prmt(_) | Op::PSetP(_) | Op::Sel(_) + | Op::Sgxt(_) | Op::Shf(_) | Op::Shl(_) | Op::Shr(_) diff --git a/src/nouveau/compiler/nak/sm70_encode.rs b/src/nouveau/compiler/nak/sm70_encode.rs index 68e480f50ea..45b7647aa73 100644 --- a/src/nouveau/compiler/nak/sm70_encode.rs +++ b/src/nouveau/compiler/nak/sm70_encode.rs @@ -2138,6 +2138,35 @@ impl SM70Op for OpSel { } } +impl SM70Op for OpSgxt { + fn legalize(&mut self, b: &mut LegalizeBuilder) { + let gpr = op_gpr(self); + b.copy_alu_src_if_not_reg(&mut self.a, gpr, SrcType::ALU); + } + + fn encode(&self, e: &mut SM70Encoder<'_>) { + if self.is_uniform() { + e.encode_ualu( + 0x09a, + Some(&self.dst), + Some(&self.a), + Some(&self.bits), + None, + ); + } else { + e.encode_alu( + 0x01a, + Some(&self.dst), + Some(&self.a), + Some(&self.bits), + None, + ); + } + e.set_bit(73, self.signed); + e.set_bit(75, false); // .W (wrap vs clamp) + } +} + impl SM70Op for OpShfl { fn legalize(&mut self, b: &mut LegalizeBuilder) { let gpr = op_gpr(self); @@ -4047,6 +4076,7 @@ macro_rules! sm70_op_match { Op::Mov($x) => $y, Op::Prmt($x) => $y, Op::Sel($x) => $y, + Op::Sgxt($x) => $y, Op::Shfl($x) => $y, Op::PLop3($x) => $y, Op::R2UR($x) => $y, diff --git a/src/nouveau/compiler/nak/sm75_instr_latencies.rs b/src/nouveau/compiler/nak/sm75_instr_latencies.rs index a052d75007e..652b694ae34 100644 --- a/src/nouveau/compiler/nak/sm75_instr_latencies.rs +++ b/src/nouveau/compiler/nak/sm75_instr_latencies.rs @@ -69,7 +69,7 @@ impl RegLatencySM75 { Op::IAdd3(_) | Op::IAdd3X(_) => CoupledAlu, Op::BMsk(_) => CoupledAlu, - // Sgxt => CoupledAlu, + Op::Sgxt(_) => CoupledAlu, Op::Lop3(_) => CoupledAlu, Op::Flo(_) => Decoupled, Op::ISetP(_) => CoupledAlu, @@ -954,7 +954,7 @@ impl URegLatencySM75 { Op::PSetP(_) => vcoupled, // UR2UP Op::Sel(_) => vcoupled, - // SGXT + Op::Sgxt(_) => vcoupled, Op::Shf(_) => vcoupled, Op::Shfl(_) => vdecoupled, diff --git a/src/nouveau/compiler/nak/sm80_instr_latencies.rs b/src/nouveau/compiler/nak/sm80_instr_latencies.rs index 860f1f4fb62..9119f9b4ee9 100644 --- a/src/nouveau/compiler/nak/sm80_instr_latencies.rs +++ b/src/nouveau/compiler/nak/sm80_instr_latencies.rs @@ -105,7 +105,7 @@ impl RegLatencySM80 { Op::IAdd3(_) | Op::IAdd3X(_) => CoupledAlu, Op::BMsk(_) => CoupledAlu, - // Sgxt => CoupledAlu, + Op::Sgxt(_) => CoupledAlu, Op::Lop3(_) => CoupledAlu, Op::Flo(_) => Decoupled, Op::ISetP(_) => CoupledAlu, @@ -1072,7 +1072,7 @@ impl URegLatencySM80 { Op::PSetP(_) => vcoupled, // UR2UP Op::Sel(_) => vcoupled, - // SGXT + Op::Sgxt(_) => vcoupled, Op::Shf(_) => vcoupled, Op::Shfl(_) => vdecoupled,