[pypy-svn] r69123 - in pypy/branch/merge-guards-2/pypy/jit: backend/llgraph metainterp metainterp/test

arigo at codespeak.net arigo at codespeak.net
Tue Nov 10 16:38:56 CET 2009


Author: arigo
Date: Tue Nov 10 16:38:56 2009
New Revision: 69123

Modified:
   pypy/branch/merge-guards-2/pypy/jit/backend/llgraph/llimpl.py
   pypy/branch/merge-guards-2/pypy/jit/metainterp/optimizeopt.py
   pypy/branch/merge-guards-2/pypy/jit/metainterp/resoperation.py
   pypy/branch/merge-guards-2/pypy/jit/metainterp/test/test_basic.py
   pypy/branch/merge-guards-2/pypy/jit/metainterp/test/test_optimizeopt.py
Log:
Merge guard_nonnull followed by guard_class and/or guard_value.


Modified: pypy/branch/merge-guards-2/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/branch/merge-guards-2/pypy/jit/backend/llgraph/llimpl.py	(original)
+++ pypy/branch/merge-guards-2/pypy/jit/backend/llgraph/llimpl.py	Tue Nov 10 16:38:56 2009
@@ -134,6 +134,7 @@
     'guard_overflow'       : ((), None),
     'guard_nonnull'        : (('ref',), None),
     'guard_isnull'        : (('ref',), None),
+    'guard_nonnull_class' : (('ref', 'ref'), None),
     'newstr'          : (('int',), 'ref'),
     'strlen'          : (('ref',), 'int'),
     'strgetitem'      : (('ref', 'int'), 'int'),
@@ -562,6 +563,11 @@
         if value.typeptr != expected_class:
             raise GuardFailed
 
+    def op_guard_nonnull_class(self, _, value, expected_class):
+        if not value:
+            raise GuardFailed
+        self.op_guard_class(_, value, expected_class)
+
     def op_guard_value(self, _, value, expected_value):
         if value != expected_value:
             raise GuardFailed

Modified: pypy/branch/merge-guards-2/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/merge-guards-2/pypy/jit/metainterp/optimizeopt.py	(original)
+++ pypy/branch/merge-guards-2/pypy/jit/metainterp/optimizeopt.py	Tue Nov 10 16:38:56 2009
@@ -42,8 +42,8 @@
 
 
 class OptValue(object):
-    _attrs_ = ('box', 'known_class', 'guard_class_index', 'level')
-    guard_class_index = -1
+    _attrs_ = ('box', 'known_class', 'last_guard_index', 'level')
+    last_guard_index = -1
 
     level = LEVEL_UNKNOWN
 
@@ -88,10 +88,15 @@
             return None
 
     def make_constant_class(self, classbox, opindex):
-        if self.level < LEVEL_KNOWNCLASS:
-            self.known_class = classbox
-            self.level = LEVEL_KNOWNCLASS
-            self.guard_class_index = opindex
+        assert self.level < LEVEL_KNOWNCLASS
+        self.known_class = classbox
+        self.level = LEVEL_KNOWNCLASS
+        self.last_guard_index = opindex
+
+    def make_nonnull(self, opindex):
+        assert self.level < LEVEL_NONNULL
+        self.level = LEVEL_NONNULL
+        self.last_guard_index = opindex
 
     def is_nonnull(self):
         level = self.level
@@ -104,7 +109,7 @@
         else:
             return False
 
-    def make_nonnull(self):
+    def ensure_nonnull(self):
         if self.level < LEVEL_NONNULL:
             self.level = LEVEL_NONNULL
 
@@ -577,17 +582,26 @@
         elif value.is_null():
             raise InvalidLoop
         self.emit_operation(op)
-        value.make_nonnull()
+        value.make_nonnull(len(self.newoperations) - 1)
 
     def optimize_GUARD_VALUE(self, op):
         value = self.getvalue(op.args[0])
         emit_operation = True
-        if value.guard_class_index != -1:
-            # there already has been a guard_class on this value, which is
-            # rather silly. replace the original guard_class with a guard_value
-            guard_class_op = self.newoperations[value.guard_class_index]
-            guard_class_op.opnum = op.opnum
-            guard_class_op.args[1] = op.args[1]
+        if value.last_guard_index != -1:
+            # there already has been a guard_nonnull or guard_class or
+            # guard_nonnull_class on this value, which is rather silly.
+            # replace the original guard with a guard_value
+            old_guard_op = self.newoperations[value.last_guard_index]
+            old_opnum = old_guard_op.opnum
+            old_guard_op.opnum = op.opnum
+            old_guard_op.args = [old_guard_op.args[0], op.args[1]]
+            if old_opnum == rop.GUARD_NONNULL:
+                # hack hack hack.  Change the guard_opnum on
+                # old_guard_op.descr so that when resuming,
+                # the operation is not skipped by pyjitpl.py.
+                descr = old_guard_op.descr
+                assert isinstance(descr, compile.ResumeGuardDescr)
+                descr.guard_opnum = rop.GUARD_NONNULL_CLASS
             emit_operation = False
         constbox = op.args[1]
         assert isinstance(constbox, Const)
@@ -610,8 +624,29 @@
             # earlier, in optimizefindnode.py.
             assert realclassbox.same_constant(expectedclassbox)
             return
-        self.emit_operation(op)
-        value.make_constant_class(expectedclassbox, len(self.newoperations) - 1)
+        emit_operation = True
+        if value.last_guard_index != -1:
+            # there already has been a guard_nonnull or guard_class or
+            # guard_nonnull_class on this value.
+            old_guard_op = self.newoperations[value.last_guard_index]
+            if old_guard_op.opnum == rop.GUARD_NONNULL:
+                # it was a guard_nonnull, which we replace with a
+                # guard_nonnull_class.
+                old_guard_op.opnum = rop.GUARD_NONNULL_CLASS
+                old_guard_op.args = [old_guard_op.args[0], op.args[1]]
+                # hack hack hack.  Change the guard_opnum on
+                # old_guard_op.descr so that when resuming,
+                # the operation is not skipped by pyjitpl.py.
+                descr = old_guard_op.descr
+                assert isinstance(descr, compile.ResumeGuardDescr)
+                descr.guard_opnum = rop.GUARD_NONNULL_CLASS
+                emit_operation = False
+        if emit_operation:
+            self.emit_operation(op)
+            last_guard_index = len(self.newoperations) - 1
+        else:
+            last_guard_index = value.last_guard_index
+        value.make_constant_class(expectedclassbox, last_guard_index)
 
     def optimize_GUARD_NO_EXCEPTION(self, op):
         if not self.exception_might_have_happened:
@@ -669,7 +704,7 @@
             assert fieldvalue is not None
             self.make_equal_to(op.result, fieldvalue)
         else:
-            value.make_nonnull()
+            value.ensure_nonnull()
             self.heap_op_optimizer.optimize_GETFIELD_GC(op, value)
 
     # note: the following line does not mean that the two operations are
@@ -681,7 +716,7 @@
         if value.is_virtual():
             value.setfield(op.descr, self.getvalue(op.args[1]))
         else:
-            value.make_nonnull()
+            value.ensure_nonnull()
             fieldvalue = self.getvalue(op.args[1])
             self.heap_op_optimizer.optimize_SETFIELD_GC(op, value, fieldvalue)
 
@@ -708,7 +743,7 @@
         if value.is_virtual():
             self.make_constant_int(op.result, value.getlength())
         else:
-            value.make_nonnull()
+            value.ensure_nonnull()
             self.optimize_default(op)
 
     def optimize_GETARRAYITEM_GC(self, op):
@@ -719,7 +754,7 @@
                 itemvalue = value.getitem(indexbox.getint())
                 self.make_equal_to(op.result, itemvalue)
                 return
-        value.make_nonnull()
+        value.ensure_nonnull()
         self.heap_op_optimizer.optimize_GETARRAYITEM_GC(op, value)
 
     # note: the following line does not mean that the two operations are
@@ -733,7 +768,7 @@
             if indexbox is not None:
                 value.setitem(indexbox.getint(), self.getvalue(op.args[2]))
                 return
-        value.make_nonnull()
+        value.ensure_nonnull()
         fieldvalue = self.getvalue(op.args[2])
         self.heap_op_optimizer.optimize_SETARRAYITEM_GC(op, value, fieldvalue)
 
@@ -873,7 +908,7 @@
             self.optimizer.make_equal_to(op.result, fieldvalue)
             return
         # default case: produce the operation
-        value.make_nonnull()
+        value.ensure_nonnull()
         self.optimizer.optimize_default(op)
         # then remember the result of reading the field
         fieldvalue = self.optimizer.getvalue(op.result)

Modified: pypy/branch/merge-guards-2/pypy/jit/metainterp/resoperation.py
==============================================================================
--- pypy/branch/merge-guards-2/pypy/jit/metainterp/resoperation.py	(original)
+++ pypy/branch/merge-guards-2/pypy/jit/metainterp/resoperation.py	Tue Nov 10 16:38:56 2009
@@ -119,6 +119,7 @@
     'GUARD_CLASS',
     'GUARD_NONNULL',
     'GUARD_ISNULL',
+    'GUARD_NONNULL_CLASS',
     '_GUARD_FOLDABLE_LAST',
     'GUARD_NO_EXCEPTION',
     'GUARD_EXCEPTION',

Modified: pypy/branch/merge-guards-2/pypy/jit/metainterp/test/test_basic.py
==============================================================================
--- pypy/branch/merge-guards-2/pypy/jit/metainterp/test/test_basic.py	(original)
+++ pypy/branch/merge-guards-2/pypy/jit/metainterp/test/test_basic.py	Tue Nov 10 16:38:56 2009
@@ -1003,10 +1003,10 @@
 
         class A(object):
             def g(self, x):
-                return x - 1
+                return x - 5
         class B(A):
             def g(self, y):
-                return y - 2
+                return y - 3
 
         a1 = A()
         a2 = A()
@@ -1021,8 +1021,125 @@
                 hint(a, promote=True)
             return x
         res = self.meta_interp(f, [299], listops=True)
+        assert res == f(299)
         self.check_loops(guard_class=0, guard_value=3)
 
+    def test_merge_guardnonnull_guardclass(self):
+        from pypy.rlib.objectmodel import instantiate
+        myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
+
+        class A(object):
+            def g(self, x):
+                return x - 3
+        class B(A):
+            def g(self, y):
+                return y - 5
+
+        a1 = A()
+        b1 = B()
+        def f(x):
+            l = [None] * 100 + [b1] * 100 + [a1] * 100
+            while x > 0:
+                myjitdriver.can_enter_jit(x=x, l=l)
+                myjitdriver.jit_merge_point(x=x, l=l)
+                a = l[x]
+                if a:
+                    x = a.g(x)
+                else:
+                    x -= 7
+            return x
+        res = self.meta_interp(f, [299], listops=True)
+        assert res == f(299)
+        self.check_loops(guard_class=0, guard_nonnull=0,
+                         guard_nonnull_class=2, guard_isnull=1)
+
+    def test_merge_guardnonnull_guardvalue(self):
+        from pypy.rlib.objectmodel import instantiate
+        myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
+
+        class A(object):
+            pass
+        class B(A):
+            pass
+
+        a1 = A()
+        b1 = B()
+        def f(x):
+            l = [b1] * 100 + [None] * 100 + [a1] * 100
+            while x > 0:
+                myjitdriver.can_enter_jit(x=x, l=l)
+                myjitdriver.jit_merge_point(x=x, l=l)
+                a = l[x]
+                if a:
+                    x -= 5
+                else:
+                    x -= 7
+                hint(a, promote=True)
+            return x
+        res = self.meta_interp(f, [299], listops=True)
+        assert res == f(299)
+        self.check_loops(guard_class=0, guard_nonnull=0, guard_value=2,
+                         guard_nonnull_class=0, guard_isnull=1)
+
+    def test_merge_guardnonnull_guardvalue_2(self):
+        from pypy.rlib.objectmodel import instantiate
+        myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
+
+        class A(object):
+            pass
+        class B(A):
+            pass
+
+        a1 = A()
+        b1 = B()
+        def f(x):
+            l = [None] * 100 + [b1] * 100 + [a1] * 100
+            while x > 0:
+                myjitdriver.can_enter_jit(x=x, l=l)
+                myjitdriver.jit_merge_point(x=x, l=l)
+                a = l[x]
+                if a:
+                    x -= 5
+                else:
+                    x -= 7
+                hint(a, promote=True)
+            return x
+        res = self.meta_interp(f, [299], listops=True)
+        assert res == f(299)
+        self.check_loops(guard_class=0, guard_nonnull=0, guard_value=2,
+                         guard_nonnull_class=0, guard_isnull=1)
+
+    def test_merge_guardnonnull_guardclass_guardvalue(self):
+        from pypy.rlib.objectmodel import instantiate
+        myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
+
+        class A(object):
+            def g(self, x):
+                return x - 3
+        class B(A):
+            def g(self, y):
+                return y - 5
+
+        a1 = A()
+        a2 = A()
+        b1 = B()
+        def f(x):
+            l = [a2] * 100 + [None] * 100 + [b1] * 100 + [a1] * 100
+            while x > 0:
+                myjitdriver.can_enter_jit(x=x, l=l)
+                myjitdriver.jit_merge_point(x=x, l=l)
+                a = l[x]
+                if a:
+                    x = a.g(x)
+                else:
+                    x -= 7
+                hint(a, promote=True)
+            return x
+        res = self.meta_interp(f, [399], listops=True)
+        assert res == f(399)
+        self.check_loops(guard_class=0, guard_nonnull=0, guard_value=3,
+                         guard_nonnull_class=0, guard_isnull=1)
+
     def test_residual_call_doesnt_lose_info(self):
         myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'l'])
 

Modified: pypy/branch/merge-guards-2/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/merge-guards-2/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/branch/merge-guards-2/pypy/jit/metainterp/test/test_optimizeopt.py	Tue Nov 10 16:38:56 2009
@@ -1472,6 +1472,56 @@
         """
         self.optimize_loop(ops, "Not, Not, Not, Not, Not", expected)
 
+    def test_merge_guard_nonnull_guard_class(self):
+        ops = """
+        [p1, i0, i1, i2, p2]
+        guard_nonnull(p1) [i0]
+        i3 = int_add(i1, i2)
+        guard_class(p1, ConstClass(node_vtable)) [i1]
+        jump(p2, i0, i1, i3, p2)
+        """
+        expected = """
+        [p1, i0, i1, i2, p2]
+        guard_nonnull_class(p1, ConstClass(node_vtable)) [i0]
+        i3 = int_add(i1, i2)
+        jump(p2, i0, i1, i3, p2)
+        """
+        self.optimize_loop(ops, "Not, Not, Not, Not, Not", expected)
+
+    def test_merge_guard_nonnull_guard_value(self):
+        ops = """
+        [p1, i0, i1, i2, p2]
+        guard_nonnull(p1) [i0]
+        i3 = int_add(i1, i2)
+        guard_value(p1, ConstPtr(myptr)) [i1]
+        jump(p2, i0, i1, i3, p2)
+        """
+        expected = """
+        [p1, i0, i1, i2, p2]
+        guard_value(p1, ConstPtr(myptr)) [i0]
+        i3 = int_add(i1, i2)
+        jump(p2, i0, i1, i3, p2)
+        """
+        self.optimize_loop(ops, "Not, Not, Not, Not, Not", expected)
+
+    def test_merge_guard_nonnull_guard_class_guard_value(self):
+        ops = """
+        [p1, i0, i1, i2, p2]
+        guard_nonnull(p1) [i0]
+        i3 = int_add(i1, i2)
+        guard_class(p1, ConstClass(node_vtable)) [i2]
+        i4 = int_sub(i3, 1)
+        guard_value(p1, ConstPtr(myptr)) [i1]
+        jump(p2, i0, i1, i4, p2)
+        """
+        expected = """
+        [p1, i0, i1, i2, p2]
+        guard_value(p1, ConstPtr(myptr)) [i0]
+        i3 = int_add(i1, i2)
+        i4 = int_sub(i3, 1)
+        jump(p2, i0, i1, i4, p2)
+        """
+        self.optimize_loop(ops, "Not, Not, Not, Not, Not", expected)
 
     # ----------
 



More information about the Pypy-commit mailing list