Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: ccc993071b36
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2d906daf7f48
Choose a head ref
  • 6 commits
  • 11 files changed
  • 1 contributor

Commits on Dec 10, 2015

  1. Revert "transforms.artiq_ir_generator: treat builtins in 'with' synta…

    …ctically."
    
    This reverts commit ccc9930.
    whitequark committed Dec 10, 2015
    Copy the full SHA
    3ec9b67 View commit details
  2. Copy the full SHA
    c660028 View commit details
  3. compiler.builtins: {fn→obj}_{serial,parallel}.

    whitequark committed Dec 10, 2015
    Copy the full SHA
    143bae4 View commit details
  4. compiler: refactor to use builtins.TInt{32,64}. (NFC)

    whitequark committed Dec 10, 2015
    Copy the full SHA
    4888e89 View commit details
  5. compiler.testbench.llvmgen: fix.

    whitequark committed Dec 10, 2015
    Copy the full SHA
    64f19b8 View commit details
  6. compiler: implement 'with watchdog' support.

    whitequark committed Dec 10, 2015
    Copy the full SHA
    2d906da View commit details
11 changes: 7 additions & 4 deletions artiq/compiler/builtins.py
Original file line number Diff line number Diff line change
@@ -144,11 +144,14 @@ def fn_print():
def fn_kernel():
return types.TBuiltinFunction("kernel")

def fn_parallel():
return types.TBuiltinFunction("parallel")
def obj_parallel():
return types.TBuiltin("parallel")

def fn_sequential():
return types.TBuiltinFunction("sequential")
def obj_sequential():
return types.TBuiltin("sequential")

def fn_watchdog():
return types.TBuiltinFunction("watchdog")

def fn_now():
return types.TBuiltinFunction("now")
4 changes: 2 additions & 2 deletions artiq/compiler/embedding.py
Original file line number Diff line number Diff line change
@@ -122,10 +122,10 @@ def quote(self, value):
else:
instance_type = types.TInstance("{}.{}".format(typ.__module__, typ.__qualname__),
OrderedDict())
instance_type.attributes['__objectid__'] = builtins.TInt(types.TValue(32))
instance_type.attributes['__objectid__'] = builtins.TInt32()

constructor_type = types.TConstructor(instance_type)
constructor_type.attributes['__objectid__'] = builtins.TInt(types.TValue(32))
constructor_type.attributes['__objectid__'] = builtins.TInt32()
instance_type.constructor = constructor_type

self.type_map[typ] = instance_type, constructor_type
5 changes: 3 additions & 2 deletions artiq/compiler/prelude.py
Original file line number Diff line number Diff line change
@@ -29,8 +29,9 @@ def globals():
"kernel": builtins.fn_kernel(),

# ARTIQ context managers
"parallel": builtins.fn_parallel(),
"sequential": builtins.fn_sequential(),
"parallel": builtins.obj_parallel(),
"sequential": builtins.obj_sequential(),
"watchdog": builtins.fn_watchdog(),

# ARTIQ time management functions
"now": builtins.fn_now(),
3 changes: 2 additions & 1 deletion artiq/compiler/testbench/llvmgen.py
Original file line number Diff line number Diff line change
@@ -21,7 +21,8 @@ def process_diagnostic(diag):
# Add main so that the result can be executed with lli
llmain = ll.Function(llmod, ll.FunctionType(ll.VoidType(), []), "main")
llbuilder = ll.IRBuilder(llmain.append_basic_block("entry"))
llbuilder.call(llmod.get_global(llmod.name + ".__modinit__"), [])
llbuilder.call(llmod.get_global(llmod.name + ".__modinit__"), [
ll.Constant(ll.IntType(8).as_pointer(), None)])
llbuilder.ret_void()

print(llmod)
57 changes: 41 additions & 16 deletions artiq/compiler/transforms/artiq_ir_generator.py
Original file line number Diff line number Diff line change
@@ -80,7 +80,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
the called function inside a translated :class:`ast.CallT` node
"""

_size_type = builtins.TInt(types.TValue(32))
_size_type = builtins.TInt32()

def __init__(self, module_name, engine, ref_period):
self.engine = engine
@@ -542,8 +542,8 @@ def raise_exn(self, exn, loc=None):
loc = self.current_loc

loc_file = ir.Constant(loc.source_buffer.name, builtins.TStr())
loc_line = ir.Constant(loc.line(), builtins.TInt(types.TValue(32)))
loc_column = ir.Constant(loc.column(), builtins.TInt(types.TValue(32)))
loc_line = ir.Constant(loc.line(), builtins.TInt32())
loc_column = ir.Constant(loc.column(), builtins.TInt32())
loc_function = ir.Constant(".".join(self.name), builtins.TStr())

self.append(ir.SetAttr(exn, "__file__", loc_file))
@@ -695,11 +695,9 @@ def visit_With(self, node):
context_expr_node = node.items[0].context_expr
optional_vars_node = node.items[0].optional_vars

if isinstance(context_expr_node, asttyped.NameT) and \
context_expr_node.id == "sequential":
if types.is_builtin(context_expr_node.type, "sequential"):
self.visit(node.body)
elif isinstance(context_expr_node, asttyped.NameT) and \
context_expr_node.id == "parallel":
elif types.is_builtin(context_expr_node.type, "parallel"):
parallel = self.append(ir.Parallel([]))

heads, tails = [], []
@@ -716,7 +714,30 @@ def visit_With(self, node):
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

@@ -1402,8 +1423,8 @@ def alloc_exn(self, typ, message=None, param0=None, param1=None, param2=None):
attributes = [
ir.Constant(typ.find().name, ir.TExceptionTypeInfo()), # typeinfo
ir.Constant("<not thrown>", builtins.TStr()), # file
ir.Constant(0, builtins.TInt(types.TValue(32))), # line
ir.Constant(0, builtins.TInt(types.TValue(32))), # column
ir.Constant(0, builtins.TInt32()), # line
ir.Constant(0, builtins.TInt32()), # column
ir.Constant("<not thrown>", builtins.TStr()), # function
]

@@ -1412,10 +1433,10 @@ def alloc_exn(self, typ, message=None, param0=None, param1=None, param2=None):
else:
attributes.append(message) # message

param_type = builtins.TInt(types.TValue(64))
param_type = builtins.TInt64()
for param in [param0, param1, param2]:
if param is None:
attributes.append(ir.Constant(0, builtins.TInt(types.TValue(64))))
attributes.append(ir.Constant(0, builtins.TInt64()))
else:
if param.type != param_type:
param = self.append(ir.Coerce(param, param_type))
@@ -1455,7 +1476,7 @@ def visit_builtin_call(self, node):
assert False
elif types.is_builtin(typ, "list"):
if len(node.args) == 0 and len(node.keywords) == 0:
length = ir.Constant(0, builtins.TInt(types.TValue(32)))
length = ir.Constant(0, builtins.TInt32())
return self.append(ir.Alloc([length], node.type))
elif len(node.args) == 1 and len(node.keywords) == 0:
arg = self.visit(node.args[0])
@@ -1520,7 +1541,7 @@ def body_gen(index):
return ir.Constant(None, builtins.TNone())
elif types.is_builtin(typ, "now"):
if len(node.args) == 0 and len(node.keywords) == 0:
now_mu = self.append(ir.Builtin("now_mu", [], builtins.TInt(types.TValue(64))))
now_mu = self.append(ir.Builtin("now_mu", [], builtins.TInt64()))
now_mu_float = self.append(ir.Coerce(now_mu, builtins.TFloat()))
return self.append(ir.Arith(ast.Mult(loc=None), now_mu_float, self.ref_period))
else:
@@ -1529,7 +1550,7 @@ def body_gen(index):
if len(node.args) == 1 and len(node.keywords) == 0:
arg = self.visit(node.args[0])
arg_mu_float = self.append(ir.Arith(ast.Div(loc=None), arg, self.ref_period))
arg_mu = self.append(ir.Coerce(arg_mu_float, builtins.TInt(types.TValue(64))))
arg_mu = self.append(ir.Coerce(arg_mu_float, builtins.TInt64()))
return self.append(ir.Builtin(typ.name + "_mu", [arg_mu], builtins.TNone()))
else:
assert False
@@ -1548,15 +1569,19 @@ def body_gen(index):
if len(node.args) == 1 and len(node.keywords) == 0:
arg = self.visit(node.args[0])
arg_mu = self.append(ir.Arith(ast.Div(loc=None), arg, self.ref_period))
return self.append(ir.Coerce(arg_mu, builtins.TInt(types.TValue(64))))
return self.append(ir.Coerce(arg_mu, builtins.TInt64()))
else:
assert False
elif types.is_exn_constructor(typ):
return self.alloc_exn(node.type, *[self.visit(arg_node) for arg_node in node.args])
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()
28 changes: 15 additions & 13 deletions artiq/compiler/transforms/inferencer.py
Original file line number Diff line number Diff line change
@@ -540,7 +540,7 @@ def simple_form(info, arg_types=[], return_type=builtins.TNone()):
self._unify(message.type, builtins.TStr(),
message.loc, None)
for param in params:
self._unify(param.type, builtins.TInt(types.TValue(64)),
self._unify(param.type, builtins.TInt64(),
param.loc, None)
else:
diagnose(valid_forms())
@@ -690,7 +690,7 @@ def makenotes(printer, typea, typeb, loca, locb):
node.loc, None)
elif builtins.is_list(arg.type):
# TODO: should be ssize_t-sized
self._unify(node.type, builtins.TInt(types.TValue(32)),
self._unify(node.type, builtins.TInt32(),
node.loc, None)
elif types.is_var(arg.type):
pass # undetermined yet
@@ -744,29 +744,28 @@ def makenotes(printer, typea, typeb, loca, locb):
[builtins.TFloat()])
elif types.is_builtin(typ, "now_mu"):
simple_form("now_mu() -> int(width=64)",
[], builtins.TInt(types.TValue(64)))
[], builtins.TInt64())
elif types.is_builtin(typ, "delay_mu"):
simple_form("delay_mu(time_mu:int(width=64)) -> None",
[builtins.TInt(types.TValue(64))])
[builtins.TInt64()])
elif types.is_builtin(typ, "at_mu"):
simple_form("at_mu(time_mu:int(width=64)) -> None",
[builtins.TInt(types.TValue(64))])
[builtins.TInt64()])
elif types.is_builtin(typ, "mu_to_seconds"):
simple_form("mu_to_seconds(time_mu:int(width=64)) -> float",
[builtins.TInt(types.TValue(64))], builtins.TFloat())
[builtins.TInt64()], builtins.TFloat())
elif types.is_builtin(typ, "seconds_to_mu"):
simple_form("seconds_to_mu(time:float) -> int(width=64)",
[builtins.TFloat()], builtins.TInt(types.TValue(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,
node.loc, None)
else:
diag = diagnostic.Diagnostic("error",
"builtin function '{name}' cannot be used in this context",
{"name": typ.name},
node.loc)
self.engine.process(diag)
assert False

def visit_CallT(self, node):
self.generic_visit(node)
@@ -946,7 +945,10 @@ def visit_withitem(self, node):
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)},
27 changes: 18 additions & 9 deletions artiq/compiler/transforms/llvm_ir_generator.py
Original file line number Diff line number Diff line change
@@ -369,6 +369,10 @@ def llbuiltin(self, name):
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 @@ def get_outer(llenv, env_ty):
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

@@ -1093,30 +1103,29 @@ def process_Return(self, insn):
def process_Unreachable(self, insn):
return self.llbuilder.unreachable()

def process_Raise(self, insn):
llexn = self.map(insn.value())
def _gen_raise(self, insn, func, args):
if insn.exception_target() is not None:
llnormalblock = self.llfunction.append_basic_block("unreachable")
llnormalblock.terminator = ll.Unreachable(llnormalblock)
llnormalblock.instructions.append(llnormalblock.terminator)

llunwindblock = self.map(insn.exception_target())
llinsn = self.llbuilder.invoke(self.llbuiltin("__artiq_raise"), [llexn],
llinsn = self.llbuilder.invoke(func, args,
llnormalblock, llunwindblock,
name=insn.name)
else:
llinsn = self.llbuilder.call(self.llbuiltin("__artiq_raise"), [llexn],
llinsn = self.llbuilder.call(func, args,
name=insn.name)
self.llbuilder.unreachable()
llinsn.attributes.add('noreturn')
return llinsn

def process_Raise(self, insn):
llexn = self.map(insn.value())
return self._gen_raise(insn, self.llbuiltin("__artiq_raise"), [llexn])

def process_Reraise(self, insn):
llinsn = self.llbuilder.call(self.llbuiltin("__artiq_reraise"), [],
name=insn.name)
llinsn.attributes.add('noreturn')
self.llbuilder.unreachable()
return llinsn
return self._gen_raise(insn, self.llbuiltin("__artiq_reraise"), [])

def process_LandingPad(self, insn):
# Layout on return from landing pad: {%_Unwind_Exception*, %Exception*}
12 changes: 12 additions & 0 deletions lit-test/libartiq_support/artiq_time.c
Original file line number Diff line number Diff line change
@@ -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);
}
5 changes: 5 additions & 0 deletions lit-test/test/codegen/error_illegal_builtin.py
Original file line number Diff line number Diff line change
@@ -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)
5 changes: 0 additions & 5 deletions lit-test/test/inferencer/error_illegal_builtin.py

This file was deleted.

35 changes: 35 additions & 0 deletions lit-test/test/time/watchdog.py
Original file line number Diff line number Diff line change
@@ -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()