forked from M-Labs/artiq
compiler: allow flagging syscalls, providing information to optimizer.
This also fixes a crash in test_cache introduced in 1d8b0d46
.
This commit is contained in:
parent
049bd11bd6
commit
6f5332f892
|
@ -693,7 +693,7 @@ class Stitcher:
|
||||||
# Let the rest of the program decide.
|
# Let the rest of the program decide.
|
||||||
return types.TVar()
|
return types.TVar()
|
||||||
|
|
||||||
def _quote_foreign_function(self, function, loc, syscall):
|
def _quote_foreign_function(self, function, loc, syscall, flags):
|
||||||
signature = inspect.signature(function)
|
signature = inspect.signature(function)
|
||||||
|
|
||||||
arg_types = OrderedDict()
|
arg_types = OrderedDict()
|
||||||
|
@ -742,7 +742,7 @@ class Stitcher:
|
||||||
service=self.object_map.store(function))
|
service=self.object_map.store(function))
|
||||||
else:
|
else:
|
||||||
function_type = types.TCFunction(arg_types, ret_type,
|
function_type = types.TCFunction(arg_types, ret_type,
|
||||||
name=syscall)
|
name=syscall, flags=flags)
|
||||||
|
|
||||||
self.functions[function] = function_type
|
self.functions[function] = function_type
|
||||||
|
|
||||||
|
@ -779,7 +779,8 @@ class Stitcher:
|
||||||
# Insert a storage-less global whose type instructs the compiler
|
# Insert a storage-less global whose type instructs the compiler
|
||||||
# to perform a system call instead of a regular call.
|
# to perform a system call instead of a regular call.
|
||||||
self._quote_foreign_function(function, loc,
|
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:
|
elif function.artiq_embedded.forbidden is not None:
|
||||||
diag = diagnostic.Diagnostic("fatal",
|
diag = diagnostic.Diagnostic("fatal",
|
||||||
"this function cannot be called as an RPC", {},
|
"this function cannot be called as an RPC", {},
|
||||||
|
@ -791,7 +792,7 @@ class Stitcher:
|
||||||
else:
|
else:
|
||||||
# Insert a storage-less global whose type instructs the compiler
|
# Insert a storage-less global whose type instructs the compiler
|
||||||
# to perform an RPC instead of a regular call.
|
# 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]
|
function_type = self.functions[function]
|
||||||
if types.is_rpc_function(function_type):
|
if types.is_rpc_function(function_type):
|
||||||
|
|
|
@ -184,8 +184,8 @@ class LLVMIRGenerator:
|
||||||
self.tbaa_tree = self.llmodule.add_metadata([
|
self.tbaa_tree = self.llmodule.add_metadata([
|
||||||
ll.MetaDataString(self.llmodule, "ARTIQ TBAA")
|
ll.MetaDataString(self.llmodule, "ARTIQ TBAA")
|
||||||
])
|
])
|
||||||
self.tbaa_noalias_call = self.llmodule.add_metadata([
|
self.tbaa_nowrite_call = self.llmodule.add_metadata([
|
||||||
ll.MetaDataString(self.llmodule, "non-aliasing function call"),
|
ll.MetaDataString(self.llmodule, "ref-only function call"),
|
||||||
self.tbaa_tree,
|
self.tbaa_tree,
|
||||||
ll.Constant(lli64, 1)
|
ll.Constant(lli64, 1)
|
||||||
])
|
])
|
||||||
|
@ -401,6 +401,9 @@ class LLVMIRGenerator:
|
||||||
llglobal = ll.Function(self.llmodule, llty, name)
|
llglobal = ll.Function(self.llmodule, llty, name)
|
||||||
if name in ("__artiq_raise", "__artiq_reraise", "llvm.trap"):
|
if name in ("__artiq_raise", "__artiq_reraise", "llvm.trap"):
|
||||||
llglobal.attributes.add("noreturn")
|
llglobal.attributes.add("noreturn")
|
||||||
|
if name in ("rtio_log", "send_rpc", "watchdog_set", "watchdog_clear",
|
||||||
|
self.target.print_function):
|
||||||
|
llglobal.attributes.add("nounwind")
|
||||||
else:
|
else:
|
||||||
llglobal = ll.GlobalVariable(self.llmodule, llty, name)
|
llglobal = ll.GlobalVariable(self.llmodule, llty, name)
|
||||||
|
|
||||||
|
@ -1117,6 +1120,8 @@ class LLVMIRGenerator:
|
||||||
byvals = [i + 1 for i in byvals]
|
byvals = [i + 1 for i in byvals]
|
||||||
for i in byvals:
|
for i in byvals:
|
||||||
llfun.args[i].add_attribute('byval')
|
llfun.args[i].add_attribute('byval')
|
||||||
|
if 'nounwind' in insn.target_function().type.flags:
|
||||||
|
llfun.attributes.add('nounwind')
|
||||||
|
|
||||||
return llfun, list(llargs)
|
return llfun, list(llargs)
|
||||||
|
|
||||||
|
@ -1282,14 +1287,14 @@ class LLVMIRGenerator:
|
||||||
else:
|
else:
|
||||||
llcall = llresult = self.llbuilder.call(llfun, llargs, name=insn.name)
|
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:
|
if insn.is_cold:
|
||||||
llcall.cconv = 'coldcc'
|
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
|
return llresult
|
||||||
|
|
||||||
def process_Invoke(self, insn):
|
def process_Invoke(self, insn):
|
||||||
|
|
|
@ -342,14 +342,21 @@ class TCFunction(TFunction):
|
||||||
A function type of a runtime-provided C function.
|
A function type of a runtime-provided C function.
|
||||||
|
|
||||||
:ivar name: (str) C function name
|
: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()
|
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)
|
super().__init__(args, OrderedDict(), ret)
|
||||||
self.name = name
|
self.name = name
|
||||||
self.delay = TFixedDelay(iodelay.Const(0))
|
self.delay = TFixedDelay(iodelay.Const(0))
|
||||||
|
self.flags = flags
|
||||||
|
|
||||||
def unify(self, other):
|
def unify(self, other):
|
||||||
if isinstance(other, TCFunction) and \
|
if isinstance(other, TCFunction) and \
|
||||||
|
|
|
@ -2,11 +2,11 @@ from artiq.language.core import *
|
||||||
from artiq.language.types import *
|
from artiq.language.types import *
|
||||||
|
|
||||||
|
|
||||||
@syscall
|
@syscall("cache_get", flags={"nounwind", "nowrite"})
|
||||||
def cache_get(key: TStr) -> TList(TInt32):
|
def cache_get(key: TStr) -> TList(TInt32):
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
@syscall
|
@syscall("cache_put", flags={"nowrite"})
|
||||||
def cache_put(key: TStr, value: TList(TInt32)) -> TNone:
|
def cache_put(key: TStr, value: TList(TInt32)) -> TNone:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ class CompileError(Exception):
|
||||||
return "\n" + _render_diagnostic(self.diagnostic, colored=colors_supported)
|
return "\n" + _render_diagnostic(self.diagnostic, colored=colors_supported)
|
||||||
|
|
||||||
|
|
||||||
@syscall
|
@syscall("rtio_get_counter", flags={"nounwind", "nowrite"})
|
||||||
def rtio_get_counter() -> TInt64:
|
def rtio_get_counter() -> TInt64:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
|
|
|
@ -10,20 +10,20 @@ PHASE_MODE_ABSOLUTE = 1
|
||||||
PHASE_MODE_TRACKING = 2
|
PHASE_MODE_TRACKING = 2
|
||||||
|
|
||||||
|
|
||||||
@syscall
|
@syscall("dds_init", flags={"nowrite"})
|
||||||
def dds_init(time_mu: TInt64, bus_channel: TInt32, channel: TInt32) -> TNone:
|
def dds_init(time_mu: TInt64, bus_channel: TInt32, channel: TInt32) -> TNone:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
@syscall
|
@syscall("dds_set", flags={"nowrite"})
|
||||||
def dds_set(time_mu: TInt64, bus_channel: TInt32, channel: TInt32, ftw: TInt32,
|
def dds_set(time_mu: TInt64, bus_channel: TInt32, channel: TInt32, ftw: TInt32,
|
||||||
pow: TInt32, phase_mode: TInt32, amplitude: TInt32) -> TNone:
|
pow: TInt32, phase_mode: TInt32, amplitude: TInt32) -> TNone:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
@syscall
|
@syscall("dds_batch_enter", flags={"nowrite"})
|
||||||
def dds_batch_enter(time_mu: TInt64) -> TNone:
|
def dds_batch_enter(time_mu: TInt64) -> TNone:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
@syscall
|
@syscall("dds_batch_exit", flags={"nowrite"})
|
||||||
def dds_batch_exit() -> TNone:
|
def dds_batch_exit() -> TNone:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
|
|
|
@ -3,27 +3,27 @@ from artiq.language.types import TBool, TInt32, TNone
|
||||||
from artiq.coredevice.exceptions import I2CError
|
from artiq.coredevice.exceptions import I2CError
|
||||||
|
|
||||||
|
|
||||||
@syscall
|
@syscall("i2c_init", flags={"nowrite"})
|
||||||
def i2c_init(busno: TInt32) -> TNone:
|
def i2c_init(busno: TInt32) -> TNone:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
|
|
||||||
@syscall
|
@syscall("i2c_start", flags={"nounwind", "nowrite"})
|
||||||
def i2c_start(busno: TInt32) -> TNone:
|
def i2c_start(busno: TInt32) -> TNone:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
|
|
||||||
@syscall
|
@syscall("i2c_stop", flags={"nounwind", "nowrite"})
|
||||||
def i2c_stop(busno: TInt32) -> TNone:
|
def i2c_stop(busno: TInt32) -> TNone:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
|
|
||||||
@syscall
|
@syscall("i2c_write", flags={"nounwind", "nowrite"})
|
||||||
def i2c_write(busno: TInt32, b: TInt32) -> TBool:
|
def i2c_write(busno: TInt32, b: TInt32) -> TBool:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
|
|
||||||
@syscall
|
@syscall("i2c_read", flags={"nounwind", "nowrite"})
|
||||||
def i2c_read(busno: TInt32, ack: TBool) -> TInt32:
|
def i2c_read(busno: TInt32, ack: TBool) -> TInt32:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,17 @@ from artiq.language.core import syscall
|
||||||
from artiq.language.types import TInt64, TInt32, TNone
|
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
|
def rtio_output(time_mu: TInt64, channel: TInt32, addr: TInt32, data: TInt32
|
||||||
) -> TNone:
|
) -> TNone:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
|
|
||||||
@syscall
|
@syscall("rtio_input_timestamp", flags={"nowrite"})
|
||||||
def rtio_input_timestamp(timeout_mu: TInt64, channel: TInt32) -> TInt64:
|
def rtio_input_timestamp(timeout_mu: TInt64, channel: TInt32) -> TInt64:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
|
|
||||||
@syscall
|
@syscall("rtio_input_data", flags={"nowrite"})
|
||||||
def rtio_input_data(channel: TInt32) -> TInt32:
|
def rtio_input_data(channel: TInt32) -> TInt32:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
|
@ -163,7 +163,7 @@ def round(value, width=32):
|
||||||
|
|
||||||
|
|
||||||
_ARTIQEmbeddedInfo = namedtuple("_ARTIQEmbeddedInfo",
|
_ARTIQEmbeddedInfo = namedtuple("_ARTIQEmbeddedInfo",
|
||||||
"core_name function syscall forbidden")
|
"core_name function syscall forbidden flags")
|
||||||
|
|
||||||
def kernel(arg):
|
def kernel(arg):
|
||||||
"""
|
"""
|
||||||
|
@ -192,7 +192,7 @@ def kernel(arg):
|
||||||
return getattr(self, arg).run(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(
|
run_on_core.artiq_embedded = _ARTIQEmbeddedInfo(
|
||||||
core_name=arg, function=function, syscall=None,
|
core_name=arg, function=function, syscall=None,
|
||||||
forbidden=False)
|
forbidden=False, flags={})
|
||||||
return run_on_core
|
return run_on_core
|
||||||
return inner_decorator
|
return inner_decorator
|
||||||
else:
|
else:
|
||||||
|
@ -210,10 +210,10 @@ def portable(function):
|
||||||
"""
|
"""
|
||||||
function.artiq_embedded = \
|
function.artiq_embedded = \
|
||||||
_ARTIQEmbeddedInfo(core_name=None, function=function, syscall=None,
|
_ARTIQEmbeddedInfo(core_name=None, function=function, syscall=None,
|
||||||
forbidden=False)
|
forbidden=False, flags={})
|
||||||
return function
|
return function
|
||||||
|
|
||||||
def syscall(arg):
|
def syscall(arg, flags={}):
|
||||||
"""
|
"""
|
||||||
This decorator marks a function as a system call. When executed on a core
|
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
|
device, a C function with the provided name (or the same name as
|
||||||
|
@ -228,7 +228,8 @@ def syscall(arg):
|
||||||
def inner_decorator(function):
|
def inner_decorator(function):
|
||||||
function.artiq_embedded = \
|
function.artiq_embedded = \
|
||||||
_ARTIQEmbeddedInfo(core_name=None, function=None,
|
_ARTIQEmbeddedInfo(core_name=None, function=None,
|
||||||
syscall=function.__name__, forbidden=False)
|
syscall=function.__name__, forbidden=False,
|
||||||
|
flags=flags)
|
||||||
return function
|
return function
|
||||||
return inner_decorator
|
return inner_decorator
|
||||||
else:
|
else:
|
||||||
|
@ -241,7 +242,7 @@ def host_only(function):
|
||||||
"""
|
"""
|
||||||
function.artiq_embedded = \
|
function.artiq_embedded = \
|
||||||
_ARTIQEmbeddedInfo(core_name=None, function=None, syscall=None,
|
_ARTIQEmbeddedInfo(core_name=None, function=None, syscall=None,
|
||||||
forbidden=True)
|
forbidden=True, flags={})
|
||||||
return function
|
return function
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue