diff --git a/pymbolic/imperative/instruction.py b/pymbolic/imperative/instruction.py index b1332a168e18ef17aa16dea6e92252748ee758dd..e6fba64702dc0601062061d1f4e1008f9efd00f8 100644 --- a/pymbolic/imperative/instruction.py +++ b/pymbolic/imperative/instruction.py @@ -22,195 +22,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ +from warnings import warn -import six -from pytools import RecordWithoutPickling +warn("pymbolic.imperative.instruction was imported. This has been renamed " + "to pymbolic.imperative.statement", DeprecationWarning, stacklevel=1) - -# {{{ instruction classes - -class Instruction(RecordWithoutPickling): - """ - .. attribute:: depends_on - - A :class:`frozenset` of instruction ids that are reuqired to be - executed within this execution context before this instruction can be - executed. - - .. attribute:: id - - A string, a unique identifier for this instruction. - - .. automethod:: get_written_variables - .. automethod:: get_read_variables - """ - - def __init__(self, **kwargs): - id = kwargs.pop("id", None) - if id is not None: - id = six.moves.intern(id) - - depends_on = frozenset(kwargs.pop("depends_on", [])) - super(Instruction, self).__init__( - id=id, - depends_on=depends_on, - **kwargs) - - def get_written_variables(self): - """Returns a :class:`frozenset` of variables being written by this - instruction. - """ - return frozenset() - - def get_read_variables(self): - """Returns a :class:`frozenset` of variables being read by this - instruction. - """ - return frozenset() - - def map_expressions(self, mapper, include_lhs=True): - """Returns a new copy of *self* with all expressions - replaced by ``mapepr(expr)`` for every - :class:`pymbolic.primitives.Expression` - contained in *self*. - """ - return self - - def get_dependency_mapper(self, include_calls="descend_args"): - from pymbolic.mapper.dependency import DependencyMapper - return DependencyMapper( - include_subscripts=False, - include_lookups=False, - include_calls=include_calls) - -# }}} - - -# {{{ instruction with condition - -class ConditionalInstruction(Instruction): - __doc__ = Instruction.__doc__ + """ - .. attribute:: condition - - The instruction condition as a :mod:`pymbolic` expression (`True` if the - instruction is unconditionally executed) - """ - - def __init__(self, **kwargs): - condition = kwargs.pop("condition", True) - super(ConditionalInstruction, self).__init__( - condition=condition, - **kwargs) - - def _condition_printing_suffix(self): - if self.condition is True: - return "" - return " if " + str(self.condition) - - def __str__(self): - return (super(ConditionalInstruction, self).__str__() - + self._condition_printing_suffix()) - - def get_read_variables(self): - dep_mapper = self.get_dependency_mapper() - return ( - super(ConditionalInstruction, self).get_read_variables() - | - frozenset( - dep.name for dep in dep_mapper(self.condition))) - -# }}} - - -# {{{ assignment - -class Assignment(Instruction): - """ - .. attribute:: lhs - .. attribute:: rhs - """ - - def __init__(self, lhs, rhs, **kwargs): - super(Assignment, self).__init__( - lhs=lhs, - rhs=rhs, - **kwargs) - - def get_written_variables(self): - from pymbolic.primitives import Variable, Subscript - if isinstance(self.lhs, Variable): - return frozenset([self.lhs.name]) - elif isinstance(self.lhs, Subscript): - assert isinstance(self.lhs.aggregate, Variable) - return frozenset([self.lhs.aggregate.name]) - else: - raise TypeError("unexpected type of LHS") - - def get_read_variables(self): - result = super(Assignment, self).get_read_variables() - get_deps = self.get_dependency_mapper() - - def get_vars(expr): - return frozenset(dep.name for dep in get_deps(self.rhs)) - - result = get_vars(self.rhs) | get_vars(self.lhs) - - return result - - def map_expressions(self, mapper, include_lhs=True): - return (super(Assignment, self) - .map_expressions(mapper, include_lhs=include_lhs) - .copy( - lhs=mapper(self.lhs) if include_lhs else self.lhs, - rhs=mapper(self.rhs))) - - def __str__(self): - result = "{assignee} <- {expr}".format( - assignee=str(self.lhs), - expr=str(self.rhs),) - - return result - -# }}} - - -# {{{ conditional assignment - -class ConditionalAssignment(ConditionalInstruction, Assignment): - """ - .. attribute:: assignee - .. attribute:: assignee_subscript - - The subscript in :attr:`assignee` which is being assigned. - A tuple, which may be empty, to indicate 'no subscript'. - - .. attribute:: expression - .. attribute:: loops - - A list of triples *(identifier, start, end)* that the assignment - should be carried out inside of these loops. - No ordering of loop iterations is implied. - The loops will typically be nested outer-to-inner, but a target - may validly use any order it likes. - - """ - - def map_expressions(self, mapper, include_lhs=True): - return (super(ConditionalAssignment, self) - .map_expressions(mapper, include_lhs=include_lhs) - .copy(condition=mapper(self.condition))) - -# }}} - - -# {{{ nop - -class Nop(Instruction): - def __str__(self): - return 'nop' - -# }}} - - -# vim: foldmethod=marker +from pymbolic.imperative.instruction import Instruction, ConditionalInstruction, Assignment, Nop diff --git a/pymbolic/imperative/statement.py b/pymbolic/imperative/statement.py new file mode 100644 index 0000000000000000000000000000000000000000..0962f840d395a29c0afcdfca3a737f18c228ab8e --- /dev/null +++ b/pymbolic/imperative/statement.py @@ -0,0 +1,220 @@ +"""Instruction types""" + +__copyright__ = "Copyright (C) 2015 Matt Wala, Andreas Kloeckner" + +__license__ = """ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +import six + +from pytools import RecordWithoutPickling + + +# {{{ statemetn classes + +class Statement(RecordWithoutPickling): + """ + .. attribute:: depends_on + + A :class:`frozenset` of instruction ids that are reuqired to be + executed within this execution context before this instruction can be + executed. + + .. attribute:: id + + A string, a unique identifier for this instruction. + + .. automethod:: get_written_variables + .. automethod:: get_read_variables + """ + + def __init__(self, **kwargs): + id = kwargs.pop("id", None) + if id is not None: + id = six.moves.intern(id) + + depends_on = frozenset(kwargs.pop("depends_on", [])) + super(Statement, self).__init__( + id=id, + depends_on=depends_on, + **kwargs) + + def get_written_variables(self): + """Returns a :class:`frozenset` of variables being written by this + instruction. + """ + return frozenset() + + def get_read_variables(self): + """Returns a :class:`frozenset` of variables being read by this + instruction. + """ + return frozenset() + + def map_expressions(self, mapper, include_lhs=True): + """Returns a new copy of *self* with all expressions + replaced by ``mapepr(expr)`` for every + :class:`pymbolic.primitives.Expression` + contained in *self*. + """ + return self + + def get_dependency_mapper(self, include_calls="descend_args"): + from pymbolic.mapper.dependency import DependencyMapper + return DependencyMapper( + include_subscripts=False, + include_lookups=False, + include_calls=include_calls) + +# }}} + + +# {{{ statement with condition + +class ConditionalStatement(Statement): + __doc__ = Statement.__doc__ + """ + .. attribute:: condition + + The instruction condition as a :mod:`pymbolic` expression (`True` if the + instruction is unconditionally executed) + """ + + def __init__(self, **kwargs): + condition = kwargs.pop("condition", True) + super(ConditionalStatement, self).__init__( + condition=condition, + **kwargs) + + def _condition_printing_suffix(self): + if self.condition is True: + return "" + return " if " + str(self.condition) + + def __str__(self): + return (super(ConditionalStatement, self).__str__() + + self._condition_printing_suffix()) + + def get_read_variables(self): + dep_mapper = self.get_dependency_mapper() + return ( + super(ConditionalStatement, self).get_read_variables() + | + frozenset( + dep.name for dep in dep_mapper(self.condition))) + +# }}} + + +# {{{ assignment + +class Assignment(Statement): + """ + .. attribute:: lhs + .. attribute:: rhs + """ + + def __init__(self, lhs, rhs, **kwargs): + super(Assignment, self).__init__( + lhs=lhs, + rhs=rhs, + **kwargs) + + def get_written_variables(self): + from pymbolic.primitives import Variable, Subscript + if isinstance(self.lhs, Variable): + return frozenset([self.lhs.name]) + elif isinstance(self.lhs, Subscript): + assert isinstance(self.lhs.aggregate, Variable) + return frozenset([self.lhs.aggregate.name]) + else: + raise TypeError("unexpected type of LHS") + + def get_read_variables(self): + result = super(Assignment, self).get_read_variables() + get_deps = self.get_dependency_mapper() + + def get_vars(expr): + return frozenset(dep.name for dep in get_deps(self.rhs)) + + result = get_vars(self.rhs) | get_vars(self.lhs) + + return result + + def map_expressions(self, mapper, include_lhs=True): + return (super(Assignment, self) + .map_expressions(mapper, include_lhs=include_lhs) + .copy( + lhs=mapper(self.lhs) if include_lhs else self.lhs, + rhs=mapper(self.rhs))) + + def __str__(self): + result = "{assignee} <- {expr}".format( + assignee=str(self.lhs), + expr=str(self.rhs),) + + return result + +# }}} + + +# {{{ conditional assignment + +class ConditionalAssignment(ConditionalStatement, Assignment): + """ + .. attribute:: assignee + .. attribute:: assignee_subscript + + The subscript in :attr:`assignee` which is being assigned. + A tuple, which may be empty, to indicate 'no subscript'. + + .. attribute:: expression + .. attribute:: loops + + A list of triples *(identifier, start, end)* that the assignment + should be carried out inside of these loops. + No ordering of loop iterations is implied. + The loops will typically be nested outer-to-inner, but a target + may validly use any order it likes. + + """ + + def map_expressions(self, mapper, include_lhs=True): + return (super(ConditionalAssignment, self) + .map_expressions(mapper, include_lhs=include_lhs) + .copy(condition=mapper(self.condition))) + +# }}} + + +# {{{ nop + +class Nop(Statement): + def __str__(self): + return 'nop' + +# }}} + + +Instruction = Statement +ConditionalInstruction = ConditionalStatement + + +# vim: foldmethod=marker diff --git a/pymbolic/imperative/transform.py b/pymbolic/imperative/transform.py index a52d44630b44266274f8703502154941796e7f15..fd5d94a92a6bae91e25d966dfc53f3307b63c89c 100644 --- a/pymbolic/imperative/transform.py +++ b/pymbolic/imperative/transform.py @@ -23,39 +23,39 @@ THE SOFTWARE. """ -# {{{ fuse instruction streams +# {{{ fuse statement streams -def fuse_instruction_streams_with_unique_ids(instructions_a, instructions_b): - new_instructions = list(instructions_a) +def fuse_statement_streams_with_unique_ids(statements_a, statements_b): + new_statements = list(statements_a) from pytools import UniqueNameGenerator - insn_id_gen = UniqueNameGenerator( - set([insna.id for insna in new_instructions])) + stmt_id_gen = UniqueNameGenerator( + set([stmta.id for stmta in new_statements])) - b_unique_instructions = [] + b_unique_statements = [] old_b_id_to_new_b_id = {} - for insnb in instructions_b: - old_id = insnb.id - new_id = insn_id_gen(old_id) + for stmtb in statements_b: + old_id = stmtb.id + new_id = stmt_id_gen(old_id) old_b_id_to_new_b_id[old_id] = new_id - b_unique_instructions.append( - insnb.copy(id=new_id)) + b_unique_statements.append( + stmtb.copy(id=new_id)) - for insnb in b_unique_instructions: - new_instructions.append( - insnb.copy( + for stmtb in b_unique_statements: + new_statements.append( + stmtb.copy( depends_on=frozenset( old_b_id_to_new_b_id[dep_id] - for dep_id in insnb.depends_on))) + for dep_id in stmtb.depends_on))) - return new_instructions, old_b_id_to_new_b_id + return new_statements, old_b_id_to_new_b_id # }}} # {{{ disambiguate_identifiers -def disambiguate_identifiers(instructions_a, instructions_b, +def disambiguate_identifiers(statements_a, statements_b, should_disambiguate_name=None): if should_disambiguate_name is None: def should_disambiguate_name(name): @@ -63,8 +63,8 @@ def disambiguate_identifiers(instructions_a, instructions_b, from pymbolic.imperative.analysis import get_all_used_identifiers - id_a = get_all_used_identifiers(instructions_a) - id_b = get_all_used_identifiers(instructions_b) + id_a = get_all_used_identifiers(statements_a) + id_b = get_all_used_identifiers(statements_b) from pytools import UniqueNameGenerator vng = UniqueNameGenerator(id_a | id_b) @@ -80,25 +80,25 @@ def disambiguate_identifiers(instructions_a, instructions_b, make_subst_func, SubstitutionMapper) subst_map = SubstitutionMapper(make_subst_func(subst_b)) - instructions_b = [ - insn.map_expressions(subst_map) for insn in instructions_b] + statements_b = [ + stmt.map_expressions(subst_map) for stmt in statements_b] - return instructions_b, subst_b + return statements_b, subst_b # }}} # {{{ disambiguate_and_fuse -def disambiguate_and_fuse(instructions_a, instructions_b, +def disambiguate_and_fuse(statements_a, statements_b, should_disambiguate_name=None): - instructions_b, subst_b = disambiguate_identifiers( - instructions_a, instructions_b, + statements_b, subst_b = disambiguate_identifiers( + statements_a, statements_b, should_disambiguate_name) fused, old_b_id_to_new_b_id = \ - fuse_instruction_streams_with_unique_ids( - instructions_a, instructions_b) + fuse_statement_streams_with_unique_ids( + statements_a, statements_b) return fused, subst_b, old_b_id_to_new_b_id