[pypy-commit] pypy guard-compatible: test and fix: deal with quasiimmut correctly

cfbolz pypy.commits at gmail.com
Wed Feb 21 12:18:38 EST 2018


Author: Carl Friedrich Bolz-Tereick <cfbolz at gmx.de>
Branch: guard-compatible
Changeset: r93855:5b83d5703851
Date: 2018-02-21 17:21 +0100
http://bitbucket.org/pypy/pypy/changeset/5b83d5703851/

Log:	test and fix: deal with quasiimmut correctly

diff --git a/rpython/jit/metainterp/compatible.py b/rpython/jit/metainterp/compatible.py
--- a/rpython/jit/metainterp/compatible.py
+++ b/rpython/jit/metainterp/compatible.py
@@ -62,8 +62,12 @@
         self.conditions.append(cond)
         return True
 
-    def register_quasi_immut_field(self, op):
-        self.last_quasi_immut_field_op = op
+    def register_quasi_immut_field(self, op, optimizer):
+        from rpython.jit.metainterp.quasiimmut import QuasiImmutDescr
+        assert optimizer.ensure_ptr_info_arg0(op)._compatibility_conditions is self
+        descr = op.getdescr()
+        assert isinstance(descr, QuasiImmutDescr)
+        self.last_quasi_immut_field_descr = descr
 
     def check_compat(self, cpu, ref):
         for i, cond in enumerate(self.conditions):
@@ -152,13 +156,12 @@
         # even though the second argument is not constant
         if arg2.getopnum() not in (rop.GETFIELD_GC_R, rop.GETFIELD_GC_I, rop.GETFIELD_GC_F):
             return None, None, "arg2 not a getfield"
-        if not self.last_quasi_immut_field_op:
+        if not self.last_quasi_immut_field_descr:
             return None, None, "no quasiimut op known"
-        qmutdescr = self.last_quasi_immut_field_op.getdescr()
+        qmutdescr = self.last_quasi_immut_field_descr
         assert isinstance(qmutdescr, QuasiImmutDescr)
         fielddescr = qmutdescr.fielddescr # XXX
-        same_arg = self.last_quasi_immut_field_op.getarg(0) is arg2.getarg(0)
-        if arg2.getdescr() is not fielddescr or not same_arg:
+        if arg2.getdescr() is not fielddescr:
             return None, None, "fielddescr doesn't match"
         if not qmutdescr.is_still_valid_for(self.known_valid):
             return None, None, "qmutdescr invalid"
diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py
--- a/rpython/jit/metainterp/optimizeopt/heap.py
+++ b/rpython/jit/metainterp/optimizeopt/heap.py
@@ -677,7 +677,7 @@
                 # the getfield_gc on the object, since it's not constant.
                 # However, if the quasi-immutable field is passed to a pure
                 # function call, we can treat it as constant then
-                ccond.register_quasi_immut_field(op)
+                ccond.register_quasi_immut_field(op, self.optimizer)
                 # don't remove the guard_not_invalidated, the guard_compatible
                 # needs it
                 self._remove_guard_not_invalidated = False
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_compatible.py b/rpython/jit/metainterp/optimizeopt/test/test_compatible.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_compatible.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_compatible.py
@@ -281,6 +281,55 @@
         }
         self.optimize_loop(ops, expected, call_pure_results)
 
+    def test_quasiimmut_bug(self):
+        # bug that happened because we hade quasiimmut_field on two different
+        # boxes (that turn out to be the same after other optimizations)
+        ops = """
+        [p1]
+        guard_compatible(p1, ConstPtr(quasiptr)) []
+        quasiimmut_field(p1, descr=quasiimmutdescr)
+        guard_not_invalidated() []
+        i0 = getfield_gc_i(p1, descr=quasifielddescr)
+        i1 = call_pure_i(123, p1, i0, descr=nonwritedescr)
+
+        # get an alias p2 to p1
+        p3 = new_with_vtable(descr=nodesize)
+        setfield_gc(p3, p1, descr=nextdescr)
+        p2 = getfield_gc_r(p3, descr=nextdescr)
+
+        # a condition via the alias
+        guard_compatible(p2, ConstPtr(quasiptr)) []
+        quasiimmut_field(p2, descr=quasiimmutdescr)
+        guard_not_invalidated() []
+        i3 = getfield_gc_i(p2, descr=quasifielddescr)
+        i4 = call_pure_i(123, p2, i3, descr=nonwritedescr)
+
+        # and now the original box
+        i5 = call_pure_i(123, p1, i0, descr=nonwritedescr)
+        escape_n(i1)
+        escape_n(i4)
+        escape_n(i5)
+        jump(p1)
+        """
+        expected = """
+        [p1]
+        guard_compatible(p1, ConstPtr(quasiptr)) []
+        guard_not_invalidated() []
+        i0 = getfield_gc_i(p1, descr=quasifielddescr) # will be removed by the backend
+        escape_n(5)
+        escape_n(5)
+        escape_n(5)
+        jump(p1)
+        """
+        call_pure_results = {
+            (ConstInt(123), ConstPtr(self.quasiptr), ConstInt(-4247)): ConstInt(5),
+        }
+        self.optimize_loop(ops, expected, call_pure_results)
+        descr = self.loop.operations[1].getdescr()
+        assert descr._compatibility_conditions is not None
+        assert descr._compatibility_conditions.known_valid.same_constant(ConstPtr(self.quasiptr))
+        assert len(descr._compatibility_conditions.conditions) == 1
+
 
 class TestCompatibleUnroll(BaseTestWithUnroll, LLtypeMixin):
 


More information about the pypy-commit mailing list