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: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36528>
This commit is contained in:
Karol Herbst
2025-08-01 21:25:28 +02:00
committed by Marge Bot
parent e6ca709a4e
commit 8cf91a4853
6 changed files with 28 additions and 16 deletions
+3 -1
View File
@@ -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];
};
+1
View File
@@ -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,
+9 -4
View File
@@ -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<T: Clone> {
@@ -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);
+1 -1
View File
@@ -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,
@@ -240,8 +240,8 @@ pub fn side_effect_type(op: &Op) -> SideEffect {
}
}
pub fn estimate_block_weight(cfg: &CFG<BasicBlock>, block_idx: usize) -> u32 {
10_u32.pow(cfg.loop_depth(block_idx).try_into().unwrap())
pub fn estimate_block_weight(cfg: &CFG<BasicBlock>, 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
@@ -141,14 +141,14 @@ fn generate_dep_graph(sm: &dyn ShaderModel, instrs: &[Box<Instr>]) -> DepGraph {
fn generate_order(
g: &mut DepGraph,
init_ready_list: Vec<usize>,
) -> (Vec<usize>, u32) {
) -> (Vec<usize>, u64) {
let mut ready_instrs: BinaryHeap<ReadyInstr> = BinaryHeap::new();
let mut future_ready_instrs: BinaryHeap<FutureReadyInstr> = 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<Box<Instr>>,
) -> (impl Iterator<Item = Box<Instr>> + use<>, u32) {
) -> (impl Iterator<Item = Box<Instr>> + 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
}