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: 3e1348a08452
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: 651e6b1b7af9
Choose a head ref
  • 2 commits
  • 10 files changed
  • 1 contributor

Commits on Sep 30, 2015

  1. Make delay component of function type unifyable.

    whitequark committed Sep 30, 2015

    Verified

    This commit was signed with the committer’s verified signature.
    headius Charles Oliver Nutter
    Copy the full SHA
    7a6fc39 View commit details
  2. Remove build products from git.

    whitequark committed Sep 30, 2015
    Copy the full SHA
    651e6b1 View commit details
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -14,4 +14,4 @@ doc/manual/_build
/.coverage
examples/master/results
Output/
/lit-test/libartiq_personality/libartiq_personality.so
/lit-test/libartiq_support/libartiq_support.so
59 changes: 0 additions & 59 deletions artiq/compiler/iodelay.py
Original file line number Diff line number Diff line change
@@ -4,9 +4,6 @@
a function.
"""

from pythonparser import diagnostic


class Expr:
def __add__(lhs, rhs):
assert isinstance(rhs, Expr)
@@ -227,59 +224,3 @@ def is_const(expr, value=None):

def is_zero(expr):
return is_const(expr, 0)


class Delay:
pass

class Unknown(Delay):
"""
Unknown delay, that is, IO delay that we have not
tried to compute yet.
"""

def __repr__(self):
return "{}.Unknown()".format(__name__)

class Indeterminate(Delay):
"""
Indeterminate delay, that is, IO delay that can vary from
invocation to invocation.
:ivar cause: (:class:`pythonparser.diagnostic.Diagnostic`)
reason for the delay not being inferred
"""

def __init__(self, cause):
assert isinstance(cause, diagnostic.Diagnostic)
self.cause = cause

def __repr__(self):
return "<{}.Indeterminate>".format(__name__)

class Fixed(Delay):
"""
Fixed delay, that is, IO delay that is always the same
for every invocation.
:ivar length: (int) delay in machine units
"""

def __init__(self, length):
assert isinstance(length, Expr)
self.length = length

def __repr__(self):
return "{}.Fixed({})".format(__name__, self.length)

def is_unknown(delay):
return isinstance(delay, Unknown)

def is_indeterminate(delay):
return isinstance(delay, Indeterminate)

def is_fixed(delay, length=None):
if length is None:
return isinstance(delay, Fixed)
else:
return isinstance(delay, Fixed) and delay.length == length
3 changes: 2 additions & 1 deletion artiq/compiler/module.py
Original file line number Diff line number Diff line change
@@ -50,7 +50,8 @@ def __init__(self, src, ref_period=1e-6):
inferencer = transforms.Inferencer(engine=self.engine)
monomorphism_validator = validators.MonomorphismValidator(engine=self.engine)
escape_validator = validators.EscapeValidator(engine=self.engine)
iodelay_estimator = transforms.IODelayEstimator(ref_period=ref_period)
iodelay_estimator = transforms.IODelayEstimator(engine=self.engine,
ref_period=ref_period)
artiq_ir_generator = transforms.ARTIQIRGenerator(engine=self.engine,
module_name=src.name,
ref_period=ref_period)
4 changes: 2 additions & 2 deletions artiq/compiler/testbench/signature.py
Original file line number Diff line number Diff line change
@@ -32,8 +32,8 @@ def process_diagnostic(diag):
if force_delays:
for var in mod.globals:
typ = mod.globals[var].find()
if types.is_function(typ) and iodelay.is_indeterminate(typ.delay):
process_diagnostic(typ.delay.cause)
if types.is_function(typ) and types.is_indeterminate_delay(typ.delay):
process_diagnostic(typ.delay.find().cause)

print(repr(mod))
except:
41 changes: 23 additions & 18 deletions artiq/compiler/transforms/iodelay_estimator.py
Original file line number Diff line number Diff line change
@@ -11,7 +11,8 @@ class _UnknownDelay(Exception):
pass

class IODelayEstimator(algorithm.Visitor):
def __init__(self, ref_period):
def __init__(self, engine, ref_period):
self.engine = engine
self.ref_period = ref_period
self.changed = False
self.current_delay = iodelay.Const(0)
@@ -83,7 +84,7 @@ def visit_ModuleT(self, node):
except (diagnostic.Error, _UnknownDelay):
pass # we don't care; module-level code is never interleaved

def visit_function(self, args, body, typ):
def visit_function(self, args, body, typ, loc):
old_args, self.current_args = self.current_args, args
old_return, self.current_return = self.current_return, None
old_delay, self.current_delay = self.current_delay, iodelay.Const(0)
@@ -93,19 +94,23 @@ def visit_function(self, args, body, typ):
self.abort("only return statement at the end of the function "
"can be interleaved", self.current_return.loc)

delay = iodelay.Fixed(self.current_delay.fold())
delay = types.TFixedDelay(self.current_delay.fold())
except diagnostic.Error as error:
delay = iodelay.Indeterminate(error.diagnostic)
delay = types.TIndeterminateDelay(error.diagnostic)
self.current_delay = old_delay
self.current_return = old_return
self.current_args = old_args

if iodelay.is_unknown(typ.delay) or iodelay.is_indeterminate(typ.delay):
typ.delay = delay
elif iodelay.is_fixed(typ.delay):
assert typ.delay.value == delay.value
else:
assert False
try:
typ.delay.unify(delay)
except types.UnificationError as e:
printer = types.TypePrinter()
diag = diagnostic.Diagnostic("fatal",
"delay {delaya} was inferred for this function, but its delay is already "
"constrained externally to {delayb}",
{"delaya": printer.name(delay), "delayb": printer.name(typ.delay)},
loc)
self.engine.process(diag)

def visit_FunctionDefT(self, node):
self.visit(node.args.defaults)
@@ -116,10 +121,10 @@ def visit_FunctionDefT(self, node):
body = node.body[:-1]
else:
body = node.body
self.visit_function(node.args, body, node.signature_type.find())
self.visit_function(node.args, body, node.signature_type.find(), node.loc)

def visit_LambdaT(self, node):
self.visit_function(node.args, node.body, node.type.find())
self.visit_function(node.args, node.body, node.type.find(), node.loc)

def get_iterable_length(self, node):
def abort(notes):
@@ -225,26 +230,26 @@ def abort(notes):
else:
assert False

delay = typ.find().delay
if iodelay.is_unknown(delay):
delay = typ.find().delay.find()
if types.is_var(delay):
raise _UnknownDelay()
elif iodelay.is_indeterminate(delay):
elif delay.is_indeterminate():
cause = delay.cause
note = diagnostic.Diagnostic("note",
"function called here", {},
node.loc)
diag = diagnostic.Diagnostic(cause.level, cause.reason, cause.arguments,
cause.location, cause.highlights, cause.notes + [note])
raise diagnostic.Error(diag)
elif iodelay.is_fixed(delay):
elif delay.is_fixed():
args = {}
for kw_node in node.keywords:
args[kw_node.arg] = kw_node.value
for arg_name, arg_node in zip(typ.args, node.args[offset:]):
args[arg_name] = arg_node

free_vars = delay.length.free_vars()
self.current_delay += delay.length.fold(
free_vars = delay.duration.free_vars()
self.current_delay += delay.duration.fold(
{ arg: self.evaluate(args[arg], abort=abort) for arg in free_vars })
else:
assert False
102 changes: 87 additions & 15 deletions artiq/compiler/types.py
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@

import string
from collections import OrderedDict
from pythonparser import diagnostic
from . import iodelay


@@ -192,21 +193,21 @@ class TFunction(Type):
optional arguments
:ivar ret: (:class:`Type`)
return type
:ivar delay: (:class:`iodelay.Delay`)
RTIO delay expression
:ivar delay: (:class:`Type`)
RTIO delay
"""

attributes = OrderedDict([
('__code__', _TPointer()),
('__closure__', _TPointer()),
])

def __init__(self, args, optargs, ret, delay=iodelay.Unknown()):
def __init__(self, args, optargs, ret):
assert isinstance(args, OrderedDict)
assert isinstance(optargs, OrderedDict)
assert isinstance(ret, Type)
assert isinstance(delay, iodelay.Delay)
self.args, self.optargs, self.ret, self.delay = args, optargs, ret, delay
self.args, self.optargs, self.ret = args, optargs, ret
self.delay = TVar()

def arity(self):
return len(self.args) + len(self.optargs)
@@ -222,6 +223,7 @@ def unify(self, other):
list(other.args.values()) + list(other.optargs.values())):
selfarg.unify(otherarg)
self.ret.unify(other.ret)
self.delay.unify(other.delay)
elif isinstance(other, TVar):
other.unify(self)
else:
@@ -261,7 +263,7 @@ class TRPCFunction(TFunction):

def __init__(self, args, optargs, ret, service):
super().__init__(args, optargs, ret,
delay=iodelay.Fixed(iodelay.Constant(0)))
delay=FixedDelay(iodelay.Constant(0)))
self.service = service

def unify(self, other):
@@ -284,7 +286,7 @@ class TCFunction(TFunction):

def __init__(self, args, ret, name):
super().__init__(args, OrderedDict(), ret,
delay=iodelay.Fixed(iodelay.Constant(0)))
delay=FixedDelay(iodelay.Constant(0)))
self.name = name

def unify(self, other):
@@ -418,6 +420,63 @@ def __eq__(self, other):
def __ne__(self, other):
return not (self == other)

class TDelay(Type):
"""
The type-level representation of IO delay.
"""

def __init__(self, duration, cause):
assert duration is None or isinstance(duration, iodelay.Expr)
assert cause is None or isinstance(cause, diagnostic.Diagnostic)
assert (not (duration and cause)) and (duration or cause)
self.duration, self.cause = duration, cause

def is_fixed(self):
return self.duration is not None

def is_indeterminate(self):
return self.cause is not None

def find(self):
return self

def unify(self, other):
other = other.find()

if self.is_fixed() and other.is_fixed() and \
self.duration.fold() == other.duration.fold():
pass
elif isinstance(other, TVar):
other.unify(self)
else:
raise UnificationError(self, other)

def fold(self, accum, fn):
# delay types do not participate in folding
pass

def __eq__(self, other):
return isinstance(other, TDelay) and \
(self.duration == other.duration and \
self.cause == other.cause)

def __ne__(self, other):
return not (self == other)

def __repr__(self):
if self.duration is None:
return "<{}.TIndeterminateDelay>".format(__name__)
elif self.cause is None:
return "{}.TFixedDelay({})".format(__name__, self.duration)
else:
assert False

def TIndeterminateDelay(cause):
return TDelay(None, cause)

def TFixedDelay(duration):
return TDelay(duration, None)


def is_var(typ):
return isinstance(typ.find(), TVar)
@@ -511,6 +570,16 @@ def get_value(typ):
else:
assert False

def is_delay(typ):
return isinstance(typ.find(), TDelay)

def is_fixed_delay(typ):
return is_delay(typ) and typ.find().is_fixed()

def is_indeterminate_delay(typ):
return is_delay(typ) and typ.find().is_indeterminate()


class TypePrinter(object):
"""
A class that prints types using Python-like syntax and gives
@@ -553,14 +622,10 @@ def name(self, typ):
args += ["?%s:%s" % (arg, self.name(typ.optargs[arg])) for arg in typ.optargs]
signature = "(%s)->%s" % (", ".join(args), self.name(typ.ret))

if iodelay.is_unknown(typ.delay) or iodelay.is_fixed(typ.delay, 0):
pass
elif iodelay.is_fixed(typ.delay):
signature += " delay({} mu)".format(typ.delay.length)
elif iodelay.is_indeterminate(typ.delay):
signature += " delay(?)"
else:
assert False
delay = typ.delay.find()
if not (isinstance(delay, TVar) or
delay.is_fixed() and iodelay.is_zero(delay.duration)):
signature += " " + self.name(delay)

if isinstance(typ, TRPCFunction):
return "rpc({}) {}".format(typ.service, signature)
@@ -580,5 +645,12 @@ def name(self, typ):
return "<constructor {} {{{}}}>".format(typ.name, attrs)
elif isinstance(typ, TValue):
return repr(typ.value)
elif isinstance(typ, TDelay):
if typ.is_fixed():
return "delay({} mu)".format(typ.duration)
elif typ.is_indeterminate():
return "delay(?)"
else:
assert False
else:
assert False
1 change: 1 addition & 0 deletions artiq/coredevice/dds.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from artiq.language.core import *
from artiq.language.types import *
from artiq.language.units import *


Binary file removed lit-test/libartiq_support/libartiq_support.so
Binary file not shown.
11 changes: 11 additions & 0 deletions lit-test/test/iodelay/error_unify.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# RUN: %python -m artiq.compiler.testbench.signature +diag +delay %s >%t
# RUN: OutputCheck %s --file-to-check=%t

def f():
delay_mu(10)

# CHECK-L: ${LINE:+1}: fatal: delay delay(20 mu) was inferred for this function, but its delay is already constrained externally to delay(10 mu)
def g():
delay_mu(20)

x = f if True else g
3 changes: 2 additions & 1 deletion lit-test/test/iodelay/return.py
Original file line number Diff line number Diff line change
@@ -7,7 +7,8 @@ def f():
delay(1.5)
return 10

# CHECK-L: g: (x:float)->int(width=32) delay(0 mu)
# CHECK-L: g: (x:float)->int(width=32)
# CHECK-NOT-L: delay
def g(x):
if x > 1.0:
return 1