compiler: add lower_units transform

This commit is contained in:
Sebastien Bourdeauducq 2014-08-18 23:06:34 +08:00
parent dcc140c5a9
commit 7ea28642e4
4 changed files with 49 additions and 21 deletions

View File

@ -1,12 +1,11 @@
import ast, types import ast, types
from artiq.language import units
from artiq.compiler.tools import * from artiq.compiler.tools import *
# -1 statement duration could not be pre-determined # -1 statement duration could not be pre-determined
# 0 statement has no effect on timeline # 0 statement has no effect on timeline
# >0 statement is a static delay that advances the timeline # >0 statement is a static delay that advances the timeline
# by the given amount (in seconds) # by the given amount (in microcycles)
def _get_duration(stmt): def _get_duration(stmt):
if isinstance(stmt, (ast.Expr, ast.Assign)): if isinstance(stmt, (ast.Expr, ast.Assign)):
return _get_duration(stmt.value) return _get_duration(stmt.value)
@ -21,10 +20,8 @@ def _get_duration(stmt):
try: try:
da = eval_constant(stmt.args[0]) da = eval_constant(stmt.args[0])
except NotConstant: except NotConstant:
return -1 da = -1
if da.unit != units.s_unit: return da
raise units.DimensionError("Delay not expressed in seconds")
return da.amount
else: else:
return 0 return 0
else: else:
@ -54,14 +51,9 @@ def _interleave_timelines(timelines):
stmt.delay -= dt stmt.delay -= dt
if stmt.delay == 0: if stmt.delay == 0:
ref_stmt = stmt.stmt ref_stmt = stmt.stmt
da_expr = ast.copy_location(
ast.Call(func=ast.Name("Quantity", ast.Load()),
args=[value_to_ast(dt), ast.Name("s_unit", ast.Load())],
keywords=[], starargs=[], kwargs=[]),
ref_stmt)
delay_stmt = ast.copy_location( delay_stmt = ast.copy_location(
ast.Expr(ast.Call(func=ast.Name("delay", ast.Load()), ast.Expr(ast.Call(func=ast.Name("delay", ast.Load()),
args=[da_expr], args=[value_to_ast(dt)],
keywords=[], starargs=[], kwargs=[])), keywords=[], starargs=[], kwargs=[])),
ref_stmt) ref_stmt)
r.append(delay_stmt) r.append(delay_stmt)

View File

@ -10,16 +10,8 @@ def _insert_int64(node):
keywords=[], starargs=[], kwargs=[]), node) keywords=[], starargs=[], kwargs=[]), 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):
if isinstance(node.func, ast.Name) \ if isinstance(node.func, ast.Name) and node.func.id == "now":
and node.func.id == "Quantity" and node.args[1].id == "s_unit":
return ast.copy_location(
ast.BinOp(left=node.args[0], op=ast.Div(), right=value_to_ast(self.ref_period.amount)),
node)
elif isinstance(node.func, ast.Name) and node.func.id == "now":
return ast.copy_location(ast.Name("now", ast.Load()), node) return ast.copy_location(ast.Name("now", ast.Load()), node)
else: else:
self.generic_visit(node) self.generic_visit(node)

View File

@ -0,0 +1,42 @@
import ast
from artiq.compiler.tools import value_to_ast
from artiq.language import units
# TODO:
# * track variable and expression dimensions
# * raise exception on dimension errors in expressions
# * modify RPC map to reintroduce units
# * handle core time conversion outside of delay/at,
# e.g. foo = now() + 1*us [...] at(foo)
class _UnitsLowerer(ast.NodeTransformer):
def __init__(self, ref_period):
self.ref_period = ref_period
self.in_core_time = False
def visit_Call(self, node):
fn = node.func.id
if fn in ("delay", "at"):
old_in_core_time = self.in_core_time
self.in_core_time = True
self.generic_visit(node)
self.in_core_time = old_in_core_time
elif fn == "Quantity":
if self.in_core_time:
if node.args[1].id == "microcycle_units":
node = node.args[0]
else:
node = ast.copy_location(
ast.BinOp(left=node.args[0], op=ast.Div(), right=value_to_ast(self.ref_period)),
node)
else:
node = node.args[0]
else:
self.generic_visit(node)
return node
def lower_units(funcdef, ref_period):
if not isinstance(ref_period, units.Quantity) or ref_period.unit is not units.s_unit:
raise units.DimensionError("Reference period not expressed in seconds")
_UnitsLowerer(ref_period.amount).visit(funcdef)

View File

@ -1,4 +1,5 @@
from artiq.compiler.inline import inline from artiq.compiler.inline import inline
from artiq.compiler.lower_units import lower_units
from artiq.compiler.fold_constants import fold_constants from artiq.compiler.fold_constants import fold_constants
from artiq.compiler.unroll_loops import unroll_loops from artiq.compiler.unroll_loops import unroll_loops
from artiq.compiler.interleave import interleave from artiq.compiler.interleave import interleave
@ -14,6 +15,7 @@ class Core:
def run(self, k_function, k_args, k_kwargs): def run(self, k_function, k_args, k_kwargs):
funcdef, rpc_map = inline(self, k_function, k_args, k_kwargs) funcdef, rpc_map = inline(self, k_function, k_args, k_kwargs)
lower_units(funcdef, self.runtime_env.ref_period)
fold_constants(funcdef) fold_constants(funcdef)
unroll_loops(funcdef, 50) unroll_loops(funcdef, 50)
interleave(funcdef) interleave(funcdef)