[pypy-svn] r67382 - in pypy/trunk/pypy/jit/metainterp: . test

cfbolz at codespeak.net cfbolz at codespeak.net
Tue Sep 1 11:00:02 CEST 2009


Author: cfbolz
Date: Tue Sep  1 11:00:02 2009
New Revision: 67382

Modified:
   pypy/trunk/pypy/jit/metainterp/optimizeopt.py
   pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py
Log:
Improve the precision of the optimization removing getfields: so far setfields
to unrelated fields would kill all stored field information. Stop doing that.
Also don't kill the fields on overflowing arithmetic operations and on
setarrayitems.


Modified: pypy/trunk/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/optimizeopt.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/optimizeopt.py	Tue Sep  1 11:00:02 2009
@@ -335,8 +335,13 @@
         self.cpu = cpu
         self.loop = loop
         self.values = {}
-        self.values_to_clean = []    # OptValues to clean when we see an
-                                     # operation with side-effects
+        # OptValues to clean when we see an operation with side-effects
+        # they are ordered by fielddescrs of the affected fields
+        # note: it is important that this is not a av_newdict2 dict!
+        # we want more precision to not clear unrelated fields, just because
+        # they are at the same offset (but in a different struct type)
+        self.values_to_clean = {}
+                                     
         self.interned_refs = {}
 
     def getinterned(self, box):
@@ -504,6 +509,21 @@
         op2.suboperations = op1.suboperations
         op1.optimized = op2
 
+    def clean_fields_of_values(self, descr=None):
+        if descr is None:
+            for descr, values in self.values_to_clean.iteritems():
+                for value in values:
+                    value._fields.clear()
+            self.values_to_clean = {}
+        else:
+            for value in self.values_to_clean.get(descr, []):
+                del value._fields[descr]
+            self.values_to_clean[descr] = []
+
+    def register_value_to_clean(self, value, descr):
+        self.values_to_clean.setdefault(descr, []).append(value)
+
+
     def optimize_default(self, op):
         if op.is_always_pure():
             for arg in op.args:
@@ -513,10 +533,9 @@
                 # all constant arguments: constant-fold away
                 self.make_constant(op.result)
                 return
-        elif not op.has_no_side_effect():
-            for value in self.values_to_clean:
-                value._fields.clear()
-            del self.values_to_clean[:]
+        elif not op.has_no_side_effect() and not op.is_ovf():
+            print "cleaning everything", op
+            self.clean_fields_of_values()
         # otherwise, the operation remains
         self.emit_operation(op)
 
@@ -567,6 +586,12 @@
         self.emit_operation(op)
         self.exception_might_have_happened = False
 
+    def optimize_GUARD_NO_OVERFLOW(self, op):
+        # otherwise the default optimizer will clear fields, which is unwanted
+        # in this case
+        self.emit_operation(op)
+
+
     def _optimize_nullness(self, op, expect_nonnull):
         if self.known_nonnull(op.args[0]):
             assert op.result.getint() == expect_nonnull
@@ -635,7 +660,7 @@
             self.optimize_default(op)
             # then remember the result of reading the field
             value._fields[op.descr] = self.getvalue(op.result)
-            self.values_to_clean.append(value)
+            self.register_value_to_clean(value, op.descr)
 
     # note: the following line does not mean that the two operations are
     # completely equivalent, because GETFIELD_GC_PURE is_always_pure().
@@ -647,12 +672,15 @@
             value.setfield(op.descr, self.getvalue(op.args[1]))
         else:
             value.make_nonnull()
-            self.optimize_default(op)
+            self.emit_operation(op)
+            # kill all fields with the same descr, as those could be affected
+            # by this setfield (via aliasing)
+            self.clean_fields_of_values(op.descr)
             # remember the result of future reads of the field
             if value._fields is None:
                 value._fields = av_newdict2()
             value._fields[op.descr] = self.getvalue(op.args[1])
-            self.values_to_clean.append(value)
+            self.register_value_to_clean(value, op.descr)
 
     def optimize_NEW_WITH_VTABLE(self, op):
         self.make_virtual(op.args[0], op.result, op)
@@ -704,7 +732,9 @@
             value.setitem(indexbox.getint(), self.getvalue(op.args[2]))
         else:
             value.make_nonnull()
-            self.optimize_default(op)
+            # don't use optimize_default, because otherwise unrelated struct
+            # fields will be cleared
+            self.emit_operation(op)
 
     def optimize_INSTANCEOF(self, op):
         value = self.getvalue(op.args[0])
@@ -716,6 +746,7 @@
     def optimize_DEBUG_MERGE_POINT(self, op):
         # special-case this operation to prevent e.g. the handling of
         # 'values_to_clean' (the op cannot be marked as side-effect-free)
+        # otherwise it would be removed
         self.newoperations.append(op)
 
 optimize_ops = _findall(Optimizer, 'optimize_')

Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py	Tue Sep  1 11:00:02 2009
@@ -943,7 +943,7 @@
         """
         self.optimize_loop(ops, 'Not', expected)
 
-    def test_duplicate_getfield_2(self):
+    def test_getfield_after_setfield(self):
         ops = """
         [p1, i1]
         setfield_gc(p1, i1, descr=valuedescr)
@@ -959,7 +959,36 @@
         """
         self.optimize_loop(ops, 'Not, Not', expected)
 
-    def test_duplicate_getfield_3(self):
+    def test_setfield_of_different_type_does_not_clear(self):
+        ops = """
+        [p1, p2, i1]
+        setfield_gc(p1, i1, descr=valuedescr)
+        setfield_gc(p2, p1, descr=nextdescr)
+        i2 = getfield_gc(p1, descr=valuedescr)
+        escape(i2)
+        jump(p1, p2, i1)
+        """
+        expected = """
+        [p1, p2, i1]
+        setfield_gc(p1, i1, descr=valuedescr)
+        setfield_gc(p2, p1, descr=nextdescr)
+        escape(i1)
+        jump(p1, p2, i1)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not', expected)
+
+    def test_setfield_of_same_type_clears(self):
+        ops = """
+        [p1, p2, i1, i2]
+        setfield_gc(p1, i1, descr=valuedescr)
+        setfield_gc(p2, i2, descr=valuedescr)
+        i3 = getfield_gc(p1, descr=valuedescr)
+        escape(i3)
+        jump(p1, p2, i1, i3)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+
+    def test_duplicate_getfield_mergepoint_has_no_side_effects(self):
         ops = """
         [p1]
         i1 = getfield_gc(p1, descr=valuedescr)
@@ -979,6 +1008,50 @@
         """
         self.optimize_loop(ops, 'Not', expected)
 
+    def test_duplicate_getfield_ovf_op_does_not_clear(self):
+        ops = """
+        [p1]
+        i1 = getfield_gc(p1, descr=valuedescr)
+        i2 = int_add_ovf(i1, 14)
+        guard_no_overflow()
+            fail()
+        i3 = getfield_gc(p1, descr=valuedescr)
+        escape(i2)
+        escape(i3)
+        jump(p1)
+        """
+        expected = """
+        [p1]
+        i1 = getfield_gc(p1, descr=valuedescr)
+        i2 = int_add_ovf(i1, 14)
+        guard_no_overflow()
+            fail()
+        escape(i2)
+        escape(i1)
+        jump(p1)
+        """
+        self.optimize_loop(ops, 'Not', expected)
+
+    def test_duplicate_getfield_setarrayitem_does_not_clear(self):
+        ops = """
+        [p1, p2]
+        i1 = getfield_gc(p1, descr=valuedescr)
+        setarrayitem_gc(p2, 0, p1, descr=arraydescr2)
+        i3 = getfield_gc(p1, descr=valuedescr)
+        escape(i1)
+        escape(i3)
+        jump(p1, p2)
+        """
+        expected = """
+        [p1, p2]
+        i1 = getfield_gc(p1, descr=valuedescr)
+        setarrayitem_gc(p2, 0, p1, descr=arraydescr2)
+        escape(i1)
+        escape(i1)
+        jump(p1, p2)
+        """
+        self.optimize_loop(ops, 'Not, Not', expected)
+
     def test_duplicate_getfield_constant(self):
         ops = """
         []



More information about the Pypy-commit mailing list