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:
from typing import Tuple, Union, Any, Iterable, Sequence, List, Set, TYPE_CHECKING # 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 .types import ValueType # noqa
from .registers import RegBank # noqa
AnyPredicate = Union[Predicate, FieldPredicate]
OperandConstraint = Union[RegClass, Register, int]
ConstraintSeq = Union[OperandConstraint, Tuple[OperandConstraint, ...]]
except ImportError:
@@ -80,8 +79,8 @@ class TargetISA(object):
Ensures that all ISA predicates have an assigned bit number in
`self.settings`.
"""
self.all_instps = list() # type: List[AnyPredicate]
instps = set() # type: Set[AnyPredicate]
self.all_instps = list() # type: List[PredNode]
instps = set() # type: Set[PredNode]
for cpumode in self.cpumodes:
for enc in cpumode.encodings:
instp = enc.instp
@@ -166,7 +165,7 @@ class EncRecipe(object):
"""
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.format = format
self.instp = instp
@@ -219,7 +218,7 @@ class Encoding(object):
"""
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(recipe, EncRecipe)
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
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
outputs.
@@ -24,6 +24,17 @@ predicate, the context is the instruction format.
from __future__ import absolute_import
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):
"""
@@ -58,7 +69,9 @@ class Predicate(object):
"""
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.context = reduce(
_descendant,
@@ -66,6 +79,7 @@ class Predicate(object):
assert self.context, "Incompatible predicate parts"
def __str__(self):
# type: () -> str
if self.name:
return '{}.{}'.format(self.context.name, self.name)
else:
@@ -74,15 +88,21 @@ class Predicate(object):
', '.join(map(str, self.parts)))
def predicate_context(self):
# type: () -> PredContext
return self.context
def predicate_leafs(self, leafs):
# type: (Set[PredLeaf]) -> None
"""
Collect all leaf predicates into the `leafs` set.
"""
for part in self.parts:
part.predicate_leafs(leafs)
def rust_predicate(self, prec):
# type: (int) -> str
raise NotImplementedError("rust_predicate is an abstract method")
class And(Predicate):
"""
@@ -92,9 +112,11 @@ class And(Predicate):
precedence = 2
def __init__(self, *args):
# type: (*PredNode) -> None
super(And, self).__init__(args)
def rust_predicate(self, prec):
# type: (int) -> str
"""
Return a Rust expression computing the value of this predicate.
@@ -112,6 +134,7 @@ class And(Predicate):
@staticmethod
def combine(*args):
# type: (*PredNode) -> PredNode
"""
Combine a sequence of predicates, allowing for `None` members.
@@ -135,9 +158,11 @@ class Or(Predicate):
precedence = 1
def __init__(self, *args):
# type: (*PredNode) -> None
super(Or, self).__init__(args)
def rust_predicate(self, prec):
# type: (int) -> str
s = ' || '.join(p.rust_predicate(Or.precedence) for p in self.parts)
if prec > Or.precedence:
s = '({})'.format(s)
@@ -152,9 +177,11 @@ class Not(Predicate):
precedence = 3
def __init__(self, part):
# type: (PredNode) -> None
super(Not, self).__init__((part,))
def rust_predicate(self, prec):
# type: (int) -> str
return '!' + self.parts[0].rust_predicate(Not.precedence)
@@ -168,15 +195,19 @@ class FieldPredicate(object):
"""
def __init__(self, field, function, args):
# type: (FormatField, str, Sequence[Any]) -> None
self.number = None # type: int
self.field = field
self.function = function
self.args = args
def __str__(self):
# type: () -> str
args = (self.field.name,) + tuple(map(str, self.args))
return '{}({})'.format(self.function, ', '.join(args))
def predicate_context(self):
# type: () -> PredContext
"""
This predicate can be evaluated in the context of an instruction
format.
@@ -184,9 +215,11 @@ class FieldPredicate(object):
return self.field.format
def predicate_leafs(self, leafs):
# type: (Set[PredLeaf]) -> None
leafs.add(self)
def rust_predicate(self, prec):
# type: (int) -> str
"""
Return a string of Rust code that evaluates this predicate.
"""
@@ -210,6 +243,7 @@ class IsSignedInt(FieldPredicate):
"""
def __init__(self, field, width, scale=0):
# type: (FormatField, int, int) -> None
super(IsSignedInt, self).__init__(
field, 'is_signed_int', (width, scale))
self.width = width
@@ -232,6 +266,7 @@ class IsUnsignedInt(FieldPredicate):
"""
def __init__(self, field, width, scale=0):
# type: (FormatField, int, int) -> None
super(IsUnsignedInt, self).__init__(
field, 'is_unsigned_int', (width, scale))
self.width = width

View File

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