Author: Carl Friedrich Bolz <[email protected]>
Branch: small-unroll-improvements
Changeset: r70488:8d213d6dda5c
Date: 2014-04-08 17:49 +0200
http://bitbucket.org/pypy/pypy/changeset/8d213d6dda5c/

Log:    intermediate checkin

        start refactoring generate_guards to no longer call
        generalization_of (which I ultimately want to deprecate). for now,
        carefully list all cases. intbounds are not supported yet.

diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py 
b/rpython/jit/metainterp/optimizeopt/optimizer.py
--- a/rpython/jit/metainterp/optimizeopt/optimizer.py
+++ b/rpython/jit/metainterp/optimizeopt/optimizer.py
@@ -31,6 +31,12 @@
     def clone(self):
         return LenBound(self.mode, self.descr, self.bound.clone())
 
+    def generalization_of(self, other):
+        return (other is not None and
+                self.mode == other.mode and
+                self.descr == other.descr and
+                self.lenbound.bound.contains_bound(other.lenbound.bound))
+
 class OptValue(object):
     __metaclass__ = extendabletype
     _attrs_ = ('box', 'known_class', 'last_guard', 'level', 'intbound', 
'lenbound')
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py 
b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
@@ -9,6 +9,7 @@
 from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin, 
BaseTest, \
                                                            equaloplists
 from rpython.jit.metainterp.optimizeopt.intutils import IntBound
+from rpython.jit.metainterp.optimizeopt.virtualize import VirtualValue
 from rpython.jit.metainterp.history import TreeLoop, JitCellToken
 from rpython.jit.metainterp.optimizeopt.test.test_optimizeopt import 
FakeMetaInterpStaticData
 from rpython.jit.metainterp.resoperation import ResOperation, rop
@@ -144,13 +145,17 @@
 
 
 class BaseTestGenerateGuards(BaseTest):
-    def guards(self, info1, info2, box_or_value, expected):
+    def _box_or_value(self, box_or_value):
         if isinstance(box_or_value, OptValue):
             value = box_or_value
             box = value.box
         else:
             box = box_or_value
             value = OptValue(box)
+        return value, box
+
+    def guards(self, info1, info2, box_or_value, expected):
+        value, box = self._box_or_value(box_or_value)
         info1.position = info2.position = 0
         guards = []
         info1.generate_guards(info2, value, self.cpu, guards, {})
@@ -166,7 +171,139 @@
             if op.is_guard():
                 op.setdescr(None)
         assert equaloplists(guards, loop.operations, False,
-                            boxmap)        
+                            boxmap)
+
+    def check_no_guards(self, info1, info2, box_or_value):
+        value, _ = self._box_or_value(box_or_value)
+        guards = []
+        info1.generate_guards(info2, value, self.cpu, guards, {})
+        assert not guards
+
+    def check_invalid(self, info1, info2, box_or_value):
+        value, _ = self._box_or_value(box_or_value)
+        guards = []
+        with py.test.raises(InvalidLoop):
+            info1.generate_guards(info2, value, self.cpu, guards, {})
+
+    def test_nonvirtual_all_combinations(self):
+        # set up infos
+        unknown_val = OptValue(self.nodebox)
+        unknownnull_val = OptValue(BoxPtr(self.nullptr))
+        unknown_info = NotVirtualStateInfo(unknown_val)
+
+        nonnull_val = OptValue(self.nodebox)
+        nonnull_val.make_nonnull(None)
+        nonnull_info = NotVirtualStateInfo(nonnull_val)
+
+        knownclass_val = OptValue(self.nodebox)
+        classbox = self.cpu.ts.cls_of_box(self.nodebox)
+        knownclass_val.make_constant_class(classbox, -1)
+        knownclass_info = NotVirtualStateInfo(knownclass_val)
+        knownclass2_val = OptValue(self.nodebox2)
+        classbox = self.cpu.ts.cls_of_box(self.nodebox2)
+        knownclass2_val.make_constant_class(classbox, -1)
+        knownclass2_info = NotVirtualStateInfo(knownclass2_val)
+
+        constant_val = OptValue(BoxInt())
+        constant_val.make_constant(ConstInt(1))
+        constant_info = NotVirtualStateInfo(constant_val)
+        constclass_val = OptValue(self.nodebox)
+        constclass_val.make_constant(self.nodebox.constbox())
+        constclass_info = NotVirtualStateInfo(constclass_val)
+        constclass2_val = OptValue(self.nodebox)
+        constclass2_val.make_constant(self.nodebox2.constbox())
+        constclass2_info = NotVirtualStateInfo(constclass2_val)
+        constantnull_val = OptValue(ConstPtr(self.nullptr))
+        constantnull_info = NotVirtualStateInfo(constantnull_val)
+
+        # unknown unknown
+        self.check_no_guards(unknown_info, unknown_info, unknown_val)
+
+        # unknown nonnull
+        self.check_no_guards(unknown_info, nonnull_info, nonnull_val)
+
+        # unknown knownclass
+        self.check_no_guards(unknown_info, knownclass_info, knownclass_val)
+
+        # unknown constant
+        self.check_no_guards(unknown_info, constant_info, constant_val)
+
+
+        # nonnull unknown
+        expected = """
+        [p0]
+        guard_nonnull(p0) []
+        """
+        self.guards(nonnull_info, unknown_info, unknown_val, expected)
+        self.check_invalid(nonnull_info, unknown_info, unknownnull_val)
+
+        # nonnull nonnull
+        self.check_no_guards(nonnull_info, nonnull_info, nonnull_val)
+
+        # nonnull knownclass
+        self.check_no_guards(nonnull_info, knownclass_info, knownclass_val)
+
+        # nonnull constant
+        self.check_no_guards(nonnull_info, constant_info, constant_val)
+        self.check_invalid(nonnull_info, constantnull_info, constantnull_val)
+
+
+        # knownclass unknown
+        expected = """
+        [p0]
+        guard_nonnull(p0) []
+        guard_class(p0, ConstClass(node_vtable)) []
+        """
+        self.guards(knownclass_info, unknown_info, unknown_val, expected)
+        self.check_invalid(knownclass_info, unknown_info, unknownnull_val)
+        self.check_invalid(knownclass_info, unknown_info, knownclass2_val)
+
+        # knownclass nonnull
+        expected = """
+        [p0]
+        guard_class(p0, ConstClass(node_vtable)) []
+        """
+        self.guards(knownclass_info, nonnull_info, knownclass_val, expected)
+        self.check_invalid(knownclass_info, nonnull_info, knownclass2_val)
+
+        # knownclass knownclass
+        self.check_no_guards(knownclass_info, knownclass_info, knownclass_val)
+        self.check_invalid(knownclass_info, knownclass2_info, knownclass2_val)
+
+        # knownclass constant
+        self.check_invalid(knownclass_info, constantnull_info, 
constantnull_val)
+        self.check_invalid(knownclass_info, constclass2_info, constclass2_val)
+
+
+        # constant unknown
+        expected = """
+        [i0]
+        guard_value(i0, 1) []
+        """
+        self.guards(constant_info, unknown_info, constant_val, expected)
+        self.check_invalid(constant_info, unknown_info, unknownnull_val)
+
+        # constant nonnull
+        expected = """
+        [i0]
+        guard_value(i0, 1) []
+        """
+        self.guards(constant_info, nonnull_info, constant_val, expected)
+        self.check_invalid(constant_info, nonnull_info, constclass2_val)
+
+        # constant knownclass
+        expected = """
+        [i0]
+        guard_value(i0, 1) []
+        """
+        self.guards(constant_info, knownclass_info, constant_val, expected)
+        self.check_invalid(constant_info, knownclass_info, unknownnull_val)
+
+        # constant constant
+        self.check_no_guards(constant_info, constant_info, constant_val)
+        self.check_invalid(constant_info, constantnull_info, constantnull_val)
+
+
     def test_intbounds(self):
         value1 = OptValue(BoxInt(15))
         value1.intbound.make_ge(IntBound(0, 10))
@@ -280,6 +417,34 @@
         vstate1.generate_guards(vstate2, [value2], self.cpu, guards)
         self.compare(guards, expected, [box2])
 
+    def test_generate_guards_on_virtual_fields_matches(self):
+        py.test.skip("not yet")
+        innervalue1 = OptValue(self.nodebox)
+        constclassbox = self.cpu.ts.cls_of_box(self.nodebox)
+        innervalue1.make_constant_class(constclassbox, -1)
+        innerinfo1 = NotVirtualStateInfo(innervalue1)
+        innerinfo1.position = 1
+        innerinfo2 = NotVirtualStateInfo(OptValue(self.nodebox))
+        innerinfo2.position = 1
+
+        info1 = VirtualStateInfo(ConstInt(42), [1])
+        info1.fieldstate = [innerinfo1]
+
+        info2 = VirtualStateInfo(ConstInt(42), [1])
+        info2.fieldstate = [innerinfo2]
+
+        value1 = VirtualValue(self.cpu, constclassbox, BoxInt())
+        value1._fields = {1: OptValue(self.nodebox)}
+
+        expected = """
+        [p0]
+        guard_nonnull(p0) []
+        guard_class(p0, ConstClass(node_vtable)) []
+        """
+        self.guards(info1, info2, value1, expected)
+
+    # _________________________________________________________________________
+    # the below tests don't really have anything to do with guard generation
 
     def test_virtuals_with_equal_fields(self):
         info1 = VirtualStateInfo(ConstInt(42), [1, 2])
@@ -681,7 +846,7 @@
         """
         self.optimize_bridge(loop, bridge, expected, p0=self.myptr)
 
-    def test_virtual(self):
+    def test_simple_virtual(self):
         loops = """
         [p0, p1]
         p2 = new_with_vtable(ConstClass(node_vtable))
diff --git a/rpython/jit/metainterp/optimizeopt/virtualstate.py 
b/rpython/jit/metainterp/optimizeopt/virtualstate.py
--- a/rpython/jit/metainterp/optimizeopt/virtualstate.py
+++ b/rpython/jit/metainterp/optimizeopt/virtualstate.py
@@ -28,18 +28,23 @@
             bad[self] = bad[other] = None
         return result
 
-    def generate_guards(self, other, value, cpu, extra_guards, renum):
+    def generate_guards(self, other, value, cpu, extra_guards, renum, 
bad=None):
+        if bad is None:
+            bad = {}
         assert isinstance(value, OptValue)
-        if self.generalization_of(other, renum, {}):
-            return
-        if renum[self.position] != other.position:
-            raise InvalidLoop('The numbering of the virtual states does not ' +
-                              'match. This means that two virtual fields ' +
-                              'have been set to the same Box in one of the ' +
-                              'virtual states but not in the other.')
-        self._generate_guards(other, value, cpu, extra_guards, renum)
+        if self.position in renum:
+            if renum[self.position] != other.position:
+                bad[self] = bad[other] = None
+                raise InvalidLoop('The numbering of the virtual states does 
not ' +
+                                  'match. This means that two virtual fields ' 
+
+                                  'have been set to the same Box in one of the 
' +
+                                  'virtual states but not in the other.')
+        else:
+            renum[self.position] = other.position
+            self._generate_guards(other, value, cpu, extra_guards, renum, bad)
 
-    def _generate_guards(self, other, value, cpu, extra_guards, renum):
+    def _generate_guards(self, other, value, cpu, extra_guards, renum, bad):
+        bad[self] = bad[other] = None
         raise InvalidLoop('Generating guards for making the VirtualStates ' +
                           'at hand match have not been implemented')
 
@@ -126,6 +131,7 @@
         return (isinstance(other, VirtualStateInfo) and
                 self.known_class.same_constant(other.known_class))
 
+
     def debug_header(self, indent):
         debug_print(indent + 'VirtualStateInfo(%d):' % self.position)
 
@@ -271,55 +277,101 @@
 
         if not self.intbound.contains_bound(other.intbound):
             return False
-        if self.lenbound and other.lenbound:
-            if self.lenbound.mode != other.lenbound.mode or \
-               self.lenbound.descr != other.lenbound.descr or \
-               not self.lenbound.bound.contains_bound(other.lenbound.bound):
-                return False
-        elif self.lenbound:
-            return False
+        if self.lenbound:
+            return self.lenbound.generalization_of(other.lenbound)
         return True
 
-    def _generate_guards(self, other, value, cpu, extra_guards, renum):
+    def _generate_guards(self, other, value, cpu, extra_guards, renum, bad):
         box = value.box
         if not isinstance(other, NotVirtualStateInfo):
+            bad[self] = bad[other] = None
             raise InvalidLoop('The VirtualStates does not match as a ' +
                               'virtual appears where a pointer is needed ' +
                               'and it is too late to force it.')
 
-        if self.lenbound or other.lenbound:
-            raise InvalidLoop('The array length bounds does not match.')
-
         if self.is_opaque:
+            bad[self] = bad[other] = None
             raise InvalidLoop('Generating guards for opaque pointers is not 
safe')
 
-        # the following conditions always peek into the runtime value that the
+        if self.lenbound and not 
self.lenbound.generalization_of(other.lenbound):
+            raise InvalidLoop()
+
+
+        if self.level == LEVEL_UNKNOWN:
+            return
+
+        # the following conditions often peek into the runtime value that the
         # box had when tracing. This value is only used as an educated guess.
         # It is used here to choose between either emitting a guard and jumping
         # to an existing compiled loop or retracing the loop. Both alternatives
         # will always generate correct behaviour, but performance will differ.
-        if (self.level == LEVEL_CONSTANT and
-                self.constbox.same_constant(box.constbox())):
-            op = ResOperation(rop.GUARD_VALUE, [box, self.constbox], None)
-            extra_guards.append(op)
-            return
+        elif self.level == LEVEL_NONNULL:
+            if other.level == LEVEL_UNKNOWN:
+                if box.nonnull():
+                    op = ResOperation(rop.GUARD_NONNULL, [box], None)
+                    extra_guards.append(op)
+                    return
+                else:
+                    raise InvalidLoop()
+            elif other.level == LEVEL_NONNULL:
+                return
+            elif other.level == LEVEL_KNOWNCLASS:
+                return # implies nonnull
+            else:
+                assert other.level == LEVEL_CONSTANT
+                assert other.constbox
+                if not other.constbox.nonnull():
+                    raise InvalidLoop("XXX")
+                return
 
-        if self.level == LEVEL_KNOWNCLASS and \
-           box.nonnull() and \
-           self.known_class.same_constant(cpu.ts.cls_of_box(box)):
-            op = ResOperation(rop.GUARD_NONNULL, [box], None)
-            extra_guards.append(op)
-            op = ResOperation(rop.GUARD_CLASS, [box, self.known_class], None)
-            extra_guards.append(op)
-            return
+        elif self.level == LEVEL_KNOWNCLASS:
+            if other.level == LEVEL_UNKNOWN:
+                if (box.nonnull() and
+                        
self.known_class.same_constant(cpu.ts.cls_of_box(box))):
+                    op = ResOperation(rop.GUARD_NONNULL, [box], None)
+                    extra_guards.append(op)
+                    op = ResOperation(rop.GUARD_CLASS, [box, 
self.known_class], None)
+                    extra_guards.append(op)
+                    return
+                else:
+                    raise InvalidLoop()
+            elif other.level == LEVEL_NONNULL:
+                if self.known_class.same_constant(cpu.ts.cls_of_box(box)):
+                    op = ResOperation(rop.GUARD_CLASS, [box, 
self.known_class], None)
+                    extra_guards.append(op)
+                    return
+                else:
+                    raise InvalidLoop()
+            elif other.level == LEVEL_KNOWNCLASS:
+                if self.known_class.same_constant(other.known_class):
+                    return
+                raise InvalidLoop()
+            else:
+                assert other.level == LEVEL_CONSTANT
+                if (other.constbox.nonnull() and
+                        
self.known_class.same_constant(cpu.ts.cls_of_box(other.constbox))):
+                    return
+                else:
+                    raise InvalidLoop()
 
-        if (self.level == LEVEL_NONNULL and
-               other.level == LEVEL_UNKNOWN and
-               isinstance(box, BoxPtr) and
-               box.nonnull()):
-            op = ResOperation(rop.GUARD_NONNULL, [box], None)
-            extra_guards.append(op)
-            return
+        else:
+            assert self.level == LEVEL_CONSTANT
+            if other.level == LEVEL_CONSTANT:
+                if self.constbox.same_constant(other.constbox):
+                    return
+                raise InvalidLoop()
+            if self.constbox.same_constant(box.constbox()):
+                op = ResOperation(rop.GUARD_VALUE, [box, self.constbox], None)
+                extra_guards.append(op)
+                return
+            else:
+                raise InvalidLoop()
+        raise InvalidLoop("XXX")
+
+        if self.lenbound or other.lenbound:
+            bad[self] = bad[other] = None
+            raise InvalidLoop('The array length bounds does not match.')
+
 
         if (self.level == LEVEL_UNKNOWN and
                other.level == LEVEL_UNKNOWN and
@@ -345,10 +397,6 @@
                     extra_guards.append(op)
             return
 
-        # Remaining cases are probably not interesting
-        raise InvalidLoop('Generating guards for making the VirtualStates ' +
-                          'at hand match have not been implemented')
-
     def enum_forced_boxes(self, boxes, value, optimizer):
         if self.level == LEVEL_CONSTANT:
             return
@@ -410,12 +458,14 @@
                 return False
         return True
 
-    def generate_guards(self, other, values, cpu, extra_guards):
+    def generate_guards(self, other, values, cpu, extra_guards, bad=None):
+        if bad is None:
+            bad = {}
         assert len(self.state) == len(other.state) == len(values)
         renum = {}
         for i in range(len(self.state)):
             self.state[i].generate_guards(other.state[i], values[i],
-                                          cpu, extra_guards, renum)
+                                          cpu, extra_guards, renum, bad)
 
     def make_inputargs(self, values, optimizer, keyboxes=False):
         if optimizer.optearlyforce:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to