[pypy-svn] r66459 - in pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp: . test

arigo at codespeak.net arigo at codespeak.net
Mon Jul 20 22:57:22 CEST 2009


Author: arigo
Date: Mon Jul 20 22:57:21 2009
New Revision: 66459

Modified:
   pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimizeopt.py
   pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimizeopt.py
Log:
In-progress: refactoring the data model.


Modified: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimizeopt.py	(original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimizeopt.py	Mon Jul 20 22:57:21 2009
@@ -1,6 +1,6 @@
 from pypy.jit.metainterp.history import Const, Box, BoxInt, BoxPtr, BoxObj
 from pypy.jit.metainterp import history
-from pypy.jit.metainterp.resoperation import rop
+from pypy.jit.metainterp.resoperation import rop, ResOperation
 from pypy.jit.metainterp.specnode import SpecNode
 from pypy.jit.metainterp.specnode import VirtualInstanceSpecNode
 from pypy.jit.metainterp.optimizeutil import av_newdict, _findall
@@ -19,12 +19,84 @@
 
 # ____________________________________________________________
 
-class VirtualBox(history.AbstractValue):
-    def __init__(self):
-        self.fields = av_newdict()     # ofs -> Box
+LEVEL_UNKNOWN    = 0
+LEVEL_NONNULL    = 1
+LEVEL_KNOWNCLASS = 2
+LEVEL_CONSTANT   = 3
+
+
+class InstanceValue(object):
+    level = LEVEL_UNKNOWN
+
+    def __init__(self, box):
+        self.box = box
+        if isinstance(box, Const):
+            self.level = LEVEL_CONSTANT
+
+    def force_box(self):
+        return self.box
+
+    def is_constant(self):
+        return self.level == LEVEL_CONSTANT
+
+    def is_null(self):
+        return self.is_constant() and not self.box.nonnull()
+
+    def make_constant(self):
+        """Mark 'self' as actually representing a Const value."""
+        self.box = self.force_box().constbox()
+        self.level = LEVEL_CONSTANT
+
+    def has_constant_class(self):
+        return self.level >= LEVEL_KNOWNCLASS
+
+    def make_constant_class(self):
+        if self.level < LEVEL_KNOWNCLASS:
+            self.level = LEVEL_KNOWNCLASS
+
+    def is_nonnull(self):
+        level = self.level
+        if level == LEVEL_NONNULL or level == LEVEL_KNOWNCLASS:
+            return True
+        elif level == LEVEL_CONSTANT:
+            return self.box.nonnull()
+        else:
+            return False
+
+    def make_nonnull(self):
+        if self.level < LEVEL_NONNULL:
+            self.level = LEVEL_NONNULL
+
+    def is_virtual(self):
+        return self.box is None
+
+
+class ConstantValue(InstanceValue):
+    level = LEVEL_CONSTANT
+
+    def __init__(self, box):
+        self.box = box
+
+
+class VirtualValue(InstanceValue):
+    box = None
+    level = LEVEL_KNOWNCLASS
+
+    def __init__(self, optimizer):
+        self.optimizer = optimizer
+        self._fields = av_newdict()
 
-    def nonnull(self):
-        return True
+    def getfield(self, ofs):
+        return self._fields[ofs]
+
+    def setfield(self, ofs, fieldvalue):
+        self._fields[ofs] = fieldvalue
+
+    def force_box(self):
+        if self.box is None:
+            optimizer = self.optimizer
+            xxxx
+        return self.box
 
 
 class __extend__(SpecNode):
@@ -35,18 +107,19 @@
 
 class __extend__(VirtualInstanceSpecNode):
     def setup_virtual_node(self, optimizer, box, newinputargs):
+        import py; py.test.skip("in-progress")
         vbox = optimizer.make_virtual(box, self.known_class)
         for ofs, subspecnode in self.fields:
-            subbox = optimizer.make_box(ofs)
+            subbox = optimizer.new_box(ofs)
             vbox.fields[ofs] = subbox
             subspecnode.setup_virtual_node(optimizer, subbox, newinputargs)
     def teardown_virtual_node(self, optimizer, box, newexitargs):
-        assert isinstance(box, VirtualBox)
+        assert isinstance(box, VirtualBox) and box.escaped_to is None
         for ofs, subspecnode in self.fields:
             try:
                 subbox = box.fields[ofs]
             except KeyError:
-                subbox = optimizer.make_const(ofs)
+                subbox = optimizer.new_const(ofs)
             subspecnode.teardown_virtual_node(optimizer, subbox, newexitargs)
 
 
@@ -55,53 +128,34 @@
     def __init__(self, cpu, loop):
         self.cpu = cpu
         self.loop = loop
-        # Boxes used a keys to _equals have been proven to be equal to
-        # something else: another Box, a Const, or a VirtualBox.  Boxes
-        # and VirtualBoxes can also be listed in _known_classes if we
-        # know their class (or just know that they are non-null, in which
-        # case we use None).  Boxes *must not* be keys in both dicts.
-        self._equals = {}          # mapping Box -> Box/Const/VirtualBox
-        self._known_classes = {}   # mapping Box -> ConstClass/None
-
-    def deref(self, box):
-        """Maps a Box/Const to the corresponding Box/Const/VirtualBox
-        by following the dict _equals.
-        """
-        box = self._equals.get(box, box)
-        assert box not in self._equals
-        return box
-
-    def _make_equal(self, box, box2):
-        assert isinstance(box, Box)
-        assert box not in self._equals
-        assert box not in self._known_classes
-        self._equals[box] = box2
+        self.values = {}
+
+    def getvalue(self, box):
+        try:
+            value = self.values[box]
+        except KeyError:
+            value = self.values[box] = InstanceValue(box)
+        return value
+
+    def is_constant(self, box):
+        if isinstance(box, Const):
+            return True
+        try:
+            return self.values[box].is_constant()
+        except KeyError:
+            return False
+
+    def make_equal_to(self, box, value):
+        assert box not in self.values
+        self.values[box] = value
 
     def make_constant(self, box):
-        """Mark the given Box as actually representing a Const value."""
-        self._make_equal(box, box.constbox())
+        self.make_equal_to(box, ConstantValue(box.constbox()))
 
-    def make_virtual(self, box, clsbox):
-        """Mark the given Box as actually representing a VirtualBox value."""
-        vbox = VirtualBox()
-        self._make_equal(box, vbox)
-        self.make_constant_class(vbox, clsbox)
-        return vbox
-
-    def has_constant_class(self, box):
-        return (isinstance(box, Const) or
-                self._known_classes.get(box, None) is not None)
-
-    def make_constant_class(self, box, clsbox):
-        assert isinstance(clsbox, Const)
-        assert box not in self._equals
-        self._known_classes[box] = clsbox
-
-    def make_nonnull(self, box):
-        assert box not in self._equals
-        self._known_classes.setdefault(box, None)
+    def known_nonnull(self, box):
+        return self.getvalue(box).is_nonnull()
 
-    def make_box(self, fieldofs):
+    def new_box(self, fieldofs):
         if fieldofs.is_pointer_field():
             if not self.cpu.is_oo:
                 return BoxPtr()
@@ -110,7 +164,7 @@
         else:
             return BoxInt()
 
-    def make_const(self, fieldofs):
+    def new_const(self, fieldofs):
         if fieldofs.is_pointer_field():
             if not self.cpu.is_oo:
                 return history.CONST_NULL
@@ -119,12 +173,6 @@
         else:
             return history.CONST_FALSE
 
-    def known_nonnull(self, box):
-        if isinstance(box, Box):
-            return box in self._known_classes
-        else:
-            return box.nonnull()   # Consts or VirtualBoxes
-
     # ----------
 
     def setup_virtuals(self):
@@ -141,26 +189,32 @@
     def propagate_forward(self):
         self.newoperations = []
         for op in self.loop.operations:
-            op2 = op.clone()
-            op2.args = [self.deref(box) for box in op.args]
-            opnum = op2.opnum
+            opnum = op.opnum
             for value, func in optimize_ops:
                 if opnum == value:
-                    func(self, op2)
+                    func(self, op)
                     break
             else:
-                self.optimize_default(op2)
+                self.optimize_default(op)
         self.loop.operations = self.newoperations
 
     def emit_operation(self, op):
-        for x in op.args:
-            assert not isinstance(x, VirtualBox)
+        must_clone = True
+        for i in range(len(op.args)):
+            arg = op.args[i]
+            if arg in self.values:
+                box = self.values[arg].force_box()
+                if box is not arg:
+                    if must_clone:
+                        op = op.clone()
+                        must_clone = False
+                    op.args[i] = box
         self.newoperations.append(op)
 
     def optimize_default(self, op):
         if op.is_always_pure():
-            for box in op.args:
-                if not isinstance(box, Const):
+            for arg in op.args:
+                if not self.is_constant(arg):
                     break
             else:
                 # all constant arguments: constant-fold away
@@ -169,7 +223,7 @@
         # otherwise, the operation remains
         self.emit_operation(op)
 
-    def optimize_JUMP(self, op):
+    def XXX_optimize_JUMP(self, op):
         orgop = self.loop.operations[-1]
         exitargs = []
         specnodes = orgop.jump_target.specnodes
@@ -177,34 +231,34 @@
         for i in range(len(specnodes)):
             specnodes[i].teardown_virtual_node(self, op.args[i], exitargs)
         op.args = exitargs
+        #XXX return op
+
+    def optimize_guard(self, op):
+        value = self.getvalue(op.args[0])
+        if value.is_constant():
+            return
         self.emit_operation(op)
+        value.make_constant()
 
     def optimize_GUARD_VALUE(self, op):
         assert isinstance(op.args[1], Const)
-        assert op.args[0].get_() == op.args[1].get_()
-        if not isinstance(op.args[0], Const):
-            self.emit_operation(op)
-            self.make_constant(op.args[0])
+        self.optimize_guard(op)
 
     def optimize_GUARD_TRUE(self, op):
         assert op.args[0].getint()
-        if not isinstance(op.args[0], Const):
-            self.emit_operation(op)
-            self.make_constant(op.args[0])
+        self.optimize_guard(op)
 
     def optimize_GUARD_FALSE(self, op):
         assert not op.args[0].getint()
-        if not isinstance(op.args[0], Const):
-            self.emit_operation(op)
-            self.make_constant(op.args[0])
+        self.optimize_guard(op)
 
     def optimize_GUARD_CLASS(self, op):
-        instbox = op.args[0]
-        clsbox = op.args[1]
         # XXX should probably assert that the class is right
-        if not self.has_constant_class(instbox):
-            self.emit_operation(op)
-            self.make_constant_class(instbox, clsbox)
+        value = self.getvalue(op.args[0])
+        if value.has_constant_class():
+            return
+        self.emit_operation(op)
+        value.make_constant_class()
 
     def optimize_OONONNULL(self, op):
         if self.known_nonnull(op.args[0]):
@@ -221,56 +275,56 @@
             self.optimize_default(op)
 
     def optimize_OOISNOT(self, op):
-        if (isinstance(op.args[0], VirtualBox) or
-            isinstance(op.args[1], VirtualBox)):
+        value0 = self.getvalue(op.args[0])
+        value1 = self.getvalue(op.args[1])
+        if value0.is_virtual() or value1.is_virtual():
             self.make_constant(op.result)
-        elif self.known_nonnull(op.args[1]):
-            op.opnum = rop.OONONNULL
-            del op.args[1]
+        elif value1.is_null():
+            op = ResOperation(rop.OONONNULL, [op.args[0]], op.result)
             self.optimize_OONONNULL(op)
-        elif self.known_nonnull(op.args[0]):
-            op.opnum = rop.OONONNULL
-            del op.args[0]
+        elif value0.is_null():
+            op = ResOperation(rop.OONONNULL, [op.args[1]], op.result)
             self.optimize_OONONNULL(op)
         else:
             self.optimize_default(op)
 
     def optimize_OOIS(self, op):
-        if (isinstance(op.args[0], VirtualBox) or
-            isinstance(op.args[1], VirtualBox)):
+        value0 = self.getvalue(op.args[0])
+        value1 = self.getvalue(op.args[1])
+        if value0.is_virtual() or value1.is_virtual():
             self.make_constant(op.result)
-        elif self.known_nonnull(op.args[1]):
-            op.opnum = rop.OOISNULL
-            del op.args[1]
+        elif value1.is_null():
+            op = ResOperation(rop.OOISNULL, [op.args[0]], op.result)
             self.optimize_OOISNULL(op)
-        elif self.known_nonnull(op.args[0]):
-            op.opnum = rop.OOISNULL
-            del op.args[0]
+        elif value0.is_null():
+            op = ResOperation(rop.OOISNULL, [op.args[1]], op.result)
             self.optimize_OOISNULL(op)
         else:
             self.optimize_default(op)
 
     def optimize_GETFIELD_GC(self, op):
-        instbox = op.args[0]
-        if isinstance(instbox, VirtualBox):
-            # optimizefindnode should ensure that 'op.descr in instbox.fields'
-            self._make_equal(op.result, instbox.fields[op.descr])
+        value = self.getvalue(op.args[0])
+        if value.is_virtual():
+            # optimizefindnode should ensure that we don't get a KeyError
+            fieldvalue = value.getfield(op.descr)
+            self.make_equal_to(op.result, fieldvalue)
         else:
-            self.make_nonnull(instbox)
+            value.make_nonnull()
             self.optimize_default(op)
 
-    optimize_GETFIELD_PURE_GC = optimize_GETFIELD_GC
+    def optimize_GETFIELD_PURE_GC(self, op):
+        xxx # optimize_GETFIELD_GC
 
     def optimize_SETFIELD_GC(self, op):
-        instbox = op.args[0]
-        if isinstance(instbox, VirtualBox):
-            instbox.fields[op.descr] = op.args[1]
+        value = self.getvalue(op.args[0])
+        if value.is_virtual():
+            value.setfield(op.descr, self.getvalue(op.args[1]))
         else:
-            self.make_nonnull(instbox)
+            value.make_nonnull()
             self.optimize_default(op)
 
     def optimize_NEW_WITH_VTABLE(self, op):
-        self.make_virtual(op.result, op.args[0])
+        import py; py.test.skip("in-progress")
 
 
 optimize_ops = _findall(Optimizer, 'optimize_')

Modified: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimizeopt.py	Mon Jul 20 22:57:21 2009
@@ -400,6 +400,57 @@
         self.optimize_loop(ops, 'Virtual(node_vtable, valuedescr=Not)',
                            expected)
 
+    def test_virtual_3(self):
+        ops = """
+        [i]
+        p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+        setfield_gc(p1, i, descr=valuedescr)
+        i0 = getfield_gc(p1, descr=valuedescr)
+        i1 = int_add(i0, 1)
+        jump(i1)
+        """
+        expected = """
+        [i]
+        i1 = int_add(i, 1)
+        jump(i1)
+        """
+        self.optimize_loop(ops, 'Not', expected)
+
+    def test_nonvirtual_1(self):
+        ops = """
+        [i]
+        p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+        setfield_gc(p1, i, descr=valuedescr)
+        i0 = getfield_gc(p1, descr=valuedescr)
+        i1 = int_add(i0, 1)
+        escape(p1)
+        escape(p1)
+        jump(i1)
+        """
+        expected = """
+        [i]
+        i1 = int_add(i, 1)
+        p9 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+        setfield_gc(p9, i, descr=valuedescr)
+        escape(p9)
+        escape(p9)
+        jump(i1)
+        """
+        self.optimize_loop(ops, 'Not', expected)
+
+    def test_nonvirtual_2(self):
+        ops = """
+        [i, p0]
+        i0 = getfield_gc(p0, descr=valuedescr)
+        escape(p0)
+        i1 = int_add(i0, i)
+        p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+        setfield_gc(p1, i1, descr=valuedescr)
+        jump(i, p1)
+        """
+        expected = ops
+        self.optimize_loop(ops, 'Not, Not', expected)
+
 
 class TestLLtype(BaseTestOptimizeOpt, LLtypeMixin):
     pass



More information about the Pypy-commit mailing list