forked from M-Labs/artiq
transforms.iodelay_estimator: fail statements with indeterminate delay inside `with parallel`.
This commit is contained in:
parent
28fa68730a
commit
88b7990714
|
@ -10,6 +10,10 @@ from .. import types, iodelay, builtins, asttyped
|
||||||
class _UnknownDelay(Exception):
|
class _UnknownDelay(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class _IndeterminateDelay(Exception):
|
||||||
|
def __init__(self, cause):
|
||||||
|
self.cause = cause
|
||||||
|
|
||||||
class IODelayEstimator(algorithm.Visitor):
|
class IODelayEstimator(algorithm.Visitor):
|
||||||
def __init__(self, engine, ref_period):
|
def __init__(self, engine, ref_period):
|
||||||
self.engine = engine
|
self.engine = engine
|
||||||
|
@ -69,7 +73,7 @@ class IODelayEstimator(algorithm.Visitor):
|
||||||
|
|
||||||
def abort(self, message, loc, notes=[]):
|
def abort(self, message, loc, notes=[]):
|
||||||
diag = diagnostic.Diagnostic("error", message, {}, loc, notes=notes)
|
diag = diagnostic.Diagnostic("error", message, {}, loc, notes=notes)
|
||||||
raise diagnostic.Error(diag)
|
raise _IndeterminateDelay(diag)
|
||||||
|
|
||||||
def visit_fixpoint(self, node):
|
def visit_fixpoint(self, node):
|
||||||
while True:
|
while True:
|
||||||
|
@ -85,7 +89,7 @@ class IODelayEstimator(algorithm.Visitor):
|
||||||
self.visit(stmt)
|
self.visit(stmt)
|
||||||
except _UnknownDelay:
|
except _UnknownDelay:
|
||||||
pass # more luck next time?
|
pass # more luck next time?
|
||||||
except diagnostic.Error:
|
except _IndeterminateDelay:
|
||||||
pass # we don't care; module-level code is never interleaved
|
pass # we don't care; module-level code is never interleaved
|
||||||
|
|
||||||
def visit_function(self, args, body, typ, loc):
|
def visit_function(self, args, body, typ, loc):
|
||||||
|
@ -99,8 +103,8 @@ class IODelayEstimator(algorithm.Visitor):
|
||||||
"can be interleaved", self.current_return.loc)
|
"can be interleaved", self.current_return.loc)
|
||||||
|
|
||||||
delay = types.TFixedDelay(self.current_delay.fold())
|
delay = types.TFixedDelay(self.current_delay.fold())
|
||||||
except diagnostic.Error as error:
|
except _IndeterminateDelay as error:
|
||||||
delay = types.TIndeterminateDelay(error.diagnostic)
|
delay = types.TIndeterminateDelay(error.cause)
|
||||||
self.current_delay = old_delay
|
self.current_delay = old_delay
|
||||||
self.current_return = old_return
|
self.current_return = old_return
|
||||||
self.current_args = old_args
|
self.current_args = old_args
|
||||||
|
@ -208,14 +212,21 @@ class IODelayEstimator(algorithm.Visitor):
|
||||||
|
|
||||||
context_expr = node.items[0].context_expr
|
context_expr = node.items[0].context_expr
|
||||||
if len(node.items) == 1 and types.is_builtin(context_expr.type, "parallel"):
|
if len(node.items) == 1 and types.is_builtin(context_expr.type, "parallel"):
|
||||||
delays = []
|
try:
|
||||||
for stmt in node.body:
|
delays = []
|
||||||
old_delay, self.current_delay = self.current_delay, iodelay.Const(0)
|
for stmt in node.body:
|
||||||
self.visit(stmt)
|
old_delay, self.current_delay = self.current_delay, iodelay.Const(0)
|
||||||
delays.append(self.current_delay)
|
self.visit(stmt)
|
||||||
self.current_delay = old_delay
|
delays.append(self.current_delay)
|
||||||
|
self.current_delay = old_delay
|
||||||
|
|
||||||
|
self.current_delay += iodelay.Max(delays)
|
||||||
|
except _IndeterminateDelay as error:
|
||||||
|
# Interleave failures inside `with` statements are hard failures,
|
||||||
|
# since there's no chance that the code will never actually execute
|
||||||
|
# inside a `with` statement after all.
|
||||||
|
self.engine.process(error.cause)
|
||||||
|
|
||||||
self.current_delay += iodelay.Max(delays)
|
|
||||||
elif len(node.items) == 1 and types.is_builtin(context_expr.type, "sequential"):
|
elif len(node.items) == 1 and types.is_builtin(context_expr.type, "sequential"):
|
||||||
self.visit(node.body)
|
self.visit(node.body)
|
||||||
else:
|
else:
|
||||||
|
@ -247,13 +258,14 @@ class IODelayEstimator(algorithm.Visitor):
|
||||||
if types.is_var(delay):
|
if types.is_var(delay):
|
||||||
raise _UnknownDelay()
|
raise _UnknownDelay()
|
||||||
elif delay.is_indeterminate():
|
elif delay.is_indeterminate():
|
||||||
cause = delay.cause
|
|
||||||
note = diagnostic.Diagnostic("note",
|
note = diagnostic.Diagnostic("note",
|
||||||
"function called here", {},
|
"function called here", {},
|
||||||
node.loc)
|
node.loc)
|
||||||
diag = diagnostic.Diagnostic(cause.level, cause.reason, cause.arguments,
|
cause = delay.cause
|
||||||
cause.location, cause.highlights, cause.notes + [note])
|
cause = diagnostic.Diagnostic(cause.level, cause.reason, cause.arguments,
|
||||||
raise diagnostic.Error(diag)
|
cause.location, cause.highlights,
|
||||||
|
cause.notes + [note])
|
||||||
|
raise _IndeterminateDelay(cause)
|
||||||
elif delay.is_fixed():
|
elif delay.is_fixed():
|
||||||
args = {}
|
args = {}
|
||||||
for kw_node in node.keywords:
|
for kw_node in node.keywords:
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
# RUN: %python -m artiq.compiler.testbench.signature +diag %s >%t
|
||||||
|
# RUN: OutputCheck %s --file-to-check=%t
|
||||||
|
|
||||||
|
def f():
|
||||||
|
with parallel:
|
||||||
|
# CHECK-L: ${LINE:+1}: error: while statement cannot be interleaved
|
||||||
|
while True:
|
||||||
|
delay_mu(1)
|
Loading…
Reference in New Issue