Compute register class intersections.
Ensure that the set of register classes is closed under intersection. Provide a RegClass::intersect() method which finds the register class representing the intersection of two classes. Generate a bit-mask of subclasses for each register class to be used by the intersect() method. Ensure that register classes are sorted topologically. This is also used by the intersect() method.
This commit is contained in:
@@ -51,6 +51,7 @@ class TargetISA(object):
|
||||
"""
|
||||
self._collect_encoding_recipes()
|
||||
self._collect_predicates()
|
||||
self._collect_regclasses()
|
||||
return self
|
||||
|
||||
def _collect_encoding_recipes(self):
|
||||
@@ -96,6 +97,18 @@ class TargetISA(object):
|
||||
if enc.isap:
|
||||
self.settings.number_predicate(enc.isap)
|
||||
|
||||
def _collect_regclasses(self):
|
||||
"""
|
||||
Collect and number register classes.
|
||||
|
||||
Every register class needs a unique index, and the classes need to be
|
||||
topologically ordered.
|
||||
"""
|
||||
rc_index = 0
|
||||
for bank in self.regbanks:
|
||||
bank.finish_regclasses(rc_index)
|
||||
rc_index += len(bank.classes)
|
||||
|
||||
|
||||
class CPUMode(object):
|
||||
"""
|
||||
|
||||
@@ -26,8 +26,11 @@ from . import is_power_of_two, next_power_of_two
|
||||
|
||||
|
||||
try:
|
||||
from typing import Sequence # noqa
|
||||
from typing import Sequence, Tuple # noqa
|
||||
from .isa import TargetISA # noqa
|
||||
# A tuple uniquely identifying a register class inside a register bank.
|
||||
# (count, width, start)
|
||||
RCTup = Tuple[int, int, int]
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
@@ -90,6 +93,63 @@ class RegBank(object):
|
||||
return ('RegBank({}, units={}, first_unit={})'
|
||||
.format(self.name, self.units, self.first_unit))
|
||||
|
||||
def finish_regclasses(self, first_index):
|
||||
# type: (int) -> None
|
||||
"""
|
||||
Assign indexes to the register classes in this bank, starting from
|
||||
`first_index`.
|
||||
|
||||
Verify that the set of register classes satisfies:
|
||||
|
||||
1. Closed under intersection: The intersection of any two register
|
||||
classes in the set is either empty or identical to a member of the
|
||||
set.
|
||||
2. There are no identical classes under different names.
|
||||
3. Classes are sorted topologically such that all subclasses have a
|
||||
higher index that the superclass.
|
||||
|
||||
We could reorder classes topologically here instead of just enforcing
|
||||
the order, but the ordering tends to fall out naturally anyway.
|
||||
"""
|
||||
cmap = dict() # type: Dict[RCTup, RegClass]
|
||||
|
||||
for idx, rc in enumerate(self.classes):
|
||||
# All register classes must be given a name.
|
||||
assert rc.name, "Anonymous register class found"
|
||||
|
||||
# Assign a unique index.
|
||||
assert rc.index is None
|
||||
rc.index = idx + first_index
|
||||
|
||||
# Check for duplicates.
|
||||
tup = rc.rctup()
|
||||
if tup in cmap:
|
||||
raise AssertionError(
|
||||
'{} and {} are identical register classes'
|
||||
.format(rc, cmap[tup]))
|
||||
cmap[tup] = rc
|
||||
|
||||
# Check intersections and topological order.
|
||||
for idx, rc1 in enumerate(self.classes):
|
||||
for rc2 in self.classes[0:idx]:
|
||||
itup = rc1.intersect(rc2)
|
||||
if itup is None:
|
||||
continue
|
||||
if itup not in cmap:
|
||||
raise AssertionError(
|
||||
'intersection of {} and {} missing'
|
||||
.format(rc1, rc2))
|
||||
irc = cmap[itup]
|
||||
# rc1 > rc2, so rc2 can't be the sub-class.
|
||||
if irc is rc2:
|
||||
raise AssertionError(
|
||||
'Bad topological order: {}/{}'
|
||||
.format(rc1, rc2))
|
||||
if irc is rc1:
|
||||
# The intersection of rc1 and rc2 is rc1, so it must be a
|
||||
# sub-class.
|
||||
rc2.subclasses.append(rc1)
|
||||
|
||||
|
||||
class RegClass(object):
|
||||
"""
|
||||
@@ -111,10 +171,14 @@ class RegClass(object):
|
||||
def __init__(self, bank, count=None, width=1, start=0):
|
||||
# type: (RegBank, int, int, int) -> None
|
||||
self.name = None # type: str
|
||||
self.index = None # type: int
|
||||
self.bank = bank
|
||||
self.start = start
|
||||
self.width = width
|
||||
|
||||
# This is computed later in `finish_regclasses()`.
|
||||
self.subclasses = list() # type: List[RegClass]
|
||||
|
||||
assert width > 0
|
||||
assert start >= 0 and start < bank.units
|
||||
|
||||
@@ -127,13 +191,43 @@ class RegClass(object):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def rctup(self):
|
||||
# type: () -> RCTup
|
||||
"""
|
||||
Get a tuple that uniquely identifies the registers in this class.
|
||||
|
||||
The tuple can be used as a dictionary key to ensure that there are no
|
||||
duplicate register classes.
|
||||
"""
|
||||
return (self.count, self.width, self.start)
|
||||
|
||||
def intersect(self, other):
|
||||
# type: (RegClass) -> RCTup
|
||||
"""
|
||||
Get a tuple representing the intersction of two register classes.
|
||||
|
||||
Returns `None` if the two classes are disjoint.
|
||||
"""
|
||||
if self.width != other.width:
|
||||
return None
|
||||
s_end = self.start + self.count * self.width
|
||||
o_end = other.start + other.count * other.width
|
||||
if self.start >= o_end or other.start >= s_end:
|
||||
return None
|
||||
|
||||
# We have an overlap.
|
||||
start = max(self.start, other.start)
|
||||
end = min(s_end, o_end)
|
||||
count = (end - start) // self.width
|
||||
assert count > 0
|
||||
return (count, self.width, start)
|
||||
|
||||
def __getitem__(self, sliced):
|
||||
"""
|
||||
Create a sub-class of a register class using slice notation. The slice
|
||||
indexes refer to allocations in the parent register class, not register
|
||||
units.
|
||||
"""
|
||||
print(repr(sliced))
|
||||
assert isinstance(sliced, slice), "RegClass slicing can't be 1 reg"
|
||||
# We could add strided sub-classes if needed.
|
||||
assert sliced.step is None, 'Subclass striding not supported'
|
||||
@@ -167,6 +261,16 @@ class RegClass(object):
|
||||
|
||||
return mask
|
||||
|
||||
def subclass_mask(self):
|
||||
# type: () -> int
|
||||
"""
|
||||
Compute a bit-mask of subclasses, including self.
|
||||
"""
|
||||
m = 1 << self.index
|
||||
for rc in self.subclasses:
|
||||
m |= 1 << rc.index
|
||||
return m
|
||||
|
||||
@staticmethod
|
||||
def extract_names(globs):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user