From d37503f21dc6c3df7bf193fb12fce870d0c91136 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Aug 2020 13:42:24 +0100 Subject: [PATCH] compiler: T{C -> External}Function, clarify docs [nfc] --- artiq/compiler/builtins.py | 2 +- artiq/compiler/embedding.py | 6 ++-- .../compiler/transforms/artiq_ir_generator.py | 2 +- .../compiler/transforms/llvm_ir_generator.py | 14 ++++----- artiq/compiler/types.py | 31 +++++++++++++------ artiq/compiler/validators/escape.py | 2 +- 6 files changed, 34 insertions(+), 23 deletions(-) diff --git a/artiq/compiler/builtins.py b/artiq/compiler/builtins.py index 7edd97d9a..7a0aa6161 100644 --- a/artiq/compiler/builtins.py +++ b/artiq/compiler/builtins.py @@ -334,6 +334,6 @@ def is_allocated(typ): return not (is_none(typ) or is_bool(typ) or is_int(typ) or is_float(typ) or is_range(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_value(typ)) diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index fb0a8be39..bdac020bb 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -1001,9 +1001,9 @@ class Stitcher: self.engine.process(diag) ret_type = types.TVar() - function_type = types.TCFunction(arg_types, ret_type, - name=function.artiq_embedded.syscall, - flags=function.artiq_embedded.flags) + function_type = types.TExternalFunction(arg_types, ret_type, + name=function.artiq_embedded.syscall, + flags=function.artiq_embedded.flags) self.functions[function] = function_type return function_type diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 9e3ccb6cc..4241669e0 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -2137,7 +2137,7 @@ class ARTIQIRGenerator(algorithm.Visitor): assert None not in args 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)) else: after_invoke = self.add_block("invoke") diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 70ef64785..31384e578 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -205,7 +205,7 @@ class LLVMIRGenerator: typ = typ.find() if types.is_tuple(typ): 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: return llvoid else: @@ -838,7 +838,7 @@ class LLVMIRGenerator: closure_type = typ.attributes[attr] assert types.is_constructor(typ) 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 llty = self.llty_of_type(typ.attributes[attr]) @@ -1443,7 +1443,7 @@ class LLVMIRGenerator: functiontyp, insn.arguments(), llnormalblock=None, llunwindblock=None) - elif types.is_c_function(functiontyp): + elif types.is_external_function(functiontyp): llfun, llargs = self._prepare_ffi_call(insn) else: llfun, llargs = self._prepare_closure_call(insn) @@ -1466,7 +1466,7 @@ class LLVMIRGenerator: # 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: + if types.is_external_function(functiontyp) and 'nowrite' in functiontyp.flags: llcall.set_metadata('tbaa', self.tbaa_nowrite_call) return llresult @@ -1480,7 +1480,7 @@ class LLVMIRGenerator: functiontyp, insn.arguments(), llnormalblock, llunwindblock) - elif types.is_c_function(functiontyp): + elif types.is_external_function(functiontyp): llfun, llargs = self._prepare_ffi_call(insn) else: llfun, llargs = self._prepare_closure_call(insn) @@ -1530,7 +1530,7 @@ class LLVMIRGenerator: attrvalue = getattr(value, attr) is_class_function = (types.is_constructor(typ) 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: attrvalue = self.embedding_map.specialize_function(typ.instance, attrvalue) 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)]) for i, (v, t) in enumerate(zip(value, typ.elts))] 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. return ll.Constant(llty, ll.Undefined) elif types.is_function(typ): diff --git a/artiq/compiler/types.py b/artiq/compiler/types.py index deeb8352b..281b53577 100644 --- a/artiq/compiler/types.py +++ b/artiq/compiler/types.py @@ -283,12 +283,18 @@ class TFunction(Type): def __hash__(self): 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 - :ivar flags: (set of str) C function flags. + This can be any function following the C ABI, such as provided by the + 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 ``nowrite`` means the function never writes any memory that the ARTIQ Python code can observe. @@ -308,7 +314,7 @@ class TCFunction(TFunction): def unify(self, other): if other is self: return - if isinstance(other, TCFunction) and \ + if isinstance(other, TExternalFunction) and \ self.name == other.name: super().unify(other) elif isinstance(other, TVar): @@ -404,6 +410,11 @@ class TBuiltin(Type): class TBuiltinFunction(TBuiltin): """ 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): @@ -609,12 +620,12 @@ def is_function(typ): def is_rpc(typ): return isinstance(typ.find(), TRPC) -def is_c_function(typ, name=None): +def is_external_function(typ, name=None): typ = typ.find() if name is None: - return isinstance(typ, TCFunction) + return isinstance(typ, TExternalFunction) else: - return isinstance(typ, TCFunction) and \ + return isinstance(typ, TExternalFunction) and \ typ.name == name def is_builtin(typ, name=None): @@ -744,7 +755,7 @@ class TypePrinter(object): return "(%s,)" % self.name(typ.elts[0], depth + 1) else: 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 += [ "%s:%s" % (arg, self.name(typ.args[arg], depth + 1)) for arg in typ.args] @@ -758,7 +769,7 @@ class TypePrinter(object): elif not (delay.is_fixed() and iodelay.is_zero(delay.duration)): signature += " " + self.name(delay, depth + 1) - if isinstance(typ, TCFunction): + if isinstance(typ, TExternalFunction): return "[ffi {}]{}".format(repr(typ.name), signature) elif isinstance(typ, TFunction): return signature diff --git a/artiq/compiler/validators/escape.py b/artiq/compiler/validators/escape.py index 125355b0c..c6ae59704 100644 --- a/artiq/compiler/validators/escape.py +++ b/artiq/compiler/validators/escape.py @@ -99,7 +99,7 @@ class RegionOf(algorithm.Visitor): visit_BinOpT = visit_sometimes_allocating 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 return Global() else: