Files
wasmtime/meta/cretonne/ast.py
Jakob Stoklund Olesen 7c91bacafe Define AST nodes and instruction transformations.
Enable syntax: iadd(x, y) which creates an Apply node.
Enable syntax: z << iadd(x, y) which creates a Def node.

Add an XForm class which represents source and destination patterns as
RTL lists.
2016-10-07 14:18:36 -07:00

123 lines
3.1 KiB
Python

"""
Abstract syntax trees.
This module defines classes that can be used to create abstract syntax trees
for patern matching an rewriting of cretonne instructions.
"""
from __future__ import absolute_import
class Def(object):
"""
An AST definition associates a set of variables with the values produced by
an expression.
Example:
>>> from .base import iadd_cout, iconst
>>> x = Var('x')
>>> y = Var('y')
>>> x << iconst(4)
(Var(x),) << Apply(iconst, (4,))
>>> (x, y) << iadd_cout(4, 5)
(Var(x), Var(y)) << Apply(iadd_cout, (4, 5))
The `<<` operator is used to create variable definitions.
:param defs: Single variable or tuple of variables to be defined.
:param expr: Expression generating the values.
"""
def __init__(self, defs, expr):
if not isinstance(defs, tuple):
defs = (defs,)
assert isinstance(expr, Expr)
self.defs = defs
self.expr = expr
def __repr__(self):
return "{} << {!r}".format(self.defs, self.expr)
def __str__(self):
if len(self.defs) == 1:
return "{!s} << {!s}".format(self.defs[0], self.expr)
else:
return "({}) << {!s}".format(", ".join(self.defs), self.expr)
class Expr(object):
"""
An AST expression.
"""
def __rlshift__(self, other):
"""
Define variables using `var << expr` or `(v1, v2) << expr`.
"""
return Def(other, self)
class Var(Expr):
"""
A free variable.
"""
def __init__(self, name):
self.name = name
# Bitmask of contexts where this variable is defined.
# See XForm._rewrite_defs().
self.defctx = 0
def __str__(self):
return self.name
def __repr__(self):
s = self.name
if self.defctx:
s += ", d={:02b}".format(self.defctx)
return "Var({})".format(s)
class Apply(Expr):
"""
Apply an instruction to arguments.
An `Apply` AST expression is created by using function call syntax on
instructions. This applies to both bound and unbound polymorphic
instructions:
>>> from .base import jump, iadd
>>> jump('next', ())
Apply(jump, ('next', ()))
>>> iadd.i32('x', 'y')
Apply(iadd.i32, ('x', 'y'))
:param inst: The instruction being applied, an `Instruction` or
`BoundInstruction` instance.
:param args: Tuple of arguments.
"""
def __init__(self, inst, args):
from . import BoundInstruction
if isinstance(inst, BoundInstruction):
self.inst = inst.inst
self.typevars = inst.typevars
else:
self.inst = inst
self.typevars = ()
self.args = args
assert len(self.inst.ins) == len(args)
def instname(self):
i = self.inst.name
for t in self.typevars:
i += '.{}'.format(t)
return i
def __repr__(self):
return "Apply({}, {})".format(self.instname(), self.args)
def __str__(self):
args = ', '.join(map(str, self.args))
return '{}({})'.format(self.instname(), args)