mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-23 19:50:11 +01:00
nak: Expose LiveSet for incremental liveness tracking
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24998>
This commit is contained in:
parent
8c04737a6a
commit
002ee9e40e
2 changed files with 114 additions and 51 deletions
|
|
@ -219,7 +219,7 @@ impl Iterator for RegFileSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct PerRegFile<T> {
|
pub struct PerRegFile<T> {
|
||||||
per_file: [T; NUM_REG_FILES],
|
per_file: [T; NUM_REG_FILES],
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ use std::cell::RefCell;
|
||||||
use std::cmp::{max, Ord, Ordering};
|
use std::cmp::{max, Ord, Ordering};
|
||||||
use std::collections::{hash_set, HashMap, HashSet};
|
use std::collections::{hash_set, HashMap, HashSet};
|
||||||
|
|
||||||
struct LiveSet {
|
#[derive(Clone)]
|
||||||
|
pub struct LiveSet {
|
||||||
live: PerRegFile<u32>,
|
live: PerRegFile<u32>,
|
||||||
set: HashSet<SSAValue>,
|
set: HashSet<SSAValue>,
|
||||||
}
|
}
|
||||||
|
|
@ -56,12 +57,120 @@ impl LiveSet {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert_instr_top_down<L: BlockLiveness>(
|
||||||
|
&mut self,
|
||||||
|
ip: usize,
|
||||||
|
instr: &Instr,
|
||||||
|
bl: &L,
|
||||||
|
) -> PerRegFile<u32> {
|
||||||
|
/* Vector destinations go live before sources are killed. Even
|
||||||
|
* in the case where the destination is immediately killed, it
|
||||||
|
* still may contribute to pressure temporarily.
|
||||||
|
*/
|
||||||
|
for dst in instr.dsts() {
|
||||||
|
if let Dst::SSA(vec) = dst {
|
||||||
|
if vec.comps() > 1 {
|
||||||
|
for ssa in vec.iter() {
|
||||||
|
self.insert(*ssa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let after_dsts_live = self.live;
|
||||||
|
|
||||||
|
instr.for_each_ssa_use(|ssa| {
|
||||||
|
if !bl.is_live_after_ip(ssa, ip) {
|
||||||
|
self.remove(ssa);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Scalar destinations are allocated last */
|
||||||
|
for dst in instr.dsts() {
|
||||||
|
if let Dst::SSA(vec) = dst {
|
||||||
|
if vec.comps() == 1 {
|
||||||
|
self.insert(vec[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let max_live = PerRegFile::new_with(|file| {
|
||||||
|
max(self.live[file], after_dsts_live[file])
|
||||||
|
});
|
||||||
|
|
||||||
|
/* It's possible (but unlikely) that a destination is immediately
|
||||||
|
* killed. Remove any which are killed by this instruction.
|
||||||
|
*/
|
||||||
|
instr.for_each_ssa_def(|ssa| {
|
||||||
|
debug_assert!(self.contains(ssa));
|
||||||
|
if !bl.is_live_after_ip(ssa, ip) {
|
||||||
|
self.remove(ssa);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
max_live
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromIterator<SSAValue> for LiveSet {
|
||||||
|
fn from_iter<T: IntoIterator<Item = SSAValue>>(iter: T) -> Self {
|
||||||
|
let mut set = LiveSet::new();
|
||||||
|
for ssa in iter {
|
||||||
|
set.insert(ssa);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BlockLiveness {
|
pub trait BlockLiveness {
|
||||||
fn is_live_after_ip(&self, val: &SSAValue, ip: usize) -> bool;
|
fn is_live_after_ip(&self, val: &SSAValue, ip: usize) -> bool;
|
||||||
fn is_live_in(&self, val: &SSAValue) -> bool;
|
fn is_live_in(&self, val: &SSAValue) -> bool;
|
||||||
fn is_live_out(&self, val: &SSAValue) -> bool;
|
fn is_live_out(&self, val: &SSAValue) -> bool;
|
||||||
|
|
||||||
|
fn get_instr_pressure(&self, ip: usize, instr: &Instr) -> PerRegFile<u8> {
|
||||||
|
let mut live = PerRegFile::new_with(|_| 0_i8);
|
||||||
|
|
||||||
|
/* Vector destinations go live before sources are killed. */
|
||||||
|
for dst in instr.dsts() {
|
||||||
|
if let Dst::SSA(vec) = dst {
|
||||||
|
if vec.comps() > 1 {
|
||||||
|
for ssa in vec.iter() {
|
||||||
|
live[ssa.file()] += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is the first high point */
|
||||||
|
let vec_dst_live = live.clone();
|
||||||
|
|
||||||
|
/* Use a hash set because sources may occur more than once */
|
||||||
|
let mut killed = HashSet::new();
|
||||||
|
instr.for_each_ssa_use(|ssa| {
|
||||||
|
if !self.is_live_after_ip(ssa, ip) {
|
||||||
|
killed.insert(*ssa);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for ssa in killed.drain() {
|
||||||
|
live[ssa.file()] -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scalar destinations are allocated last */
|
||||||
|
for dst in instr.dsts() {
|
||||||
|
if let Dst::SSA(vec) = dst {
|
||||||
|
if vec.comps() == 1 {
|
||||||
|
live[vec[0].file()] += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PerRegFile::new_with(|file| {
|
||||||
|
max(0, max(vec_dst_live[file], live[file]))
|
||||||
|
.try_into()
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Liveness {
|
pub trait Liveness {
|
||||||
|
|
@ -91,55 +200,9 @@ pub trait Liveness {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ip, instr) in bb.instrs.iter().enumerate() {
|
for (ip, instr) in bb.instrs.iter().enumerate() {
|
||||||
/* Vector destinations go live before sources are killed. Even
|
let live_at_instr = live.insert_instr_top_down(ip, instr, bl);
|
||||||
* in the case where the destination is immediately killed, it
|
max_live = PerRegFile::new_with(|file| {
|
||||||
* still may contribute to pressure temporarily.
|
max(max_live[file], live_at_instr[file])
|
||||||
*/
|
|
||||||
for dst in instr.dsts() {
|
|
||||||
if let Dst::SSA(vec) = dst {
|
|
||||||
if vec.comps() > 1 {
|
|
||||||
for ssa in vec.iter() {
|
|
||||||
live.insert(*ssa);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ml, l) in max_live.values_mut().zip(live.counts().values())
|
|
||||||
{
|
|
||||||
*ml = max(*ml, *l);
|
|
||||||
}
|
|
||||||
|
|
||||||
instr.for_each_ssa_use(|ssa| {
|
|
||||||
if !bl.is_live_after_ip(ssa, ip) {
|
|
||||||
live.remove(ssa);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* Scalar destinations are allocated last */
|
|
||||||
for dst in instr.dsts() {
|
|
||||||
if let Dst::SSA(vec) = dst {
|
|
||||||
if vec.comps() == 1 {
|
|
||||||
live.insert(vec[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ml, l) in max_live.values_mut().zip(live.counts().values())
|
|
||||||
{
|
|
||||||
*ml = max(*ml, *l);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We already added destinations to the live count but haven't
|
|
||||||
* inserted them into the live set yet. If a destination is
|
|
||||||
* killed immediately, subtract from the count, otherwise add to
|
|
||||||
* the set.
|
|
||||||
*/
|
|
||||||
instr.for_each_ssa_def(|ssa| {
|
|
||||||
debug_assert!(live.contains(ssa));
|
|
||||||
if !bl.is_live_after_ip(ssa, ip) {
|
|
||||||
live.remove(ssa);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue