[pypy-commit] pypy default: extend storesink to be super-local, ie to follow links that are not merge links

cfbolz noreply at buildbot.pypy.org
Tue Sep 23 11:46:28 CEST 2014


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: 
Changeset: r73659:9f2eaab7ceeb
Date: 2014-09-06 18:56 +0200
http://bitbucket.org/pypy/pypy/changeset/9f2eaab7ceeb/

Log:	extend storesink to be super-local, ie to follow links that are not
	merge links

diff --git a/rpython/translator/backendopt/storesink.py b/rpython/translator/backendopt/storesink.py
--- a/rpython/translator/backendopt/storesink.py
+++ b/rpython/translator/backendopt/storesink.py
@@ -1,6 +1,8 @@
 
 from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.flowspace.model import mkentrymap, Variable
 from rpython.translator.backendopt import removenoops
+from rpython.translator import simplify
 
 def has_side_effects(op):
     if op.opname == 'debug_assert':
@@ -12,22 +14,63 @@
 
 
 def storesink_graph(graph):
+    """ remove superfluous getfields. use a super-local method: all non-join
+    blocks inherit the heap information from their (single) predecessor
+    """
     added_some_same_as = False
+    entrymap = mkentrymap(graph)
 
-    for block in graph.iterblocks():
-        newops = []
-        cache = {}
+    # all merge blocks are starting points
+    todo = [(block, None, None) for (block, prev_blocks) in entrymap.iteritems()
+                if len(prev_blocks) > 1 or block is graph.startblock]
 
-        newops, _some_same_as = _storesink_block(block, cache)
-        added_some_same_as = _some_same_as or added_some_same_as
+    visited = 0
+
+    while todo:
+        block, cache, inputlink = todo.pop()
+        visited += 1
+        if cache is None:
+            cache = {}
+
         if block.operations:
-            block.operations = newops
+            newops, changed_block = _storesink_block(block, cache, inputlink)
+            added_some_same_as = changed_block or added_some_same_as
+            if changed_block:
+                block.operations = newops
+        for link in block.exits:
+            if len(entrymap[link.target]) == 1:
+                new_cache = _translate_cache(cache, link)
+                todo.append((link.target, new_cache, link))
 
+    assert visited == len(entrymap)
     if added_some_same_as:
         removenoops.remove_same_as(graph)
+        simplify.transform_dead_op_vars(graph)
 
+def _translate_cache(cache, link):
+    if link.target.operations == (): # exit or except block:
+        return {}
+    block = link.target
+    local_versions = {var1: var2 for var1, var2 in zip(link.args, block.inputargs)}
+    def _translate_arg(arg):
+        if isinstance(arg, Variable):
+            res = local_versions.get(arg, None)
+            if res is None:
+                res = Variable(arg)
+                res.concretetype = arg.concretetype
+                link.args.append(arg)
+                block.inputargs.append(res)
+                local_versions[arg] = res
+            return res
+        else:
+            return arg
+    new_cache = {}
+    for (var, field), res in cache.iteritems():
+        if var in local_versions or not isinstance(var, Variable):
+            new_cache[_translate_arg(var), field] = _translate_arg(res)
+    return new_cache
 
-def _storesink_block(block, cache):
+def _storesink_block(block, cache, inputlink):
     def clear_cache_for(cache, concretetype, fieldname):
         for k in cache.keys():
             if k[0].concretetype == concretetype and k[1] == fieldname:
@@ -53,6 +96,6 @@
             clear_cache_for(cache, target.concretetype, field)
             cache[target, field] = op.args[2]
         elif has_side_effects(op):
-            cache = {}
+            cache.clear()
         newops.append(op)
     return newops, added_some_same_as
diff --git a/rpython/translator/backendopt/test/test_storesink.py b/rpython/translator/backendopt/test/test_storesink.py
--- a/rpython/translator/backendopt/test/test_storesink.py
+++ b/rpython/translator/backendopt/test/test_storesink.py
@@ -134,3 +134,22 @@
             return n
 
         self.check(f, [int], 0)
+
+
+    def test_cfg_splits(self):
+        class A(object):
+            pass
+
+        def f(i):
+            a = A()
+            j = i
+            for i in range(i):
+                a.x = i
+                if i:
+                    j = a.x + a.x
+                else:
+                    j = a.x * 5
+            return j
+
+        self.check(f, [int], 0)
+


More information about the pypy-commit mailing list