From 8cf91a485362586450468aed257d5cdcb2f8808b Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Fri, 1 Aug 2025 21:25:28 +0200 Subject: [PATCH] nak: protect static cycle counting against overflows Now with the loop aware cycle counting it's very likely that we'll overflow an u32 when counting, so do the counting in u64. Part-of: --- src/nouveau/compiler/nak.h | 4 +++- src/nouveau/compiler/nak/api.rs | 1 + src/nouveau/compiler/nak/calc_instr_deps.rs | 13 ++++++++---- src/nouveau/compiler/nak/ir.rs | 2 +- .../compiler/nak/opt_instr_sched_common.rs | 4 ++-- .../compiler/nak/opt_instr_sched_postpass.rs | 20 +++++++++++-------- 6 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/nouveau/compiler/nak.h b/src/nouveau/compiler/nak.h index 6b2d08095ef..f50b0c708e8 100644 --- a/src/nouveau/compiler/nak.h +++ b/src/nouveau/compiler/nak.h @@ -146,7 +146,7 @@ struct nak_shader_info { uint32_t num_instrs; /** Number of cycles used by fixed-latency instructions */ - uint32_t num_static_cycles; + uint64_t num_static_cycles; /** Number of spills from GPRs to Memory */ uint32_t num_spills_to_mem; @@ -211,6 +211,8 @@ struct nak_shader_info { struct nak_xfb_info xfb; } vtg; + uint8_t _pad1[4]; + /** Shader header for 3D stages */ uint32_t hdr[32]; }; diff --git a/src/nouveau/compiler/nak/api.rs b/src/nouveau/compiler/nak/api.rs index ebd7f4bba82..237d9b111b8 100644 --- a/src/nouveau/compiler/nak/api.rs +++ b/src/nouveau/compiler/nak/api.rs @@ -266,6 +266,7 @@ impl ShaderBin { }, num_control_barriers: info.num_control_barriers, _pad0: Default::default(), + _pad1: Default::default(), max_warps_per_sm: info.max_warps_per_sm, num_instrs: info.num_instrs, num_static_cycles: info.num_static_cycles, diff --git a/src/nouveau/compiler/nak/calc_instr_deps.rs b/src/nouveau/compiler/nak/calc_instr_deps.rs index e442c9e4751..a3e3c650754 100644 --- a/src/nouveau/compiler/nak/calc_instr_deps.rs +++ b/src/nouveau/compiler/nak/calc_instr_deps.rs @@ -10,7 +10,7 @@ use crate::reg_tracker::RegTracker; use rustc_hash::{FxHashMap, FxHashSet}; use std::cmp::max; use std::ops::Range; -use std::{slice, u32, u8}; +use std::{slice, u8}; #[derive(Clone)] enum RegUse { @@ -670,7 +670,7 @@ fn assign_barriers(f: &mut Function, sm: &dyn ShaderModel) { } } -fn calc_delays(f: &mut Function, sm: &dyn ShaderModel) -> u32 { +fn calc_delays(f: &mut Function, sm: &dyn ShaderModel) -> u64 { let mut min_num_static_cycles = 0; for i in (0..f.blocks.len()).rev() { let b = &mut f.blocks[i]; @@ -784,7 +784,12 @@ fn calc_delays(f: &mut Function, sm: &dyn ShaderModel) -> u32 { cycle = min_start; } - min_num_static_cycles += cycle * estimate_block_weight(&f.blocks, i); + let block_weight = estimate_block_weight(&f.blocks, i); + min_num_static_cycles = u64::from(cycle) + .checked_mul(block_weight) + .expect("Cycle count estimate overflow") + .checked_add(min_num_static_cycles) + .expect("Cycle count estimate overflow"); } let max_instr_delay = sm.max_instr_delay(); @@ -861,7 +866,7 @@ impl Shader<'_> { if DEBUG.serial() { self.assign_deps_serial(); } else { - let mut min_num_static_cycles = 0; + let mut min_num_static_cycles = 0u64; for f in &mut self.functions { assign_barriers(f, self.sm); min_num_static_cycles += calc_delays(f, self.sm); diff --git a/src/nouveau/compiler/nak/ir.rs b/src/nouveau/compiler/nak/ir.rs index a886baeb2f2..210a2bcdefb 100644 --- a/src/nouveau/compiler/nak/ir.rs +++ b/src/nouveau/compiler/nak/ir.rs @@ -8970,7 +8970,7 @@ pub struct ShaderInfo { pub num_gprs: u8, pub num_control_barriers: u8, pub num_instrs: u32, - pub num_static_cycles: u32, + pub num_static_cycles: u64, pub num_spills_to_mem: u32, pub num_fills_from_mem: u32, pub num_spills_to_reg: u32, diff --git a/src/nouveau/compiler/nak/opt_instr_sched_common.rs b/src/nouveau/compiler/nak/opt_instr_sched_common.rs index bf14ba2c250..d5378c5bc72 100644 --- a/src/nouveau/compiler/nak/opt_instr_sched_common.rs +++ b/src/nouveau/compiler/nak/opt_instr_sched_common.rs @@ -240,8 +240,8 @@ pub fn side_effect_type(op: &Op) -> SideEffect { } } -pub fn estimate_block_weight(cfg: &CFG, block_idx: usize) -> u32 { - 10_u32.pow(cfg.loop_depth(block_idx).try_into().unwrap()) +pub fn estimate_block_weight(cfg: &CFG, block_idx: usize) -> u64 { + 10_u64.pow(cfg.loop_depth(block_idx).try_into().unwrap()) } /// Try to guess how many cycles a variable latency instruction will take diff --git a/src/nouveau/compiler/nak/opt_instr_sched_postpass.rs b/src/nouveau/compiler/nak/opt_instr_sched_postpass.rs index 6bbc1cfa9d2..bccc5f3f18d 100644 --- a/src/nouveau/compiler/nak/opt_instr_sched_postpass.rs +++ b/src/nouveau/compiler/nak/opt_instr_sched_postpass.rs @@ -141,14 +141,14 @@ fn generate_dep_graph(sm: &dyn ShaderModel, instrs: &[Box]) -> DepGraph { fn generate_order( g: &mut DepGraph, init_ready_list: Vec, -) -> (Vec, u32) { +) -> (Vec, u64) { let mut ready_instrs: BinaryHeap = BinaryHeap::new(); let mut future_ready_instrs: BinaryHeap = init_ready_list .into_iter() .map(|i| FutureReadyInstr::new(g, i)) .collect(); - let mut current_cycle = 0; + let mut current_cycle = 0u32; let mut instr_order = Vec::with_capacity(g.nodes.len()); loop { // Move ready instructions to the ready list @@ -198,13 +198,13 @@ fn generate_order( } } - (instr_order, current_cycle) + (instr_order, u64::from(current_cycle)) } fn sched_buffer( sm: &dyn ShaderModel, instrs: Vec>, -) -> (impl Iterator> + use<>, u32) { +) -> (impl Iterator> + use<>, u64) { let mut g = generate_dep_graph(sm, &instrs); let init_ready_list = calc_statistics(&mut g); // save_graphviz(&instrs, &g).unwrap(); @@ -221,8 +221,8 @@ fn sched_buffer( } impl Function { - pub fn opt_instr_sched_postpass(&mut self, sm: &dyn ShaderModel) -> u32 { - let mut num_static_cycles = 0; + pub fn opt_instr_sched_postpass(&mut self, sm: &dyn ShaderModel) -> u64 { + let mut num_static_cycles = 0u64; for i in 0..self.blocks.len() { let block = &mut self.blocks[i]; @@ -232,8 +232,12 @@ impl Function { block.instrs = instrs.collect(); assert_eq!(orig_instr_count, block.instrs.len()); - num_static_cycles += - cycle_count * estimate_block_weight(&self.blocks, i); + let block_weight = estimate_block_weight(&self.blocks, i); + num_static_cycles = cycle_count + .checked_mul(block_weight) + .expect("Cycle count estimate overflow") + .checked_add(num_static_cycles) + .expect("Cycle count estimate overflow"); } num_static_cycles }