compiler: implement 'with watchdog' support.

This commit is contained in:
whitequark 2015-12-10 23:11:00 +08:00
parent 64f19b84f2
commit 2d906daf7f
8 changed files with 104 additions and 2 deletions

View File

@ -150,6 +150,9 @@ def obj_parallel():
def obj_sequential():
return types.TBuiltin("sequential")
def fn_watchdog():
return types.TBuiltinFunction("watchdog")
def fn_now():
return types.TBuiltinFunction("now")

View File

@ -31,6 +31,7 @@ def globals():
# ARTIQ context managers
"parallel": builtins.obj_parallel(),
"sequential": builtins.obj_sequential(),
"watchdog": builtins.fn_watchdog(),
# ARTIQ time management functions
"now": builtins.fn_now(),

View File

@ -714,6 +714,32 @@ class ARTIQIRGenerator(algorithm.Visitor):
for tail in tails:
if not tail.is_terminated():
tail.append(ir.Branch(self.current_block))
elif isinstance(context_expr_node, asttyped.CallT) and \
types.is_builtin(context_expr_node.func.type, "watchdog"):
timeout = self.visit(context_expr_node.args[0])
timeout_ms = self.append(ir.Arith(ast.Mult(loc=None), timeout,
ir.Constant(1000, builtins.TFloat())))
timeout_ms_int = self.append(ir.Coerce(timeout_ms, builtins.TInt32()))
watchdog = self.append(ir.Builtin("watchdog_set", [timeout_ms_int], builtins.TInt32()))
dispatcher = self.add_block("watchdog.dispatch")
try:
old_unwind, self.unwind_target = self.unwind_target, dispatcher
self.visit(node.body)
finally:
self.unwind_target = old_unwind
cleanup = self.add_block('watchdog.cleanup')
landingpad = dispatcher.append(ir.LandingPad(cleanup))
cleanup.append(ir.Builtin("watchdog_clear", [watchdog], builtins.TNone()))
cleanup.append(ir.Reraise(self.unwind_target))
if not self.current_block.is_terminated():
self.append(ir.Builtin("watchdog_clear", [watchdog], builtins.TNone()))
else:
assert False
# Expression visitors
# These visitors return a node in addition to mutating
@ -1551,7 +1577,11 @@ class ARTIQIRGenerator(algorithm.Visitor):
elif types.is_constructor(typ):
return self.append(ir.Alloc([], typ.instance))
else:
assert False
diag = diagnostic.Diagnostic("error",
"builtin function '{name}' cannot be used in this context",
{"name": typ.name},
node.loc)
self.engine.process(diag)
def visit_CallT(self, node):
typ = node.func.type.find()

View File

@ -757,6 +757,9 @@ class Inferencer(algorithm.Visitor):
elif types.is_builtin(typ, "seconds_to_mu"):
simple_form("seconds_to_mu(time:float) -> int(width=64)",
[builtins.TFloat()], builtins.TInt64())
elif types.is_builtin(typ, "watchdog"):
simple_form("watchdog(time:float) -> [builtin context manager]",
[builtins.TFloat()], builtins.TNone())
elif types.is_constructor(typ):
# An user-defined class.
self._unify(node.type, typ.find().instance,
@ -942,7 +945,10 @@ class Inferencer(algorithm.Visitor):
self.generic_visit(node)
typ = node.context_expr.type
if not (types.is_builtin(typ, "parallel") or types.is_builtin(typ, "sequential")):
if not (types.is_builtin(typ, "parallel") or
types.is_builtin(typ, "sequential") or
(isinstance(node.context_expr, asttyped.CallT) and
types.is_builtin(node.context_expr.func.type, "watchdog"))):
diag = diagnostic.Diagnostic("error",
"value of type {type} cannot act as a context manager",
{"type": types.TypePrinter().name(typ)},

View File

@ -369,6 +369,10 @@ class LLVMIRGenerator:
llty = ll.FunctionType(lli32, [llptr])
elif name == "now":
llty = lli64
elif name == "watchdog_set":
llty = ll.FunctionType(lli32, [lli32])
elif name == "watchdog_clear":
llty = ll.FunctionType(llvoid, [lli32])
else:
assert False
@ -793,6 +797,12 @@ class LLVMIRGenerator:
llnow = self.llbuilder.load(llnowptr)
lladjusted = self.llbuilder.add(llnow, self.map(interval))
return self.llbuilder.store(lladjusted, llnowptr)
elif insn.op == "watchdog_set":
interval, = insn.operands
return self.llbuilder.call(self.llbuiltin("watchdog_set"), [self.map(interval)])
elif insn.op == "watchdog_clear":
id, = insn.operands
return self.llbuilder.call(self.llbuiltin("watchdog_clear"), [self.map(id)])
else:
assert False

View File

@ -1,3 +1,15 @@
#include <stdint.h>
#include <stdio.h>
int64_t now = 0;
int watchdog_set(int ms)
{
printf("watchdog_set %d\n", ms);
return ms;
}
void watchdog_clear(int id)
{
printf("watchdog_clear %d\n", id);
}

View File

@ -0,0 +1,5 @@
# RUN: %python -m artiq.compiler.testbench.signature +diag %s >%t
# RUN: OutputCheck %s --file-to-check=%t
# CHECK-L: ${LINE:+1}: error: builtin function 'watchdog' cannot be used in this context
watchdog(1.0)

View File

@ -0,0 +1,35 @@
# RUN: %python -m artiq.compiler.testbench.jit %s >%t
# RUN: OutputCheck %s --file-to-check=%t
def f():
with watchdog(1.0):
pass
def g():
with watchdog(2.0):
raise Exception()
def h():
try:
g()
except:
pass
def i():
try:
with watchdog(3.0):
raise Exception()
except:
pass
# CHECK-L: watchdog_set 1000
# CHECK-L: watchdog_clear 1000
f()
# CHECK-L: watchdog_set 2000
# CHECK-L: watchdog_clear 2000
h()
# CHECK-L: watchdog_set 3000
# CHECK-L: watchdog_clear 3000
i()