forked from M-Labs/artiq
compiler: T{C -> External}Function, clarify docs [nfc]
This commit is contained in:
parent
da255bee1b
commit
d37503f21d
|
@ -334,6 +334,6 @@ def is_allocated(typ):
|
||||||
return not (is_none(typ) or is_bool(typ) or is_int(typ) or
|
return not (is_none(typ) or is_bool(typ) or is_int(typ) or
|
||||||
is_float(typ) or is_range(typ) or
|
is_float(typ) or is_range(typ) or
|
||||||
types._is_pointer(typ) or types.is_function(typ) or
|
types._is_pointer(typ) or types.is_function(typ) or
|
||||||
types.is_c_function(typ) or types.is_rpc(typ) or
|
types.is_external_function(typ) or types.is_rpc(typ) or
|
||||||
types.is_method(typ) or types.is_tuple(typ) or
|
types.is_method(typ) or types.is_tuple(typ) or
|
||||||
types.is_value(typ))
|
types.is_value(typ))
|
||||||
|
|
|
@ -1001,7 +1001,7 @@ class Stitcher:
|
||||||
self.engine.process(diag)
|
self.engine.process(diag)
|
||||||
ret_type = types.TVar()
|
ret_type = types.TVar()
|
||||||
|
|
||||||
function_type = types.TCFunction(arg_types, ret_type,
|
function_type = types.TExternalFunction(arg_types, ret_type,
|
||||||
name=function.artiq_embedded.syscall,
|
name=function.artiq_embedded.syscall,
|
||||||
flags=function.artiq_embedded.flags)
|
flags=function.artiq_embedded.flags)
|
||||||
self.functions[function] = function_type
|
self.functions[function] = function_type
|
||||||
|
|
|
@ -2137,7 +2137,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
assert None not in args
|
assert None not in args
|
||||||
|
|
||||||
if self.unwind_target is None or \
|
if self.unwind_target is None or \
|
||||||
types.is_c_function(callee.type) and "nounwind" in callee.type.flags:
|
types.is_external_function(callee.type) and "nounwind" in callee.type.flags:
|
||||||
insn = self.append(ir.Call(func, args, arg_exprs))
|
insn = self.append(ir.Call(func, args, arg_exprs))
|
||||||
else:
|
else:
|
||||||
after_invoke = self.add_block("invoke")
|
after_invoke = self.add_block("invoke")
|
||||||
|
|
|
@ -205,7 +205,7 @@ class LLVMIRGenerator:
|
||||||
typ = typ.find()
|
typ = typ.find()
|
||||||
if types.is_tuple(typ):
|
if types.is_tuple(typ):
|
||||||
return ll.LiteralStructType([self.llty_of_type(eltty) for eltty in typ.elts])
|
return ll.LiteralStructType([self.llty_of_type(eltty) for eltty in typ.elts])
|
||||||
elif types.is_rpc(typ) or types.is_c_function(typ):
|
elif types.is_rpc(typ) or types.is_external_function(typ):
|
||||||
if for_return:
|
if for_return:
|
||||||
return llvoid
|
return llvoid
|
||||||
else:
|
else:
|
||||||
|
@ -838,7 +838,7 @@ class LLVMIRGenerator:
|
||||||
closure_type = typ.attributes[attr]
|
closure_type = typ.attributes[attr]
|
||||||
assert types.is_constructor(typ)
|
assert types.is_constructor(typ)
|
||||||
assert types.is_function(closure_type) or types.is_rpc(closure_type)
|
assert types.is_function(closure_type) or types.is_rpc(closure_type)
|
||||||
if types.is_c_function(closure_type) or types.is_rpc(closure_type):
|
if types.is_external_function(closure_type) or types.is_rpc(closure_type):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
llty = self.llty_of_type(typ.attributes[attr])
|
llty = self.llty_of_type(typ.attributes[attr])
|
||||||
|
@ -1443,7 +1443,7 @@ class LLVMIRGenerator:
|
||||||
functiontyp,
|
functiontyp,
|
||||||
insn.arguments(),
|
insn.arguments(),
|
||||||
llnormalblock=None, llunwindblock=None)
|
llnormalblock=None, llunwindblock=None)
|
||||||
elif types.is_c_function(functiontyp):
|
elif types.is_external_function(functiontyp):
|
||||||
llfun, llargs = self._prepare_ffi_call(insn)
|
llfun, llargs = self._prepare_ffi_call(insn)
|
||||||
else:
|
else:
|
||||||
llfun, llargs = self._prepare_closure_call(insn)
|
llfun, llargs = self._prepare_closure_call(insn)
|
||||||
|
@ -1466,7 +1466,7 @@ class LLVMIRGenerator:
|
||||||
|
|
||||||
# Never add TBAA nowrite metadata to a functon with sret!
|
# Never add TBAA nowrite metadata to a functon with sret!
|
||||||
# This leads to miscompilations.
|
# This leads to miscompilations.
|
||||||
if types.is_c_function(functiontyp) and 'nowrite' in functiontyp.flags:
|
if types.is_external_function(functiontyp) and 'nowrite' in functiontyp.flags:
|
||||||
llcall.set_metadata('tbaa', self.tbaa_nowrite_call)
|
llcall.set_metadata('tbaa', self.tbaa_nowrite_call)
|
||||||
|
|
||||||
return llresult
|
return llresult
|
||||||
|
@ -1480,7 +1480,7 @@ class LLVMIRGenerator:
|
||||||
functiontyp,
|
functiontyp,
|
||||||
insn.arguments(),
|
insn.arguments(),
|
||||||
llnormalblock, llunwindblock)
|
llnormalblock, llunwindblock)
|
||||||
elif types.is_c_function(functiontyp):
|
elif types.is_external_function(functiontyp):
|
||||||
llfun, llargs = self._prepare_ffi_call(insn)
|
llfun, llargs = self._prepare_ffi_call(insn)
|
||||||
else:
|
else:
|
||||||
llfun, llargs = self._prepare_closure_call(insn)
|
llfun, llargs = self._prepare_closure_call(insn)
|
||||||
|
@ -1530,7 +1530,7 @@ class LLVMIRGenerator:
|
||||||
attrvalue = getattr(value, attr)
|
attrvalue = getattr(value, attr)
|
||||||
is_class_function = (types.is_constructor(typ) and
|
is_class_function = (types.is_constructor(typ) and
|
||||||
types.is_function(typ.attributes[attr]) and
|
types.is_function(typ.attributes[attr]) and
|
||||||
not types.is_c_function(typ.attributes[attr]))
|
not types.is_external_function(typ.attributes[attr]))
|
||||||
if is_class_function:
|
if is_class_function:
|
||||||
attrvalue = self.embedding_map.specialize_function(typ.instance, attrvalue)
|
attrvalue = self.embedding_map.specialize_function(typ.instance, attrvalue)
|
||||||
if not (types.is_instance(typ) and attr in typ.constant_attributes):
|
if not (types.is_instance(typ) and attr in typ.constant_attributes):
|
||||||
|
@ -1600,7 +1600,7 @@ class LLVMIRGenerator:
|
||||||
llelts = [self._quote(v, t, lambda: path() + [str(i)])
|
llelts = [self._quote(v, t, lambda: path() + [str(i)])
|
||||||
for i, (v, t) in enumerate(zip(value, typ.elts))]
|
for i, (v, t) in enumerate(zip(value, typ.elts))]
|
||||||
return ll.Constant(llty, llelts)
|
return ll.Constant(llty, llelts)
|
||||||
elif types.is_rpc(typ) or types.is_c_function(typ) or types.is_builtin_function(typ):
|
elif types.is_rpc(typ) or types.is_external_function(typ) or types.is_builtin_function(typ):
|
||||||
# RPC, C and builtin functions have no runtime representation.
|
# RPC, C and builtin functions have no runtime representation.
|
||||||
return ll.Constant(llty, ll.Undefined)
|
return ll.Constant(llty, ll.Undefined)
|
||||||
elif types.is_function(typ):
|
elif types.is_function(typ):
|
||||||
|
|
|
@ -283,12 +283,18 @@ class TFunction(Type):
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash((_freeze(self.args), _freeze(self.optargs), self.ret))
|
return hash((_freeze(self.args), _freeze(self.optargs), self.ret))
|
||||||
|
|
||||||
class TCFunction(TFunction):
|
class TExternalFunction(TFunction):
|
||||||
"""
|
"""
|
||||||
A function type of a runtime-provided C function.
|
A type of an externally-provided function.
|
||||||
|
|
||||||
:ivar name: (str) C function name
|
This can be any function following the C ABI, such as provided by the
|
||||||
:ivar flags: (set of str) C function flags.
|
C/Rust runtime, or a compiler backend intrinsic. The mangled name to link
|
||||||
|
against is encoded as part of the type.
|
||||||
|
|
||||||
|
:ivar name: (str) external symbol name.
|
||||||
|
This will be the symbol linked against (following any extra C name
|
||||||
|
mangling rules).
|
||||||
|
:ivar flags: (set of str) function flags.
|
||||||
Flag ``nounwind`` means the function never raises an exception.
|
Flag ``nounwind`` means the function never raises an exception.
|
||||||
Flag ``nowrite`` means the function never writes any memory
|
Flag ``nowrite`` means the function never writes any memory
|
||||||
that the ARTIQ Python code can observe.
|
that the ARTIQ Python code can observe.
|
||||||
|
@ -308,7 +314,7 @@ class TCFunction(TFunction):
|
||||||
def unify(self, other):
|
def unify(self, other):
|
||||||
if other is self:
|
if other is self:
|
||||||
return
|
return
|
||||||
if isinstance(other, TCFunction) and \
|
if isinstance(other, TExternalFunction) and \
|
||||||
self.name == other.name:
|
self.name == other.name:
|
||||||
super().unify(other)
|
super().unify(other)
|
||||||
elif isinstance(other, TVar):
|
elif isinstance(other, TVar):
|
||||||
|
@ -404,6 +410,11 @@ class TBuiltin(Type):
|
||||||
class TBuiltinFunction(TBuiltin):
|
class TBuiltinFunction(TBuiltin):
|
||||||
"""
|
"""
|
||||||
A type of a builtin function.
|
A type of a builtin function.
|
||||||
|
|
||||||
|
Builtin functions are treated specially throughout all stages of the
|
||||||
|
compilation process according to their name (e.g. calls may not actually
|
||||||
|
lower to a function call). See :class:`TExternalFunction` for externally
|
||||||
|
defined functions that are otherwise regular.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class TConstructor(TBuiltin):
|
class TConstructor(TBuiltin):
|
||||||
|
@ -609,12 +620,12 @@ def is_function(typ):
|
||||||
def is_rpc(typ):
|
def is_rpc(typ):
|
||||||
return isinstance(typ.find(), TRPC)
|
return isinstance(typ.find(), TRPC)
|
||||||
|
|
||||||
def is_c_function(typ, name=None):
|
def is_external_function(typ, name=None):
|
||||||
typ = typ.find()
|
typ = typ.find()
|
||||||
if name is None:
|
if name is None:
|
||||||
return isinstance(typ, TCFunction)
|
return isinstance(typ, TExternalFunction)
|
||||||
else:
|
else:
|
||||||
return isinstance(typ, TCFunction) and \
|
return isinstance(typ, TExternalFunction) and \
|
||||||
typ.name == name
|
typ.name == name
|
||||||
|
|
||||||
def is_builtin(typ, name=None):
|
def is_builtin(typ, name=None):
|
||||||
|
@ -744,7 +755,7 @@ class TypePrinter(object):
|
||||||
return "(%s,)" % self.name(typ.elts[0], depth + 1)
|
return "(%s,)" % self.name(typ.elts[0], depth + 1)
|
||||||
else:
|
else:
|
||||||
return "(%s)" % ", ".join([self.name(typ, depth + 1) for typ in typ.elts])
|
return "(%s)" % ", ".join([self.name(typ, depth + 1) for typ in typ.elts])
|
||||||
elif isinstance(typ, (TFunction, TCFunction)):
|
elif isinstance(typ, (TFunction, TExternalFunction)):
|
||||||
args = []
|
args = []
|
||||||
args += [ "%s:%s" % (arg, self.name(typ.args[arg], depth + 1))
|
args += [ "%s:%s" % (arg, self.name(typ.args[arg], depth + 1))
|
||||||
for arg in typ.args]
|
for arg in typ.args]
|
||||||
|
@ -758,7 +769,7 @@ class TypePrinter(object):
|
||||||
elif not (delay.is_fixed() and iodelay.is_zero(delay.duration)):
|
elif not (delay.is_fixed() and iodelay.is_zero(delay.duration)):
|
||||||
signature += " " + self.name(delay, depth + 1)
|
signature += " " + self.name(delay, depth + 1)
|
||||||
|
|
||||||
if isinstance(typ, TCFunction):
|
if isinstance(typ, TExternalFunction):
|
||||||
return "[ffi {}]{}".format(repr(typ.name), signature)
|
return "[ffi {}]{}".format(repr(typ.name), signature)
|
||||||
elif isinstance(typ, TFunction):
|
elif isinstance(typ, TFunction):
|
||||||
return signature
|
return signature
|
||||||
|
|
|
@ -99,7 +99,7 @@ class RegionOf(algorithm.Visitor):
|
||||||
visit_BinOpT = visit_sometimes_allocating
|
visit_BinOpT = visit_sometimes_allocating
|
||||||
|
|
||||||
def visit_CallT(self, node):
|
def visit_CallT(self, node):
|
||||||
if types.is_c_function(node.func.type, "cache_get"):
|
if types.is_external_function(node.func.type, "cache_get"):
|
||||||
# The cache is borrow checked dynamically
|
# The cache is borrow checked dynamically
|
||||||
return Global()
|
return Global()
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in New Issue