forked from M-Labs/artiq
compiler: add `delay` IR instruction.
This commit is contained in:
parent
956d2afcb2
commit
de9d7eb2e4
|
@ -46,7 +46,9 @@ class BinOpT(ast.BinOp, commontyped):
|
||||||
class BoolOpT(ast.BoolOp, commontyped):
|
class BoolOpT(ast.BoolOp, commontyped):
|
||||||
pass
|
pass
|
||||||
class CallT(ast.Call, commontyped):
|
class CallT(ast.Call, commontyped):
|
||||||
pass
|
"""
|
||||||
|
:ivar iodelay: (:class:`iodelay.Expr`)
|
||||||
|
"""
|
||||||
class CompareT(ast.Compare, commontyped):
|
class CompareT(ast.Compare, commontyped):
|
||||||
pass
|
pass
|
||||||
class DictT(ast.Dict, commontyped):
|
class DictT(ast.Dict, commontyped):
|
||||||
|
|
|
@ -173,7 +173,7 @@ class ASTSynthesizer:
|
||||||
for kw, value, (arg_loc, equals_loc)
|
for kw, value, (arg_loc, equals_loc)
|
||||||
in zip(kwargs, kwarg_nodes, kwarg_locs)],
|
in zip(kwargs, kwarg_nodes, kwarg_locs)],
|
||||||
starargs=None, kwargs=None,
|
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,
|
begin_loc=begin_loc, end_loc=end_loc, star_loc=None, dstar_loc=None,
|
||||||
loc=name_loc.join(end_loc))
|
loc=name_loc.join(end_loc))
|
||||||
|
|
||||||
|
|
|
@ -1188,6 +1188,43 @@ class LandingPad(Terminator):
|
||||||
return "cleanup {}, [{}]".format(self.cleanup().as_operand(type_printer),
|
return "cleanup {}, [{}]".format(self.cleanup().as_operand(type_printer),
|
||||||
", ".join(table))
|
", ".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):
|
class Parallel(Terminator):
|
||||||
"""
|
"""
|
||||||
An instruction that schedules several threads of execution
|
An instruction that schedules several threads of execution
|
||||||
|
|
|
@ -44,6 +44,9 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
can become upvalues
|
can become upvalues
|
||||||
:ivar current_private_env: (:class:`ir.Alloc` of type :class:`ir.TEnvironment`)
|
:ivar current_private_env: (:class:`ir.Alloc` of type :class:`ir.TEnvironment`)
|
||||||
the private function environment, containing internal state
|
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)
|
:ivar current_assign: (:class:`ir.Value` or None)
|
||||||
the right-hand side of current assignment statement, or
|
the right-hand side of current assignment statement, or
|
||||||
a component of a composite right-hand side when visiting
|
a component of a composite right-hand side when visiting
|
||||||
|
@ -91,6 +94,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
self.current_block = None
|
self.current_block = None
|
||||||
self.current_env = None
|
self.current_env = None
|
||||||
self.current_private_env = None
|
self.current_private_env = None
|
||||||
|
self.current_args = None
|
||||||
self.current_assign = None
|
self.current_assign = None
|
||||||
self.current_assert_env = None
|
self.current_assert_env = None
|
||||||
self.current_assert_subexprs = None
|
self.current_assert_subexprs = None
|
||||||
|
@ -228,13 +232,19 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
|
|
||||||
env_arg = ir.EnvironmentArgument(self.current_env.type, "outerenv")
|
env_arg = ir.EnvironmentArgument(self.current_env.type, "outerenv")
|
||||||
|
|
||||||
|
old_args, self.current_args = self.current_args, {}
|
||||||
|
|
||||||
args = []
|
args = []
|
||||||
for arg_name in typ.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 = []
|
optargs = []
|
||||||
for arg_name in typ.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,
|
func = ir.Function(typ, ".".join(self.name), [env_arg] + args + optargs,
|
||||||
loc=node.lambda_loc if is_lambda else node.keyword_loc)
|
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())
|
self.current_block.append(ir.Unreachable())
|
||||||
finally:
|
finally:
|
||||||
self.name = old_name
|
self.name = old_name
|
||||||
|
self.current_args = old_args
|
||||||
self.current_function = old_func
|
self.current_function = old_func
|
||||||
self.current_block = old_block
|
self.current_block = old_block
|
||||||
self.current_globals = old_globals
|
self.current_globals = old_globals
|
||||||
|
@ -1544,7 +1555,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
typ = node.func.type.find()
|
typ = node.func.type.find()
|
||||||
|
|
||||||
if types.is_builtin(typ):
|
if types.is_builtin(typ):
|
||||||
return self.visit_builtin_call(node)
|
insn = self.visit_builtin_call(node)
|
||||||
else:
|
else:
|
||||||
if types.is_function(typ):
|
if types.is_function(typ):
|
||||||
func = self.visit(node.func)
|
func = self.visit(node.func)
|
||||||
|
@ -1557,6 +1568,8 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
self_arg = self.append(ir.GetAttr(method, "__self__"))
|
self_arg = self.append(ir.GetAttr(method, "__self__"))
|
||||||
fn_typ = types.get_method_function(typ)
|
fn_typ = types.get_method_function(typ)
|
||||||
offset = 1
|
offset = 1
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
args = [None] * (len(fn_typ.args) + len(fn_typ.optargs))
|
args = [None] * (len(fn_typ.args) + len(fn_typ.optargs))
|
||||||
|
|
||||||
|
@ -1606,7 +1619,15 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
attr_node = node.func
|
attr_node = node.func
|
||||||
self.method_map[(attr_node.value.type, attr_node.attr)].append(insn)
|
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):
|
def visit_QuoteT(self, node):
|
||||||
return self.append(ir.Quote(node.value, node.type))
|
return self.append(ir.Quote(node.value, node.type))
|
||||||
|
|
|
@ -426,7 +426,7 @@ class ASTTypedRewriter(algorithm.Transformer):
|
||||||
|
|
||||||
def visit_Call(self, node):
|
def visit_Call(self, node):
|
||||||
node = self.generic_visit(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,
|
func=node.func, args=node.args, keywords=node.keywords,
|
||||||
starargs=node.starargs, kwargs=node.kwargs,
|
starargs=node.starargs, kwargs=node.kwargs,
|
||||||
star_loc=node.star_loc, dstar_loc=node.dstar_loc,
|
star_loc=node.star_loc, dstar_loc=node.dstar_loc,
|
||||||
|
|
|
@ -230,10 +230,10 @@ class IODelayEstimator(algorithm.Visitor):
|
||||||
|
|
||||||
if types.is_builtin(typ, "delay"):
|
if types.is_builtin(typ, "delay"):
|
||||||
value = self.evaluate(node.args[0], abort=abort)
|
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"):
|
elif types.is_builtin(typ, "delay_mu"):
|
||||||
value = self.evaluate(node.args[0], abort=abort)
|
value = self.evaluate(node.args[0], abort=abort)
|
||||||
self.current_delay += value
|
call_delay = value
|
||||||
elif not types.is_builtin(typ):
|
elif not types.is_builtin(typ):
|
||||||
if types.is_function(typ):
|
if types.is_function(typ):
|
||||||
offset = 0
|
offset = 0
|
||||||
|
@ -262,7 +262,10 @@ class IODelayEstimator(algorithm.Visitor):
|
||||||
args[arg_name] = arg_node
|
args[arg_name] = arg_node
|
||||||
|
|
||||||
free_vars = delay.duration.free_vars()
|
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 })
|
{ arg: self.evaluate(args[arg], abort=abort) for arg in free_vars })
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
self.current_delay += call_delay
|
||||||
|
node.iodelay = call_delay
|
||||||
|
|
Loading…
Reference in New Issue