compiler: add delay IR instruction.

This commit is contained in:
whitequark 2015-11-17 05:16:43 +03:00
parent 956d2afcb2
commit de9d7eb2e4
6 changed files with 73 additions and 10 deletions

View File

@ -46,7 +46,9 @@ class BinOpT(ast.BinOp, commontyped):
class BoolOpT(ast.BoolOp, commontyped):
pass
class CallT(ast.Call, commontyped):
pass
"""
:ivar iodelay: (:class:`iodelay.Expr`)
"""
class CompareT(ast.Compare, commontyped):
pass
class DictT(ast.Dict, commontyped):

View File

@ -173,7 +173,7 @@ class ASTSynthesizer:
for kw, value, (arg_loc, equals_loc)
in zip(kwargs, kwarg_nodes, kwarg_locs)],
starargs=None, kwargs=None,
type=types.TVar(),
type=types.TVar(), iodelay=None,
begin_loc=begin_loc, end_loc=end_loc, star_loc=None, dstar_loc=None,
loc=name_loc.join(end_loc))

View File

@ -1188,6 +1188,43 @@ class LandingPad(Terminator):
return "cleanup {}, [{}]".format(self.cleanup().as_operand(type_printer),
", ".join(table))
class Delay(Terminator):
"""
A delay operation. Ties an :class:`iodelay.Expr` to SSA values so that
inlining could lead to the expression folding to a constant.
:ivar expr: (:class:`iodelay.Expr`) expression
:ivar var_names: (list of string)
iodelay expression names corresponding to operands
"""
"""
:param expr: (:class:`iodelay.Expr`) expression
:param substs: (dict of str to :class:`Value`)
:param target: (:class:`BasicBlock`) branch target
"""
def __init__(self, expr, substs, target, name=""):
for var_name in substs: assert isinstance(var_name, str)
assert isinstance(target, BasicBlock)
super().__init__([target, *substs.values()], builtins.TNone(), name)
self.expr = expr
self.var_names = list(substs.keys())
def target(self):
return self.operands[0]
def substs(self):
return zip(self.var_names, self.operands[1:])
def _operands_as_string(self, type_printer):
substs = []
for var_name, operand in self.substs():
substs.append("{}={}".format(var_name, operand))
return "[{}], {}".format(", ".join(substs), self.target().as_operand(type_printer))
def opcode(self):
return "delay({})".format(self.expr)
class Parallel(Terminator):
"""
An instruction that schedules several threads of execution

View File

@ -44,6 +44,9 @@ class ARTIQIRGenerator(algorithm.Visitor):
can become upvalues
:ivar current_private_env: (:class:`ir.Alloc` of type :class:`ir.TEnvironment`)
the private function environment, containing internal state
:ivar current_args: (dict of string to :class:`ir.Argument`)
the map of Python names of formal arguments to
the current function to their SSA names
:ivar current_assign: (:class:`ir.Value` or None)
the right-hand side of current assignment statement, or
a component of a composite right-hand side when visiting
@ -91,6 +94,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
self.current_block = None
self.current_env = None
self.current_private_env = None
self.current_args = None
self.current_assign = None
self.current_assert_env = None
self.current_assert_subexprs = None
@ -228,13 +232,19 @@ class ARTIQIRGenerator(algorithm.Visitor):
env_arg = ir.EnvironmentArgument(self.current_env.type, "outerenv")
old_args, self.current_args = self.current_args, {}
args = []
for arg_name in typ.args:
args.append(ir.Argument(typ.args[arg_name], "arg." + arg_name))
arg = ir.Argument(typ.args[arg_name], "arg." + arg_name)
self.current_args[arg_name] = arg
args.append(arg)
optargs = []
for arg_name in typ.optargs:
optargs.append(ir.Argument(ir.TOption(typ.optargs[arg_name]), "arg." + arg_name))
arg = ir.Argument(ir.TOption(typ.optargs[arg_name]), "arg." + arg_name)
self.current_args[arg_name] = arg
optargs.append(arg)
func = ir.Function(typ, ".".join(self.name), [env_arg] + args + optargs,
loc=node.lambda_loc if is_lambda else node.keyword_loc)
@ -284,6 +294,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
self.current_block.append(ir.Unreachable())
finally:
self.name = old_name
self.current_args = old_args
self.current_function = old_func
self.current_block = old_block
self.current_globals = old_globals
@ -1544,7 +1555,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
typ = node.func.type.find()
if types.is_builtin(typ):
return self.visit_builtin_call(node)
insn = self.visit_builtin_call(node)
else:
if types.is_function(typ):
func = self.visit(node.func)
@ -1557,6 +1568,8 @@ class ARTIQIRGenerator(algorithm.Visitor):
self_arg = self.append(ir.GetAttr(method, "__self__"))
fn_typ = types.get_method_function(typ)
offset = 1
else:
assert False
args = [None] * (len(fn_typ.args) + len(fn_typ.optargs))
@ -1606,7 +1619,15 @@ class ARTIQIRGenerator(algorithm.Visitor):
attr_node = node.func
self.method_map[(attr_node.value.type, attr_node.attr)].append(insn)
return insn
if node.iodelay is not None:
after_delay = self.add_block()
self.append(ir.Delay(node.iodelay,
{var_name: self.current_args[var_name]
for var_name in node.iodelay.free_vars()},
after_delay))
self.current_block = after_delay
return insn
def visit_QuoteT(self, node):
return self.append(ir.Quote(node.value, node.type))

View File

@ -426,7 +426,7 @@ class ASTTypedRewriter(algorithm.Transformer):
def visit_Call(self, node):
node = self.generic_visit(node)
node = asttyped.CallT(type=types.TVar(),
node = asttyped.CallT(type=types.TVar(), iodelay=None,
func=node.func, args=node.args, keywords=node.keywords,
starargs=node.starargs, kwargs=node.kwargs,
star_loc=node.star_loc, dstar_loc=node.dstar_loc,

View File

@ -230,10 +230,10 @@ class IODelayEstimator(algorithm.Visitor):
if types.is_builtin(typ, "delay"):
value = self.evaluate(node.args[0], abort=abort)
self.current_delay += iodelay.SToMU(value, ref_period=self.ref_period)
call_delay = iodelay.SToMU(value, ref_period=self.ref_period)
elif types.is_builtin(typ, "delay_mu"):
value = self.evaluate(node.args[0], abort=abort)
self.current_delay += value
call_delay = value
elif not types.is_builtin(typ):
if types.is_function(typ):
offset = 0
@ -262,7 +262,10 @@ class IODelayEstimator(algorithm.Visitor):
args[arg_name] = arg_node
free_vars = delay.duration.free_vars()
self.current_delay += delay.duration.fold(
call_delay = delay.duration.fold(
{ arg: self.evaluate(args[arg], abort=abort) for arg in free_vars })
else:
assert False
self.current_delay += call_delay
node.iodelay = call_delay