Example #1
0
    def inline_inlineable_portals(self):
        """
        Find all the graphs which have been decorated with @jitdriver.inline
        and inline them in the callers, making them JIT portals. Then, create
        a fresh copy of the jitdriver for each of those new portals, because
        they cannot share the same one.  See
        test_ajit::test_inline_jit_merge_point
        """
        from rpython.translator.backendopt.inline import (
            inlinable_static_callers, auto_inlining)

        jmp_calls = {}
        def get_jmp_call(graph, _inline_jit_merge_point_):
            # there might be multiple calls to the @inlined function: the
            # first time we see it, we remove the call to the jit_merge_point
            # and we remember the corresponding op. Then, we create a new call
            # to it every time we need a new one (i.e., for each callsite
            # which becomes a new portal)
            try:
                op, jmp_graph = jmp_calls[graph]
            except KeyError:
                op, jmp_graph = fish_jmp_call(graph, _inline_jit_merge_point_)
                jmp_calls[graph] = op, jmp_graph
            #
            # clone the op
            newargs = op.args[:]
            newresult = Variable()
            newresult.concretetype = op.result.concretetype
            op = SpaceOperation(op.opname, newargs, newresult)
            return op, jmp_graph

        def fish_jmp_call(graph, _inline_jit_merge_point_):
            # graph is function which has been decorated with
            # @jitdriver.inline, so its very first op is a call to the
            # function which contains the actual jit_merge_point: fish it!
            jmp_block, op_jmp_call = next(callee.iterblockops())
            msg = ("The first operation of an _inline_jit_merge_point_ graph must be "
                   "a direct_call to the function passed to @jitdriver.inline()")
            assert op_jmp_call.opname == 'direct_call', msg
            jmp_funcobj = op_jmp_call.args[0].value._obj
            assert jmp_funcobj._callable is _inline_jit_merge_point_, msg
            jmp_block.operations.remove(op_jmp_call)
            return op_jmp_call, jmp_funcobj.graph

        # find all the graphs which call an @inline_in_portal function
        callgraph = inlinable_static_callers(self.translator.graphs, store_calls=True)
        new_callgraph = []
        new_portals = set()
        inlined_jit_merge_points = set()
        for caller, block, op_call, callee in callgraph:
            func = getattr(callee, 'func', None)
            _inline_jit_merge_point_ = getattr(func, '_inline_jit_merge_point_', None)
            if _inline_jit_merge_point_:
                _inline_jit_merge_point_._always_inline_ = True
                inlined_jit_merge_points.add(_inline_jit_merge_point_)
                op_jmp_call, jmp_graph = get_jmp_call(callee, _inline_jit_merge_point_)
                #
                # now we move the op_jmp_call from callee to caller, just
                # before op_call. We assume that the args passed to
                # op_jmp_call are the very same which are received by callee
                # (i.e., the one passed to op_call)
                assert len(op_call.args) == len(op_jmp_call.args)
                op_jmp_call.args[1:] = op_call.args[1:]
                idx = block.operations.index(op_call)
                block.operations.insert(idx, op_jmp_call)
                #
                # finally, we signal that we want to inline op_jmp_call into
                # caller, so that finally the actuall call to
                # driver.jit_merge_point will be seen there
                new_callgraph.append((caller, jmp_graph))
                new_portals.add(caller)

        # inline them!
        inline_threshold = 0.1 # we rely on the _always_inline_ set above
        auto_inlining(self.translator, inline_threshold, new_callgraph)
        # clean up _always_inline_ = True, it can explode later
        for item in inlined_jit_merge_points:
            del item._always_inline_

        # make a fresh copy of the JitDriver in all newly created
        # jit_merge_points
        self.clone_inlined_jit_merge_points(new_portals)
Example #2
0
    def inline_inlineable_portals(self):
        """
        Find all the graphs which have been decorated with @jitdriver.inline
        and inline them in the callers, making them JIT portals. Then, create
        a fresh copy of the jitdriver for each of those new portals, because
        they cannot share the same one.  See
        test_ajit::test_inline_jit_merge_point
        """
        from rpython.translator.backendopt.inline import (
            inlinable_static_callers, auto_inlining)

        jmp_calls = {}

        def get_jmp_call(graph, _inline_jit_merge_point_):
            # there might be multiple calls to the @inlined function: the
            # first time we see it, we remove the call to the jit_merge_point
            # and we remember the corresponding op. Then, we create a new call
            # to it every time we need a new one (i.e., for each callsite
            # which becomes a new portal)
            try:
                op, jmp_graph = jmp_calls[graph]
            except KeyError:
                op, jmp_graph = fish_jmp_call(graph, _inline_jit_merge_point_)
                jmp_calls[graph] = op, jmp_graph
            #
            # clone the op
            newargs = op.args[:]
            newresult = Variable()
            newresult.concretetype = op.result.concretetype
            op = SpaceOperation(op.opname, newargs, newresult)
            return op, jmp_graph

        def fish_jmp_call(graph, _inline_jit_merge_point_):
            # graph is function which has been decorated with
            # @jitdriver.inline, so its very first op is a call to the
            # function which contains the actual jit_merge_point: fish it!
            jmp_block, op_jmp_call = next(callee.iterblockops())
            msg = (
                "The first operation of an _inline_jit_merge_point_ graph must be "
                "a direct_call to the function passed to @jitdriver.inline()")
            assert op_jmp_call.opname == 'direct_call', msg
            jmp_funcobj = op_jmp_call.args[0].value._obj
            assert jmp_funcobj._callable is _inline_jit_merge_point_, msg
            jmp_block.operations.remove(op_jmp_call)
            return op_jmp_call, jmp_funcobj.graph

        # find all the graphs which call an @inline_in_portal function
        callgraph = inlinable_static_callers(self.translator.graphs,
                                             store_calls=True)
        new_callgraph = []
        new_portals = set()
        inlined_jit_merge_points = set()
        for caller, block, op_call, callee in callgraph:
            func = getattr(callee, 'func', None)
            _inline_jit_merge_point_ = getattr(func,
                                               '_inline_jit_merge_point_',
                                               None)
            if _inline_jit_merge_point_:
                _inline_jit_merge_point_._always_inline_ = True
                inlined_jit_merge_points.add(_inline_jit_merge_point_)
                op_jmp_call, jmp_graph = get_jmp_call(
                    callee, _inline_jit_merge_point_)
                #
                # now we move the op_jmp_call from callee to caller, just
                # before op_call. We assume that the args passed to
                # op_jmp_call are the very same which are received by callee
                # (i.e., the one passed to op_call)
                assert len(op_call.args) == len(op_jmp_call.args)
                op_jmp_call.args[1:] = op_call.args[1:]
                idx = block.operations.index(op_call)
                block.operations.insert(idx, op_jmp_call)
                #
                # finally, we signal that we want to inline op_jmp_call into
                # caller, so that finally the actuall call to
                # driver.jit_merge_point will be seen there
                new_callgraph.append((caller, jmp_graph))
                new_portals.add(caller)

        # inline them!
        inline_threshold = 0.1  # we rely on the _always_inline_ set above
        auto_inlining(self.translator, inline_threshold, new_callgraph)
        # clean up _always_inline_ = True, it can explode later
        for item in inlined_jit_merge_points:
            del item._always_inline_

        # make a fresh copy of the JitDriver in all newly created
        # jit_merge_points
        self.clone_inlined_jit_merge_points(new_portals)