Add a pressure_tracking flag to register banks.

This makes it possible to define register banks that opt out of register
pressure tracking. This will be used to define banks for special-purpose
registers like the CPU flags.

The pressure tracker does not need to use resources for a top-level
register class in a non-tracked bank. The constant MAX_TOPRCS is renamed
to MAX_TRACKED_TOPRCS to indicate that there may be top-level register
classes with higher numbers, but they won't require pressure tracking.

We won't be tracking register pressure for CPU flags since only one
value is allowed to be live at a time.
This commit is contained in:
Jakob Stoklund Olesen
2017-10-13 10:54:44 -07:00
parent c808447468
commit 1dbc55dadf
5 changed files with 66 additions and 21 deletions

View File

@@ -136,13 +136,21 @@ class TargetISA(object):
# Collect the top-level classes so they get numbered consecutively. # Collect the top-level classes so they get numbered consecutively.
for bank in self.regbanks: for bank in self.regbanks:
bank.finish_regclasses() bank.finish_regclasses()
# Always get the pressure tracking classes in first.
if bank.pressure_tracking:
self.regclasses.extend(bank.toprcs) self.regclasses.extend(bank.toprcs)
# The limit on the number of top-level register classes can be raised. # The limit on the number of top-level register classes can be raised.
# This should be coordinated with the `MAX_TOPRCS` constant in # This should be coordinated with the `MAX_TRACKED_TOPRCS` constant in
# `isa/registers.rs`. # `isa/registers.rs`.
assert len(self.regclasses) <= 4, "Too many top-level register classes" assert len(self.regclasses) <= 4, "Too many top-level register classes"
# Get the remaining top-level register classes which may exceed
# `MAX_TRACKED_TOPRCS`.
for bank in self.regbanks:
if not bank.pressure_tracking:
self.regclasses.extend(bank.toprcs)
# Collect all of the non-top-level register classes. # Collect all of the non-top-level register classes.
# They are numbered strictly after the top-level classes. # They are numbered strictly after the top-level classes.
for bank in self.regbanks: for bank in self.regbanks:

View File

@@ -61,17 +61,28 @@ class RegBank(object):
:param name: Name of this register bank. :param name: Name of this register bank.
:param doc: Documentation string. :param doc: Documentation string.
:param units: Number of register units. :param units: Number of register units.
:param pressure_tracking: Enable tracking of register pressure.
:param prefix: Prefix for generated unit names. :param prefix: Prefix for generated unit names.
:param names: Special names for the first units. May be shorter than :param names: Special names for the first units. May be shorter than
`units`, the remaining units are named using `prefix`. `units`, the remaining units are named using `prefix`.
""" """
def __init__(self, name, isa, doc, units, prefix='r', names=()): def __init__(
# type: (str, TargetISA, str, int, str, Sequence[str]) -> None self,
name, # type: str
isa, # type: TargetISA
doc, # type: str
units, # type: int
pressure_tracking=True, # type: bool
prefix='r', # type: str
names=() # type: Sequence[str]
):
# type: (...) -> None
self.name = name self.name = name
self.isa = isa self.isa = isa
self.first_unit = 0 self.first_unit = 0
self.units = units self.units = units
self.pressure_tracking = pressure_tracking
self.prefix = prefix self.prefix = prefix
self.names = names self.names = names
self.classes = list() # type: List[RegClass] self.classes = list() # type: List[RegClass]

View File

@@ -28,6 +28,9 @@ def gen_regbank(regbank, fmt):
fmt.format('prefix: "{}",', regbank.prefix) fmt.format('prefix: "{}",', regbank.prefix)
fmt.format('first_toprc: {},', regbank.toprcs[0].index) fmt.format('first_toprc: {},', regbank.toprcs[0].index)
fmt.format('num_toprcs: {},', len(regbank.toprcs)) fmt.format('num_toprcs: {},', len(regbank.toprcs))
fmt.format(
'pressure_tracking: {},',
'true' if regbank.pressure_tracking else 'false')
def gen_regbank_units(regbank, fmt): def gen_regbank_units(regbank, fmt):

View File

@@ -27,10 +27,10 @@ pub type RegUnitMask = [u32; 3];
/// This type should be coordinated with meta/cdsl/isa.py. /// This type should be coordinated with meta/cdsl/isa.py.
pub type RegClassMask = u32; pub type RegClassMask = u32;
/// Guaranteed maximum number of top-level register classes in any ISA. /// Guaranteed maximum number of top-level register classes with pressure tracking in any ISA.
/// ///
/// This can be increased, but should be coordinated with meta/cdsl/isa.py. /// This can be increased, but should be coordinated with meta/cdsl/isa.py.
pub const MAX_TOPRCS: usize = 4; pub const MAX_TRACKED_TOPRCS: usize = 4;
/// The register units in a target ISA are divided into disjoint register banks. Each bank covers a /// The register units in a target ISA are divided into disjoint register banks. Each bank covers a
/// contiguous range of register units. /// contiguous range of register units.
@@ -63,6 +63,9 @@ pub struct RegBank {
/// The top-level register classes in a bank are guaranteed to be numbered sequentially from /// The top-level register classes in a bank are guaranteed to be numbered sequentially from
/// `first_toprc`, and all top-level register classes across banks come before any sub-classes. /// `first_toprc`, and all top-level register classes across banks come before any sub-classes.
pub num_toprcs: usize, pub num_toprcs: usize,
/// Is register pressure tracking enabled for this bank?
pub pressure_tracking: bool,
} }
impl RegBank { impl RegBank {

View File

@@ -36,7 +36,7 @@
// Remove once we're using the pressure tracker. // Remove once we're using the pressure tracker.
#![allow(dead_code)] #![allow(dead_code)]
use isa::registers::{RegInfo, MAX_TOPRCS, RegClass, RegClassMask}; use isa::registers::{RegInfo, MAX_TRACKED_TOPRCS, RegClass, RegClassMask};
use regalloc::AllocatableSet; use regalloc::AllocatableSet;
use std::cmp::min; use std::cmp::min;
use std::fmt; use std::fmt;
@@ -76,7 +76,7 @@ pub struct Pressure {
aliased: RegClassMask, aliased: RegClassMask,
// Current register counts per top-level register class. // Current register counts per top-level register class.
toprc: [TopRC; MAX_TOPRCS], toprc: [TopRC; MAX_TRACKED_TOPRCS],
} }
impl Pressure { impl Pressure {
@@ -88,9 +88,11 @@ impl Pressure {
}; };
// Get the layout of aliasing top-level register classes from the register banks. // Get the layout of aliasing top-level register classes from the register banks.
for bank in reginfo.banks { for bank in reginfo.banks.iter() {
let first = bank.first_toprc; let first = bank.first_toprc;
let num = bank.num_toprcs; let num = bank.num_toprcs;
if bank.pressure_tracking {
for rc in &mut p.toprc[first..first + num] { for rc in &mut p.toprc[first..first + num] {
rc.first_toprc = first as u8; rc.first_toprc = first as u8;
rc.num_toprcs = num as u8; rc.num_toprcs = num as u8;
@@ -100,6 +102,15 @@ impl Pressure {
if num > 1 { if num > 1 {
p.aliased |= ((1 << num) - 1) << first; p.aliased |= ((1 << num) - 1) << first;
} }
} else {
// This bank has no pressure tracking, so its top-level register classes may exceed
// `MAX_TRACKED_TOPRCS`. Fill in dummy entries.
for rc in &mut p.toprc[first..min(first + num, MAX_TRACKED_TOPRCS)] {
// These aren't used if we don't set the `aliased` bit.
rc.first_toprc = !0;
rc.limit = !0;
}
}
} }
// Compute per-class limits from `usable`. // Compute per-class limits from `usable`.
@@ -123,9 +134,12 @@ impl Pressure {
/// pressure should be eased in one of the returned top-level register classes before calling /// pressure should be eased in one of the returned top-level register classes before calling
/// `can_take()` to check again. /// `can_take()` to check again.
fn check_avail(&self, rc: RegClass) -> RegClassMask { fn check_avail(&self, rc: RegClass) -> RegClassMask {
let entry = &self.toprc[rc.toprc as usize]; let entry = match self.toprc.get(rc.toprc as usize) {
None => return 0, // Not a pressure tracked bank.
Some(e) => e,
};
let mask = 1 << rc.toprc; let mask = 1 << rc.toprc;
if self.aliased & mask == 0 { if (self.aliased & mask) == 0 {
// This is a simple unaliased top-level register class. // This is a simple unaliased top-level register class.
if entry.total_count() < entry.limit { if entry.total_count() < entry.limit {
0 0
@@ -189,12 +203,16 @@ impl Pressure {
/// ///
/// This does not check if there are enough registers available. /// This does not check if there are enough registers available.
pub fn take(&mut self, rc: RegClass) { pub fn take(&mut self, rc: RegClass) {
self.toprc[rc.toprc as usize].base_count += 1 self.toprc.get_mut(rc.toprc as usize).map(
|t| t.base_count += 1,
);
} }
/// Free a register in `rc`. /// Free a register in `rc`.
pub fn free(&mut self, rc: RegClass) { pub fn free(&mut self, rc: RegClass) {
self.toprc[rc.toprc as usize].base_count -= 1 self.toprc.get_mut(rc.toprc as usize).map(
|t| t.base_count -= 1,
);
} }
/// Reset all counts to 0, both base and transient. /// Reset all counts to 0, both base and transient.
@@ -211,7 +229,9 @@ impl Pressure {
pub fn take_transient(&mut self, rc: RegClass) -> Result<(), RegClassMask> { pub fn take_transient(&mut self, rc: RegClass) -> Result<(), RegClassMask> {
let mask = self.check_avail(rc); let mask = self.check_avail(rc);
if mask == 0 { if mask == 0 {
self.toprc[rc.toprc as usize].transient_count += 1; self.toprc.get_mut(rc.toprc as usize).map(|t| {
t.transient_count += 1
});
Ok(()) Ok(())
} else { } else {
Err(mask) Err(mask)