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):
|
||||
pass
|
||||
class CallT(ast.Call, commontyped):
|
||||
pass
|
||||
"""
|
||||
:ivar iodelay: (:class:`iodelay.Expr`)
|
||||
"""
|
||||
class CompareT(ast.Compare, commontyped):
|
||||
pass
|
||||
class DictT(ast.Dict, commontyped):
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue