From 9ff785fabc1ec9edc956f071fc53a50f332d051f Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Wed, 26 Jul 2017 09:30:29 -0700 Subject: [PATCH] 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. --- lib/cretonne/meta/cdsl/isa.py | 27 ++++++++++++++++++++++++--- lib/cretonne/meta/cdsl/predicates.py | 21 +++++++++++++++++++++ lib/cretonne/meta/cdsl/settings.py | 23 ++++++++++++++--------- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/lib/cretonne/meta/cdsl/isa.py b/lib/cretonne/meta/cdsl/isa.py index 563cf91e92..cdb1923a05 100644 --- a/lib/cretonne/meta/cdsl/isa.py +++ b/lib/cretonne/meta/cdsl/isa.py @@ -13,7 +13,7 @@ try: from typing import Tuple, Union, Any, Iterable, Sequence, List, Set, Dict, TYPE_CHECKING # noqa if TYPE_CHECKING: from .instructions import MaybeBoundInst, InstructionGroup, InstructionFormat # noqa - from .predicates import PredNode # noqa + from .predicates import PredNode, PredKey # noqa from .settings import SettingGroup # noqa from .registers import RegBank # noqa from .xform import XFormGroup # noqa @@ -50,6 +50,8 @@ class TargetISA(object): self.regbanks = list() # type: List[RegBank] self.regclasses = list() # type: List[RegClass] 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,\ "InstructionGroup {} is still open!"\ @@ -86,12 +88,15 @@ class TargetISA(object): for enc in cpumode.encodings: recipe = enc.recipe if recipe not in rcps: + assert recipe.number is None recipe.number = len(rcps) rcps.add(recipe) self.all_recipes.append(recipe) # Make sure ISA predicates are registered. if recipe.isap: + recipe.isap = self.unique_pred(recipe.isap) self.settings.number_predicate(recipe.isap) + recipe.instp = self.unique_pred(recipe.instp) def _collect_predicates(self): # type: () -> None @@ -111,6 +116,7 @@ class TargetISA(object): instp = enc.instp if instp and instp not in instps: # assign predicate number starting from 0. + assert instp.number is None instp.number = len(instps) instps.add(instp) self.all_instps.append(instp) @@ -175,6 +181,21 @@ class TargetISA(object): self.legalize_codes[xgrp] = 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): """ @@ -413,8 +434,8 @@ class Encoding(object): instp = And.combine(instp, typred) # Record specific predicates. Note that the recipe also has predicates. - self.instp = instp - self.isap = isap + self.instp = self.cpumode.isa.unique_pred(instp) + self.isap = self.cpumode.isa.unique_pred(isap) def __str__(self): # type: () -> str diff --git a/lib/cretonne/meta/cdsl/predicates.py b/lib/cretonne/meta/cdsl/predicates.py index 62779c2d15..ca5d87aa9a 100644 --- a/lib/cretonne/meta/cdsl/predicates.py +++ b/lib/cretonne/meta/cdsl/predicates.py @@ -37,6 +37,9 @@ try: InstructionContext] PredLeaf = Union[BoolSetting, 'FieldPredicate', 'TypePredicate'] 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: pass @@ -84,6 +87,7 @@ class Predicate(object): _descendant, (p.predicate_context() for p in parts)) assert self.context, "Incompatible predicate parts" + self.predkey = None # type: PredKey def __str__(self): # type: () -> str @@ -110,6 +114,14 @@ class Predicate(object): # type: (int) -> str 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): """ @@ -224,6 +236,11 @@ class FieldPredicate(object): iform = self.field.format # type: InstructionFormat 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): # type: (Set[PredLeaf]) -> None leafs.add(self) @@ -332,6 +349,10 @@ class TypePredicate(object): # type: () -> PredContext return instruction_context + def predicate_key(self): + # type: () -> PredKey + return ('typecheck', self.value_arg, self.value_type.name) + def predicate_leafs(self, leafs): # type: (Set[PredLeaf]) -> None leafs.add(self) diff --git a/lib/cretonne/meta/cdsl/settings.py b/lib/cretonne/meta/cdsl/settings.py index aca3ac296f..bf3d37dc00 100644 --- a/lib/cretonne/meta/cdsl/settings.py +++ b/lib/cretonne/meta/cdsl/settings.py @@ -7,7 +7,7 @@ try: from typing import Tuple, Set, List, Dict, Any, Union, TYPE_CHECKING # noqa BoolOrPresetOrDict = Union['BoolSetting', 'Preset', Dict['Setting', Any]] if TYPE_CHECKING: - from .predicates import PredLeaf, PredNode # noqa + from .predicates import PredLeaf, PredNode, PredKey # noqa except ImportError: pass @@ -36,14 +36,6 @@ class Setting(object): # 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 default_byte(self): # type: () -> int raise NotImplementedError("default_byte is an abstract method") @@ -96,6 +88,19 @@ class BoolSetting(Setting): # type: () -> int 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): # type: (Set[PredLeaf]) -> None leafs.add(self)