From 1dbc55dadf062e6721b47e2c30dc277b877b6007 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Fri, 13 Oct 2017 10:54:44 -0700 Subject: [PATCH] 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. --- lib/cretonne/meta/cdsl/isa.py | 12 +++++-- lib/cretonne/meta/cdsl/registers.py | 15 ++++++-- lib/cretonne/meta/gen_registers.py | 3 ++ lib/cretonne/src/isa/registers.rs | 7 ++-- lib/cretonne/src/regalloc/pressure.rs | 50 +++++++++++++++++++-------- 5 files changed, 66 insertions(+), 21 deletions(-) diff --git a/lib/cretonne/meta/cdsl/isa.py b/lib/cretonne/meta/cdsl/isa.py index ae517203e1..2fd8e4c7b5 100644 --- a/lib/cretonne/meta/cdsl/isa.py +++ b/lib/cretonne/meta/cdsl/isa.py @@ -136,13 +136,21 @@ class TargetISA(object): # Collect the top-level classes so they get numbered consecutively. for bank in self.regbanks: bank.finish_regclasses() - self.regclasses.extend(bank.toprcs) + # Always get the pressure tracking classes in first. + if bank.pressure_tracking: + self.regclasses.extend(bank.toprcs) # 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`. 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. # They are numbered strictly after the top-level classes. for bank in self.regbanks: diff --git a/lib/cretonne/meta/cdsl/registers.py b/lib/cretonne/meta/cdsl/registers.py index 89c6db0a28..37d75d3d58 100644 --- a/lib/cretonne/meta/cdsl/registers.py +++ b/lib/cretonne/meta/cdsl/registers.py @@ -61,17 +61,28 @@ class RegBank(object): :param name: Name of this register bank. :param doc: Documentation string. :param units: Number of register units. + :param pressure_tracking: Enable tracking of register pressure. :param prefix: Prefix for generated unit names. :param names: Special names for the first units. May be shorter than `units`, the remaining units are named using `prefix`. """ - def __init__(self, name, isa, doc, units, prefix='r', names=()): - # type: (str, TargetISA, str, int, str, Sequence[str]) -> None + def __init__( + 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.isa = isa self.first_unit = 0 self.units = units + self.pressure_tracking = pressure_tracking self.prefix = prefix self.names = names self.classes = list() # type: List[RegClass] diff --git a/lib/cretonne/meta/gen_registers.py b/lib/cretonne/meta/gen_registers.py index 9056441cb1..5917312d96 100644 --- a/lib/cretonne/meta/gen_registers.py +++ b/lib/cretonne/meta/gen_registers.py @@ -28,6 +28,9 @@ def gen_regbank(regbank, fmt): fmt.format('prefix: "{}",', regbank.prefix) fmt.format('first_toprc: {},', regbank.toprcs[0].index) fmt.format('num_toprcs: {},', len(regbank.toprcs)) + fmt.format( + 'pressure_tracking: {},', + 'true' if regbank.pressure_tracking else 'false') def gen_regbank_units(regbank, fmt): diff --git a/lib/cretonne/src/isa/registers.rs b/lib/cretonne/src/isa/registers.rs index db68399cb4..f21c946b99 100644 --- a/lib/cretonne/src/isa/registers.rs +++ b/lib/cretonne/src/isa/registers.rs @@ -27,10 +27,10 @@ pub type RegUnitMask = [u32; 3]; /// This type should be coordinated with meta/cdsl/isa.py. 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. -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 /// 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 /// `first_toprc`, and all top-level register classes across banks come before any sub-classes. pub num_toprcs: usize, + + /// Is register pressure tracking enabled for this bank? + pub pressure_tracking: bool, } impl RegBank { diff --git a/lib/cretonne/src/regalloc/pressure.rs b/lib/cretonne/src/regalloc/pressure.rs index 28cf15f48f..7a3a3a00f6 100644 --- a/lib/cretonne/src/regalloc/pressure.rs +++ b/lib/cretonne/src/regalloc/pressure.rs @@ -36,7 +36,7 @@ // Remove once we're using the pressure tracker. #![allow(dead_code)] -use isa::registers::{RegInfo, MAX_TOPRCS, RegClass, RegClassMask}; +use isa::registers::{RegInfo, MAX_TRACKED_TOPRCS, RegClass, RegClassMask}; use regalloc::AllocatableSet; use std::cmp::min; use std::fmt; @@ -76,7 +76,7 @@ pub struct Pressure { aliased: RegClassMask, // Current register counts per top-level register class. - toprc: [TopRC; MAX_TOPRCS], + toprc: [TopRC; MAX_TRACKED_TOPRCS], } impl Pressure { @@ -88,17 +88,28 @@ impl Pressure { }; // 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 num = bank.num_toprcs; - for rc in &mut p.toprc[first..first + num] { - rc.first_toprc = first as u8; - rc.num_toprcs = num as u8; - } - // Flag the top-level register classes with aliases. - if num > 1 { - p.aliased |= ((1 << num) - 1) << first; + if bank.pressure_tracking { + for rc in &mut p.toprc[first..first + num] { + rc.first_toprc = first as u8; + rc.num_toprcs = num as u8; + } + + // Flag the top-level register classes with aliases. + if num > 1 { + 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; + } } } @@ -123,9 +134,12 @@ impl Pressure { /// pressure should be eased in one of the returned top-level register classes before calling /// `can_take()` to check again. 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; - if self.aliased & mask == 0 { + if (self.aliased & mask) == 0 { // This is a simple unaliased top-level register class. if entry.total_count() < entry.limit { 0 @@ -189,12 +203,16 @@ impl Pressure { /// /// This does not check if there are enough registers available. 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`. 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. @@ -211,7 +229,9 @@ impl Pressure { pub fn take_transient(&mut self, rc: RegClass) -> Result<(), RegClassMask> { let mask = self.check_avail(rc); 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(()) } else { Err(mask)