forked from M-Labs/artiq
transforms: quantize time before interleaving
This commit is contained in:
parent
ddc9c3423f
commit
e02ca0b404
|
@ -2,6 +2,7 @@ import os
|
||||||
|
|
||||||
from artiq.transforms.inline import inline
|
from artiq.transforms.inline import inline
|
||||||
from artiq.transforms.lower_units import lower_units
|
from artiq.transforms.lower_units import lower_units
|
||||||
|
from artiq.transforms.quantize_time import quantize_time
|
||||||
from artiq.transforms.remove_inter_assigns import remove_inter_assigns
|
from artiq.transforms.remove_inter_assigns import remove_inter_assigns
|
||||||
from artiq.transforms.fold_constants import fold_constants
|
from artiq.transforms.fold_constants import fold_constants
|
||||||
from artiq.transforms.remove_dead_code import remove_dead_code
|
from artiq.transforms.remove_dead_code import remove_dead_code
|
||||||
|
@ -54,6 +55,9 @@ class Core:
|
||||||
remove_inter_assigns(func_def)
|
remove_inter_assigns(func_def)
|
||||||
debug_unparse("remove_inter_assigns_1", func_def)
|
debug_unparse("remove_inter_assigns_1", func_def)
|
||||||
|
|
||||||
|
quantize_time(func_def, self.runtime_env.ref_period)
|
||||||
|
debug_unparse("quantize_time", func_def)
|
||||||
|
|
||||||
fold_constants(func_def)
|
fold_constants(func_def)
|
||||||
debug_unparse("fold_constants_1", func_def)
|
debug_unparse("fold_constants_1", func_def)
|
||||||
|
|
||||||
|
@ -63,9 +67,7 @@ class Core:
|
||||||
interleave(func_def)
|
interleave(func_def)
|
||||||
debug_unparse("interleave", func_def)
|
debug_unparse("interleave", func_def)
|
||||||
|
|
||||||
lower_time(func_def,
|
lower_time(func_def, getattr(self.runtime_env, "initial_time", 0))
|
||||||
getattr(self.runtime_env, "initial_time", 0),
|
|
||||||
self.runtime_env.ref_period)
|
|
||||||
debug_unparse("lower_time", func_def)
|
debug_unparse("lower_time", func_def)
|
||||||
|
|
||||||
remove_inter_assigns(func_def)
|
remove_inter_assigns(func_def)
|
||||||
|
|
|
@ -1,63 +1,28 @@
|
||||||
|
"""This transform implements time management functions (delay/now/at)
|
||||||
|
using an accumulator 'now' and simple replacement rules:
|
||||||
|
|
||||||
|
delay(t) -> now += t
|
||||||
|
now() -> now
|
||||||
|
at(t) -> now = t
|
||||||
|
|
||||||
|
Time parameters must be quantized to integers before running this transform.
|
||||||
|
The accumulator is initialized to an int64 value at the beginning of the
|
||||||
|
output function.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
from artiq.transforms.tools import value_to_ast
|
from artiq.transforms.tools import value_to_ast
|
||||||
from artiq.language.core import int64
|
from artiq.language.core import int64
|
||||||
|
|
||||||
|
|
||||||
def _time_to_cycles(ref_period, node):
|
|
||||||
divided = ast.copy_location(
|
|
||||||
ast.BinOp(left=node,
|
|
||||||
op=ast.Div(),
|
|
||||||
right=value_to_ast(ref_period)),
|
|
||||||
node)
|
|
||||||
return ast.copy_location(
|
|
||||||
ast.Call(func=ast.Name("round64", ast.Load()),
|
|
||||||
args=[divided],
|
|
||||||
keywords=[], starargs=[], kwargs=[]),
|
|
||||||
divided)
|
|
||||||
|
|
||||||
|
|
||||||
def _time_to_cycles_opt(ref_period, node):
|
|
||||||
if (isinstance(node, ast.Call)
|
|
||||||
and isinstance(node.func, ast.Name)
|
|
||||||
and node.func.id == "cycles_to_time"):
|
|
||||||
return node.args[0]
|
|
||||||
else:
|
|
||||||
return _time_to_cycles(ref_period, node)
|
|
||||||
|
|
||||||
|
|
||||||
def _cycles_to_time(ref_period, node):
|
|
||||||
return ast.copy_location(
|
|
||||||
ast.BinOp(left=node,
|
|
||||||
op=ast.Mult(),
|
|
||||||
right=value_to_ast(ref_period)),
|
|
||||||
node)
|
|
||||||
|
|
||||||
|
|
||||||
class _TimeLowerer(ast.NodeTransformer):
|
class _TimeLowerer(ast.NodeTransformer):
|
||||||
def __init__(self, ref_period):
|
|
||||||
self.ref_period = ref_period
|
|
||||||
|
|
||||||
def visit_Call(self, node):
|
def visit_Call(self, node):
|
||||||
# optimize time_to_cycles(now()) -> now
|
if isinstance(node.func, ast.Name) and node.func.id == "now":
|
||||||
if (isinstance(node.func, ast.Name)
|
|
||||||
and node.func.id == "time_to_cycles"
|
|
||||||
and isinstance(node.args[0], ast.Call)
|
|
||||||
and isinstance(node.args[0].func, ast.Name)
|
|
||||||
and node.args[0].func.id == "now"):
|
|
||||||
return ast.copy_location(ast.Name("now", ast.Load()), node)
|
return ast.copy_location(ast.Name("now", ast.Load()), node)
|
||||||
|
else:
|
||||||
self.generic_visit(node)
|
self.generic_visit(node)
|
||||||
if isinstance(node.func, ast.Name):
|
|
||||||
funcname = node.func.id
|
|
||||||
if funcname == "now":
|
|
||||||
return _cycles_to_time(
|
|
||||||
self.ref_period,
|
|
||||||
ast.copy_location(ast.Name("now", ast.Load()), node))
|
|
||||||
elif funcname == "time_to_cycles":
|
|
||||||
return _time_to_cycles(self.ref_period, node.args[0])
|
|
||||||
elif funcname == "cycles_to_time":
|
|
||||||
return _cycles_to_time(self.ref_period, node.args[0])
|
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def visit_Expr(self, node):
|
def visit_Expr(self, node):
|
||||||
|
@ -69,23 +34,19 @@ class _TimeLowerer(ast.NodeTransformer):
|
||||||
r = ast.copy_location(
|
r = ast.copy_location(
|
||||||
ast.AugAssign(target=ast.Name("now", ast.Store()),
|
ast.AugAssign(target=ast.Name("now", ast.Store()),
|
||||||
op=ast.Add(),
|
op=ast.Add(),
|
||||||
value=_time_to_cycles_opt(
|
value=node.value.args[0]),
|
||||||
self.ref_period,
|
|
||||||
node.value.args[0])),
|
|
||||||
node)
|
node)
|
||||||
elif funcname == "at":
|
elif funcname == "at":
|
||||||
r = ast.copy_location(
|
r = ast.copy_location(
|
||||||
ast.Assign(targets=[ast.Name("now", ast.Store())],
|
ast.Assign(targets=[ast.Name("now", ast.Store())],
|
||||||
value=_time_to_cycles_opt(
|
value=node.value.args[0]),
|
||||||
self.ref_period,
|
|
||||||
node.value.args[0])),
|
|
||||||
node)
|
node)
|
||||||
self.generic_visit(r)
|
self.generic_visit(r)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def lower_time(func_def, initial_time, ref_period):
|
def lower_time(func_def, initial_time):
|
||||||
_TimeLowerer(ref_period).visit(func_def)
|
_TimeLowerer().visit(func_def)
|
||||||
func_def.body.insert(0, ast.copy_location(
|
func_def.body.insert(0, ast.copy_location(
|
||||||
ast.Assign(targets=[ast.Name("now", ast.Store())],
|
ast.Assign(targets=[ast.Name("now", ast.Store())],
|
||||||
value=value_to_ast(int64(initial_time))),
|
value=value_to_ast(int64(initial_time))),
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
"""This transform turns calls to delay/now/at that use non-integer time
|
||||||
|
expressed in seconds into calls that use int64 time expressed in multiples of
|
||||||
|
ref_period.
|
||||||
|
|
||||||
|
It does so by inserting multiplication/division/rounding operations around
|
||||||
|
those calls.
|
||||||
|
|
||||||
|
The time_to_cycles and cycles_to_time core language functions are also
|
||||||
|
implemented here.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import ast
|
||||||
|
|
||||||
|
from artiq.transforms.tools import value_to_ast
|
||||||
|
|
||||||
|
|
||||||
|
def _call_now(node):
|
||||||
|
return ast.copy_location(
|
||||||
|
ast.Call(func=ast.Name("now", ast.Load()),
|
||||||
|
args=[], keywords=[], starargs=[], kwargs=[]),
|
||||||
|
node)
|
||||||
|
|
||||||
|
|
||||||
|
def _time_to_cycles(ref_period, node):
|
||||||
|
divided = ast.copy_location(
|
||||||
|
ast.BinOp(left=node,
|
||||||
|
op=ast.Div(),
|
||||||
|
right=value_to_ast(ref_period)),
|
||||||
|
node)
|
||||||
|
return ast.copy_location(
|
||||||
|
ast.Call(func=ast.Name("round64", ast.Load()),
|
||||||
|
args=[divided],
|
||||||
|
keywords=[], starargs=[], kwargs=[]),
|
||||||
|
divided)
|
||||||
|
|
||||||
|
|
||||||
|
def _cycles_to_time(ref_period, node):
|
||||||
|
return ast.copy_location(
|
||||||
|
ast.BinOp(left=node,
|
||||||
|
op=ast.Mult(),
|
||||||
|
right=value_to_ast(ref_period)),
|
||||||
|
node)
|
||||||
|
|
||||||
|
|
||||||
|
class _TimeQuantizer(ast.NodeTransformer):
|
||||||
|
def __init__(self, ref_period):
|
||||||
|
self.ref_period = ref_period
|
||||||
|
|
||||||
|
def visit_Call(self, node):
|
||||||
|
funcname = node.func.id
|
||||||
|
if funcname == "now":
|
||||||
|
return _cycles_to_time(self.ref_period, _call_now(node))
|
||||||
|
elif funcname == "delay" or funcname == "at":
|
||||||
|
if (isinstance(node.args[0], ast.Call)
|
||||||
|
and node.args[0].func.id == "cycles_to_time"):
|
||||||
|
# optimize:
|
||||||
|
# delay/at(cycles_to_time(x)) -> delay/at(x)
|
||||||
|
node.args[0] = self.visit(node.args[0].args[0])
|
||||||
|
else:
|
||||||
|
node.args[0] = _time_to_cycles(self.ref_period,
|
||||||
|
self.visit(node.args[0]))
|
||||||
|
return node
|
||||||
|
elif funcname == "time_to_cycles":
|
||||||
|
if (isinstance(node.args[0], ast.Call)
|
||||||
|
and node.args[0].func.id == "now"):
|
||||||
|
# optimize:
|
||||||
|
# time_to_cycles(now()) -> now()
|
||||||
|
return _call_now(node)
|
||||||
|
else:
|
||||||
|
return _time_to_cycles(self.ref_period,
|
||||||
|
self.visit(node.args[0]))
|
||||||
|
elif funcname == "cycles_to_time":
|
||||||
|
return _cycles_to_time(self.ref_period,
|
||||||
|
self.visit(node.args[0]))
|
||||||
|
else:
|
||||||
|
self.generic_visit(node)
|
||||||
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
def quantize_time(func_def, ref_period):
|
||||||
|
_TimeQuantizer(ref_period).visit(func_def)
|
Loading…
Reference in New Issue