예제 #1
0
    def _runPass(self, index, pss, internal_state):
        mutated = False

        def check(func, compiler_state):
            mangled = func(compiler_state)
            if mangled not in (True, False):
                msg = (
                    "CompilerPass implementations should return True/False. "
                    "CompilerPass with name '%s' did not.")
                raise ValueError(msg % pss.name())
            return mangled

        def debug_print(pass_name, print_condition, printable_condition):
            if pass_name in print_condition:
                fid = internal_state.func_id
                args = (fid.modname, fid.func_qualname, self.pipeline_name,
                        printable_condition, pass_name)
                print(("%s.%s: %s: %s %s" % args).center(120, '-'))
                if internal_state.func_ir is not None:
                    internal_state.func_ir.dump()
                else:
                    print("func_ir is None")

        # debug print before this pass?
        debug_print(pss.name(), self._print_before + self._print_wrap,
                    "BEFORE")

        # wire in the analysis info so it's accessible
        pss.analysis = self._analysis

        with SimpleTimer() as init_time:
            mutated |= check(pss.run_initialization, internal_state)
        with SimpleTimer() as pass_time:
            mutated |= check(pss.run_pass, internal_state)
        with SimpleTimer() as finalize_time:
            mutated |= check(pss.run_finalizer, internal_state)

        # Check that if the pass is an instance of a FunctionPass that it hasn't
        # emitted ir.Dels.
        if isinstance(pss, FunctionPass):
            enforce_no_dels(internal_state.func_ir)

        if self._ENFORCING:
            # TODO: Add in self consistency enforcement for
            # `func_ir._definitions` etc
            if _pass_registry.get(pss.__class__).mutates_CFG:
                if mutated:  # block level changes, rebuild all
                    PostProcessor(internal_state.func_ir).run()
                else:  # CFG level changes rebuild CFG
                    internal_state.func_ir.blocks = transforms.canonicalize_cfg(
                        internal_state.func_ir.blocks)

        # inject runtimes
        pt = pass_timings(init_time.elapsed, pass_time.elapsed,
                          finalize_time.elapsed)
        self.exec_times["%s_%s" % (index, pss.name())] = pt

        # debug print after this pass?
        debug_print(pss.name(), self._print_after + self._print_wrap, "AFTER")
예제 #2
0
def _pre_looplift_transform(func_ir):
    """Canonicalize loops for looplifting.
    """
    from numba.core.postproc import PostProcessor

    cfg = compute_cfg_from_blocks(func_ir.blocks)
    # For every loop that has multiple exits, combine the exits into one.
    for loop_info in cfg.loops().values():
        if _has_multiple_loop_exits(cfg, loop_info):
            func_ir, _common_key = _fix_multi_exit_blocks(
                func_ir, loop_info.exits)
    # Reset and reprocess the func_ir
    func_ir._reset_analysis_variables()
    PostProcessor(func_ir).run()
    return func_ir
예제 #3
0
def relatively_deep_copy(obj, memo):
    # WARNING: there are some issues with genarators which were not investigated
    # and root cause is not found. Though copied IR seems to work fine there are
    # some extra references kept on generator objects which may result in a
    # memory leak.

    obj_id = id(obj)
    if obj_id in memo:
        return memo[obj_id]

    from ctypes import _CFuncPtr
    from types import ModuleType

    from numba.core.bytecode import FunctionIdentity
    from numba.core.compiler import CompileResult
    from numba.core.dispatcher import _DispatcherBase
    from numba.core.types.abstract import Type
    from numba.core.types.functions import Dispatcher, Function
    from numba.core.typing.templates import Signature
    from numba.np.ufunc.dufunc import DUFunc

    from numba_dppy.compiler import DPPYFunctionTemplate

    # objects which shouldn't or can't be copied and it's ok not to copy it.
    if isinstance(
            obj,
        (
            FunctionIdentity,
            _DispatcherBase,
            Function,
            Type,
            Dispatcher,
            ModuleType,
            Signature,
            DPPYFunctionTemplate,
            CompileResult,
            DUFunc,
            _CFuncPtr,
            type,
            str,
            bool,
            type(None),
        ),
    ):
        return obj

    from numba.core.funcdesc import FunctionDescriptor
    from numba.core.ir import FreeVar, FunctionIR, Global
    from numba.core.postproc import PostProcessor

    if isinstance(obj, FunctionDescriptor):
        cpy = FunctionDescriptor(
            native=obj.native,
            modname=obj.modname,
            qualname=obj.qualname,
            unique_name=obj.unique_name,
            doc=obj.doc,
            typemap=relatively_deep_copy(obj.typemap, memo),
            restype=obj.restype,
            calltypes=relatively_deep_copy(obj.calltypes, memo),
            args=obj.args,
            kws=obj.kws,
            mangler=None,
            argtypes=relatively_deep_copy(obj.argtypes, memo),
            inline=obj.inline,
            noalias=obj.noalias,
            env_name=obj.env_name,
            global_dict=obj.global_dict,
        )
        # mangler parameter is not saved in FunctionDescriptor, but used to generated name.
        # So pass None as mangler parameter and then copy mangled_name by hands
        cpy.mangled_name = obj.mangled_name

        memo[obj_id] = cpy

        return cpy

    if isinstance(obj, FunctionIR):
        # PostProcessor do the following:
        # 1. canonicolize cfg, modifying IR
        # 2. fills internal generators status
        # 3. creates and fills VariableLifetime object
        # We can't copy this objects. So in order to have copy of it we need run PostProcessor on copied IR.
        # This means, that in case PostProcess wasn't run for original object copied object would defer.
        # In order to avoid this we are running PostProcess on original object firstly.
        # This means that copy of IR actually has a side effect on it.
        pp = PostProcessor(obj)
        pp.run()
        cpy = FunctionIR(
            blocks=relatively_deep_copy(obj.blocks, memo),
            is_generator=relatively_deep_copy(obj.is_generator, memo),
            func_id=relatively_deep_copy(obj.func_id, memo),
            loc=obj.loc,
            definitions=relatively_deep_copy(obj._definitions, memo),
            arg_count=obj.arg_count,
            arg_names=relatively_deep_copy(obj.arg_names, memo),
        )
        pp = PostProcessor(cpy)
        pp.run()

        memo[obj_id] = cpy

        return cpy

    if isinstance(obj, Global):
        cpy = Global(name=obj.name, value=obj.value, loc=obj.loc)
        memo[obj_id] = cpy

        return cpy

    if isinstance(obj, FreeVar):
        cpy = FreeVar(index=obj.index,
                      name=obj.name,
                      value=obj.value,
                      loc=obj.loc)
        memo[obj_id] = cpy

        return cpy

    # for containers we need to copy container itself first. And then fill it with copied items.
    if isinstance(obj, list):
        cpy = copy.copy(obj)
        cpy.clear()
        for item in obj:
            cpy.append(relatively_deep_copy(item, memo))
        memo[obj_id] = cpy
        return cpy
    elif isinstance(obj, dict):
        cpy = copy.copy(obj)
        cpy.clear()
        for key, item in obj.items():
            cpy[relatively_deep_copy(key,
                                     memo)] = relatively_deep_copy(item, memo)
        memo[obj_id] = cpy
        return cpy
    elif isinstance(obj, tuple):
        # subclass constructors could have different parameters than superclass.
        # e.g. tuple and namedtuple constructors accepts quite different parameters.
        # it is better to have separate section for namedtuple
        tpl = tuple([relatively_deep_copy(item, memo) for item in obj])
        if type(obj) == tuple:
            cpy = tpl
        else:
            cpy = type(obj)(*tpl)
        memo[obj_id] = cpy
        return cpy
    elif isinstance(obj, set):
        cpy = copy.copy(obj)
        cpy.clear()
        for item in obj:
            cpy.add(relatively_deep_copy(item, memo))
        memo[obj_id] = cpy
        return cpy

    # some python objects are not copyable. In such case exception would be raised
    # it is just a convinient point to find such objects
    try:
        cpy = copy.copy(obj)
    except Exception as e:
        raise e

    # __slots__ for subclass specify only members declared in subclass. So to get all members we need to go through
    # all supeclasses
    def get_slots_members(obj):
        keys = []
        typ = obj
        if not isinstance(typ, type):
            typ = type(obj)

        try:
            if len(typ.__slots__):
                keys.extend(typ.__slots__)
            if len(typ.__bases__):
                for base in typ.__bases__:
                    keys.extend(get_slots_members(base))
        except:
            pass

        return keys

    memo[obj_id] = cpy
    keys = []

    # Objects have either __dict__ or __slots__ or neither.
    # If object has none of it and it is copyable we already made a copy, just return it
    # If object is not copyable we shouldn't reach this point.
    try:
        keys = obj.__dict__.keys()
    except:
        try:
            obj.__slots__
            keys = get_slots_members(obj)
        except:
            return cpy

    for key in keys:
        attr = getattr(obj, key)
        attr_cpy = relatively_deep_copy(attr, memo)
        setattr(cpy, key, attr_cpy)

    return cpy