Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 17f5a3132047
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: e02ca0b404ad
Choose a head ref
  • 2 commits
  • 4 files changed
  • 1 contributor

Commits on Nov 15, 2014

  1. Copy the full SHA
    ddc9c34 View commit details
  2. Copy the full SHA
    e02ca0b View commit details
Showing with 109 additions and 62 deletions.
  1. +5 −3 artiq/coredevice/core.py
  2. +2 −0 artiq/transforms/interleave.py
  3. +20 −59 artiq/transforms/lower_time.py
  4. +82 −0 artiq/transforms/quantize_time.py
8 changes: 5 additions & 3 deletions artiq/coredevice/core.py
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@

from artiq.transforms.inline import inline
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.fold_constants import fold_constants
from artiq.transforms.remove_dead_code import remove_dead_code
@@ -54,6 +55,9 @@ def transform_stack(self, func_def, rpc_map, exception_map,
remove_inter_assigns(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)
debug_unparse("fold_constants_1", func_def)

@@ -63,9 +67,7 @@ def transform_stack(self, func_def, rpc_map, exception_map,
interleave(func_def)
debug_unparse("interleave", func_def)

lower_time(func_def,
getattr(self.runtime_env, "initial_time", 0),
self.runtime_env.ref_period)
lower_time(func_def, getattr(self.runtime_env, "initial_time", 0))
debug_unparse("lower_time", func_def)

remove_inter_assigns(func_def)
2 changes: 2 additions & 0 deletions artiq/transforms/interleave.py
Original file line number Diff line number Diff line change
@@ -34,6 +34,8 @@ def _get_duration(stmt):
except NotConstant:
da = -1
return da
elif name == "at":
return -1
else:
return 0
else:
79 changes: 20 additions & 59 deletions artiq/transforms/lower_time.py
Original file line number Diff line number Diff line change
@@ -1,64 +1,29 @@
import ast

from artiq.transforms.tools import value_to_ast
from artiq.language.core import int64

"""This transform implements time management functions (delay/now/at)
using an accumulator 'now' and simple replacement rules:
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)
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.
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)
"""

import ast

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)
from artiq.transforms.tools import value_to_ast
from artiq.language.core import int64


class _TimeLowerer(ast.NodeTransformer):
def __init__(self, ref_period):
self.ref_period = ref_period

def visit_Call(self, node):
# optimize time_to_cycles(now()) -> 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"):
if isinstance(node.func, ast.Name) and node.func.id == "now":
return ast.copy_location(ast.Name("now", ast.Load()), 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
else:
self.generic_visit(node)
return node

def visit_Expr(self, node):
r = node
@@ -69,23 +34,19 @@ def visit_Expr(self, node):
r = ast.copy_location(
ast.AugAssign(target=ast.Name("now", ast.Store()),
op=ast.Add(),
value=_time_to_cycles_opt(
self.ref_period,
node.value.args[0])),
value=node.value.args[0]),
node)
elif funcname == "at":
r = ast.copy_location(
ast.Assign(targets=[ast.Name("now", ast.Store())],
value=_time_to_cycles_opt(
self.ref_period,
node.value.args[0])),
value=node.value.args[0]),
node)
self.generic_visit(r)
return r


def lower_time(func_def, initial_time, ref_period):
_TimeLowerer(ref_period).visit(func_def)
def lower_time(func_def, initial_time):
_TimeLowerer().visit(func_def)
func_def.body.insert(0, ast.copy_location(
ast.Assign(targets=[ast.Name("now", ast.Store())],
value=value_to_ast(int64(initial_time))),
82 changes: 82 additions & 0 deletions artiq/transforms/quantize_time.py
Original file line number Diff line number Diff line change
@@ -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)