[pypy-svn] r70273 - in pypy/branch/jit-delayed-write/pypy/jit/metainterp: . test

arigo at codespeak.net arigo at codespeak.net
Fri Dec 25 20:29:17 CET 2009


Author: arigo
Date: Fri Dec 25 20:29:16 2009
New Revision: 70273

Modified:
   pypy/branch/jit-delayed-write/pypy/jit/metainterp/effectinfo.py
   pypy/branch/jit-delayed-write/pypy/jit/metainterp/optimizeopt.py
   pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_effectinfo.py
   pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizefindnode.py
   pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizeopt.py
Log:
Get optimizeopt.py to delay some writes.  All tests pass
so far but might be slightly wrong.


Modified: pypy/branch/jit-delayed-write/pypy/jit/metainterp/effectinfo.py
==============================================================================
--- pypy/branch/jit-delayed-write/pypy/jit/metainterp/effectinfo.py	(original)
+++ pypy/branch/jit-delayed-write/pypy/jit/metainterp/effectinfo.py	Fri Dec 25 20:29:16 2009
@@ -7,16 +7,16 @@
 class EffectInfo(object):
     _cache = {}
 
-    def __new__(cls, read_descrs_fields, write_descrs_fields,
+    def __new__(cls, readonly_descrs_fields, write_descrs_fields,
                 write_descrs_arrays, promotes_virtualizables=False):
-        key = (frozenset(read_descrs_fields),
+        key = (frozenset(readonly_descrs_fields),
                frozenset(write_descrs_fields),
                frozenset(write_descrs_arrays),
                promotes_virtualizables)
         if key in cls._cache:
             return cls._cache[key]
         result = object.__new__(cls)
-        result.read_descrs_fields = read_descrs_fields
+        result.readonly_descrs_fields = readonly_descrs_fields
         result.write_descrs_fields = write_descrs_fields
         result.write_descrs_arrays = write_descrs_arrays
         result.promotes_virtualizables = promotes_virtualizables
@@ -27,8 +27,8 @@
     from pypy.translator.backendopt.writeanalyze import top_set
     if effects is top_set:
         return None
-    read_descrs_fields = []
-    # read_descrs_arrays = [] --- not enabled for now
+    readonly_descrs_fields = []
+    # readonly_descrs_arrays = [] --- not enabled for now
     write_descrs_fields = []
     write_descrs_arrays = []
 
@@ -48,14 +48,16 @@
         if tup[0] == "struct":
             add_struct(write_descrs_fields, tup)
         elif tup[0] == "readstruct":
-            add_struct(read_descrs_fields, tup)
+            tupw = ("struct",) + tup[1:]
+            if tupw not in effects:
+                add_struct(readonly_descrs_fields, tup)
         elif tup[0] == "array":
             add_array(write_descrs_arrays, tup)
         elif tup[0] == "readarray":
             pass
         else:
             assert 0
-    return EffectInfo(read_descrs_fields,
+    return EffectInfo(readonly_descrs_fields,
                       write_descrs_fields,
                       write_descrs_arrays,
                       promotes_virtualizables)

Modified: pypy/branch/jit-delayed-write/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/jit-delayed-write/pypy/jit/metainterp/optimizeopt.py	(original)
+++ pypy/branch/jit-delayed-write/pypy/jit/metainterp/optimizeopt.py	Fri Dec 25 20:29:16 2009
@@ -512,6 +512,9 @@
 
     def emit_operation(self, op, must_clone=True):
         self.heap_op_optimizer.emitting_operation(op)
+        self._emit_operation(op, must_clone)
+
+    def _emit_operation(self, op, must_clone=True):
         for i in range(len(op.args)):
             arg = op.args[i]
             if arg in self.values:
@@ -836,11 +839,13 @@
 class HeapOpOptimizer(object):
     def __init__(self, optimizer):
         self.optimizer = optimizer
-        # cached OptValues for each field descr
+        # cached fields:  {descr: {OptValue_instance: OptValue_fieldvalue}}
         self.cached_fields = {}
-
-        # cached OptValues for each field descr
+        # cached array items:  {descr: CachedArrayItems}
         self.cached_arrayitems = {}
+        # lazily written setfields (at most one per descr):  {descr: op}
+        self.lazy_setfields = {}
+        self.lazy_setfields_descrs = []     # keys (at least) of previous dict
 
     def clean_caches(self):
         self.cached_fields.clear()
@@ -908,8 +913,6 @@
         return None
 
     def emitting_operation(self, op):
-        if op.is_always_pure():
-            return
         if op.has_no_side_effect():
             return
         if op.is_ovf():
@@ -921,12 +924,16 @@
             opnum == rop.SETARRAYITEM_GC or
             opnum == rop.DEBUG_MERGE_POINT):
             return
-        if opnum == rop.CALL:
+        if (opnum == rop.CALL or
+            opnum == rop.CALL_MAY_FORCE):
             effectinfo = op.descr.get_extra_info()
             if effectinfo is not None:
                 # XXX we can get the wrong complexity here, if the lists
                 # XXX stored on effectinfo are large
+                for fielddescr in effectinfo.readonly_descrs_fields:
+                    self.force_lazy_setfield(fielddescr)
                 for fielddescr in effectinfo.write_descrs_fields:
+                    self.force_lazy_setfield(fielddescr)
                     try:
                         del self.cached_fields[fielddescr]
                     except KeyError:
@@ -937,9 +944,38 @@
                     except KeyError:
                         pass
                 return
+            self.force_all_lazy_setfields()
+        elif op.is_final() or (not we_are_translated() and
+                               op.opnum < 0):   # escape() operations
+            self.force_all_lazy_setfields()
         self.clean_caches()
 
+    def force_lazy_setfield(self, descr):
+        try:
+            op = self.lazy_setfields[descr]
+        except KeyError:
+            return
+        del self.lazy_setfields[descr]
+        self.optimizer._emit_operation(op)
+
+    def force_all_lazy_setfields(self):
+        if len(self.lazy_setfields_descrs) > 0:
+            for descr in self.lazy_setfields_descrs:
+                self.force_lazy_setfield(descr)
+            del self.lazy_setfields_descrs[:]
+
+    def force_lazy_setfield_if_necessary(self, op, value, write=False):
+        try:
+            op1 = self.lazy_setfields[op.descr]
+        except KeyError:
+            if write:
+                self.lazy_setfields_descrs.append(op.descr)
+        else:
+            if self.optimizer.getvalue(op1.args[0]) is not value:
+                self.force_lazy_setfield(op.descr)
+
     def optimize_GETFIELD_GC(self, op, value):
+        self.force_lazy_setfield_if_necessary(op, value)
         # check if the field was read from another getfield_gc just before
         # or has been written to recently
         fieldvalue = self.read_cached_field(op.descr, value)
@@ -954,7 +990,8 @@
         self.cache_field_value(op.descr, value, fieldvalue)
 
     def optimize_SETFIELD_GC(self, op, value, fieldvalue):
-        self.optimizer.emit_operation(op)
+        self.force_lazy_setfield_if_necessary(op, value, write=True)
+        self.lazy_setfields[op.descr] = op
         # remember the result of future reads of the field
         self.cache_field_value(op.descr, value, fieldvalue, write=True)
 

Modified: pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_effectinfo.py
==============================================================================
--- pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_effectinfo.py	(original)
+++ pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_effectinfo.py	Fri Dec 25 20:29:16 2009
@@ -13,7 +13,7 @@
     S = lltype.GcStruct("S", ("a", lltype.Signed))
     effects = frozenset([("readstruct", lltype.Ptr(S), "a")])
     effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU())
-    assert list(effectinfo.read_descrs_fields) == [('fielddescr', S, "a")]
+    assert list(effectinfo.readonly_descrs_fields) == [('fielddescr', S, "a")]
     assert not effectinfo.write_descrs_fields
     assert not effectinfo.write_descrs_arrays
 
@@ -22,49 +22,58 @@
     effects = frozenset([("struct", lltype.Ptr(S), "a")])
     effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU())
     assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")]
-    assert not effectinfo.read_descrs_fields
+    assert not effectinfo.readonly_descrs_fields
     assert not effectinfo.write_descrs_arrays
 
 def test_include_write_array():
     A = lltype.GcArray(lltype.Signed)
     effects = frozenset([("array", lltype.Ptr(A))])
     effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU())
-    assert not effectinfo.read_descrs_fields
+    assert not effectinfo.readonly_descrs_fields
     assert not effectinfo.write_descrs_fields
     assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)]
 
+def test_dont_include_read_and_write_field():
+    S = lltype.GcStruct("S", ("a", lltype.Signed))
+    effects = frozenset([("readstruct", lltype.Ptr(S), "a"),
+                         ("struct", lltype.Ptr(S), "a")])
+    effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU())
+    assert not effectinfo.readonly_descrs_fields
+    assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")]
+    assert not effectinfo.write_descrs_arrays
+
 
 def test_filter_out_typeptr():
     effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")])
     effectinfo = effectinfo_from_writeanalyze(effects, None)
-    assert not effectinfo.read_descrs_fields
+    assert not effectinfo.readonly_descrs_fields
     assert not effectinfo.write_descrs_fields
     assert not effectinfo.write_descrs_arrays
 
 def test_filter_out_array_of_void():
     effects = frozenset([("array", lltype.Ptr(lltype.GcArray(lltype.Void)))])
     effectinfo = effectinfo_from_writeanalyze(effects, None)
-    assert not effectinfo.read_descrs_fields
+    assert not effectinfo.readonly_descrs_fields
     assert not effectinfo.write_descrs_fields
     assert not effectinfo.write_descrs_arrays
 
 def test_filter_out_struct_with_void():
     effects = frozenset([("struct", lltype.Ptr(lltype.GcStruct("x", ("a", lltype.Void))), "a")])
     effectinfo = effectinfo_from_writeanalyze(effects, None)
-    assert not effectinfo.read_descrs_fields
+    assert not effectinfo.readonly_descrs_fields
     assert not effectinfo.write_descrs_fields
     assert not effectinfo.write_descrs_arrays
 
 def test_filter_out_ooarray_of_void():
     effects = frozenset([("array", ootype.Array(ootype.Void))])
     effectinfo = effectinfo_from_writeanalyze(effects, None)
-    assert not effectinfo.read_descrs_fields
+    assert not effectinfo.readonly_descrs_fields
     assert not effectinfo.write_descrs_fields
     assert not effectinfo.write_descrs_arrays
 
 def test_filter_out_instance_with_void():
     effects = frozenset([("struct", ootype.Instance("x", ootype.ROOT, {"a": ootype.Void}), "a")])
     effectinfo = effectinfo_from_writeanalyze(effects, None)
-    assert not effectinfo.read_descrs_fields
+    assert not effectinfo.readonly_descrs_fields
     assert not effectinfo.write_descrs_fields
     assert not effectinfo.write_descrs_arrays

Modified: pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizefindnode.py
==============================================================================
--- pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizefindnode.py	(original)
+++ pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizefindnode.py	Fri Dec 25 20:29:16 2009
@@ -95,6 +95,7 @@
     onedescr = cpu.fielddescrof(U, 'one')
 
     FUNC = lltype.FuncType([lltype.Signed], lltype.Signed)
+    plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
     nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
                                     EffectInfo([], [], []))
     writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,

Modified: pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizeopt.py	Fri Dec 25 20:29:16 2009
@@ -606,10 +606,10 @@
         p3sub = getfield_gc(p3, descr=nextdescr)
         i3 = getfield_gc(p3sub, descr=valuedescr)
         escape(i3)
+        p1 = new_with_vtable(ConstClass(node_vtable))
         p2sub = new_with_vtable(ConstClass(node_vtable2))
         setfield_gc(p2sub, i1, descr=valuedescr)
         setfield_gc(p2, p2sub, descr=nextdescr)
-        p1 = new_with_vtable(ConstClass(node_vtable))
         jump(i1, p1, p2)
         """
         # The same as test_p123_simple, but in the end the "old" p2 contains
@@ -1307,6 +1307,65 @@
         """
         self.optimize_loop(ops, 'Not, Not, Not', expected)
 
+    def test_duplicate_setfield_2(self):
+        ops = """
+        [p1, i1, i3]
+        setfield_gc(p1, i1, descr=valuedescr)
+        i2 = getfield_gc(p1, descr=valuedescr)
+        setfield_gc(p1, i3, descr=valuedescr)
+        escape(i2)
+        jump(p1, i1, i3)
+        """
+        expected = """
+        [p1, i1, i3]
+        setfield_gc(p1, i3, descr=valuedescr)
+        escape(i1)
+        jump(p1, i1, i3)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not', expected)
+
+    def test_duplicate_setfield_3(self):
+        ops = """
+        [p1, p2, i1, i3]
+        setfield_gc(p1, i1, descr=valuedescr)
+        i2 = getfield_gc(p2, descr=valuedescr)
+        setfield_gc(p1, i3, descr=valuedescr)
+        escape(i2)
+        jump(p1, p2, i1, i3)
+        """
+        # potential aliasing of p1 and p2 means that we cannot kill the
+        # the setfield_gc
+        self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+
+    def test_duplicate_setfield_4(self):
+        ops = """
+        [p1, i1, i2, p3]
+        setfield_gc(p1, i1, descr=valuedescr)
+        #
+        # some operations on which the above setfield_gc cannot have effect
+        i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr)
+        i4 = getarrayitem_gc(p3, i3, descr=arraydescr)
+        i5 = int_add(i3, i4)
+        setarrayitem_gc(p3, 0, i5, descr=arraydescr)
+        setfield_gc(p1, i4, descr=nextdescr)
+        #
+        setfield_gc(p1, i2, descr=valuedescr)
+        jump(p1, i1, i2, p3)
+        """
+        expected = """
+        [p1, i1, i2, p3]
+        #
+        i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr)
+        i4 = getarrayitem_gc(p3, i3, descr=arraydescr)
+        i5 = int_add(i3, i4)
+        setarrayitem_gc(p3, 0, i5, descr=arraydescr)
+        #
+        setfield_gc(p1, i2, descr=valuedescr)
+        setfield_gc(p1, i4, descr=nextdescr)
+        jump(p1, i1, i2, p3)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
+
     def test_duplicate_setfield_sideeffects_1(self):
         ops = """
         [p1, i1, i2]
@@ -1342,7 +1401,7 @@
         setfield_gc(ConstPtr(myptr), i2, descr=valuedescr)
         jump(i1, i2)
         """
-        self.optimize_loop(ops, 'Constant(myptr)', expected)
+        self.optimize_loop(ops, 'Constant(myptr), Not, Not', expected)
 
     def test_duplicate_getarrayitem_1(self):
         ops = """
@@ -2082,7 +2141,7 @@
         """
         self.optimize_loop(ops, 'Not, Not, Not', expected)
 
-    def test_residual_call_invalidates_some_read_caches(self):
+    def test_residual_call_invalidates_some_read_caches_1(self):
         ops = """
         [p1, i1, p2, i2]
         setfield_gc(p1, i1, descr=valuedescr)
@@ -2102,6 +2161,38 @@
         """
         self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
 
+    def test_residual_call_invalidates_some_read_caches_2(self):
+        ops = """
+        [p1, i1, p2, i2]
+        setfield_gc(p1, i1, descr=valuedescr)
+        setfield_gc(p2, i2, descr=adescr)
+        i3 = call(i1, descr=writeadescr)
+        setfield_gc(p1, i3, descr=valuedescr)
+        setfield_gc(p2, i3, descr=adescr)
+        jump(p1, i1, p2, i2)
+        """
+        expected = """
+        [p1, i1, p2, i2]
+        setfield_gc(p2, i2, descr=adescr)
+        i3 = call(i1, descr=writeadescr)
+        setfield_gc(p1, i3, descr=valuedescr)
+        setfield_gc(p2, i3, descr=adescr)
+        jump(p1, i1, p2, i2)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
+
+    def test_residual_call_invalidates_some_read_caches_3(self):
+        ops = """
+        [p1, i1, p2, i2]
+        setfield_gc(p1, i1, descr=valuedescr)
+        setfield_gc(p2, i2, descr=adescr)
+        i3 = call(i1, descr=plaincalldescr)
+        setfield_gc(p1, i3, descr=valuedescr)
+        setfield_gc(p2, i3, descr=adescr)
+        jump(p1, i1, p2, i2)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+
 
 class TestOOtype(BaseTestOptimizeOpt, OOtypeMixin):
 



More information about the Pypy-commit mailing list