[pypy-svn] r58621 - in pypy/dist/pypy/translator/backendopt: . test

arigo at codespeak.net arigo at codespeak.net
Mon Oct 6 11:52:45 CEST 2008


Author: arigo
Date: Mon Oct  6 11:52:43 2008
New Revision: 58621

Modified:
   pypy/dist/pypy/translator/backendopt/mallocv.py
   pypy/dist/pypy/translator/backendopt/test/test_mallocv.py
Log:
(iko, arigo)

Support virtualizing objects that go into calls, by specializing the
called functions.  (In-progress; this is wrong so far for mutable
objects.)



Modified: pypy/dist/pypy/translator/backendopt/mallocv.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/mallocv.py	(original)
+++ pypy/dist/pypy/translator/backendopt/mallocv.py	Mon Oct  6 11:52:43 2008
@@ -1,6 +1,8 @@
 from pypy.objspace.flow.model import Variable, Constant, Block, Link
-from pypy.objspace.flow.model import SpaceOperation
+from pypy.objspace.flow.model import SpaceOperation, FunctionGraph
 from pypy.translator.backendopt.support import log
+from pypy.rpython.typesystem import getfunctionptr
+from pypy.rpython.lltypesystem import lltype
 
 
 # ____________________________________________________________
@@ -13,7 +15,8 @@
 class MallocVirtualizer(object):
 
     def __init__(self, graphs):
-        self.graphs = list(graphs)
+        self.graphs = graphs
+        self.new_graphs = {}
         self.cache = BlockSpecCache()
         self.count_virtualized = 0
 
@@ -42,6 +45,7 @@
                 except CannotVirtualize, e:
                     if verbose:
                         log.mallocv('%s failed: %s' % (op.result, e))
+        self.put_new_graphs_back_in_translator()
         progress = self.report_result() - prev
         return progress
 
@@ -53,12 +57,19 @@
         mallocspec.commit()
         self.count_virtualized += 1
 
+    def put_new_graphs_back_in_translator(self):
+        for graph in self.cache.graph_starting_at.values():
+            if graph not in self.new_graphs:
+                self.new_graphs[graph] = True
+                self.graphs.append(graph)
+
 
 class BlockSpecCache(object):
 
     def __init__(self, fallback=None):
         self.specialized_blocks = {}
         self.block_keys = {}
+        self.graph_starting_at = {}
         self.fallback = fallback
 
     def lookup_spec_block(self, block, extra_key):
@@ -78,9 +89,22 @@
         self.specialized_blocks[key] = specblock
         self.block_keys[specblock] = key
 
+    def lookup_graph_starting_at(self, startblock):
+        try:
+            return self.graph_starting_at[startblock]
+        except KeyError:
+            if self.fallback is None:
+                return None
+            else:
+                return self.fallback.graph_starting_at.get(startblock)
+
+    def remember_graph_starting_at(self, startblock, graph):
+        self.graph_starting_at[startblock] = graph
+
     def push_changes(self):
         self.fallback.specialized_blocks.update(self.specialized_blocks)
         self.fallback.block_keys.update(self.block_keys)
+        self.fallback.graph_starting_at.update(self.graph_starting_at)
 
 
 class MallocSpecializer(object):
@@ -138,6 +162,15 @@
                                            specblock)
         return specblock
 
+    def get_specialized_graph(self, graph, v):
+        block = graph.startblock
+        specblock = self.get_specialized_block(block, v)
+        specgraph = self.cache.lookup_graph_starting_at(specblock)
+        if specgraph is None:
+            specgraph = FunctionGraph(graph.name + '_spec', specblock)
+            self.cache.remember_graph_starting_at(specblock, specgraph)
+        return specgraph
+
     def propagate_specializations(self):
         while self.pending_specializations:
             spec, block, specblock = self.pending_specializations.pop()
@@ -172,6 +205,8 @@
             self.expanded_v.append(c)
 
     def rename_nonvirtual(self, v, where=None):
+        if isinstance(v, Constant):
+            return v
         if v in self.curvars:
             raise CannotVirtualize(where)
         [v2] = self.renamings[v]
@@ -234,3 +269,34 @@
             return []
         else:
             return self.handle_default(op)
+
+    def handle_op_direct_call(self, op):
+        fobj = op.args[0].value._obj
+        if hasattr(fobj, 'graph'):
+            graph = fobj.graph
+            nb_args = len(op.args) - 1
+            assert nb_args == len(graph.getargs())
+            newargs = []
+            for i in range(nb_args):
+                v1 = op.args[1+i]
+                if v1 not in self.curvars:
+                    newargs.append(v1)
+                else:
+                    inputarg_index_in_specgraph = len(newargs)
+                    v2 = graph.getargs()[inputarg_index_in_specgraph]
+                    assert v1.concretetype == v2.concretetype
+                    specgraph = self.mallocspec.get_specialized_graph(graph,
+                                                                      v2)
+                    newargs.extend(self.expanded_v)
+                    graph = specgraph
+            assert len(newargs) == len(graph.getargs())
+            fspecptr = getfunctionptr(graph)
+            newargs.insert(0, Constant(fspecptr,
+                                       concretetype=lltype.typeOf(fspecptr)))
+            newresult = Variable(op.result)
+            newresult.concretetype = op.result.concretetype
+            self.renamings[op.result] = [newresult]
+            newop = SpaceOperation('direct_call', newargs, newresult)
+            return [newop]
+        else:
+            return self.handle_default(op)

Modified: pypy/dist/pypy/translator/backendopt/test/test_mallocv.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/test/test_mallocv.py	(original)
+++ pypy/dist/pypy/translator/backendopt/test/test_mallocv.py	Mon Oct  6 11:52:43 2008
@@ -23,18 +23,15 @@
     def check_malloc_removed(cls, graph):
         #remover = cls.MallocRemover()
         checkgraph(graph)
-        count1 = count2 = 0
+        count = 0
         for node in flatten(graph):
             if isinstance(node, Block):
                 for op in node.operations:
                     if op.opname == 'malloc': #cls.MallocRemover.MALLOC_OP:
                         S = op.args[0].value
                         #if not remover.union_wrapper(S):   # union wrappers are fine
-                        count1 += 1
-                    if op.opname in ('direct_call', 'indirect_call'):
-                        count2 += 1
-        assert count1 == 0   # number of mallocs left
-        assert count2 == 0   # number of calls left
+                        count += 1
+        assert count == 0   # number of mallocs left
     check_malloc_removed = classmethod(check_malloc_removed)
 
     def check(self, fn, signature, args, expected_result, must_be_removed=True):
@@ -75,6 +72,14 @@
         insns = summary(graph)
         assert insns['int_mul'] == 1
 
+    def test_direct_call(self):
+        def g(t):
+            a, b = t
+            return a * b
+        def f(x):
+            return g((x+1, x-1))
+        graph = self.check(f, [int], [10], 99)
+
     def test_fn2(self):
         py.test.skip("redo me")
         class T:



More information about the Pypy-commit mailing list