From 8457f67e34e2a8b27c7aa6c49a366b8f79c98c47 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Thu, 11 Aug 2016 14:22:23 -0700 Subject: [PATCH] Introduce predicates. Predcates are boolean functions. There will be ISA predicates and instruction predicates. The ISA predicates will be turned into member functions on the generated Flags structs. --- meta/cretonne/__init__.py | 37 +++++++++------ meta/cretonne/predicates.py | 94 +++++++++++++++++++++++++++++++++++++ meta/isa/riscv/settings.py | 6 ++- 3 files changed, 121 insertions(+), 16 deletions(-) create mode 100644 meta/cretonne/predicates.py diff --git a/meta/cretonne/__init__.py b/meta/cretonne/__init__.py index 801ac5a171..f576380f65 100644 --- a/meta/cretonne/__init__.py +++ b/meta/cretonne/__init__.py @@ -31,19 +31,14 @@ class Setting(object): self.__doc__ = doc # Offset of byte in settings vector containing this setting. self.byte_offset = None - SettingGroup.append(self) + self.group = SettingGroup.append(self) - @staticmethod - def extract_names(globs): + def predicate_context(self): """ - Given a dict mapping name -> object as returned by `globals()`, find - all the Setting objects and set their name from the dict key. This is - used to name a bunch of global variables in a module. + Return the context where this setting can be evaluated as a (leaf) + predicate. """ - for name, obj in globs.iteritems(): - if isinstance(obj, Setting): - assert obj.name is None - obj.name = name + return self.group class BoolSetting(Setting): @@ -116,14 +111,17 @@ class SettingGroup(object): opened. :param name: Short mnemonic name for setting group. + :param parent: Parent settings group. """ # The currently open setting group. _current = None - def __init__(self, name): + def __init__(self, name, parent=None): self.name = name + self.parent = parent self.settings = [] + self.predicates = [] self.open() def open(self): @@ -149,13 +147,22 @@ class SettingGroup(object): .format(self, SettingGroup._current)) SettingGroup._current = None if globs: - Setting.extract_names(globs) + from predicates import Predicate + for name, obj in globs.iteritems(): + if isinstance(obj, Setting): + assert obj.name is None, obj.name + obj.name = name + if isinstance(obj, Predicate): + assert obj.name is None + obj.name = name + self.predicates.append(obj) @staticmethod def append(setting): - assert SettingGroup._current, \ - "Open a setting group before defining settings." - SettingGroup._current.settings.append(setting) + g = SettingGroup._current + assert g, "Open a setting group before defining settings." + g.settings.append(setting) + return g # Kinds of operands. diff --git a/meta/cretonne/predicates.py b/meta/cretonne/predicates.py new file mode 100644 index 0000000000..2c34e489e5 --- /dev/null +++ b/meta/cretonne/predicates.py @@ -0,0 +1,94 @@ +""" +Cretonne predicates. + +A *predicate* is a function that computes a boolean result. The inputs to the +function determine the kind of predicate: + +- An *ISA predicate* is evaluated on the current ISA settings together with the + shared settings defined in the :py:mod:`settings` module. Once a target ISA + has been configured, the value of all ISA predicates is known. + +- 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 + can not depend on specific register assignments to the value operands or + outputs. + +Predicates can also be computed from other predicates using the `And`, `Or`, +and `Not` combinators defined in this module. + +All predicates have a *context* which determines where they can be evaluated. +For an ISA predicate, the context is the ISA settings group. For an instruction +predicate, the context is the instruction format. +""" + + +def _is_parent(a, b): + """ + Return true if a is a parent of b, or equal to it. + """ + while b and a is not b: + b = getattr(b, 'parent', None) + return a is b + + +def _descendant(a, b): + """ + If a is a parent of b or b is a parent of a, return the descendant of the + two. + + If neiher is a parent of the other, return None. + """ + if _is_parent(a, b): + return b + if _is_parent(b, a): + return a + return None + + +class Predicate(object): + """ + Superclass for all computed predicates. + + Leaf predicates can have other types, such as `Setting`. + + :param parts: Tuple of components in the predicate expression. + """ + + def __init__(self, parts): + self.name = None + self.parts = parts + self.context = reduce( + _descendant, + (p.predicate_context() for p in parts)) + assert self.context, "Incompatible predicate parts" + + def predicate_context(self): + return self.context + + +class And(Predicate): + """ + Computed predicate that is true if all parts are true. + """ + + def __init__(self, *args): + super(And, self).__init__(args) + + +class Or(Predicate): + """ + Computed predicate that is true if any parts are true. + """ + + def __init__(self, *args): + super(Or, self).__init__(args) + + +class Not(Predicate): + """ + Computed predicate that is true if its single part is false. + """ + + def __init__(self, part): + super(Not, self).__init__((part,)) diff --git a/meta/isa/riscv/settings.py b/meta/isa/riscv/settings.py index d2366ad829..ade60372d6 100644 --- a/meta/isa/riscv/settings.py +++ b/meta/isa/riscv/settings.py @@ -3,13 +3,17 @@ RISC-V settings. """ from cretonne import SettingGroup, BoolSetting +from cretonne.predicates import And +import cretonne.settings as shared from defs import isa -isa.settings = SettingGroup('riscv') +isa.settings = SettingGroup('riscv', parent=shared.group) supports_m = BoolSetting("CPU supports the 'M' extension (mul/div)") supports_a = BoolSetting("CPU supports the 'A' extension (atomics)") supports_f = BoolSetting("CPU supports the 'F' extension (float)") supports_d = BoolSetting("CPU supports the 'D' extension (double)") +full_float = And(shared.enable_simd, supports_f, supports_d) + isa.settings.close(globals())