Esempio n. 1
0
    def create_exception_handling(self, graph):
        """After an exception in a direct_call (or indirect_call), that is not caught
        by an explicit
        except statement, we need to reraise the exception. So after this
        direct_call we need to test if an exception had occurred. If so, we return
        from the current graph with a special value (False/-1/-1.0/null).
        Because of the added exitswitch we need an additional block.
        """
        if hasattr(graph, 'exceptiontransformed'):
            assert self.same_obj(self.exc_data_ptr, graph.exceptiontransformed)
            return
        else:
            self.raise_analyzer.analyze_direct_call(graph)
            graph.exceptiontransformed = self.exc_data_ptr

        join_blocks(graph)
        # collect the blocks before changing them
        n_need_exc_matching_blocks = 0
        n_gen_exc_checks = 0
        #
        entrymap = mkentrymap(graph)
        if graph.exceptblock in entrymap:
            for link in entrymap[graph.exceptblock]:
                self.transform_jump_to_except_block(graph, entrymap, link)
        #
        for block in list(graph.iterblocks()):
            self.replace_fetch_restore_operations(block)
            need_exc_matching, gen_exc_checks = self.transform_block(
                graph, block)
            n_need_exc_matching_blocks += need_exc_matching
            n_gen_exc_checks += gen_exc_checks
        cleanup_graph(graph)
        return n_need_exc_matching_blocks, n_gen_exc_checks
Esempio n. 2
0
    def create_exception_handling(self, graph):
        """After an exception in a direct_call (or indirect_call), that is not caught
        by an explicit
        except statement, we need to reraise the exception. So after this
        direct_call we need to test if an exception had occurred. If so, we return
        from the current graph with a special value (False/-1/-1.0/null).
        Because of the added exitswitch we need an additional block.
        """
        if hasattr(graph, 'exceptiontransformed'):
            assert self.same_obj(self.exc_data_ptr, graph.exceptiontransformed)
            return
        else:
            self.raise_analyzer.analyze_direct_call(graph)
            graph.exceptiontransformed = self.exc_data_ptr

        join_blocks(graph)
        # collect the blocks before changing them
        n_need_exc_matching_blocks = 0
        n_gen_exc_checks           = 0
        #
        entrymap = mkentrymap(graph)
        if graph.exceptblock in entrymap:
            for link in entrymap[graph.exceptblock]:
                self.transform_jump_to_except_block(graph, entrymap, link)
        #
        for block in list(graph.iterblocks()):
            self.replace_fetch_restore_operations(block)
            need_exc_matching, gen_exc_checks = self.transform_block(graph, block)
            n_need_exc_matching_blocks += need_exc_matching
            n_gen_exc_checks           += gen_exc_checks
        cleanup_graph(graph)
        return n_need_exc_matching_blocks, n_gen_exc_checks
Esempio n. 3
0
def test_fix_graph_after_inlining():
    # the graph of f looks like it inlined another graph, which itself
    # would be "if x > 100: foobar()".  The foobar() function is supposed
    # to be the big slow-path.
    def foobar():
        print 42

    def f(x):
        llop.gc_push_roots(lltype.Void, x)
        if x > 100:  # slow-path
            foobar()
        llop.gc_pop_roots(lltype.Void, x)
        return x

    graph = make_graph(f, [int])
    postprocess_inlining(graph)
    cleanup_graph(graph)
    assert [op.opname
            for op in graph.startblock.operations] == ['int_gt', 'same_as']
    [fastpath, slowpath] = graph.startblock.exits
    assert fastpath.target is graph.returnblock
    block2 = slowpath.target
    [v] = block2.inputargs
    assert block2.operations[0].opname == 'gc_push_roots'
    assert block2.operations[0].args == [v]
    assert block2.operations[1].opname == 'direct_call'  # -> foobar
    assert block2.operations[2].opname == 'gc_pop_roots'
    assert block2.operations[2].args == [v]
    assert len(block2.exits) == 1
    assert block2.exits[0].target is graph.returnblock
Esempio n. 4
0
 def inline_helpers(self, graph):
     if not self.prepared:
         raise Exception("Need to call prepare_inline_helpers first")
     if self.inline:
         raise_analyzer = RaiseAnalyzer(self.translator)
         to_enum = self.graph_dependencies.get(graph, self.graphs_to_inline)
         must_constfold = False
         for inline_graph in to_enum:
             try:
                 inline.inline_function(self.translator, inline_graph, graph,
                                        self.lltype_to_classdef,
                                        raise_analyzer,
                                        cleanup=False)
                 must_constfold = True
             except inline.CannotInline, e:
                 print 'CANNOT INLINE:', e
                 print '\t%s into %s' % (inline_graph, graph)
         cleanup_graph(graph)
         if must_constfold:
             constant_fold_graph(graph)
Esempio n. 5
0
 def inline_helpers(self, graphs):
     from rpython.translator.backendopt.inline import iter_callsites
     raise_analyzer = RaiseAnalyzer(self.translator)
     for graph in graphs:
         to_enum = []
         for called, block, i in iter_callsites(graph, None):
             if called in self.graphs_to_inline:
                 to_enum.append(called)
         must_constfold = False
         for inline_graph in to_enum:
             try:
                 inline.inline_function(self.translator, inline_graph, graph,
                                        self.lltype_to_classdef,
                                        raise_analyzer,
                                        cleanup=False)
                 must_constfold = True
             except inline.CannotInline as e:
                 print 'CANNOT INLINE:', e
                 print '\t%s into %s' % (inline_graph, graph)
         cleanup_graph(graph)
         if must_constfold:
             constant_fold_graph(graph)
Esempio n. 6
0
 def inline_helpers_into(self, graph):
     from rpython.translator.backendopt.inline import iter_callsites
     to_enum = []
     for called, block, i in iter_callsites(graph, None):
         if called in self.graphs_to_inline:
             to_enum.append(called)
     any_inlining = False
     for inline_graph in to_enum:
         try:
             inline.inline_function(self.translator, inline_graph, graph,
                                    self.lltype_to_classdef,
                                    self.raise_analyzer,
                                    cleanup=False)
             any_inlining = True
         except inline.CannotInline as e:
             print 'CANNOT INLINE:', e
             print '\t%s into %s' % (inline_graph, graph)
             raise      # for now, make it a fatal error
     cleanup_graph(graph)
     if any_inlining:
         constant_fold_graph(graph)
     return any_inlining
Esempio n. 7
0
 def inline_helpers(self, graph):
     if not self.prepared:
         raise Exception("Need to call prepare_inline_helpers first")
     if self.inline:
         raise_analyzer = RaiseAnalyzer(self.translator)
         to_enum = self.graph_dependencies.get(graph, self.graphs_to_inline)
         must_constfold = False
         for inline_graph in to_enum:
             try:
                 inline.inline_function(self.translator,
                                        inline_graph,
                                        graph,
                                        self.lltype_to_classdef,
                                        raise_analyzer,
                                        cleanup=False)
                 must_constfold = True
             except inline.CannotInline, e:
                 print 'CANNOT INLINE:', e
                 print '\t%s into %s' % (inline_graph, graph)
         cleanup_graph(graph)
         if must_constfold:
             constant_fold_graph(graph)
Esempio n. 8
0
 def inline_helpers(self, graphs):
     from rpython.translator.backendopt.inline import iter_callsites
     raise_analyzer = RaiseAnalyzer(self.translator)
     for graph in graphs:
         to_enum = []
         for called, block, i in iter_callsites(graph, None):
             if called in self.graphs_to_inline:
                 to_enum.append(called)
         must_constfold = False
         for inline_graph in to_enum:
             try:
                 inline.inline_function(self.translator,
                                        inline_graph,
                                        graph,
                                        self.lltype_to_classdef,
                                        raise_analyzer,
                                        cleanup=False)
                 must_constfold = True
             except inline.CannotInline, e:
                 print 'CANNOT INLINE:', e
                 print '\t%s into %s' % (inline_graph, graph)
         cleanup_graph(graph)
         if must_constfold:
             constant_fold_graph(graph)
Esempio n. 9
0
File: inline.py Progetto: Mu-L/pypy
def auto_inlining(translator, threshold=None,
                  callgraph=None,
                  call_count_pred=None,
                  heuristic=inlining_heuristic):

    assert threshold is not None and threshold != 1
    to_cleanup = {}
    from heapq import heappush, heappop, heapreplace, heapify
    callers = {}     # {graph: {graphs-that-call-it}}
    callees = {}     # {graph: {graphs-that-it-calls}}
    if callgraph is None:
        callgraph = inlinable_static_callers(translator.graphs)
    for graph1, graph2 in callgraph:
        callers.setdefault(graph2, {})[graph1] = True
        callees.setdefault(graph1, {})[graph2] = True
    # the -len(callers) change is OK
    heap = [(0.0, -len(callers[graph]), graph) for graph in callers]
    valid_weight = {}
    try_again = {}
    lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping()
    raise_analyzer = RaiseAnalyzer(translator)
    count = 0
    while heap:
        weight, _, graph = heap[0]
        if not valid_weight.get(graph):
            if always_inline(graph):
                weight, fixed = 0.0, True
            else:
                weight, fixed = heuristic(graph)
                # Don't let 'weight' be NaN past this point.  If we do,
                # then heapify() might (sometimes, rarely) not do its job
                # correctly.  I suspect it's because the algorithm gets
                # confused by the fact that both 'a < b' and 'b < a' are
                # false.  A concrete example: [39.0, 0.0, 33.0, nan, nan]
                # heapifies to [33.0, nan, 39.0, nan, 0.0], but 33.0 is
                # not the smallest item.
                if not (weight < 1e9):
                    weight = 1e9
            #print '  + cost %7.2f %50s' % (weight, graph.name)
            heapreplace(heap, (weight, -len(callers[graph]), graph))
            valid_weight[graph] = True
            if not fixed:
                try_again[graph] = 'initial'
            continue

        if weight >= threshold:
            # finished... unless some graphs not in valid_weight would now
            # have a weight below the threshold.  Re-insert such graphs
            # at the start of the heap
            finished = True
            for i in range(len(heap)):
                graph = heap[i][2]
                if not valid_weight.get(graph):
                    heap[i] = (0.0, heap[i][1], graph)
                    finished = False
            if finished:
                break
            else:
                heapify(heap)
                continue

        heappop(heap)
        if callers[graph]:
            if translator.config.translation.verbose:
                log.inlining('%7.2f %50s' % (weight, graph.name))
            else:
                log.dot()
        for parentgraph in callers[graph]:
            if parentgraph == graph:
                continue
            subcount = 0
            try:
                subcount = inline_function(translator, graph, parentgraph,
                                           lltype_to_classdef, raise_analyzer,
                                           call_count_pred, cleanup=False)
                to_cleanup[parentgraph] = True
                res = bool(subcount)
            except CannotInline as e:
                try_again[graph] = str(e)
                res = CannotInline
            if res is True:
                count += subcount
                # the parentgraph should now contain all calls that were
                # done by 'graph'
                for graph2 in callees.get(graph, {}):
                    callees[parentgraph][graph2] = True
                    callers[graph2][parentgraph] = True
                if parentgraph in try_again:
                    # the parentgraph was previously uninlinable, but it has
                    # been modified.  Maybe now we can inline it into further
                    # parents?
                    del try_again[parentgraph]
                    heappush(heap, (0.0, -len(callers[parentgraph]), parentgraph))
                valid_weight[parentgraph] = False

    invalid = [(graph, msg) for graph, msg in try_again.items()
                            if always_inline(graph) is True]
    if invalid:
        message = '\n'.join([
            "%s has _always_inline_=True but inlining failed:\n\t%s" %
            (graph, msg) for (graph, msg) in invalid])
        raise CannotInline(message)

    for graph in to_cleanup:
        cleanup_graph(graph)
    return count
Esempio n. 10
0
File: inline.py Progetto: Mu-L/pypy
 def cleanup(self):
     """ cleaning up -- makes sense to be done after inlining, because the
     inliner inserted quite some empty blocks and blocks that can be
     joined. """
     cleanup_graph(self.graph)
Esempio n. 11
0
 def cleanup(self):
     """ cleaning up -- makes sense to be done after inlining, because the
     inliner inserted quite some empty blocks and blocks that can be
     joined. """
     cleanup_graph(self.graph)
Esempio n. 12
0
                    # been modified.  Maybe now we can inline it into further
                    # parents?
                    del try_again[parentgraph]
                    heappush(heap, (0.0, -len(callers[parentgraph]), parentgraph))
                valid_weight[parentgraph] = False

    invalid = [(graph, msg) for graph, msg in try_again.items()
                            if always_inline(graph) is True]
    if invalid:
        message = '\n'.join([
            "%s has _always_inline_=True but inlining failed:\n\t%s" %
            (graph, msg) for (graph, msg) in invalid])
        raise CannotInline(message)

    for graph in to_cleanup:
        cleanup_graph(graph)
    return count

def auto_inline_graphs(translator, graphs, threshold, call_count_pred=None,
                       heuristic=inlining_heuristic,
                       inline_graph_from_anywhere=False):
    if inline_graph_from_anywhere:
        # it's ok to inline calls to any graph, with the exception of
        # graphs that would be already exception-transformed
        ok_to_call = set([graph for graph in translator.graphs
                                if not hasattr(graph, 'exceptiontransformed')])
    else:
        ok_to_call = None
    callgraph = inlinable_static_callers(graphs, ok_to_call=ok_to_call)
    count = auto_inlining(translator, threshold, callgraph=callgraph,
                          heuristic=heuristic,
Esempio n. 13
0
def auto_inlining(translator, threshold=None,
                  callgraph=None,
                  call_count_pred=None,
                  heuristic=inlining_heuristic):

    assert threshold is not None and threshold != 1
    to_cleanup = {}
    from heapq import heappush, heappop, heapreplace, heapify
    callers = {}     # {graph: {graphs-that-call-it}}
    callees = {}     # {graph: {graphs-that-it-calls}}
    if callgraph is None:
        callgraph = inlinable_static_callers(translator.graphs)
    for graph1, graph2 in callgraph:
        callers.setdefault(graph2, {})[graph1] = True
        callees.setdefault(graph1, {})[graph2] = True
    # the -len(callers) change is OK
    heap = [(0.0, -len(callers[graph]), graph) for graph in callers]
    valid_weight = {}
    try_again = {}
    lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping()
    raise_analyzer = RaiseAnalyzer(translator)
    count = 0
    while heap:
        weight, _, graph = heap[0]
        if not valid_weight.get(graph):
            if always_inline(graph):
                weight, fixed = 0.0, True
            else:
                weight, fixed = heuristic(graph)
            #print '  + cost %7.2f %50s' % (weight, graph.name)
            heapreplace(heap, (weight, -len(callers[graph]), graph))
            valid_weight[graph] = True
            if not fixed:
                try_again[graph] = 'initial'
            continue

        if weight >= threshold:
            # finished... unless some graphs not in valid_weight would now
            # have a weight below the threshold.  Re-insert such graphs
            # at the start of the heap
            finished = True
            for i in range(len(heap)):
                graph = heap[i][2]
                if not valid_weight.get(graph):
                    heap[i] = (0.0, heap[i][1], graph)
                    finished = False
            if finished:
                break
            else:
                heapify(heap)
                continue

        heappop(heap)
        if callers[graph]:
            if translator.config.translation.verbose:
                log.inlining('%7.2f %50s' % (weight, graph.name))
            else:
                log.dot()
        for parentgraph in callers[graph]:
            if parentgraph == graph:
                continue
            subcount = 0
            try:
                subcount = inline_function(translator, graph, parentgraph,
                                           lltype_to_classdef, raise_analyzer,
                                           call_count_pred, cleanup=False)
                to_cleanup[parentgraph] = True
                res = bool(subcount)
            except CannotInline as e:
                try_again[graph] = str(e)
                res = CannotInline
            if res is True:
                count += subcount
                # the parentgraph should now contain all calls that were
                # done by 'graph'
                for graph2 in callees.get(graph, {}):
                    callees[parentgraph][graph2] = True
                    callers[graph2][parentgraph] = True
                if parentgraph in try_again:
                    # the parentgraph was previously uninlinable, but it has
                    # been modified.  Maybe now we can inline it into further
                    # parents?
                    del try_again[parentgraph]
                    heappush(heap, (0.0, -len(callers[parentgraph]), parentgraph))
                valid_weight[parentgraph] = False

    invalid = [(graph, msg) for graph, msg in try_again.items()
                            if always_inline(graph) is True]
    if invalid:
        message = '\n'.join([
            "%s has _always_inline_=True but inlining failed:\n\t%s" %
            (graph, msg) for (graph, msg) in invalid])
        raise CannotInline(message)

    for graph in to_cleanup:
        cleanup_graph(graph)
    return count
Esempio n. 14
0
                    del try_again[parentgraph]
                    heappush(heap,
                             (0.0, -len(callers[parentgraph]), parentgraph))
                valid_weight[parentgraph] = False

    invalid = [(graph, msg) for graph, msg in try_again.items()
               if always_inline(graph) is True]
    if invalid:
        message = '\n'.join([
            "%s has _always_inline_=True but inlining failed:\n\t%s" %
            (graph, msg) for (graph, msg) in invalid
        ])
        raise CannotInline(message)

    for graph in to_cleanup:
        cleanup_graph(graph)
    return count


def auto_inline_graphs(translator,
                       graphs,
                       threshold,
                       call_count_pred=None,
                       heuristic=inlining_heuristic,
                       inline_graph_from_anywhere=False):
    if inline_graph_from_anywhere:
        # it's ok to inline calls to any graph, with the exception of
        # graphs that would be already exception-transformed
        ok_to_call = set([
            graph for graph in translator.graphs
            if not hasattr(graph, 'exceptiontransformed')