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():
|
def obj_sequential():
|
||||||
return types.TBuiltin("sequential")
|
return types.TBuiltin("sequential")
|
||||||
|
|
||||||
|
def fn_watchdog():
|
||||||
|
return types.TBuiltinFunction("watchdog")
|
||||||
|
|
||||||
def fn_now():
|
def fn_now():
|
||||||
return types.TBuiltinFunction("now")
|
return types.TBuiltinFunction("now")
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ def globals():
|
||||||
# ARTIQ context managers
|
# ARTIQ context managers
|
||||||
"parallel": builtins.obj_parallel(),
|
"parallel": builtins.obj_parallel(),
|
||||||
"sequential": builtins.obj_sequential(),
|
"sequential": builtins.obj_sequential(),
|
||||||
|
"watchdog": builtins.fn_watchdog(),
|
||||||
|
|
||||||
# ARTIQ time management functions
|
# ARTIQ time management functions
|
||||||
"now": builtins.fn_now(),
|
"now": builtins.fn_now(),
|
||||||
|
|
|
@ -714,6 +714,32 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
for tail in tails:
|
for tail in tails:
|
||||||
if not tail.is_terminated():
|
if not tail.is_terminated():
|
||||||
tail.append(ir.Branch(self.current_block))
|
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
|
# Expression visitors
|
||||||
# These visitors return a node in addition to mutating
|
# These visitors return a node in addition to mutating
|
||||||
|
@ -1551,7 +1577,11 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
elif types.is_constructor(typ):
|
elif types.is_constructor(typ):
|
||||||
return self.append(ir.Alloc([], typ.instance))
|
return self.append(ir.Alloc([], typ.instance))
|
||||||
else:
|
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):
|
def visit_CallT(self, node):
|
||||||
typ = node.func.type.find()
|
typ = node.func.type.find()
|
||||||
|
|
|
@ -757,6 +757,9 @@ class Inferencer(algorithm.Visitor):
|
||||||
elif types.is_builtin(typ, "seconds_to_mu"):
|
elif types.is_builtin(typ, "seconds_to_mu"):
|
||||||
simple_form("seconds_to_mu(time:float) -> int(width=64)",
|
simple_form("seconds_to_mu(time:float) -> int(width=64)",
|
||||||
[builtins.TFloat()], builtins.TInt64())
|
[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):
|
elif types.is_constructor(typ):
|
||||||
# An user-defined class.
|
# An user-defined class.
|
||||||
self._unify(node.type, typ.find().instance,
|
self._unify(node.type, typ.find().instance,
|
||||||
|
@ -942,7 +945,10 @@ class Inferencer(algorithm.Visitor):
|
||||||
self.generic_visit(node)
|
self.generic_visit(node)
|
||||||
|
|
||||||
typ = node.context_expr.type
|
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",
|
diag = diagnostic.Diagnostic("error",
|
||||||
"value of type {type} cannot act as a context manager",
|
"value of type {type} cannot act as a context manager",
|
||||||
{"type": types.TypePrinter().name(typ)},
|
{"type": types.TypePrinter().name(typ)},
|
||||||
|
|
|
@ -369,6 +369,10 @@ class LLVMIRGenerator:
|
||||||
llty = ll.FunctionType(lli32, [llptr])
|
llty = ll.FunctionType(lli32, [llptr])
|
||||||
elif name == "now":
|
elif name == "now":
|
||||||
llty = lli64
|
llty = lli64
|
||||||
|
elif name == "watchdog_set":
|
||||||
|
llty = ll.FunctionType(lli32, [lli32])
|
||||||
|
elif name == "watchdog_clear":
|
||||||
|
llty = ll.FunctionType(llvoid, [lli32])
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
@ -793,6 +797,12 @@ class LLVMIRGenerator:
|
||||||
llnow = self.llbuilder.load(llnowptr)
|
llnow = self.llbuilder.load(llnowptr)
|
||||||
lladjusted = self.llbuilder.add(llnow, self.map(interval))
|
lladjusted = self.llbuilder.add(llnow, self.map(interval))
|
||||||
return self.llbuilder.store(lladjusted, llnowptr)
|
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:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
int64_t now = 0;
|
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