Skip to content

Commit

Permalink
compiler: allow flagging syscalls, providing information to optimizer.
Browse files Browse the repository at this point in the history
This also fixes a crash in test_cache introduced in 1d8b0d4.
whitequark committed Mar 28, 2016
1 parent 049bd11 commit 6f5332f
Showing 9 changed files with 47 additions and 33 deletions.
9 changes: 5 additions & 4 deletions artiq/compiler/embedding.py
Original file line number Diff line number Diff line change
@@ -693,7 +693,7 @@ def proxy_diagnostic(diag):
# Let the rest of the program decide.
return types.TVar()

def _quote_foreign_function(self, function, loc, syscall):
def _quote_foreign_function(self, function, loc, syscall, flags):
signature = inspect.signature(function)

arg_types = OrderedDict()
@@ -742,7 +742,7 @@ def _quote_foreign_function(self, function, loc, syscall):
service=self.object_map.store(function))
else:
function_type = types.TCFunction(arg_types, ret_type,
name=syscall)
name=syscall, flags=flags)

self.functions[function] = function_type

@@ -779,7 +779,8 @@ def _quote_function(self, function, loc):
# Insert a storage-less global whose type instructs the compiler
# to perform a system call instead of a regular call.
self._quote_foreign_function(function, loc,
syscall=function.artiq_embedded.syscall)
syscall=function.artiq_embedded.syscall,
flags=function.artiq_embedded.flags)
elif function.artiq_embedded.forbidden is not None:
diag = diagnostic.Diagnostic("fatal",
"this function cannot be called as an RPC", {},
@@ -791,7 +792,7 @@ def _quote_function(self, function, loc):
else:
# Insert a storage-less global whose type instructs the compiler
# to perform an RPC instead of a regular call.
self._quote_foreign_function(function, loc, syscall=None)
self._quote_foreign_function(function, loc, syscall=None, flags=None)

function_type = self.functions[function]
if types.is_rpc_function(function_type):
19 changes: 12 additions & 7 deletions artiq/compiler/transforms/llvm_ir_generator.py
Original file line number Diff line number Diff line change
@@ -184,8 +184,8 @@ def __init__(self, engine, module_name, target, function_map, object_map, type_m
self.tbaa_tree = self.llmodule.add_metadata([
ll.MetaDataString(self.llmodule, "ARTIQ TBAA")
])
self.tbaa_noalias_call = self.llmodule.add_metadata([
ll.MetaDataString(self.llmodule, "non-aliasing function call"),
self.tbaa_nowrite_call = self.llmodule.add_metadata([
ll.MetaDataString(self.llmodule, "ref-only function call"),
self.tbaa_tree,
ll.Constant(lli64, 1)
])
@@ -401,6 +401,9 @@ def llbuiltin(self, name):
llglobal = ll.Function(self.llmodule, llty, name)
if name in ("__artiq_raise", "__artiq_reraise", "llvm.trap"):
llglobal.attributes.add("noreturn")
if name in ("rtio_log", "send_rpc", "watchdog_set", "watchdog_clear",
self.target.print_function):
llglobal.attributes.add("nounwind")
else:
llglobal = ll.GlobalVariable(self.llmodule, llty, name)

@@ -1117,6 +1120,8 @@ def _prepare_ffi_call(self, insn):
byvals = [i + 1 for i in byvals]
for i in byvals:
llfun.args[i].add_attribute('byval')
if 'nounwind' in insn.target_function().type.flags:
llfun.attributes.add('nounwind')

return llfun, list(llargs)

@@ -1282,14 +1287,14 @@ def process_Call(self, insn):
else:
llcall = llresult = self.llbuilder.call(llfun, llargs, name=insn.name)

# Never add TBAA nowrite metadata to a functon with sret!
# This leads to miscompilations.
if types.is_c_function(functiontyp) and 'nowrite' in functiontyp.flags:
llcall.metadata['tbaa'] = self.tbaa_nowrite_call

if insn.is_cold:
llcall.cconv = 'coldcc'

if types.is_c_function(functiontyp):
# All our global state is confined to our compilation unit,
# so by definition no FFI call can mutate it.
llcall.metadata['tbaa'] = self.tbaa_noalias_call

return llresult

def process_Invoke(self, insn):
9 changes: 8 additions & 1 deletion artiq/compiler/types.py
Original file line number Diff line number Diff line change
@@ -342,14 +342,21 @@ class TCFunction(TFunction):
A function type of a runtime-provided C function.
:ivar name: (str) C function name
:ivar flags: (set of str) C function flags.
Flag ``nounwind`` means the function never raises an exception.
Flag ``nowrite`` means the function never writes any memory
that the ARTIQ Python code can observe.
"""

attributes = OrderedDict()

def __init__(self, args, ret, name):
def __init__(self, args, ret, name, flags={}):
for flag in flags:
assert flag in {'nounwind', 'nowrite'}
super().__init__(args, OrderedDict(), ret)
self.name = name
self.delay = TFixedDelay(iodelay.Const(0))
self.flags = flags

def unify(self, other):
if isinstance(other, TCFunction) and \
4 changes: 2 additions & 2 deletions artiq/coredevice/cache.py
Original file line number Diff line number Diff line change
@@ -2,11 +2,11 @@
from artiq.language.types import *


@syscall
@syscall("cache_get", flags={"nounwind", "nowrite"})
def cache_get(key: TStr) -> TList(TInt32):
raise NotImplementedError("syscall not simulated")

@syscall
@syscall("cache_put", flags={"nowrite"})
def cache_put(key: TStr, value: TList(TInt32)) -> TNone:
raise NotImplementedError("syscall not simulated")

2 changes: 1 addition & 1 deletion artiq/coredevice/core.py
Original file line number Diff line number Diff line change
@@ -37,7 +37,7 @@ def __str__(self):
return "\n" + _render_diagnostic(self.diagnostic, colored=colors_supported)


@syscall
@syscall("rtio_get_counter", flags={"nounwind", "nowrite"})
def rtio_get_counter() -> TInt64:
raise NotImplementedError("syscall not simulated")

8 changes: 4 additions & 4 deletions artiq/coredevice/dds.py
Original file line number Diff line number Diff line change
@@ -10,20 +10,20 @@
PHASE_MODE_TRACKING = 2


@syscall
@syscall("dds_init", flags={"nowrite"})
def dds_init(time_mu: TInt64, bus_channel: TInt32, channel: TInt32) -> TNone:
raise NotImplementedError("syscall not simulated")

@syscall
@syscall("dds_set", flags={"nowrite"})
def dds_set(time_mu: TInt64, bus_channel: TInt32, channel: TInt32, ftw: TInt32,
pow: TInt32, phase_mode: TInt32, amplitude: TInt32) -> TNone:
raise NotImplementedError("syscall not simulated")

@syscall
@syscall("dds_batch_enter", flags={"nowrite"})
def dds_batch_enter(time_mu: TInt64) -> TNone:
raise NotImplementedError("syscall not simulated")

@syscall
@syscall("dds_batch_exit", flags={"nowrite"})
def dds_batch_exit() -> TNone:
raise NotImplementedError("syscall not simulated")

10 changes: 5 additions & 5 deletions artiq/coredevice/i2c.py
Original file line number Diff line number Diff line change
@@ -3,27 +3,27 @@
from artiq.coredevice.exceptions import I2CError


@syscall
@syscall("i2c_init", flags={"nowrite"})
def i2c_init(busno: TInt32) -> TNone:
raise NotImplementedError("syscall not simulated")


@syscall
@syscall("i2c_start", flags={"nounwind", "nowrite"})
def i2c_start(busno: TInt32) -> TNone:
raise NotImplementedError("syscall not simulated")


@syscall
@syscall("i2c_stop", flags={"nounwind", "nowrite"})
def i2c_stop(busno: TInt32) -> TNone:
raise NotImplementedError("syscall not simulated")


@syscall
@syscall("i2c_write", flags={"nounwind", "nowrite"})
def i2c_write(busno: TInt32, b: TInt32) -> TBool:
raise NotImplementedError("syscall not simulated")


@syscall
@syscall("i2c_read", flags={"nounwind", "nowrite"})
def i2c_read(busno: TInt32, ack: TBool) -> TInt32:
raise NotImplementedError("syscall not simulated")

6 changes: 3 additions & 3 deletions artiq/coredevice/rtio.py
Original file line number Diff line number Diff line change
@@ -2,17 +2,17 @@
from artiq.language.types import TInt64, TInt32, TNone


@syscall
@syscall("rtio_output", flags={"nowrite"})
def rtio_output(time_mu: TInt64, channel: TInt32, addr: TInt32, data: TInt32
) -> TNone:
raise NotImplementedError("syscall not simulated")


@syscall
@syscall("rtio_input_timestamp", flags={"nowrite"})
def rtio_input_timestamp(timeout_mu: TInt64, channel: TInt32) -> TInt64:
raise NotImplementedError("syscall not simulated")


@syscall
@syscall("rtio_input_data", flags={"nowrite"})
def rtio_input_data(channel: TInt32) -> TInt32:
raise NotImplementedError("syscall not simulated")
13 changes: 7 additions & 6 deletions artiq/language/core.py
Original file line number Diff line number Diff line change
@@ -163,7 +163,7 @@ def round(value, width=32):


_ARTIQEmbeddedInfo = namedtuple("_ARTIQEmbeddedInfo",
"core_name function syscall forbidden")
"core_name function syscall forbidden flags")

def kernel(arg):
"""
@@ -192,7 +192,7 @@ def run_on_core(self, *k_args, **k_kwargs):
return getattr(self, arg).run(run_on_core, ((self,) + k_args), k_kwargs)
run_on_core.artiq_embedded = _ARTIQEmbeddedInfo(
core_name=arg, function=function, syscall=None,
forbidden=False)
forbidden=False, flags={})
return run_on_core
return inner_decorator
else:
@@ -210,10 +210,10 @@ def portable(function):
"""
function.artiq_embedded = \
_ARTIQEmbeddedInfo(core_name=None, function=function, syscall=None,
forbidden=False)
forbidden=False, flags={})
return function

def syscall(arg):
def syscall(arg, flags={}):
"""
This decorator marks a function as a system call. When executed on a core
device, a C function with the provided name (or the same name as
@@ -228,7 +228,8 @@ def syscall(arg):
def inner_decorator(function):
function.artiq_embedded = \
_ARTIQEmbeddedInfo(core_name=None, function=None,
syscall=function.__name__, forbidden=False)
syscall=function.__name__, forbidden=False,
flags=flags)
return function
return inner_decorator
else:
@@ -241,7 +242,7 @@ def host_only(function):
"""
function.artiq_embedded = \
_ARTIQEmbeddedInfo(core_name=None, function=None, syscall=None,
forbidden=True)
forbidden=True, flags={})
return function


0 comments on commit 6f5332f

Please sign in to comment.