[pypy-svn] r24491 - pypy/dist/pypy/translator/backendopt

cfbolz at codespeak.net cfbolz at codespeak.net
Thu Mar 16 20:35:33 CET 2006


Author: cfbolz
Date: Thu Mar 16 20:35:32 2006
New Revision: 24491

Modified:
   pypy/dist/pypy/translator/backendopt/inline.py
Log:
try to make inlining behave a bit less quadratical :-) don't search for calls
to the to-be-inlined function all over again after inlining one call.  just
look in blocks that actually changed


Modified: pypy/dist/pypy/translator/backendopt/inline.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/inline.py	(original)
+++ pypy/dist/pypy/translator/backendopt/inline.py	Thu Mar 16 20:35:32 2006
@@ -39,16 +39,15 @@
 
 def iter_callsites(graph, calling_what):
     for block in graph.iterblocks():
-        if isinstance(block, Block):
-            for i, op in enumerate(block.operations):
-                if not op.opname == "direct_call":
-                    continue
-                funcobj = op.args[0].value._obj
-                graph = getattr(funcobj, 'graph', None)
-                # accept a function or a graph as 'inline_func'
-                if (graph is calling_what or
-                    getattr(funcobj, '_callable', None) is calling_what):
-                    yield graph, block, i
+        for i, op in enumerate(block.operations):
+            if not op.opname == "direct_call":
+                continue
+            funcobj = op.args[0].value._obj
+            graph = getattr(funcobj, 'graph', None)
+            # accept a function or a graph as 'inline_func'
+            if (graph is calling_what or
+                getattr(funcobj, '_callable', None) is calling_what):
+                yield graph, block, i
 
 def find_callsites(graph, calling_what):
     return list(iter_callsites(graph, calling_what))
@@ -69,19 +68,8 @@
         return False
 
 def inline_function(translator, inline_func, graph):
-    count = 0
-    for subgraph, block, index_operation in iter_first_callsites(graph, inline_func):
-        if contains_call(subgraph, subgraph):
-            raise CannotInline("inlining a recursive function")
-        operation = block.operations[index_operation]
-        if getattr(operation, "cleanup", None) is not None:
-            finallyops, exceptops = operation.cleanup
-            if finallyops or exceptops:
-                raise CannotInline("cannot inline a function with cleanup attached")
-        _inline_function(translator, graph, block, index_operation)
-        checkgraph(graph)
-        count += 1
-    return count
+    inliner = Inliner(translator, graph, inline_func)
+    return inliner.inline_all()
 
 def _find_exception_type(block):
     #XXX slightly brittle: find the exception type for simple cases
@@ -101,11 +89,39 @@
 
 
 class Inliner(object):
-    def __init__(self, translator, graph, block, index_operation):
+    def __init__(self, translator, graph, inline_func):
         self.translator = translator
         self.graph = graph
+        self.inline_func = inline_func
+        callsites = find_callsites(graph, inline_func)
+        self.block_to_index = {}
+        for g, block, i in callsites:
+            self.block_to_index.setdefault(block, {})[i] = g
+
+    def inline_all(self):
+        count = 0
+        non_recursive = {}
+        while self.block_to_index:
+            block, d = self.block_to_index.popitem()
+            index_operation, subgraph = d.popitem()
+            if d:
+                self.block_to_index[block] = d
+            if subgraph not in non_recursive and contains_call(subgraph, subgraph):
+                raise CannotInline("inlining a recursive function")
+            else:
+                non_recursive[subgraph] = True
+            operation = block.operations[index_operation]
+            if getattr(operation, "cleanup", None) is not None:
+                finallyops, exceptops = operation.cleanup
+                if finallyops or exceptops:
+                    raise CannotInline("cannot inline a function with cleanup attached")
+            self.inline_once(block, index_operation)
+            count += 1
+        self.cleanup()
+        return count
+
+    def inline_once(self, block, index_operation):
         self.varmap = {}
-        self.beforeblock = block
         self._copied_blocks = {}
         self._copied_cleanups = {}
         self.op = block.operations[index_operation]
@@ -119,7 +135,25 @@
         self._passon_vars = {}
         self.entrymap = mkentrymap(self.graph_to_inline)
         self.do_inline(block, index_operation)
-        self.cleanup()
+
+    def search_for_calls(self, block):
+        d = {}
+        for i, op in enumerate(block.operations):
+            if not op.opname == "direct_call":
+                continue
+            funcobj = op.args[0].value._obj
+            graph = getattr(funcobj, 'graph', None)
+            # accept a function or a graph as 'inline_func'
+            if (graph is self.inline_func or
+                getattr(funcobj, '_callable', None) is self.inline_func):
+                d[i] = graph
+        if d:
+            self.block_to_index[block] = d
+        else:
+            try:
+                del self.block_to_index[block]
+            except KeyError:
+                pass
 
     def get_new_name(self, var):
         if var is None:
@@ -172,6 +206,7 @@
         newblock.exits = [self.copy_link(link, block) for link in block.exits]
         newblock.exitswitch = self.get_new_name(block.exitswitch)
         newblock.exc_handler = block.exc_handler
+        self.search_for_calls(newblock)
         return newblock
 
     def copy_link(self, link, prevblock):
@@ -322,11 +357,11 @@
         # the inlined function
         # for every inserted block we need a new copy of these variables,
         # this copy is created with the method passon_vars
-        self.original_passon_vars = [arg for arg in self.beforeblock.exits[0].args
+        self.original_passon_vars = [arg for arg in block.exits[0].args
                                          if isinstance(arg, Variable)]
         assert afterblock.operations[0] is self.op
         #vars that need to be passed through the blocks of the inlined function
-        linktoinlined = self.beforeblock.exits[0]
+        linktoinlined = block.exits[0]
         assert linktoinlined.target is afterblock
         copiedstartblock = self.copy_block(self.graph_to_inline.startblock)
         copiedstartblock.isstartblock = False
@@ -352,6 +387,8 @@
             assert afterblock.exits[0].exitcase is None
             afterblock.exits = [afterblock.exits[0]]
             afterblock.exitswitch = None
+        self.search_for_calls(afterblock)
+        self.search_for_calls(block)
 
     def cleanup(self):
         """ cleaning up -- makes sense to be done after inlining, because the
@@ -363,7 +400,9 @@
         remove_identical_vars(self.graph)
 
 
-_inline_function = Inliner
+def _inline_function(translator, graph, block, index_operation):
+    inline_func = block.operations[index_operation].args[0].value._obj._callable
+    inliner = Inliner(translator, graph, inline_func)
 
 # ____________________________________________________________
 #



More information about the Pypy-commit mailing list