forked from M-Labs/artiq
compiler: implement 'with watchdog' support.
This commit is contained in:
parent
64f19b84f2
commit
2d906daf7f
|
@ -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")
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)},
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
|
@ -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()
|
Loading…
Reference in New Issue