Skip to content

Commit

Permalink
Merge branch 'master' into drtio
Browse files Browse the repository at this point in the history
sbourdeauducq committed Nov 22, 2016
2 parents 02adae7 + ef971ef commit 3459793
Showing 69 changed files with 871 additions and 1,000 deletions.
6 changes: 6 additions & 0 deletions RELEASE_NOTES.rst
Original file line number Diff line number Diff line change
@@ -16,6 +16,12 @@ Release notes
* Datasets requested by experiments are by default archived into their HDF5
output. If this behavior is undesirable, turn it off by passing
``archive=False`` to ``get_dataset``.
* ``seconds_to_mu`` and ``mu_to_seconds`` have become methods of the core
device driver (use e.g. ``self.core.seconds_to_mu()``).
* AD9858 DDSes and NIST QC1 hardware are no longer supported.
* The Pipistrello port now has exclusively TTLs.
* The DDS class names and setup options have changed, this requires an update of
the device database.


2.0
1 change: 1 addition & 0 deletions artiq/compiler/analyses/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .constness import Constness
from .domination import DominatorTree
from .devirtualization import Devirtualization
from .invariant_detection import InvariantDetection
6 changes: 6 additions & 0 deletions artiq/compiler/analyses/constness.py
Original file line number Diff line number Diff line change
@@ -17,6 +17,12 @@ def visit_Assign(self, node):
self.visit(node.targets)
self.in_assign = False

def visit_SubscriptT(self, node):
old_in_assign, self.in_assign = self.in_assign, False
self.visit(node.value)
self.visit(node.slice)
self.in_assign = old_in_assign

def visit_AttributeT(self, node):
self.generic_visit(node)
if self.in_assign:
49 changes: 49 additions & 0 deletions artiq/compiler/analyses/invariant_detection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""
:class:`InvariantDetection` determines which attributes can be safely
marked kernel invariant.
"""

from pythonparser import diagnostic
from .. import ir, types

class InvariantDetection:
def __init__(self, engine):
self.engine = engine

def process(self, functions):
self.attr_locs = dict()
self.attr_written = set()

for func in functions:
self.process_function(func)

for key in self.attr_locs:
if key not in self.attr_written:
typ, attr = key
if attr in typ.constant_attributes:
continue

diag = diagnostic.Diagnostic("note",
"attribute '{attr}' of type '{type}' is never written to; " +
"it could be marked as kernel invariant to potentially increase performance",
{"attr": attr,
"type": typ.name},
self.attr_locs[key])
self.engine.process(diag)

def process_function(self, func):
for block in func.basic_blocks:
for insn in block.instructions:
if not isinstance(insn, (ir.GetAttr, ir.SetAttr)):
continue
if not types.is_instance(insn.object().type):
continue

key = (insn.object().type, insn.attr)
if isinstance(insn, ir.GetAttr):
if types.is_method(insn.type):
continue
if key not in self.attr_locs and insn.loc is not None:
self.attr_locs[key] = insn.loc
elif isinstance(insn, ir.SetAttr):
self.attr_written.add(key)
10 changes: 2 additions & 8 deletions artiq/compiler/builtins.py
Original file line number Diff line number Diff line change
@@ -126,10 +126,10 @@ def fn_int():
return types.TConstructor(TInt())

def fn_int32():
return types.TConstructor(TInt32())
return types.TBuiltinFunction("int32")

def fn_int64():
return types.TConstructor(TInt64())
return types.TBuiltinFunction("int64")

def fn_float():
return types.TConstructor(TFloat())
@@ -203,12 +203,6 @@ def fn_delay_mu():
def fn_at_mu():
return types.TBuiltinFunction("at_mu")

def fn_mu_to_seconds():
return types.TBuiltinFunction("mu_to_seconds")

def fn_seconds_to_mu():
return types.TBuiltinFunction("seconds_to_mu")

def fn_rtio_log():
return types.TBuiltinFunction("rtio_log")

9 changes: 7 additions & 2 deletions artiq/compiler/module.py
Original file line number Diff line number Diff line change
@@ -40,7 +40,8 @@ def from_filename(cls, filename, engine=None):
return cls(source.Buffer(f.read(), filename, 1), engine=engine)

class Module:
def __init__(self, src, ref_period=1e-6):
def __init__(self, src, ref_period=1e-6, attribute_writeback=True, remarks=True):
self.attribute_writeback = attribute_writeback
self.engine = src.engine
self.embedding_map = src.embedding_map
self.name = src.name
@@ -60,6 +61,7 @@ def __init__(self, src, ref_period=1e-6):
local_access_validator = validators.LocalAccessValidator(engine=self.engine)
devirtualization = analyses.Devirtualization()
interleaver = transforms.Interleaver(engine=self.engine)
invariant_detection = analyses.InvariantDetection(engine=self.engine)

int_monomorphizer.visit(src.typedtree)
inferencer.visit(src.typedtree)
@@ -73,13 +75,16 @@ def __init__(self, src, ref_period=1e-6):
dead_code_eliminator.process(self.artiq_ir)
interleaver.process(self.artiq_ir)
local_access_validator.process(self.artiq_ir)
if remarks:
invariant_detection.process(self.artiq_ir)

def build_llvm_ir(self, target):
"""Compile the module to LLVM IR for the specified target."""
llvm_ir_generator = transforms.LLVMIRGenerator(
engine=self.engine, module_name=self.name, target=target,
embedding_map=self.embedding_map)
return llvm_ir_generator.process(self.artiq_ir, attribute_writeback=True)
return llvm_ir_generator.process(self.artiq_ir,
attribute_writeback=self.attribute_writeback)

def __repr__(self):
printer = types.TypePrinter()
4 changes: 2 additions & 2 deletions artiq/compiler/prelude.py
Original file line number Diff line number Diff line change
@@ -14,6 +14,8 @@ def globals():
"list": builtins.fn_list(),
"array": builtins.fn_array(),
"range": builtins.fn_range(),
"int32": builtins.fn_int32(),
"int64": builtins.fn_int64(),

# Exception constructors
"Exception": builtins.fn_Exception(),
@@ -44,8 +46,6 @@ def globals():
"now_mu": builtins.fn_now_mu(),
"delay_mu": builtins.fn_delay_mu(),
"at_mu": builtins.fn_at_mu(),
"mu_to_seconds": builtins.fn_mu_to_seconds(),
"seconds_to_mu": builtins.fn_seconds_to_mu(),

# ARTIQ utility functions
"rtio_log": builtins.fn_rtio_log(),
5 changes: 1 addition & 4 deletions artiq/compiler/targets.py
Original file line number Diff line number Diff line change
@@ -86,14 +86,11 @@ def target_machine(self):
llmachine = lltarget.create_target_machine(
features=",".join(["+{}".format(f) for f in self.features]),
reloc="pic", codemodel="default")
llmachine.set_verbose(True)
llmachine.set_asm_verbosity(True)
return llmachine

def optimize(self, llmodule):
llmachine = self.target_machine()
llpassmgr = llvm.create_module_pass_manager()
llmachine.target_data.add_pass(llpassmgr)
llmachine.add_analysis_passes(llpassmgr)

# Register our alias analysis passes.
llpassmgr.add_basic_alias_analysis_pass()
17 changes: 2 additions & 15 deletions artiq/compiler/transforms/artiq_ir_generator.py
Original file line number Diff line number Diff line change
@@ -1599,7 +1599,8 @@ def visit_builtin_call(self, node):
return self.coerce_to_bool(arg)
else:
assert False
elif types.is_builtin(typ, "int"):
elif types.is_builtin(typ, "int") or \
types.is_builtin(typ, "int32") or types.is_builtin(typ, "int64"):
if len(node.args) == 0 and len(node.keywords) == 0:
return ir.Constant(0, node.type)
elif len(node.args) == 1 and \
@@ -1731,20 +1732,6 @@ def body_gen(index):
or types.is_builtin(typ, "at_mu"):
return self.append(ir.Builtin(typ.name,
[self.visit(arg) for arg in node.args], node.type))
elif types.is_builtin(typ, "mu_to_seconds"):
if len(node.args) == 1 and len(node.keywords) == 0:
arg = self.visit(node.args[0])
arg_float = self.append(ir.Coerce(arg, builtins.TFloat()))
return self.append(ir.Arith(ast.Mult(loc=None), arg_float, self.ref_period))
else:
assert False
elif types.is_builtin(typ, "seconds_to_mu"):
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.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):
74 changes: 37 additions & 37 deletions artiq/compiler/transforms/inferencer.py
Original file line number Diff line number Diff line change
@@ -622,14 +622,28 @@ def simple_form(info, arg_types=[], return_type=builtins.TNone()):

self._unify(node.type, builtins.TBool(),
node.loc, None)
elif types.is_builtin(typ, "int"):
valid_forms = lambda: [
valid_form("int() -> numpy.int?"),
valid_form("int(x:'a) -> numpy.int?"),
valid_form("int(x:'a, width=?) -> numpy.int?")
]
elif types.is_builtin(typ, "int") or \
types.is_builtin(typ, "int32") or types.is_builtin(typ, "int64"):
if types.is_builtin(typ, "int"):
valid_forms = lambda: [
valid_form("int() -> numpy.int?"),
valid_form("int(x:'a) -> numpy.int? where 'a is numeric")
]
result_typ = builtins.TInt()
elif types.is_builtin(typ, "int32"):
valid_forms = lambda: [
valid_form("numpy.int32() -> numpy.int32"),
valid_form("numpy.int32(x:'a) -> numpy.int32 where 'a is numeric")
]
result_typ = builtins.TInt32()
elif types.is_builtin(typ, "int64"):
valid_forms = lambda: [
valid_form("numpy.int64() -> numpy.int64"),
valid_form("numpy.int64(x:'a) -> numpy.int64 where 'a is numeric")
]
result_typ = builtins.TInt64()

self._unify(node.type, builtins.TInt(),
self._unify(node.type, result_typ,
node.loc, None)

if len(node.args) == 0 and len(node.keywords) == 0:
@@ -639,20 +653,7 @@ def simple_form(info, arg_types=[], return_type=builtins.TNone()):
pass # undetermined yet
elif len(node.args) == 1 and len(node.keywords) == 0 and \
builtins.is_numeric(node.args[0].type):
self._unify(node.type, builtins.TInt(),
node.loc, None)
elif len(node.args) == 1 and len(node.keywords) == 1 and \
builtins.is_numeric(node.args[0].type) and \
node.keywords[0].arg == 'width':
width = node.keywords[0].value
if not (isinstance(width, asttyped.NumT) and isinstance(width.n, int)):
diag = diagnostic.Diagnostic("error",
"the width argument of int() must be an integer literal", {},
node.keywords[0].loc)
self.engine.process(diag)
return

self._unify(node.type, builtins.TInt(types.TValue(width.n)),
self._unify(node.type, result_typ,
node.loc, None)
else:
diagnose(valid_forms())
@@ -899,12 +900,6 @@ def makenotes(printer, typea, typeb, loca, locb):
elif types.is_builtin(typ, "at_mu"):
simple_form("at_mu(time_mu:numpy.int64) -> None",
[builtins.TInt64()])
elif types.is_builtin(typ, "mu_to_seconds"):
simple_form("mu_to_seconds(time_mu:numpy.int64) -> float",
[builtins.TInt64()], builtins.TFloat())
elif types.is_builtin(typ, "seconds_to_mu"):
simple_form("seconds_to_mu(time:float) -> numpy.int64",
[builtins.TFloat()], builtins.TInt64())
elif types.is_builtin(typ, "watchdog"):
simple_form("watchdog(time:float) -> [builtin context manager]",
[builtins.TFloat()], builtins.TNone())
@@ -1049,36 +1044,41 @@ def visit_AugAssign(self, node):
if coerced:
return_type, target_type, value_type = coerced

if isinstance(node.value, asttyped.CoerceT):
orig_value_type = node.value.value.type
else:
orig_value_type = node.value.type

try:
node.target.type.unify(target_type)
node.target.type.unify(return_type)
except types.UnificationError as e:
printer = types.TypePrinter()
note = diagnostic.Diagnostic("note",
"expression of type {typec}",
{"typec": printer.name(node.value.type)},
{"typec": printer.name(orig_value_type)},
node.value.loc)
diag = diagnostic.Diagnostic("error",
"expression of type {typea} has to be coerced to {typeb}, "
"which makes assignment invalid",
"the result of this operation has type {typeb}, "
"which cannot be assigned to a left-hand side of type {typea}",
{"typea": printer.name(node.target.type),
"typeb": printer.name(target_type)},
"typeb": printer.name(return_type)},
node.op.loc, [node.target.loc], [note])
self.engine.process(diag)
return

try:
node.target.type.unify(return_type)
node.target.type.unify(target_type)
except types.UnificationError as e:
printer = types.TypePrinter()
note = diagnostic.Diagnostic("note",
"expression of type {typec}",
{"typec": printer.name(node.value.type)},
{"typec": printer.name(orig_value_type)},
node.value.loc)
diag = diagnostic.Diagnostic("error",
"the result of this operation has type {typeb}, "
"which makes assignment to a slot of type {typea} invalid",
"this operation requires the left-hand side of type {typea} "
"to be coerced to {typeb}, which cannot be done",
{"typea": printer.name(node.target.type),
"typeb": printer.name(return_type)},
"typeb": printer.name(target_type)},
node.op.loc, [node.target.loc], [note])
self.engine.process(diag)
return
Loading

0 comments on commit 3459793

Please sign in to comment.