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: e9e12adcebbb
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: b163c9f7ea5e
Choose a head ref
  • 2 commits
  • 3 files changed
  • 1 contributor

Commits on Nov 3, 2014

  1. Copy the full SHA
    9b93b0c View commit details
  2. Copy the full SHA
    b163c9f View commit details
Showing with 103 additions and 47 deletions.
  1. +33 −25 artiq/coredevice/core.py
  2. +25 −22 artiq/transforms/unparse.py
  3. +45 −0 test/transforms.py
58 changes: 33 additions & 25 deletions artiq/coredevice/core.py
Original file line number Diff line number Diff line change
@@ -8,13 +8,13 @@
from artiq.transforms.unroll_loops import unroll_loops
from artiq.transforms.interleave import interleave
from artiq.transforms.lower_time import lower_time
from artiq.transforms.unparse import Unparser
from artiq.transforms.unparse import unparse
from artiq.py2llvm import get_runtime_binary


def _unparse(label, node):
def _announce_unparse(label, node):
print("*** Unparsing: "+label)
Unparser(node)
print(unparse(node))


def _make_debug_unparse(final):
@@ -24,69 +24,77 @@ def _make_debug_unparse(final):
env = ""
selected_labels = set(env.split())
if "all" in selected_labels:
return _unparse
return _announce_unparse
else:
if "final" in selected_labels:
selected_labels.add(final)

def _filtered_unparse(label, node):
if label in selected_labels:
_unparse(label, node)
_announce_unparse(label, node)
return _filtered_unparse


def _no_debug_unparse(label, node):
pass


class Core:
def __init__(self, core_com, runtime_env=None):
if runtime_env is None:
runtime_env = core_com.get_runtime_env()
self.runtime_env = runtime_env
self.core_com = core_com

def run(self, k_function, k_args, k_kwargs):
# transform/simplify AST
_debug_unparse = _make_debug_unparse("remove_dead_code_2")

func_def, rpc_map, exception_map = inline(
self, k_function, k_args, k_kwargs)
_debug_unparse("inline", func_def)

def transform_stack(self, func_def, rpc_map, exception_map,
debug_unparse=_no_debug_unparse):
lower_units(func_def, rpc_map)
_debug_unparse("lower_units", func_def)
debug_unparse("lower_units", func_def)

remove_inter_assigns(func_def)
_debug_unparse("remove_inter_assigns_1", func_def)
debug_unparse("remove_inter_assigns_1", func_def)

fold_constants(func_def)
_debug_unparse("fold_constants_1", func_def)
debug_unparse("fold_constants_1", func_def)

unroll_loops(func_def, 500)
_debug_unparse("unroll_loops", func_def)
debug_unparse("unroll_loops", func_def)

interleave(func_def)
_debug_unparse("interleave", func_def)
debug_unparse("interleave", func_def)

lower_time(func_def,
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)
_debug_unparse("remove_inter_assigns_2", func_def)
debug_unparse("remove_inter_assigns_2", func_def)

fold_constants(func_def)
_debug_unparse("fold_constants_2", func_def)
debug_unparse("fold_constants_2", func_def)

remove_dead_code(func_def)
_debug_unparse("remove_dead_code_1", func_def)
debug_unparse("remove_dead_code_1", func_def)

remove_inter_assigns(func_def)
_debug_unparse("remove_inter_assigns_3", func_def)
debug_unparse("remove_inter_assigns_3", func_def)

fold_constants(func_def)
_debug_unparse("fold_constants_3", func_def)
debug_unparse("fold_constants_3", func_def)

remove_dead_code(func_def)
_debug_unparse("remove_dead_code_2", func_def)
debug_unparse("remove_dead_code_2", func_def)

def run(self, k_function, k_args, k_kwargs):
# transform/simplify AST
debug_unparse = _make_debug_unparse("remove_dead_code_2")

func_def, rpc_map, exception_map = inline(
self, k_function, k_args, k_kwargs)
debug_unparse("inline", func_def)

self.transform_stack(func_def, rpc_map, exception_map, debug_unparse)

# compile to machine code and run
binary = get_runtime_binary(self.runtime_env, func_def)
47 changes: 25 additions & 22 deletions artiq/transforms/unparse.py
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@
INFSTR = "1e" + repr(sys.float_info.max_10_exp + 1)


def interleave(inter, f, seq):
def _interleave(inter, f, seq):
"""Call f on each item in seq, calling inter() in between.
"""
seq = iter(seq)
@@ -21,27 +21,25 @@ def interleave(inter, f, seq):
f(x)


class Unparser:
class _Unparser:
"""Methods in this class recursively traverse an AST and
output source code for the abstract syntax; original formatting
is disregarded. """

def __init__(self, tree, file=sys.stdout):
"""Unparser(tree, file=sys.stdout) -> None.
Print the source for tree to file."""
self.f = file
def __init__(self, tree):
"""Print the source for tree to the "result" string."""
self.result = ""
self._indent = 0
self.dispatch(tree)
print("", file=self.f)
self.f.flush()
self.result += "\n"

def fill(self, text=""):
"Indent a piece of text, according to the current indentation level"
self.f.write("\n"+" "*self._indent + text)
self.result += "\n"+" "*self._indent + text

def write(self, text):
"Append a piece of text to the current line."
self.f.write(text)
self.result += text

def enter(self):
"Print ':', and increase the indentation."
@@ -79,15 +77,15 @@ def _Expr(self, tree):

def _Import(self, t):
self.fill("import ")
interleave(lambda: self.write(", "), self.dispatch, t.names)
_interleave(lambda: self.write(", "), self.dispatch, t.names)

def _ImportFrom(self, t):
self.fill("from ")
self.write("." * t.level)
if t.module:
self.write(t.module)
self.write(" import ")
interleave(lambda: self.write(", "), self.dispatch, t.names)
_interleave(lambda: self.write(", "), self.dispatch, t.names)

def _Assign(self, t):
self.fill()
@@ -119,7 +117,7 @@ def _Continue(self, t):

def _Delete(self, t):
self.fill("del ")
interleave(lambda: self.write(", "), self.dispatch, t.targets)
_interleave(lambda: self.write(", "), self.dispatch, t.targets)

def _Assert(self, t):
self.fill("assert ")
@@ -130,11 +128,11 @@ def _Assert(self, t):

def _Global(self, t):
self.fill("global ")
interleave(lambda: self.write(", "), self.write, t.names)
_interleave(lambda: self.write(", "), self.write, t.names)

def _Nonlocal(self, t):
self.fill("nonlocal ")
interleave(lambda: self.write(", "), self.write, t.names)
_interleave(lambda: self.write(", "), self.write, t.names)

def _Yield(self, t):
self.write("(")
@@ -298,7 +296,7 @@ def _While(self, t):

def _With(self, t):
self.fill("with ")
interleave(lambda: self.write(", "), self.dispatch, t.items)
_interleave(lambda: self.write(", "), self.dispatch, t.items)
self.enter()
self.dispatch(t.body)
self.leave()
@@ -322,7 +320,7 @@ def _Num(self, t):

def _List(self, t):
self.write("[")
interleave(lambda: self.write(", "), self.dispatch, t.elts)
_interleave(lambda: self.write(", "), self.dispatch, t.elts)
self.write("]")

def _ListComp(self, t):
@@ -376,7 +374,7 @@ def _IfExp(self, t):
def _Set(self, t):
assert(t.elts) # should be at least one element
self.write("{")
interleave(lambda: self.write(", "), self.dispatch, t.elts)
_interleave(lambda: self.write(", "), self.dispatch, t.elts)
self.write("}")

def _Dict(self, t):
@@ -387,7 +385,7 @@ def write_pair(pair):
self.dispatch(k)
self.write(": ")
self.dispatch(v)
interleave(lambda: self.write(", "), write_pair, zip(t.keys, t.values))
_interleave(lambda: self.write(", "), write_pair, zip(t.keys, t.values))
self.write("}")

def _Tuple(self, t):
@@ -397,7 +395,7 @@ def _Tuple(self, t):
self.dispatch(elt)
self.write(",")
else:
interleave(lambda: self.write(", "), self.dispatch, t.elts)
_interleave(lambda: self.write(", "), self.dispatch, t.elts)
self.write(")")

unop = {"Invert": "~", "Not": "not", "UAdd": "+", "USub": "-"}
@@ -438,7 +436,7 @@ def _Compare(self, t):
def _BoolOp(self, t):
self.write("(")
s = " %s " % self.boolops[t.op.__class__]
interleave(lambda: self.write(s), self.dispatch, t.values)
_interleave(lambda: self.write(s), self.dispatch, t.values)
self.write(")")

def _Attribute(self, t):
@@ -511,7 +509,7 @@ def _Slice(self, t):
self.dispatch(t.step)

def _ExtSlice(self, t):
interleave(lambda: self.write(', '), self.dispatch, t.dims)
_interleave(lambda: self.write(', '), self.dispatch, t.dims)

# argument
def _arg(self, t):
@@ -594,3 +592,8 @@ def _withitem(self, t):
if t.optional_vars:
self.write(" as ")
self.dispatch(t.optional_vars)


def unparse(tree):
unparser = _Unparser(tree)
return unparser.result
45 changes: 45 additions & 0 deletions test/transforms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import unittest
import ast

from artiq.coredevice import comm_dummy, core
from artiq.transforms.unparse import unparse


# Original code before inline:
#
# n = time_to_cycles(1.2345*ns)
# ftw = self.dds.frequency_to_ftw(345*MHz)
# f = self.dds.ftw_to_frequency(ftw)
# phi = 1000*cycles_to_time(n)*f
# do_someting(int(phi))
#
optimize_in = """
def run():
dds_sysclk = Quantity(Fraction(1000000000, 1), 'Hz')
n = time_to_cycles((1.2345 * Quantity(Fraction(1, 1000000000), 's')))
with sequential:
frequency = (345 * Quantity(Fraction(1000000, 1), 'Hz'))
frequency_to_ftw_return = int((((2 ** 32) * frequency) / dds_sysclk))
ftw = frequency_to_ftw_return
with sequential:
ftw2 = ftw
ftw_to_frequency_return = ((ftw2 * dds_sysclk) / (2 ** 32))
f = ftw_to_frequency_return
phi = ((1000 * cycles_to_time(n)) * f)
do_something(int(phi))
"""

optimize_out = """
def run():
do_something(344)
"""


class OptimizeCase(unittest.TestCase):
def test_optimize(self):
coredev = core.Core(comm_dummy.Comm())
func_def = ast.parse(optimize_in).body[0]
coredev.transform_stack(func_def, dict(), dict())
self.assertEqual(unparse(func_def), optimize_out)