Add a predicate_key() method to all predicates.
This enables interning of predicates to avoid duplicates. Add a predicate registry to TargetIsa for interning predicates per ISA.
This commit is contained in:
@@ -13,7 +13,7 @@ try:
|
|||||||
from typing import Tuple, Union, Any, Iterable, Sequence, List, Set, Dict, TYPE_CHECKING # noqa
|
from typing import Tuple, Union, Any, Iterable, Sequence, List, Set, Dict, TYPE_CHECKING # noqa
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .instructions import MaybeBoundInst, InstructionGroup, InstructionFormat # noqa
|
from .instructions import MaybeBoundInst, InstructionGroup, InstructionFormat # noqa
|
||||||
from .predicates import PredNode # noqa
|
from .predicates import PredNode, PredKey # noqa
|
||||||
from .settings import SettingGroup # noqa
|
from .settings import SettingGroup # noqa
|
||||||
from .registers import RegBank # noqa
|
from .registers import RegBank # noqa
|
||||||
from .xform import XFormGroup # noqa
|
from .xform import XFormGroup # noqa
|
||||||
@@ -50,6 +50,8 @@ class TargetISA(object):
|
|||||||
self.regbanks = list() # type: List[RegBank]
|
self.regbanks = list() # type: List[RegBank]
|
||||||
self.regclasses = list() # type: List[RegClass]
|
self.regclasses = list() # type: List[RegClass]
|
||||||
self.legalize_codes = OrderedDict() # type: OrderedDict[XFormGroup, int] # noqa
|
self.legalize_codes = OrderedDict() # type: OrderedDict[XFormGroup, int] # noqa
|
||||||
|
# Unique copies of all predicates.
|
||||||
|
self._predicates = dict() # type: Dict[PredKey, PredNode]
|
||||||
|
|
||||||
assert InstructionGroup._current is None,\
|
assert InstructionGroup._current is None,\
|
||||||
"InstructionGroup {} is still open!"\
|
"InstructionGroup {} is still open!"\
|
||||||
@@ -86,12 +88,15 @@ class TargetISA(object):
|
|||||||
for enc in cpumode.encodings:
|
for enc in cpumode.encodings:
|
||||||
recipe = enc.recipe
|
recipe = enc.recipe
|
||||||
if recipe not in rcps:
|
if recipe not in rcps:
|
||||||
|
assert recipe.number is None
|
||||||
recipe.number = len(rcps)
|
recipe.number = len(rcps)
|
||||||
rcps.add(recipe)
|
rcps.add(recipe)
|
||||||
self.all_recipes.append(recipe)
|
self.all_recipes.append(recipe)
|
||||||
# Make sure ISA predicates are registered.
|
# Make sure ISA predicates are registered.
|
||||||
if recipe.isap:
|
if recipe.isap:
|
||||||
|
recipe.isap = self.unique_pred(recipe.isap)
|
||||||
self.settings.number_predicate(recipe.isap)
|
self.settings.number_predicate(recipe.isap)
|
||||||
|
recipe.instp = self.unique_pred(recipe.instp)
|
||||||
|
|
||||||
def _collect_predicates(self):
|
def _collect_predicates(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
@@ -111,6 +116,7 @@ class TargetISA(object):
|
|||||||
instp = enc.instp
|
instp = enc.instp
|
||||||
if instp and instp not in instps:
|
if instp and instp not in instps:
|
||||||
# assign predicate number starting from 0.
|
# assign predicate number starting from 0.
|
||||||
|
assert instp.number is None
|
||||||
instp.number = len(instps)
|
instp.number = len(instps)
|
||||||
instps.add(instp)
|
instps.add(instp)
|
||||||
self.all_instps.append(instp)
|
self.all_instps.append(instp)
|
||||||
@@ -175,6 +181,21 @@ class TargetISA(object):
|
|||||||
self.legalize_codes[xgrp] = code
|
self.legalize_codes[xgrp] = code
|
||||||
return code
|
return code
|
||||||
|
|
||||||
|
def unique_pred(self, pred):
|
||||||
|
# type: (PredNode) -> PredNode
|
||||||
|
"""
|
||||||
|
Get a unique predicate that is equivalent to `pred`.
|
||||||
|
"""
|
||||||
|
if pred is None:
|
||||||
|
return pred
|
||||||
|
# TODO: We could actually perform some algebraic simplifications. It's
|
||||||
|
# not clear if it is worthwhile.
|
||||||
|
k = pred.predicate_key()
|
||||||
|
if k in self._predicates:
|
||||||
|
return self._predicates[k]
|
||||||
|
self._predicates[k] = pred
|
||||||
|
return pred
|
||||||
|
|
||||||
|
|
||||||
class CPUMode(object):
|
class CPUMode(object):
|
||||||
"""
|
"""
|
||||||
@@ -413,8 +434,8 @@ class Encoding(object):
|
|||||||
instp = And.combine(instp, typred)
|
instp = And.combine(instp, typred)
|
||||||
|
|
||||||
# Record specific predicates. Note that the recipe also has predicates.
|
# Record specific predicates. Note that the recipe also has predicates.
|
||||||
self.instp = instp
|
self.instp = self.cpumode.isa.unique_pred(instp)
|
||||||
self.isap = isap
|
self.isap = self.cpumode.isa.unique_pred(isap)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
# type: () -> str
|
# type: () -> str
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ try:
|
|||||||
InstructionContext]
|
InstructionContext]
|
||||||
PredLeaf = Union[BoolSetting, 'FieldPredicate', 'TypePredicate']
|
PredLeaf = Union[BoolSetting, 'FieldPredicate', 'TypePredicate']
|
||||||
PredNode = Union[PredLeaf, 'Predicate']
|
PredNode = Union[PredLeaf, 'Predicate']
|
||||||
|
# A predicate key is a (recursive) tuple of primitive types that
|
||||||
|
# uniquely describes a predicate. It is used for interning.
|
||||||
|
PredKey = Tuple[Any, ...]
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -84,6 +87,7 @@ class Predicate(object):
|
|||||||
_descendant,
|
_descendant,
|
||||||
(p.predicate_context() for p in parts))
|
(p.predicate_context() for p in parts))
|
||||||
assert self.context, "Incompatible predicate parts"
|
assert self.context, "Incompatible predicate parts"
|
||||||
|
self.predkey = None # type: PredKey
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
# type: () -> str
|
# type: () -> str
|
||||||
@@ -110,6 +114,14 @@ class Predicate(object):
|
|||||||
# type: (int) -> str
|
# type: (int) -> str
|
||||||
raise NotImplementedError("rust_predicate is an abstract method")
|
raise NotImplementedError("rust_predicate is an abstract method")
|
||||||
|
|
||||||
|
def predicate_key(self):
|
||||||
|
# type: () -> PredKey
|
||||||
|
"""Tuple uniquely identifying a predicate."""
|
||||||
|
if not self.predkey:
|
||||||
|
p = tuple(p.predicate_key() for p in self.parts) # type: PredKey
|
||||||
|
self.predkey = (type(self).__name__,) + p
|
||||||
|
return self.predkey
|
||||||
|
|
||||||
|
|
||||||
class And(Predicate):
|
class And(Predicate):
|
||||||
"""
|
"""
|
||||||
@@ -224,6 +236,11 @@ class FieldPredicate(object):
|
|||||||
iform = self.field.format # type: InstructionFormat
|
iform = self.field.format # type: InstructionFormat
|
||||||
return iform
|
return iform
|
||||||
|
|
||||||
|
def predicate_key(self):
|
||||||
|
# type: () -> PredKey
|
||||||
|
a = tuple(map(str, self.args))
|
||||||
|
return (self.function, str(self.field)) + a
|
||||||
|
|
||||||
def predicate_leafs(self, leafs):
|
def predicate_leafs(self, leafs):
|
||||||
# type: (Set[PredLeaf]) -> None
|
# type: (Set[PredLeaf]) -> None
|
||||||
leafs.add(self)
|
leafs.add(self)
|
||||||
@@ -332,6 +349,10 @@ class TypePredicate(object):
|
|||||||
# type: () -> PredContext
|
# type: () -> PredContext
|
||||||
return instruction_context
|
return instruction_context
|
||||||
|
|
||||||
|
def predicate_key(self):
|
||||||
|
# type: () -> PredKey
|
||||||
|
return ('typecheck', self.value_arg, self.value_type.name)
|
||||||
|
|
||||||
def predicate_leafs(self, leafs):
|
def predicate_leafs(self, leafs):
|
||||||
# type: (Set[PredLeaf]) -> None
|
# type: (Set[PredLeaf]) -> None
|
||||||
leafs.add(self)
|
leafs.add(self)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ try:
|
|||||||
from typing import Tuple, Set, List, Dict, Any, Union, TYPE_CHECKING # noqa
|
from typing import Tuple, Set, List, Dict, Any, Union, TYPE_CHECKING # noqa
|
||||||
BoolOrPresetOrDict = Union['BoolSetting', 'Preset', Dict['Setting', Any]]
|
BoolOrPresetOrDict = Union['BoolSetting', 'Preset', Dict['Setting', Any]]
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .predicates import PredLeaf, PredNode # noqa
|
from .predicates import PredLeaf, PredNode, PredKey # noqa
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -36,14 +36,6 @@ class Setting(object):
|
|||||||
# type: () -> str
|
# type: () -> str
|
||||||
return '{}.{}'.format(self.group.name, self.name)
|
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 default_byte(self):
|
def default_byte(self):
|
||||||
# type: () -> int
|
# type: () -> int
|
||||||
raise NotImplementedError("default_byte is an abstract method")
|
raise NotImplementedError("default_byte is an abstract method")
|
||||||
@@ -96,6 +88,19 @@ class BoolSetting(Setting):
|
|||||||
# type: () -> int
|
# type: () -> int
|
||||||
return 1 << self.bit_offset
|
return 1 << self.bit_offset
|
||||||
|
|
||||||
|
def predicate_context(self):
|
||||||
|
# type: () -> SettingGroup
|
||||||
|
"""
|
||||||
|
Return the context where this setting can be evaluated as a (leaf)
|
||||||
|
predicate.
|
||||||
|
"""
|
||||||
|
return self.group
|
||||||
|
|
||||||
|
def predicate_key(self):
|
||||||
|
# type: () -> PredKey
|
||||||
|
assert self.name, "Can't compute key before setting is named"
|
||||||
|
return ('setting', self.group.name, self.name)
|
||||||
|
|
||||||
def predicate_leafs(self, leafs):
|
def predicate_leafs(self, leafs):
|
||||||
# type: (Set[PredLeaf]) -> None
|
# type: (Set[PredLeaf]) -> None
|
||||||
leafs.add(self)
|
leafs.add(self)
|
||||||
|
|||||||
Reference in New Issue
Block a user