Ejemplo n.º 1
0
    def finalize(self):
        inferencer = StitchingInferencer(engine=self.engine,
                                         value_map=self.value_map,
                                         quote=self._quote)
        hasher = TypedtreeHasher()

        # Iterate inference to fixed point.
        old_typedtree_hash = None
        while True:
            inferencer.visit(self.typedtree)
            typedtree_hash = hasher.visit(self.typedtree)

            if old_typedtree_hash == typedtree_hash:
                break
            old_typedtree_hash = typedtree_hash

        # When we have an excess of type information, sometimes we can infer every type
        # in the AST without discovering every referenced attribute of host objects, so
        # do one last pass unconditionally.
        inferencer.visit(self.typedtree)

        # After we have found all functions, synthesize a module to hold them.
        source_buffer = source.Buffer("", "<synthesized>")
        self.typedtree = asttyped.ModuleT(
            typing_env=self.globals, globals_in_scope=set(),
            body=self.typedtree, loc=source.Range(source_buffer, 0, 0))
Ejemplo n.º 2
0
 def __init__(self, embedding_map, value_map, quote_function=None, expanded_from=None):
     self.source = ""
     self.source_buffer = source.Buffer(self.source, "<synthesized>")
     self.embedding_map = embedding_map
     self.value_map = value_map
     self.quote_function = quote_function
     self.expanded_from = expanded_from
     self.diagnostics = []
Ejemplo n.º 3
0
 def __init__(self, full_package_name, runtime, libroot, filename, src,
              future_features):
     Block.__init__(self, None, '<module>')
     self._full_package_name = full_package_name
     self._runtime = runtime
     self._libroot = libroot
     self._filename = filename
     self._buffer = source.Buffer(src)
     self._strings = set()
     self.imports = {}
     self._future_features = future_features
Ejemplo n.º 4
0
    def finalize(self):
        inferencer = StitchingInferencer(engine=self.engine,
                                         value_map=self.value_map,
                                         quote=self._quote)
        typedtree_hasher = TypedtreeHasher()

        # Iterate inference to fixed point.
        old_typedtree_hash = None
        old_attr_count = None
        while True:
            inferencer.visit(self.typedtree)
            typedtree_hash = typedtree_hasher.visit(self.typedtree)
            attr_count = self.embedding_map.attribute_count()

            if old_typedtree_hash == typedtree_hash and old_attr_count == attr_count:
                break
            old_typedtree_hash = typedtree_hash
            old_attr_count = attr_count

        # After we've discovered every referenced attribute, check if any kernel_invariant
        # specifications refers to ones we didn't encounter.
        for host_type in self.embedding_map.type_map:
            instance_type, constructor_type = self.embedding_map.type_map[host_type]
            if not hasattr(instance_type, "constant_attributes"):
                # Exceptions lack user-definable attributes.
                continue

            for attribute in instance_type.constant_attributes:
                if attribute in instance_type.attributes:
                    # Fast path; if the ARTIQ Python type has the attribute, then every observed
                    # value is guaranteed to have it too.
                    continue

                for value, loc in self.value_map[instance_type]:
                    if hasattr(value, attribute):
                        continue

                    diag = diagnostic.Diagnostic("warning",
                        "object {value} of type {typ} declares attribute '{attr}' as "
                        "kernel invariant, but the instance referenced here does not "
                        "have this attribute",
                        {"value": repr(value),
                         "typ": types.TypePrinter().name(instance_type, max_depth=0),
                         "attr": attribute},
                        loc)
                    self.engine.process(diag)

        # After we have found all functions, synthesize a module to hold them.
        source_buffer = source.Buffer("", "<synthesized>")
        self.typedtree = asttyped.ModuleT(
            typing_env=self.globals, globals_in_scope=set(),
            body=self.typedtree, loc=source.Range(source_buffer, 0, 0))
Ejemplo n.º 5
0
def main():
    if len(sys.argv) > 1 and sys.argv[1] == "+mono":
        del sys.argv[1]
        monomorphize = True
    else:
        monomorphize = False

    if len(sys.argv) > 1 and sys.argv[1] == "+iodelay":
        del sys.argv[1]
        iodelay = True
    else:
        iodelay = False

    if len(sys.argv) > 1 and sys.argv[1] == "+diag":
        del sys.argv[1]

        def process_diagnostic(diag):
            print("\n".join(diag.render(only_line=True)))
            if diag.level == "fatal":
                exit()
    else:

        def process_diagnostic(diag):
            print("\n".join(diag.render()))
            if diag.level in ("fatal", "error"):
                exit(1)

    engine = diagnostic.Engine()
    engine.process = process_diagnostic

    buf = source.Buffer("".join(fileinput.input()).expandtabs(),
                        os.path.basename(fileinput.filename()))
    parsed, comments = parse_buffer(buf, engine=engine)
    typed = ASTTypedRewriter(engine=engine,
                             prelude=prelude.globals()).visit(parsed)
    Inferencer(engine=engine).visit(typed)
    ConstnessValidator(engine=engine).visit(typed)
    if monomorphize:
        CastMonomorphizer(engine=engine).visit(typed)
        IntMonomorphizer(engine=engine).visit(typed)
        Inferencer(engine=engine).visit(typed)
    if iodelay:
        IODelayEstimator(engine=engine, ref_period=1e6).visit_fixpoint(typed)

    printer = Printer(buf)
    printer.visit(typed)
    for comment in comments:
        if comment.text.find("CHECK") >= 0:
            printer.rewriter.remove(comment.loc)
    print(printer.rewrite().source)
Ejemplo n.º 6
0
    def _function_loc(self, function):
        if isinstance(function, SpecializedFunction):
            function = function.host_function
        if hasattr(function, 'artiq_embedded') and function.artiq_embedded.function:
            function = function.artiq_embedded.function

        if isinstance(function, str):
            return source.Range(source.Buffer(function, "<string>"), 0, 0)

        filename = function.__code__.co_filename
        line     = function.__code__.co_firstlineno
        name     = function.__code__.co_name

        source_line = linecache.getline(filename, line).lstrip()
        while source_line.startswith("@") or source_line == "":
            line += 1
            source_line = linecache.getline(filename, line).lstrip()

        if "<lambda>" in function.__qualname__:
            column = 0 # can't get column of lambda
        else:
            column = re.search("def", source_line).start(0)
        source_buffer = source.Buffer(source_line, filename, line)
        return source.Range(source_buffer, column, column)
Ejemplo n.º 7
0
    def _function_loc(self, function):
        filename = function.__code__.co_filename
        line     = function.__code__.co_firstlineno
        name     = function.__code__.co_name

        source_line = linecache.getline(filename, line).lstrip()
        while source_line.startswith("@") or source_line == "":
            line += 1
            source_line = linecache.getline(filename, line).lstrip()

        if "<lambda>" in function.__qualname__:
            column = 0 # can't get column of lambda
        else:
            column = re.search("def", source_line).start(0)
        source_buffer = source.Buffer(source_line, filename, line)
        return source.Range(source_buffer, column, column)
Ejemplo n.º 8
0
    def finalize(self):
        inferencer = StitchingInferencer(engine=self.engine,
                                         value_map=self.value_map,
                                         quote=self._quote)
        hasher = TypedtreeHasher()

        # Iterate inference to fixed point.
        old_typedtree_hash = None
        while True:
            inferencer.visit(self.typedtree)
            typedtree_hash = hasher.visit(self.typedtree)

            if old_typedtree_hash == typedtree_hash:
                break
            old_typedtree_hash = typedtree_hash

        # After we have found all functions, synthesize a module to hold them.
        source_buffer = source.Buffer("", "<synthesized>")
        self.typedtree = asttyped.ModuleT(typing_env=self.globals,
                                          globals_in_scope=set(),
                                          body=self.typedtree,
                                          loc=source.Range(
                                              source_buffer, 0, 0))
Ejemplo n.º 9
0
    def _quote_embedded_function(self, function, flags):
        if isinstance(function, SpecializedFunction):
            host_function = function.host_function
        else:
            host_function = function

        if not hasattr(host_function, "artiq_embedded"):
            raise ValueError("{} is not an embedded function".format(repr(host_function)))

        # Extract function source.
        embedded_function = host_function.artiq_embedded.function
        source_code = inspect.getsource(embedded_function)
        filename = embedded_function.__code__.co_filename
        module_name = embedded_function.__globals__['__name__']
        first_line = embedded_function.__code__.co_firstlineno

        # Extract function annotation.
        signature = inspect.signature(embedded_function)
        loc = self._function_loc(embedded_function)

        arg_types = OrderedDict()
        optarg_types = OrderedDict()
        for param in signature.parameters.values():
            if param.kind == inspect.Parameter.VAR_POSITIONAL or \
                    param.kind == inspect.Parameter.VAR_KEYWORD:
                diag = diagnostic.Diagnostic("error",
                    "variadic arguments are not supported; '{argument}' is variadic",
                    {"argument": param.name},
                    self._function_loc(function),
                    notes=self._call_site_note(loc, fn_kind='kernel'))
                self.engine.process(diag)

            arg_type = self._type_of_param(function, loc, param, fn_kind='kernel')
            if param.default is inspect.Parameter.empty:
                arg_types[param.name] = arg_type
            else:
                optarg_types[param.name] = arg_type

        if signature.return_annotation is not inspect.Signature.empty:
            ret_type = self._extract_annot(function, signature.return_annotation,
                                           "return type", loc, fn_kind='kernel')
        else:
            ret_type = types.TVar()

        # Extract function environment.
        host_environment = dict()
        host_environment.update(embedded_function.__globals__)
        cells = embedded_function.__closure__
        cell_names = embedded_function.__code__.co_freevars
        host_environment.update({var: cells[index] for index, var in enumerate(cell_names)})

        # Find out how indented we are.
        initial_whitespace = re.search(r"^\s*", source_code).group(0)
        initial_indent = len(initial_whitespace.expandtabs())

        # Parse.
        source_buffer = source.Buffer(source_code, filename, first_line)
        lexer = source_lexer.Lexer(source_buffer, version=sys.version_info[0:2],
                                   diagnostic_engine=self.engine)
        lexer.indent = [(initial_indent,
                         source.Range(source_buffer, 0, len(initial_whitespace)),
                         initial_whitespace)]
        parser = source_parser.Parser(lexer, version=sys.version_info[0:2],
                                      diagnostic_engine=self.engine)
        function_node = parser.file_input().body[0]

        # Mangle the name, since we put everything into a single module.
        full_function_name = "{}.{}".format(module_name, host_function.__qualname__)
        if isinstance(function, SpecializedFunction):
            instance_type = function.instance_type
            function_node.name = "_Z{}{}I{}{}Ezz".format(len(full_function_name), full_function_name,
                                                         len(instance_type.name), instance_type.name)
        else:
            function_node.name = "_Z{}{}zz".format(len(full_function_name), full_function_name)

        # Record the function in the function map so that LLVM IR generator
        # can handle quoting it.
        self.embedding_map.store_function(function, function_node.name)

        # Fill in the function type before typing it to handle recursive
        # invocations.
        self.functions[function] = types.TFunction(arg_types, optarg_types, ret_type)

        # Rewrite into typed form.
        asttyped_rewriter = StitchingASTTypedRewriter(
            engine=self.engine, prelude=self.prelude,
            globals=self.globals, host_environment=host_environment,
            quote=self._quote)
        function_node = asttyped_rewriter.visit_quoted_function(function_node, embedded_function)
        function_node.flags = flags

        # Add it into our typedtree so that it gets inferenced and codegen'd.
        self._inject(function_node)

        # Tie the typing knot.
        self.functions[function].unify(function_node.signature_type)

        return function_node
Ejemplo n.º 10
0
    def _quote_embedded_function(self, function, flags):
        if isinstance(function, SpecializedFunction):
            host_function = function.host_function
        else:
            host_function = function

        if not hasattr(host_function, "artiq_embedded"):
            raise ValueError("{} is not an embedded function".format(repr(host_function)))

        # Extract function source.
        embedded_function = host_function.artiq_embedded.function
        source_code = inspect.getsource(embedded_function)
        filename = embedded_function.__code__.co_filename
        module_name = embedded_function.__globals__['__name__']
        first_line = embedded_function.__code__.co_firstlineno

        # Extract function environment.
        host_environment = dict()
        host_environment.update(embedded_function.__globals__)
        cells = embedded_function.__closure__
        cell_names = embedded_function.__code__.co_freevars
        host_environment.update({var: cells[index] for index, var in enumerate(cell_names)})

        # Find out how indented we are.
        initial_whitespace = re.search(r"^\s*", source_code).group(0)
        initial_indent = len(initial_whitespace.expandtabs())

        # Parse.
        source_buffer = source.Buffer(source_code, filename, first_line)
        lexer = source_lexer.Lexer(source_buffer, version=sys.version_info[0:2],
                                   diagnostic_engine=self.engine)
        lexer.indent = [(initial_indent,
                         source.Range(source_buffer, 0, len(initial_whitespace)),
                         initial_whitespace)]
        parser = source_parser.Parser(lexer, version=sys.version_info[0:2],
                                      diagnostic_engine=self.engine)
        function_node = parser.file_input().body[0]

        # Mangle the name, since we put everything into a single module.
        full_function_name = "{}.{}".format(module_name, host_function.__qualname__)
        if isinstance(function, SpecializedFunction):
            instance_type = function.instance_type
            function_node.name = "_Z{}{}I{}{}Ezz".format(len(full_function_name), full_function_name,
                                                         len(instance_type.name), instance_type.name)
        else:
            function_node.name = "_Z{}{}zz".format(len(full_function_name), full_function_name)

        # Record the function in the function map so that LLVM IR generator
        # can handle quoting it.
        self.embedding_map.store_function(function, function_node.name)

        # Memoize the function type before typing it to handle recursive
        # invocations.
        self.functions[function] = types.TVar()

        # Rewrite into typed form.
        asttyped_rewriter = StitchingASTTypedRewriter(
            engine=self.engine, prelude=self.prelude,
            globals=self.globals, host_environment=host_environment,
            quote=self._quote)
        function_node = asttyped_rewriter.visit_quoted_function(function_node, embedded_function)
        function_node.flags = flags

        # Add it into our typedtree so that it gets inferenced and codegen'd.
        self._inject(function_node)

        # Tie the typing knot.
        self.functions[function].unify(function_node.signature_type)

        return function_node