transforms.iodelay_estimator: fail statements with indeterminate delay inside `with parallel`.

This commit is contained in:
whitequark 2015-11-20 17:10:25 +08:00
parent 28fa68730a
commit 88b7990714
2 changed files with 35 additions and 15 deletions

View File

@ -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,6 +212,7 @@ 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"):
try:
delays = [] delays = []
for stmt in node.body: for stmt in node.body:
old_delay, self.current_delay = self.current_delay, iodelay.Const(0) old_delay, self.current_delay = self.current_delay, iodelay.Const(0)
@ -216,6 +221,12 @@ class IODelayEstimator(algorithm.Visitor):
self.current_delay = old_delay self.current_delay = old_delay
self.current_delay += iodelay.Max(delays) 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)
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:

View File

@ -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)