Ejemplo n.º 1
0
 def test_register(self) -> None:
     op = LoadInt(5)
     self.block.ops.append(op)
     fn = FuncIR(
         FuncDecl('myfunc', None, 'mod',
                  FuncSignature([self.arg], list_rprimitive)), [self.reg],
         [self.block])
     value_names = generate_names_for_ir(fn.arg_regs, fn.blocks)
     emitter = Emitter(EmitterContext(NameGenerator([['mod']])),
                       value_names)
     generate_native_function(fn,
                              emitter,
                              'prog.py',
                              'prog',
                              optimize_int=False)
     result = emitter.fragments
     assert_string_arrays_equal([
         'PyObject *CPyDef_myfunc(CPyTagged cpy_r_arg) {\n',
         '    CPyTagged cpy_r_i0;\n',
         'CPyL0: ;\n',
         '    cpy_r_i0 = 10;\n',
         '}\n',
     ],
                                result,
                                msg='Generated code invalid')
Ejemplo n.º 2
0
 def test_simple(self) -> None:
     self.block.ops.append(Return(self.reg))
     fn = FuncIR(FuncDecl('myfunc', None, 'mod', FuncSignature([self.arg], int_rprimitive)),
                 [self.block], self.env)
     emitter = Emitter(EmitterContext(NameGenerator([['mod']])))
     generate_native_function(fn, emitter, 'prog.py', 'prog', optimize_int=False)
     result = emitter.fragments
     assert_string_arrays_equal(
         [
             'CPyTagged CPyDef_myfunc(CPyTagged cpy_r_arg) {\n',
             'CPyL0: ;\n',
             '    return cpy_r_arg;\n',
             '}\n',
         ],
         result, msg='Generated code invalid')
Ejemplo n.º 3
0
 def test_register(self) -> None:
     self.env.temp_index = 0
     op = LoadInt(5)
     self.block.ops.append(op)
     self.env.add_op(op)
     fn = FuncIR(FuncDecl('myfunc', None, 'mod', FuncSignature([self.arg], list_rprimitive)),
                 [self.block], self.env)
     emitter = Emitter(EmitterContext(NameGenerator([['mod']])))
     generate_native_function(fn, emitter, 'prog.py', 'prog', False)
     result = emitter.fragments
     assert_string_arrays_equal(
         [
             'PyObject *CPyDef_myfunc(CPyTagged cpy_r_arg) {\n',
             '    CPyTagged cpy_r_i0;\n',
             'CPyL0: ;\n',
             '    cpy_r_i0 = 10;\n',
             '}\n',
         ],
         result, msg='Generated code invalid')
Ejemplo n.º 4
0
    def generate_c_for_modules(self) -> List[Tuple[str, str]]:
        file_contents = []
        multi_file = self.use_shared_lib and self.multi_file

        base_emitter = Emitter(self.context)
        # Optionally just include the runtime library c files to
        # reduce the number of compiler invocations needed
        if self.compiler_options.include_runtime_files:
            base_emitter.emit_line('#include "CPy.c"')
            base_emitter.emit_line('#include "getargs.c"')
        base_emitter.emit_line('#include "__native{}.h"'.format(
            self.short_group_suffix))
        base_emitter.emit_line('#include "__native_internal{}.h"'.format(
            self.short_group_suffix))
        emitter = base_emitter

        for (_, literal), identifier in self.literals.items():
            if isinstance(literal, int):
                symbol = emitter.static_name(identifier, None)
                self.declare_global('CPyTagged ', symbol)
            else:
                self.declare_static_pyobject(identifier, emitter)

        for module_name, module in self.modules:
            if multi_file:
                emitter = Emitter(self.context)
                emitter.emit_line('#include "__native{}.h"'.format(
                    self.short_group_suffix))
                emitter.emit_line('#include "__native_internal{}.h"'.format(
                    self.short_group_suffix))

            self.declare_module(module_name, emitter)
            self.declare_internal_globals(module_name, emitter)
            self.declare_imports(module.imports, emitter)

            for cl in module.classes:
                if cl.is_ext_class:
                    generate_class(cl, module_name, emitter)

            # Generate Python extension module definitions and module initialization functions.
            self.generate_module_def(emitter, module_name, module)

            for fn in module.functions:
                emitter.emit_line()
                generate_native_function(fn, emitter,
                                         self.source_paths[module_name],
                                         module_name)
                if fn.name != TOP_LEVEL_NAME:
                    emitter.emit_line()
                    generate_wrapper_function(fn, emitter,
                                              self.source_paths[module_name],
                                              module_name)

            if multi_file:
                name = ('__native_{}.c'.format(
                    emitter.names.private_name(module_name)))
                file_contents.append((name, ''.join(emitter.fragments)))

        # The external header file contains type declarations while
        # the internal contains declarations of functions and objects
        # (which are shared between shared libraries via dynamic
        # exports tables and not accessed directly.)
        ext_declarations = Emitter(self.context)
        ext_declarations.emit_line('#ifndef MYPYC_NATIVE{}_H'.format(
            self.group_suffix))
        ext_declarations.emit_line('#define MYPYC_NATIVE{}_H'.format(
            self.group_suffix))
        ext_declarations.emit_line('#include <Python.h>')
        ext_declarations.emit_line('#include <CPy.h>')

        declarations = Emitter(self.context)
        declarations.emit_line('#ifndef MYPYC_NATIVE_INTERNAL{}_H'.format(
            self.group_suffix))
        declarations.emit_line('#define MYPYC_NATIVE_INTERNAL{}_H'.format(
            self.group_suffix))
        declarations.emit_line('#include <Python.h>')
        declarations.emit_line('#include <CPy.h>')
        declarations.emit_line('#include "__native{}.h"'.format(
            self.short_group_suffix))
        declarations.emit_line()
        declarations.emit_line('int CPyGlobalsInit(void);')
        declarations.emit_line()

        for module_name, module in self.modules:
            self.declare_finals(module_name, module.final_names, declarations)
            for cl in module.classes:
                generate_class_type_decl(cl, emitter, ext_declarations,
                                         declarations)
            for fn in module.functions:
                generate_function_declaration(fn, declarations)

        for lib in sorted(self.context.group_deps):
            elib = exported_name(lib)
            short_lib = exported_name(lib.split('.')[-1])
            declarations.emit_lines(
                '#include <{}>'.format(
                    os.path.join(group_dir(lib),
                                 "__native_{}.h".format(short_lib))),
                'struct export_table_{} exports_{};'.format(elib, elib))

        sorted_decls = self.toposort_declarations()

        emitter = base_emitter
        self.generate_globals_init(emitter)

        emitter.emit_line()

        for declaration in sorted_decls:
            decls = ext_declarations if declaration.is_type else declarations
            if not declaration.is_type:
                decls.emit_lines('extern {}'.format(declaration.decl[0]),
                                 *declaration.decl[1:])
                # If there is a definition, emit it. Otherwise repeat the declaration
                # (without an extern).
                if declaration.defn:
                    emitter.emit_lines(*declaration.defn)
                else:
                    emitter.emit_lines(*declaration.decl)
            else:
                decls.emit_lines(*declaration.decl)

        if self.group_name:
            self.generate_export_table(ext_declarations, emitter)

            self.generate_shared_lib_init(emitter)

        ext_declarations.emit_line('#endif')
        declarations.emit_line('#endif')

        output_dir = group_dir(self.group_name) if self.group_name else ''
        return file_contents + [
            (os.path.join(output_dir, '__native{}.c'.format(
                self.short_group_suffix)), ''.join(emitter.fragments)),
            (os.path.join(
                output_dir, '__native_internal{}.h'.format(
                    self.short_group_suffix)), ''.join(
                        declarations.fragments)),
            (os.path.join(output_dir, '__native{}.h'.format(
                self.short_group_suffix)), ''.join(
                    ext_declarations.fragments)),
        ]
Ejemplo n.º 5
0
    def generate_c_for_modules(self) -> List[Tuple[str, str]]:
        file_contents = []
        multi_file = self.use_shared_lib and self.multi_file

        # Collect all literal refs in IR.
        for _, module in self.modules:
            for fn in module.functions:
                collect_literals(fn, self.context.literals)

        base_emitter = Emitter(self.context)
        # Optionally just include the runtime library c files to
        # reduce the number of compiler invocations needed
        if self.compiler_options.include_runtime_files:
            for name in RUNTIME_C_FILES:
                base_emitter.emit_line(f'#include "{name}"')
        base_emitter.emit_line(
            f'#include "__native{self.short_group_suffix}.h"')
        base_emitter.emit_line(
            f'#include "__native_internal{self.short_group_suffix}.h"')
        emitter = base_emitter

        self.generate_literal_tables()

        for module_name, module in self.modules:
            if multi_file:
                emitter = Emitter(self.context)
                emitter.emit_line(
                    f'#include "__native{self.short_group_suffix}.h"')
                emitter.emit_line(
                    f'#include "__native_internal{self.short_group_suffix}.h"')

            self.declare_module(module_name, emitter)
            self.declare_internal_globals(module_name, emitter)
            self.declare_imports(module.imports, emitter)

            for cl in module.classes:
                if cl.is_ext_class:
                    generate_class(cl, module_name, emitter)

            # Generate Python extension module definitions and module initialization functions.
            self.generate_module_def(emitter, module_name, module)

            for fn in module.functions:
                emitter.emit_line()
                generate_native_function(fn, emitter,
                                         self.source_paths[module_name],
                                         module_name)
                if fn.name != TOP_LEVEL_NAME:
                    emitter.emit_line()
                    if is_fastcall_supported(fn, emitter.capi_version):
                        generate_wrapper_function(
                            fn, emitter, self.source_paths[module_name],
                            module_name)
                    else:
                        generate_legacy_wrapper_function(
                            fn, emitter, self.source_paths[module_name],
                            module_name)
            if multi_file:
                name = (
                    f'__native_{emitter.names.private_name(module_name)}.c')
                file_contents.append((name, ''.join(emitter.fragments)))

        # The external header file contains type declarations while
        # the internal contains declarations of functions and objects
        # (which are shared between shared libraries via dynamic
        # exports tables and not accessed directly.)
        ext_declarations = Emitter(self.context)
        ext_declarations.emit_line(
            f'#ifndef MYPYC_NATIVE{self.group_suffix}_H')
        ext_declarations.emit_line(
            f'#define MYPYC_NATIVE{self.group_suffix}_H')
        ext_declarations.emit_line('#include <Python.h>')
        ext_declarations.emit_line('#include <CPy.h>')

        declarations = Emitter(self.context)
        declarations.emit_line(
            f'#ifndef MYPYC_NATIVE_INTERNAL{self.group_suffix}_H')
        declarations.emit_line(
            f'#define MYPYC_NATIVE_INTERNAL{self.group_suffix}_H')
        declarations.emit_line('#include <Python.h>')
        declarations.emit_line('#include <CPy.h>')
        declarations.emit_line(
            f'#include "__native{self.short_group_suffix}.h"')
        declarations.emit_line()
        declarations.emit_line('int CPyGlobalsInit(void);')
        declarations.emit_line()

        for module_name, module in self.modules:
            self.declare_finals(module_name, module.final_names, declarations)
            for cl in module.classes:
                generate_class_type_decl(cl, emitter, ext_declarations,
                                         declarations)
            for fn in module.functions:
                generate_function_declaration(fn, declarations)

        for lib in sorted(self.context.group_deps):
            elib = exported_name(lib)
            short_lib = exported_name(lib.split('.')[-1])
            declarations.emit_lines(
                '#include <{}>'.format(
                    os.path.join(group_dir(lib), f"__native_{short_lib}.h")),
                f'struct export_table_{elib} exports_{elib};')

        sorted_decls = self.toposort_declarations()

        emitter = base_emitter
        self.generate_globals_init(emitter)

        emitter.emit_line()

        for declaration in sorted_decls:
            decls = ext_declarations if declaration.is_type else declarations
            if not declaration.is_type:
                decls.emit_lines(f'extern {declaration.decl[0]}',
                                 *declaration.decl[1:])
                # If there is a definition, emit it. Otherwise repeat the declaration
                # (without an extern).
                if declaration.defn:
                    emitter.emit_lines(*declaration.defn)
                else:
                    emitter.emit_lines(*declaration.decl)
            else:
                decls.emit_lines(*declaration.decl)

        if self.group_name:
            self.generate_export_table(ext_declarations, emitter)

            self.generate_shared_lib_init(emitter)

        ext_declarations.emit_line('#endif')
        declarations.emit_line('#endif')

        output_dir = group_dir(self.group_name) if self.group_name else ''
        return file_contents + [
            (os.path.join(output_dir, f'__native{self.short_group_suffix}.c'),
             ''.join(emitter.fragments)),
            (os.path.join(output_dir,
                          f'__native_internal{self.short_group_suffix}.h'),
             ''.join(declarations.fragments)),
            (os.path.join(output_dir, f'__native{self.short_group_suffix}.h'),
             ''.join(ext_declarations.fragments)),
        ]