Add mypy annotations to cdsl.predicates, settings.

Wherein we learned that only BoolSettings can be used as predicates.
This commit is contained in:
Jakob Stoklund Olesen
2017-03-30 14:11:19 -07:00
parent d2eb745265
commit ae12c94d04
3 changed files with 77 additions and 16 deletions

View File

@@ -8,11 +8,10 @@ from .registers import RegClass, Register
try: try:
from typing import Tuple, Union, Any, Iterable, Sequence, List, Set, TYPE_CHECKING # noqa from typing import Tuple, Union, Any, Iterable, Sequence, List, Set, TYPE_CHECKING # noqa
from .instructions import MaybeBoundInst, InstructionGroup, InstructionFormat # noqa from .instructions import MaybeBoundInst, InstructionGroup, InstructionFormat # noqa
from .predicates import Predicate, FieldPredicate # noqa from .predicates import PredNode # noqa
from .settings import SettingGroup # noqa from .settings import SettingGroup # noqa
from .types import ValueType # noqa from .types import ValueType # noqa
from .registers import RegBank # noqa from .registers import RegBank # noqa
AnyPredicate = Union[Predicate, FieldPredicate]
OperandConstraint = Union[RegClass, Register, int] OperandConstraint = Union[RegClass, Register, int]
ConstraintSeq = Union[OperandConstraint, Tuple[OperandConstraint, ...]] ConstraintSeq = Union[OperandConstraint, Tuple[OperandConstraint, ...]]
except ImportError: except ImportError:
@@ -80,8 +79,8 @@ class TargetISA(object):
Ensures that all ISA predicates have an assigned bit number in Ensures that all ISA predicates have an assigned bit number in
`self.settings`. `self.settings`.
""" """
self.all_instps = list() # type: List[AnyPredicate] self.all_instps = list() # type: List[PredNode]
instps = set() # type: Set[AnyPredicate] instps = set() # type: Set[PredNode]
for cpumode in self.cpumodes: for cpumode in self.cpumodes:
for enc in cpumode.encodings: for enc in cpumode.encodings:
instp = enc.instp instp = enc.instp
@@ -166,7 +165,7 @@ class EncRecipe(object):
""" """
def __init__(self, name, format, ins, outs, instp=None, isap=None): def __init__(self, name, format, ins, outs, instp=None, isap=None):
# type: (str, InstructionFormat, ConstraintSeq, ConstraintSeq, AnyPredicate, AnyPredicate) -> None # noqa # type: (str, InstructionFormat, ConstraintSeq, ConstraintSeq, PredNode, PredNode) -> None # noqa
self.name = name self.name = name
self.format = format self.format = format
self.instp = instp self.instp = instp
@@ -219,7 +218,7 @@ class Encoding(object):
""" """
def __init__(self, cpumode, inst, recipe, encbits, instp=None, isap=None): def __init__(self, cpumode, inst, recipe, encbits, instp=None, isap=None):
# type: (CPUMode, MaybeBoundInst, EncRecipe, int, AnyPredicate, AnyPredicate) -> None # noqa # type: (CPUMode, MaybeBoundInst, EncRecipe, int, PredNode, PredNode) -> None # noqa
assert isinstance(cpumode, CPUMode) assert isinstance(cpumode, CPUMode)
assert isinstance(recipe, EncRecipe) assert isinstance(recipe, EncRecipe)
self.inst, self.typevars = inst.fully_bound() self.inst, self.typevars = inst.fully_bound()

View File

@@ -10,7 +10,7 @@ function determine the kind of predicate:
- An *Instruction predicate* is evaluated on an instruction instance, so it can - An *Instruction predicate* is evaluated on an instruction instance, so it can
inspect all the immediate fields and type variables of the instruction. inspect all the immediate fields and type variables of the instruction.
Instruction predicates can be evaluatd before register allocation, so they Instruction predicates can be evaluated before register allocation, so they
can not depend on specific register assignments to the value operands or can not depend on specific register assignments to the value operands or
outputs. outputs.
@@ -24,6 +24,17 @@ predicate, the context is the instruction format.
from __future__ import absolute_import from __future__ import absolute_import
from functools import reduce from functools import reduce
try:
from typing import Sequence, Tuple, Set, Any, Union, TYPE_CHECKING # noqa
if TYPE_CHECKING:
from .formats import InstructionFormat, FormatField # noqa
from .settings import BoolSetting, SettingGroup # noqa
PredContext = Union[SettingGroup, InstructionFormat]
PredLeaf = Union[BoolSetting, 'FieldPredicate']
PredNode = Union[PredLeaf, 'Predicate']
except ImportError:
pass
def _is_parent(a, b): def _is_parent(a, b):
""" """
@@ -58,7 +69,9 @@ class Predicate(object):
""" """
def __init__(self, parts): def __init__(self, parts):
self.name = None # type: (Sequence[PredNode]) -> None
self.name = None # type: str
self.number = None # type: int
self.parts = parts self.parts = parts
self.context = reduce( self.context = reduce(
_descendant, _descendant,
@@ -66,6 +79,7 @@ class Predicate(object):
assert self.context, "Incompatible predicate parts" assert self.context, "Incompatible predicate parts"
def __str__(self): def __str__(self):
# type: () -> str
if self.name: if self.name:
return '{}.{}'.format(self.context.name, self.name) return '{}.{}'.format(self.context.name, self.name)
else: else:
@@ -74,15 +88,21 @@ class Predicate(object):
', '.join(map(str, self.parts))) ', '.join(map(str, self.parts)))
def predicate_context(self): def predicate_context(self):
# type: () -> PredContext
return self.context return self.context
def predicate_leafs(self, leafs): def predicate_leafs(self, leafs):
# type: (Set[PredLeaf]) -> None
""" """
Collect all leaf predicates into the `leafs` set. Collect all leaf predicates into the `leafs` set.
""" """
for part in self.parts: for part in self.parts:
part.predicate_leafs(leafs) part.predicate_leafs(leafs)
def rust_predicate(self, prec):
# type: (int) -> str
raise NotImplementedError("rust_predicate is an abstract method")
class And(Predicate): class And(Predicate):
""" """
@@ -92,9 +112,11 @@ class And(Predicate):
precedence = 2 precedence = 2
def __init__(self, *args): def __init__(self, *args):
# type: (*PredNode) -> None
super(And, self).__init__(args) super(And, self).__init__(args)
def rust_predicate(self, prec): def rust_predicate(self, prec):
# type: (int) -> str
""" """
Return a Rust expression computing the value of this predicate. Return a Rust expression computing the value of this predicate.
@@ -112,6 +134,7 @@ class And(Predicate):
@staticmethod @staticmethod
def combine(*args): def combine(*args):
# type: (*PredNode) -> PredNode
""" """
Combine a sequence of predicates, allowing for `None` members. Combine a sequence of predicates, allowing for `None` members.
@@ -135,9 +158,11 @@ class Or(Predicate):
precedence = 1 precedence = 1
def __init__(self, *args): def __init__(self, *args):
# type: (*PredNode) -> None
super(Or, self).__init__(args) super(Or, self).__init__(args)
def rust_predicate(self, prec): def rust_predicate(self, prec):
# type: (int) -> str
s = ' || '.join(p.rust_predicate(Or.precedence) for p in self.parts) s = ' || '.join(p.rust_predicate(Or.precedence) for p in self.parts)
if prec > Or.precedence: if prec > Or.precedence:
s = '({})'.format(s) s = '({})'.format(s)
@@ -152,9 +177,11 @@ class Not(Predicate):
precedence = 3 precedence = 3
def __init__(self, part): def __init__(self, part):
# type: (PredNode) -> None
super(Not, self).__init__((part,)) super(Not, self).__init__((part,))
def rust_predicate(self, prec): def rust_predicate(self, prec):
# type: (int) -> str
return '!' + self.parts[0].rust_predicate(Not.precedence) return '!' + self.parts[0].rust_predicate(Not.precedence)
@@ -168,15 +195,19 @@ class FieldPredicate(object):
""" """
def __init__(self, field, function, args): def __init__(self, field, function, args):
# type: (FormatField, str, Sequence[Any]) -> None
self.number = None # type: int
self.field = field self.field = field
self.function = function self.function = function
self.args = args self.args = args
def __str__(self): def __str__(self):
# type: () -> str
args = (self.field.name,) + tuple(map(str, self.args)) args = (self.field.name,) + tuple(map(str, self.args))
return '{}({})'.format(self.function, ', '.join(args)) return '{}({})'.format(self.function, ', '.join(args))
def predicate_context(self): def predicate_context(self):
# type: () -> PredContext
""" """
This predicate can be evaluated in the context of an instruction This predicate can be evaluated in the context of an instruction
format. format.
@@ -184,9 +215,11 @@ class FieldPredicate(object):
return self.field.format return self.field.format
def predicate_leafs(self, leafs): def predicate_leafs(self, leafs):
# type: (Set[PredLeaf]) -> None
leafs.add(self) leafs.add(self)
def rust_predicate(self, prec): def rust_predicate(self, prec):
# type: (int) -> str
""" """
Return a string of Rust code that evaluates this predicate. Return a string of Rust code that evaluates this predicate.
""" """
@@ -210,6 +243,7 @@ class IsSignedInt(FieldPredicate):
""" """
def __init__(self, field, width, scale=0): def __init__(self, field, width, scale=0):
# type: (FormatField, int, int) -> None
super(IsSignedInt, self).__init__( super(IsSignedInt, self).__init__(
field, 'is_signed_int', (width, scale)) field, 'is_signed_int', (width, scale))
self.width = width self.width = width
@@ -232,6 +266,7 @@ class IsUnsignedInt(FieldPredicate):
""" """
def __init__(self, field, width, scale=0): def __init__(self, field, width, scale=0):
# type: (FormatField, int, int) -> None
super(IsUnsignedInt, self).__init__( super(IsUnsignedInt, self).__init__(
field, 'is_unsigned_int', (width, scale)) field, 'is_unsigned_int', (width, scale))
self.width = width self.width = width

View File

@@ -3,6 +3,13 @@ from __future__ import absolute_import
from collections import OrderedDict from collections import OrderedDict
from .predicates import Predicate from .predicates import Predicate
try:
from typing import Set, List, Dict, Any, TYPE_CHECKING # noqa
if TYPE_CHECKING:
from .predicates import PredLeaf, PredNode # noqa
except ImportError:
pass
class Setting(object): class Setting(object):
""" """
@@ -13,25 +20,26 @@ class Setting(object):
""" """
def __init__(self, doc): def __init__(self, doc):
self.name = None # Assigned later by `extract_names()`. # type: (str) -> None
self.name = None # type: str # Assigned later by `extract_names()`.
self.number = None # type: int
self.__doc__ = doc self.__doc__ = doc
# Offset of byte in settings vector containing this setting. # Offset of byte in settings vector containing this setting.
self.byte_offset = None self.byte_offset = None # type: int
self.group = SettingGroup.append(self) self.group = SettingGroup.append(self)
def __str__(self): def __str__(self):
# type: () -> str
return '{}.{}'.format(self.group.name, self.name) return '{}.{}'.format(self.group.name, self.name)
def predicate_context(self): def predicate_context(self):
# type: () -> SettingGroup
""" """
Return the context where this setting can be evaluated as a (leaf) Return the context where this setting can be evaluated as a (leaf)
predicate. predicate.
""" """
return self.group return self.group
def predicate_leafs(self, leafs):
leafs.add(self)
class BoolSetting(Setting): class BoolSetting(Setting):
""" """
@@ -42,10 +50,13 @@ class BoolSetting(Setting):
""" """
def __init__(self, doc, default=False): def __init__(self, doc, default=False):
# type: (str, bool) -> None
super(BoolSetting, self).__init__(doc) super(BoolSetting, self).__init__(doc)
self.default = default self.default = default
self.bit_offset = None # type: int
def default_byte(self): def default_byte(self):
# type: () -> int
""" """
Get the default value of this setting, as a byte that can be bitwise Get the default value of this setting, as a byte that can be bitwise
or'ed with the other booleans sharing the same byte. or'ed with the other booleans sharing the same byte.
@@ -55,7 +66,12 @@ class BoolSetting(Setting):
else: else:
return 0 return 0
def predicate_leafs(self, leafs):
# type: (Set[PredLeaf]) -> None
leafs.add(self)
def rust_predicate(self, prec): def rust_predicate(self, prec):
# type: (int) -> str
""" """
Return the Rust code to compute the value of this setting. Return the Rust code to compute the value of this setting.
@@ -74,12 +90,14 @@ class NumSetting(Setting):
""" """
def __init__(self, doc, default=0): def __init__(self, doc, default=0):
# type: (str, int) -> None
super(NumSetting, self).__init__(doc) super(NumSetting, self).__init__(doc)
assert default == int(default) assert default == int(default)
assert default >= 0 and default <= 255 assert default >= 0 and default <= 255
self.default = default self.default = default
def default_byte(self): def default_byte(self):
# type: () -> int
return self.default return self.default
@@ -94,12 +112,14 @@ class EnumSetting(Setting):
""" """
def __init__(self, doc, *args): def __init__(self, doc, *args):
# type: (str, *str) -> None
super(EnumSetting, self).__init__(doc) super(EnumSetting, self).__init__(doc)
assert len(args) > 0, "EnumSetting must have at least one value" assert len(args) > 0, "EnumSetting must have at least one value"
self.values = tuple(str(x) for x in args) self.values = tuple(str(x) for x in args)
self.default = self.values[0] self.default = self.values[0]
def default_byte(self): def default_byte(self):
# type: () -> int
return 0 return 0
@@ -119,23 +139,25 @@ class SettingGroup(object):
_current = None # type: SettingGroup _current = None # type: SettingGroup
def __init__(self, name, parent=None): def __init__(self, name, parent=None):
# type: (str, SettingGroup) -> None
self.name = name self.name = name
self.parent = parent self.parent = parent
self.settings = [] self.settings = [] # type: List[Setting]
# Named predicates computed from settings in this group or its # Named predicates computed from settings in this group or its
# parents. # parents.
self.named_predicates = [] self.named_predicates = [] # type: List[Predicate]
# All boolean predicates that can be accessed by number. This includes: # All boolean predicates that can be accessed by number. This includes:
# - All boolean settings in this group. # - All boolean settings in this group.
# - All named predicates. # - All named predicates.
# - Added anonymous predicates, see `number_predicate()`. # - Added anonymous predicates, see `number_predicate()`.
# - Added parent predicates that are replicated in this group. # - Added parent predicates that are replicated in this group.
# Maps predicate -> number. # Maps predicate -> number.
self.predicate_number = OrderedDict() self.predicate_number = OrderedDict() # type: OrderedDict[PredNode, int] # noqa
self.open() self.open()
def open(self): def open(self):
# type: () -> None
""" """
Open this setting group such that future new settings are added to this Open this setting group such that future new settings are added to this
group. group.
@@ -146,6 +168,7 @@ class SettingGroup(object):
SettingGroup._current = self SettingGroup._current = self
def close(self, globs=None): def close(self, globs=None):
# type: (Dict[str, Any]) -> None
""" """
Close this setting group. This function must be called before opening Close this setting group. This function must be called before opening
another setting group. another setting group.
@@ -170,12 +193,14 @@ class SettingGroup(object):
@staticmethod @staticmethod
def append(setting): def append(setting):
# type: (Setting) -> SettingGroup
g = SettingGroup._current g = SettingGroup._current
assert g, "Open a setting group before defining settings." assert g, "Open a setting group before defining settings."
g.settings.append(setting) g.settings.append(setting)
return g return g
def number_predicate(self, pred): def number_predicate(self, pred):
# type: (PredNode) -> int
""" """
Make sure that `pred` has an assigned number, and will be included in Make sure that `pred` has an assigned number, and will be included in
this group's bit vector. this group's bit vector.
@@ -200,6 +225,7 @@ class SettingGroup(object):
return number return number
def layout(self): def layout(self):
# type: () -> None
""" """
Compute the layout of the byte vector used to represent this settings Compute the layout of the byte vector used to represent this settings
group. group.
@@ -250,6 +276,7 @@ class SettingGroup(object):
self.number_predicate(p) self.number_predicate(p)
def byte_size(self): def byte_size(self):
# type: () -> int
""" """
Compute the number of bytes required to hold all settings and Compute the number of bytes required to hold all settings and
precomputed predicates. precomputed predicates.