Compute top-level register classes for each register bank.
A top-level register class is one that has no sub-classes. It is possible to have multiple top-level register classes in the same register bank. For example, ARM's FPR bank has both D and Q top-level register classes. Number register classes such that all top-level register classes appear as a contiguous sequence starting from 0. This will be used by the register allocator when counting used registers per top-level register class.
This commit is contained in:
@@ -42,6 +42,7 @@ class TargetISA(object):
|
|||||||
self.instruction_groups = instruction_groups
|
self.instruction_groups = instruction_groups
|
||||||
self.cpumodes = list() # type: List[CPUMode]
|
self.cpumodes = list() # type: List[CPUMode]
|
||||||
self.regbanks = list() # type: List[RegBank]
|
self.regbanks = list() # type: List[RegBank]
|
||||||
|
self.regclasses = list() # type: List[RegClass]
|
||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
# type: () -> TargetISA
|
# type: () -> TargetISA
|
||||||
@@ -109,11 +110,23 @@ class TargetISA(object):
|
|||||||
|
|
||||||
Every register class needs a unique index, and the classes need to be
|
Every register class needs a unique index, and the classes need to be
|
||||||
topologically ordered.
|
topologically ordered.
|
||||||
|
|
||||||
|
We also want all the top-level register classes to be first.
|
||||||
"""
|
"""
|
||||||
rc_index = 0
|
# Compute subclasses and top-level classes in each bank.
|
||||||
|
# Collect the top-level classes so they get numbered consecutively.
|
||||||
for bank in self.regbanks:
|
for bank in self.regbanks:
|
||||||
bank.finish_regclasses(rc_index)
|
bank.finish_regclasses()
|
||||||
rc_index += len(bank.classes)
|
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:
|
||||||
|
self.regclasses.extend(
|
||||||
|
rc for rc in bank.classes if not rc.is_toprc())
|
||||||
|
|
||||||
|
for idx, rc in enumerate(self.regclasses):
|
||||||
|
rc.index = idx
|
||||||
|
|
||||||
|
|
||||||
class CPUMode(object):
|
class CPUMode(object):
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ class RegBank(object):
|
|||||||
self.prefix = prefix
|
self.prefix = prefix
|
||||||
self.names = names
|
self.names = names
|
||||||
self.classes = list() # type: List[RegClass]
|
self.classes = list() # type: List[RegClass]
|
||||||
|
self.toprcs = list() # type: List[RegClass]
|
||||||
|
self.first_toprc_index = None # type: int
|
||||||
|
|
||||||
assert len(names) <= units
|
assert len(names) <= units
|
||||||
|
|
||||||
@@ -95,11 +97,10 @@ class RegBank(object):
|
|||||||
return ('RegBank({}, units={}, first_unit={})'
|
return ('RegBank({}, units={}, first_unit={})'
|
||||||
.format(self.name, self.units, self.first_unit))
|
.format(self.name, self.units, self.first_unit))
|
||||||
|
|
||||||
def finish_regclasses(self, first_index):
|
def finish_regclasses(self):
|
||||||
# type: (int) -> None
|
# type: () -> None
|
||||||
"""
|
"""
|
||||||
Assign indexes to the register classes in this bank, starting from
|
Compute subclasses and the top-level register class.
|
||||||
`first_index`.
|
|
||||||
|
|
||||||
Verify that the set of register classes satisfies:
|
Verify that the set of register classes satisfies:
|
||||||
|
|
||||||
@@ -115,14 +116,10 @@ class RegBank(object):
|
|||||||
"""
|
"""
|
||||||
cmap = dict() # type: Dict[RCTup, RegClass]
|
cmap = dict() # type: Dict[RCTup, RegClass]
|
||||||
|
|
||||||
for idx, rc in enumerate(self.classes):
|
for rc in self.classes:
|
||||||
# All register classes must be given a name.
|
# All register classes must be given a name.
|
||||||
assert rc.name, "Anonymous register class found"
|
assert rc.name, "Anonymous register class found"
|
||||||
|
|
||||||
# Assign a unique index.
|
|
||||||
assert rc.index is None
|
|
||||||
rc.index = idx + first_index
|
|
||||||
|
|
||||||
# Check for duplicates.
|
# Check for duplicates.
|
||||||
tup = rc.rctup()
|
tup = rc.rctup()
|
||||||
if tup in cmap:
|
if tup in cmap:
|
||||||
@@ -133,6 +130,7 @@ class RegBank(object):
|
|||||||
|
|
||||||
# Check intersections and topological order.
|
# Check intersections and topological order.
|
||||||
for idx, rc1 in enumerate(self.classes):
|
for idx, rc1 in enumerate(self.classes):
|
||||||
|
rc1.toprc = rc1
|
||||||
for rc2 in self.classes[0:idx]:
|
for rc2 in self.classes[0:idx]:
|
||||||
itup = rc1.intersect(rc2)
|
itup = rc1.intersect(rc2)
|
||||||
if itup is None:
|
if itup is None:
|
||||||
@@ -151,6 +149,10 @@ class RegBank(object):
|
|||||||
# The intersection of rc1 and rc2 is rc1, so it must be a
|
# The intersection of rc1 and rc2 is rc1, so it must be a
|
||||||
# sub-class.
|
# sub-class.
|
||||||
rc2.subclasses.append(rc1)
|
rc2.subclasses.append(rc1)
|
||||||
|
rc1.toprc = rc2.toprc
|
||||||
|
|
||||||
|
if rc1.is_toprc():
|
||||||
|
self.toprcs.append(rc1)
|
||||||
|
|
||||||
def unit_by_name(self, name):
|
def unit_by_name(self, name):
|
||||||
# type: (str) -> int
|
# type: (str) -> int
|
||||||
@@ -192,6 +194,7 @@ class RegClass(object):
|
|||||||
|
|
||||||
# This is computed later in `finish_regclasses()`.
|
# This is computed later in `finish_regclasses()`.
|
||||||
self.subclasses = list() # type: List[RegClass]
|
self.subclasses = list() # type: List[RegClass]
|
||||||
|
self.toprc = None # type: RegClass
|
||||||
|
|
||||||
assert width > 0
|
assert width > 0
|
||||||
assert start >= 0 and start < bank.units
|
assert start >= 0 and start < bank.units
|
||||||
@@ -206,6 +209,16 @@ class RegClass(object):
|
|||||||
# type: () -> str
|
# type: () -> str
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def is_toprc(self):
|
||||||
|
# type: () -> bool
|
||||||
|
"""
|
||||||
|
Is this a top-level register class?
|
||||||
|
|
||||||
|
A top-level register class has no sub-classes. This can only be
|
||||||
|
answered aster running `finish_regclasses()`.
|
||||||
|
"""
|
||||||
|
return self.toprc is self
|
||||||
|
|
||||||
def rctup(self):
|
def rctup(self):
|
||||||
# type: () -> RCTup
|
# type: () -> RCTup
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -19,13 +19,15 @@ def gen_regbank(regbank, fmt):
|
|||||||
Emit a static data definition for regbank.
|
Emit a static data definition for regbank.
|
||||||
"""
|
"""
|
||||||
with fmt.indented('RegBank {', '},'):
|
with fmt.indented('RegBank {', '},'):
|
||||||
fmt.line('name: "{}",'.format(regbank.name))
|
fmt.format('name: "{}",', regbank.name)
|
||||||
fmt.line('first_unit: {},'.format(regbank.first_unit))
|
fmt.format('first_unit: {},', regbank.first_unit)
|
||||||
fmt.line('units: {},'.format(regbank.units))
|
fmt.format('units: {},', regbank.units)
|
||||||
fmt.line(
|
fmt.format(
|
||||||
'names: &[{}],'
|
'names: &[{}],',
|
||||||
.format(', '.join('"{}"'.format(n) for n in regbank.names)))
|
', '.join('"{}"'.format(n) for n in regbank.names))
|
||||||
fmt.line('prefix: "{}",'.format(regbank.prefix))
|
fmt.format('prefix: "{}",', regbank.prefix)
|
||||||
|
fmt.format('first_toprc: {},', regbank.toprcs[0].index)
|
||||||
|
fmt.format('num_toprcs: {},', len(regbank.toprcs))
|
||||||
|
|
||||||
|
|
||||||
def gen_regclass(rc, fmt):
|
def gen_regclass(rc, fmt):
|
||||||
@@ -38,6 +40,7 @@ def gen_regclass(rc, fmt):
|
|||||||
fmt.format('index: {},', rc.index)
|
fmt.format('index: {},', rc.index)
|
||||||
fmt.format('width: {},', rc.width)
|
fmt.format('width: {},', rc.width)
|
||||||
fmt.format('bank: {},', rc.bank.index)
|
fmt.format('bank: {},', rc.bank.index)
|
||||||
|
fmt.format('toprc: {},', rc.toprc.index)
|
||||||
fmt.format('first: {},', rc.bank.first_unit + rc.start)
|
fmt.format('first: {},', rc.bank.first_unit + rc.start)
|
||||||
fmt.format('subclasses: 0x{:x},', rc.subclass_mask())
|
fmt.format('subclasses: 0x{:x},', rc.subclass_mask())
|
||||||
mask = ', '.join('0x{:08x}'.format(x) for x in rc.mask())
|
mask = ', '.join('0x{:08x}'.format(x) for x in rc.mask())
|
||||||
@@ -52,24 +55,23 @@ def gen_isa(isa, fmt):
|
|||||||
if not isa.regbanks:
|
if not isa.regbanks:
|
||||||
print('cargo:warning={} has no register banks'.format(isa.name))
|
print('cargo:warning={} has no register banks'.format(isa.name))
|
||||||
|
|
||||||
rcs = list() # type: List[RegClass]
|
|
||||||
with fmt.indented('pub static INFO: RegInfo = RegInfo {', '};'):
|
with fmt.indented('pub static INFO: RegInfo = RegInfo {', '};'):
|
||||||
# Bank descriptors.
|
# Bank descriptors.
|
||||||
with fmt.indented('banks: &[', '],'):
|
with fmt.indented('banks: &[', '],'):
|
||||||
for regbank in isa.regbanks:
|
for regbank in isa.regbanks:
|
||||||
gen_regbank(regbank, fmt)
|
gen_regbank(regbank, fmt)
|
||||||
rcs += regbank.classes
|
|
||||||
fmt.line('classes: &CLASSES,')
|
fmt.line('classes: &CLASSES,')
|
||||||
|
|
||||||
# Register class descriptors.
|
# Register class descriptors.
|
||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
'const CLASSES: [RegClassData; {}] = ['.format(len(rcs)), '];'):
|
'const CLASSES: [RegClassData; {}] = ['
|
||||||
for idx, rc in enumerate(rcs):
|
.format(len(isa.regclasses)), '];'):
|
||||||
|
for idx, rc in enumerate(isa.regclasses):
|
||||||
assert idx == rc.index
|
assert idx == rc.index
|
||||||
gen_regclass(rc, fmt)
|
gen_regclass(rc, fmt)
|
||||||
|
|
||||||
# Emit constants referencing the register classes.
|
# Emit constants referencing the register classes.
|
||||||
for rc in rcs:
|
for rc in isa.regclasses:
|
||||||
fmt.line('#[allow(dead_code)]')
|
fmt.line('#[allow(dead_code)]')
|
||||||
fmt.line(
|
fmt.line(
|
||||||
'pub const {}: RegClass = &CLASSES[{}];'
|
'pub const {}: RegClass = &CLASSES[{}];'
|
||||||
|
|||||||
@@ -42,6 +42,15 @@ pub struct RegBank {
|
|||||||
/// The remaining register units will be named this prefix followed by their decimal offset in
|
/// The remaining register units will be named this prefix followed by their decimal offset in
|
||||||
/// the bank. So with a prefix `r`, registers will be named `r8`, `r9`, ...
|
/// the bank. So with a prefix `r`, registers will be named `r8`, `r9`, ...
|
||||||
pub prefix: &'static str,
|
pub prefix: &'static str,
|
||||||
|
|
||||||
|
/// Index of the first top-level register class in this bank.
|
||||||
|
pub first_toprc: usize,
|
||||||
|
|
||||||
|
/// Number of top-level register classes in this bank.
|
||||||
|
///
|
||||||
|
/// 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,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegBank {
|
impl RegBank {
|
||||||
@@ -111,6 +120,9 @@ pub struct RegClassData {
|
|||||||
/// Index of the register bank this class belongs to.
|
/// Index of the register bank this class belongs to.
|
||||||
pub bank: u8,
|
pub bank: u8,
|
||||||
|
|
||||||
|
/// Index of the top-level register class contains this one.
|
||||||
|
pub toprc: u8,
|
||||||
|
|
||||||
/// The first register unit in this class.
|
/// The first register unit in this class.
|
||||||
pub first: RegUnit,
|
pub first: RegUnit,
|
||||||
|
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ mod tests {
|
|||||||
index: 0,
|
index: 0,
|
||||||
width: 1,
|
width: 1,
|
||||||
bank: 0,
|
bank: 0,
|
||||||
|
toprc: 0,
|
||||||
first: 28,
|
first: 28,
|
||||||
subclasses: 0,
|
subclasses: 0,
|
||||||
mask: [0xf0000000, 0x0000000f, 0],
|
mask: [0xf0000000, 0x0000000f, 0],
|
||||||
@@ -150,6 +151,7 @@ mod tests {
|
|||||||
index: 0,
|
index: 0,
|
||||||
width: 2,
|
width: 2,
|
||||||
bank: 0,
|
bank: 0,
|
||||||
|
toprc: 0,
|
||||||
first: 28,
|
first: 28,
|
||||||
subclasses: 0,
|
subclasses: 0,
|
||||||
mask: [0x50000000, 0x0000000a, 0],
|
mask: [0x50000000, 0x0000000a, 0],
|
||||||
|
|||||||
Reference in New Issue
Block a user