[pypy-commit] pypy better-storesink: use the write analyzer to know when to invalidate the cache

cfbolz pypy.commits at gmail.com
Fri Sep 16 17:12:48 EDT 2016


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: better-storesink
Changeset: r87151:e53758af61e3
Date: 2016-08-22 13:59 +0100
http://bitbucket.org/pypy/pypy/changeset/e53758af61e3/

Log:	use the write analyzer to know when to invalidate the cache

diff --git a/rpython/translator/backendopt/cse.py b/rpython/translator/backendopt/cse.py
--- a/rpython/translator/backendopt/cse.py
+++ b/rpython/translator/backendopt/cse.py
@@ -6,10 +6,9 @@
 from rpython.translator.backendopt import removenoops
 from rpython.translator import simplify
 from rpython.translator.backendopt import ssa
+from rpython.translator.backendopt.writeanalyze import WriteAnalyzer
 
 def has_side_effects(op):
-    if op.opname == 'debug_assert' or op.opname == 'jit_force_virtualizable':
-        return False
     try:
         return getattr(llop, op.opname).sideeffects
     except AttributeError:
@@ -22,7 +21,7 @@
     return getattr(llop, op.opname).canfold
 
 class Cache(object):
-    def __init__(self, variable_families, purecache=None, heapcache=None):
+    def __init__(self, variable_families, analyzer, purecache=None, heapcache=None):
         if purecache is None:
             purecache = {}
         if heapcache is None:
@@ -30,10 +29,12 @@
         self.purecache = purecache
         self.heapcache = heapcache
         self.variable_families = variable_families
+        self.analyzer = analyzer
 
     def copy(self):
         return Cache(
-                self.variable_families, self.purecache.copy(),
+                self.variable_families, self.analyzer,
+                self.purecache.copy(),
                 self.heapcache.copy())
 
 
@@ -72,13 +73,21 @@
                     block.inputargs.append(newres)
                 heapcache[key] = newres
 
-        return Cache(self.variable_families, purecache, heapcache)
+        return Cache(
+                self.variable_families, self.analyzer, purecache, heapcache)
 
     def _clear_heapcache_for(self, concretetype, fieldname):
         for k in self.heapcache.keys():
             if k[0].concretetype == concretetype and k[1] == fieldname:
                 del self.heapcache[k]
 
+    def _clear_heapcache_for_effects(self, op):
+        effects = self.analyzer.analyze(op)
+        for k in self.heapcache.keys():
+            key = ('struct', k[0].concretetype, k[1])
+            if key in effects:
+                del self.heapcache[k]
+
     def cse_block(self, block):
         def representative_arg(arg):
             if isinstance(arg, Variable):
@@ -97,8 +106,6 @@
                 else:
                     self.heapcache[tup] = op.result
                 continue
-            if op.opname in ('setarrayitem', 'setinteriorfield', "malloc", "malloc_varsize"):
-                continue
             if op.opname == 'setfield':
                 target = representative_arg(op.args[0])
                 field = op.args[1].value
@@ -106,7 +113,7 @@
                 self.heapcache[target, field] = op.args[2]
                 continue
             if has_side_effects(op):
-                self.heapcache.clear()
+                self._clear_heapcache_for_effects(op)
                 continue
 
             # foldable operations
@@ -124,9 +131,9 @@
                 self.purecache[key] = op.result
         return added_some_same_as
 
-def _merge(tuples, variable_families):
+def _merge(tuples, variable_families, analyzer):
     if not tuples:
-        return Cache(variable_families)
+        return Cache(variable_families, analyzer)
     if len(tuples) == 1:
         (link, cache), = tuples
         return cache.copy()
@@ -136,6 +143,7 @@
 class CSE(object):
     def __init__(self, translator):
         self.translator = translator
+        self.analyzer = WriteAnalyzer(translator)
 
     def transform(self, graph):
         variable_families = ssa.DataFlowFamilyBuilder(graph).get_variable_families()
@@ -156,9 +164,10 @@
 
             if block.operations:
                 if not can_cache:
-                    cache = Cache(variable_families)
+                    cache = Cache(variable_families, self.analyzer)
                 else:
-                    cache = _merge(caches_to_merge[block], variable_families)
+                    cache = _merge(
+                        caches_to_merge[block], variable_families, self.analyzer)
                 changed_block = cache.cse_block(block)
                 added_some_same_as = changed_block or added_some_same_as
             done.add(block)
diff --git a/rpython/translator/backendopt/test/test_cse.py b/rpython/translator/backendopt/test/test_cse.py
--- a/rpython/translator/backendopt/test/test_cse.py
+++ b/rpython/translator/backendopt/test/test_cse.py
@@ -212,3 +212,23 @@
             return j
 
         self.check(f, [int], getfield=0)
+
+    def test_dont_invalidate_on_call(self):
+        class A(object):
+            pass
+        class B(object):
+            pass
+        def g(b, a):
+            b.x = 1
+            a.y = 2
+
+        def f(i):
+            a = A()
+            a.x = i
+            a.y = i + 1
+            b = B()
+            g(b, a)
+            return a.x + a.y
+
+        self.check(f, [int], getfield=1)
+


More information about the pypy-commit mailing list