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)