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

arigo at codespeak.net arigo at codespeak.net
Wed Jul 15 21:17:51 CEST 2009


Author: arigo
Date: Wed Jul 15 21:17:49 2009
New Revision: 66248

Added:
   pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimize.py
      - copied, changed from r66241, pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimize4.py
   pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimize.py
      - copied, changed from r66241, pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimize4.py
Log:
Start writing the new version of optimize.py.
So far, only find_nodes is implemented.
Work in progress.


Copied: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimize.py (from r66241, pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimize4.py)
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimize4.py	(original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimize.py	Wed Jul 15 21:17:49 2009
@@ -1,16 +1,7 @@
-from pypy.jit.metainterp.resoperation import rop
-from pypy.jit.metainterp.history import (Box, Const, ConstInt, BoxInt, BoxPtr,
-                                         ResOperation, AbstractDescr,
-                                         Options, AbstractValue, ConstPtr,
-                                         ConstObj)
-from pypy.jit.metainterp.specnode4 import (FixedClassSpecNode,
-                                           prebuiltNotSpecNode,
-                                           VirtualInstanceSpecNode)
-from pypy.jit.metainterp import executor
-from pypy.rlib.objectmodel import we_are_translated
-from pypy.rpython.lltypesystem import lltype, llmemory
-from pypy.rpython.ootypesystem import ootype
 from pypy.rlib.objectmodel import r_dict
+from pypy.rlib.unroll import unrolling_iterable
+from pypy.jit.metainterp import resoperation
+from pypy.jit.metainterp.history import AbstractValue
 
 
 def av_eq(self, other):
@@ -19,559 +10,130 @@
 def av_hash(self):
     return self.sort_key()
 
+def av_newdict():
+    return r_dict(av_eq, av_hash)
+
+def _findall(Class, name_prefix):
+    result = []
+    for value, name in resoperation.opname.items():
+        if hasattr(Class, name_prefix + name):
+            result.append((value, getattr(Class, name_prefix + name)))
+    return unrolling_iterable(result)
+
+# ____________________________________________________________
+
 class InstanceNode(object):
-    def __init__(self, source, escaped=True, startbox=False):
-        self.source = source       # a Box
+    """For the first phase: InstanceNode is used to match the start and
+    the end of the loop, so it contains both 'origfields' that represents
+    the field's status at the start and 'curfields' that represents it
+    at the current point (== the end when the first phase is complete).
+    """
+    origfields = None   # optimization; equivalent to an empty dict
+    curfields = None    # optimization; equivalent to an empty dict
+    dependencies = None
+
+    def __init__(self, escaped, startbox=False):
         self.escaped = escaped
         self.startbox = startbox
-        self.virtual = False
-        self.const = isinstance(source, Const)  # forced to True by guard_value
-        self.cls = None
-        self.origfields = r_dict(av_eq, av_hash)
-        self.curfields = r_dict(av_eq, av_hash)
-
-    def is_nonzero(self):
-        return self.cls is not None or (self.const and self.source.get_() != 0)
-
-    def is_zero(self):
-        return self.const and self.source.get_() == 0
-
-    def escape_if_startbox(self, memo, cpu):
-        if self in memo:
-            return
-        memo[self] = None
-        if self.startbox:
-            self.escaped = True
-        for node in self.curfields.values():
-            node.escape_if_startbox(memo, cpu)
 
-    def add_to_dependency_graph(self, other, dep_graph):
-        dep_graph.append((self, other))
-        for ofs, node in self.origfields.items():
-            if ofs in other.curfields:
-                node.add_to_dependency_graph(other.curfields[ofs], dep_graph)
-
-    def intersect(self, other, nodes):
-        if not other.cls:
-            return prebuiltNotSpecNode
-        if self.cls:
-            if not self.cls.source.equals(other.cls.source):
-                return prebuiltNotSpecNode
-            known_class = self.cls.source
-        else:
-            known_class = other.cls.source
-        if other.escaped:
-            if self.cls is None:
-                return prebuiltNotSpecNode
-            return FixedClassSpecNode(known_class)
-        else:
-            assert self is not other
-            fields = []
-            d = other.curfields
-            lst = d.keys()
-            sort_descrs(lst)
-            for ofs in lst:
-                node = d[ofs]
-                if ofs not in self.origfields:
-                    box = node.source.clonebox()
-                    self.origfields[ofs] = InstanceNode(box, escaped=False)
-                    self.origfields[ofs].cls = node.cls
-                    nodes[box] = self.origfields[ofs]
-                specnode = self.origfields[ofs].intersect(node, nodes)
-                fields.append((ofs, specnode))
-            return VirtualInstanceSpecNode(known_class, fields)
+    def add_escape_dependency(self, other):
+        assert not self.escaped
+        if self.dependencies is None:
+            self.dependencies = []
+        self.dependencies.append(other)
+
+    def mark_escaped(self):
+        # invariant: if escaped=True, then dependencies is None
+        if not self.escaped:
+            self.escaped = True
+            if self.dependencies is not None:
+                deps = self.dependencies
+                self.dependencies = None
+                for box in deps:
+                    box.mark_escaped()
 
     def __repr__(self):
         flags = ''
-        if self.escaped:           flags += 'e'
-        if self.startbox:          flags += 's'
-        if self.const:             flags += 'c'
-        if self.virtual:           flags += 'v'
-        return "<InstanceNode %s (%s)>" % (self.source, flags)
-
-def optimize_loop(options, old_loops, loop, cpu=None):
-    if not options.specialize:         # for tests only
-        if old_loops:
-            return old_loops[0]
-        else:
-            return None
+        if self.escaped:  flags += 'e'
+        if self.startbox: flags += 's'
+        return "<InstanceNode (%s)>" % (flags,)
+
+
+class PerfectSpecializationFinder(object):
 
-    # This does "Perfect specialization" as per doc/jitpl5.txt.
-    perfect_specializer = PerfectSpecializer(loop, options, cpu)
-    perfect_specializer.find_nodes()
-    perfect_specializer.intersect_input_and_output()
-    for old_loop in old_loops:
-        if perfect_specializer.match_exactly(old_loop):
-            return old_loop
-    perfect_specializer.optimize_loop()
-    return None
-
-def optimize_bridge(options, old_loops, loop, cpu=None):
-    if not options.specialize:         # for tests only
-        return old_loops[0]
-
-    perfect_specializer = PerfectSpecializer(loop, options, cpu)
-    perfect_specializer.find_nodes()
-    for old_loop in old_loops:
-        if perfect_specializer.match(old_loop):
-            # xxx slow, maybe
-            # XXX the next loop is a big hack.  Ideally it should set cls=None
-            # to prevent assuming something about the cls -- but only if there
-            # is no code in the previous loop that checks the cls.
-            for node in perfect_specializer.nodes.values():
-                if node.startbox:
-                    node.cls = None
-                    assert not node.virtual
-            perfect_specializer.propagate_escapes()
-            perfect_specializer.adapt_for_match(old_loop)
-            perfect_specializer.optimize_loop()
-            return old_loop
-    return None     # no loop matches
-
-class PerfectSpecializer(object):
-    _allow_automatic_node_creation = False
-
-    def __init__(self, loop, options=Options(), cpu=None):
-        self.loop = loop
-        self.options = options
-        self.cpu = cpu
-        self.nodes = {}
-        self.dependency_graph = []
+    def __init__(self):
+        self.nodes = {}     # Box -> InstanceNode
+        self.node_escaped = InstanceNode(escaped=True)
+
+    def clear(self):
+        self.nodes.clear()
 
     def getnode(self, box):
-        try:
-            return self.nodes[box]
-        except KeyError:
-            if isinstance(box, Const):
-                node = InstanceNode(box, escaped=True)
+        return self.nodes.get(box, self.node_escaped)
+
+    def find_nodes(self, loop):
+        self.clear()
+        for box in loop.inputargs:
+            self.nodes[box] = InstanceNode(escaped=False, startbox=True)
+        #
+        for op in loop.operations:
+            opnum = op.opnum
+            for value, func in find_nodes_ops:
+                if opnum == value:
+                    func(self, op)
+                    break
             else:
-                assert self._allow_automatic_node_creation
-                node = InstanceNode(box, escaped=True, startbox=True)
-            self.nodes[box] = node
-            return node
-
-    def getsource(self, box):
-        if isinstance(box, Const):
-            return box
-        return self.nodes[box].source
-
-    def find_nodes_setfield(self, instnode, ofs, fieldnode):
-        assert isinstance(ofs, AbstractValue)
-        instnode.curfields[ofs] = fieldnode
-        self.dependency_graph.append((instnode, fieldnode))
+                self.find_nodes_default(op)
 
-    def find_nodes_getfield(self, instnode, field, box):
+    def find_nodes_default(self, op):
+        if not op.has_no_side_effect():
+            # default case: mark the arguments as escaping
+            for box in op.args:
+                self.getnode(box).mark_escaped()
+
+    def find_nodes_NEW_WITH_VTABLE(self, op):
+        self.nodes[op.result] = InstanceNode(escaped=False)
+
+    def find_nodes_SETFIELD_GC(self, op):
+        instnode = self.getnode(op.args[0])
+        if instnode.escaped:
+            return     # nothing to be gained from tracking the field
+        fieldnode = self.getnode(op.args[1])
+        field = op.descr
+        assert isinstance(field, AbstractValue)
+        if instnode.curfields is None:
+            instnode.curfields = av_newdict()
+        instnode.curfields[field] = fieldnode
+        instnode.add_escape_dependency(fieldnode)
+
+    def find_nodes_GETFIELD_GC(self, op):
+        instnode = self.getnode(op.args[0])
+        if instnode.escaped:
+            return     # nothing to be gained from tracking the field
+        field = op.descr
         assert isinstance(field, AbstractValue)
-        if field in instnode.curfields:
+        if instnode.curfields is not None and field in instnode.curfields:
             fieldnode = instnode.curfields[field]
-        elif field in instnode.origfields:
+        elif instnode.origfields is not None and field in instnode.origfields:
             fieldnode = instnode.origfields[field]
         else:
-            fieldnode = InstanceNode(box, escaped=False)
-            if instnode.startbox:
-                fieldnode.startbox = True
-            self.dependency_graph.append((instnode, fieldnode))
+            fieldnode = InstanceNode(escaped=False, startbox=instnode.startbox)
+            instnode.add_escape_dependency(fieldnode)
+            if instnode.origfields is None:
+                instnode.origfields = av_newdict()
             instnode.origfields[field] = fieldnode
-        self.nodes[box] = fieldnode
+        self.nodes[op.result] = fieldnode
 
-    def find_nodes(self):
-        # Steps (1) and (2)
-        if self.loop.inputargs is not None:
-            for box in self.loop.inputargs:
-                self.nodes[box] = InstanceNode(box, escaped=False,
-                                               startbox=True)
-        else:
-            self._allow_automatic_node_creation = True
-        #
-        for op in self.loop.operations:
-            #print '| ' + op.repr()
-            if op.is_guard():
-                self.find_nodes_guard(op)
-            opnum = op.opnum
-            if opnum == rop.JUMP:
-                break
-            elif opnum == rop.NEW_WITH_VTABLE:
-                box = op.result
-                instnode = InstanceNode(box, escaped=False)
-                instnode.cls = InstanceNode(op.args[0])
-                self.nodes[box] = instnode
-                continue
-            elif opnum == rop.SETFIELD_GC:
-                instnode = self.getnode(op.args[0])
-                field = op.descr
-                self.find_nodes_setfield(instnode, field,
-                                         self.getnode(op.args[1]))
-                continue
-            elif opnum == rop.GETFIELD_GC:
-                instnode = self.getnode(op.args[0])
-                field = op.descr
-                box = op.result
-                self.find_nodes_getfield(instnode, field, box)
-                continue
-            elif opnum == rop.GETFIELD_GC_PURE:
-                instnode = self.getnode(op.args[0])
-                field = op.descr
-                if not instnode.const:
-                    box = op.result
-                    self.find_nodes_getfield(instnode, field, box)
-                    continue
-            elif opnum == rop.GUARD_CLASS:
-                instnode = self.getnode(op.args[0])
-                if instnode.cls is None:
-                    instnode.cls = InstanceNode(op.args[1])
-                continue
-            elif op.is_always_pure():
-                is_pure = True
-                for arg in op.args:
-                    if not self.getnode(arg).const:
-                        is_pure = False
-                if is_pure:
-                    box = op.result
-                    assert box is not None
-                    self.nodes[box] = InstanceNode(box.constbox(),
-                                                   escaped=True)
-                    continue
-            elif not op.has_no_side_effect():
-                # default case
-                for box in op.args:
-                    if isinstance(box, Box):
-                        self.getnode(box).escaped = True
-            box = op.result
-            if box is not None:
-                self.nodes[box] = InstanceNode(box, escaped=True)
-
-    def find_nodes_guard(self, op):
-        assert len(op.suboperations) == 1
-        for arg in op.suboperations[0].args:
-            self.getnode(arg)
-
-    def recursively_find_escaping_values(self):
-        end_args = self.loop.operations[-1].args
-        assert len(self.loop.inputargs) == len(end_args)
-        memo = {}
-        for i in range(len(end_args)):
-            end_box = end_args[i]
-            if isinstance(end_box, Box):
-                self.nodes[end_box].escape_if_startbox(memo, self.cpu)
-        for i in range(len(end_args)):
-            box = self.loop.inputargs[i]
-            other_box = end_args[i]
-            if isinstance(other_box, Box):
-                self.nodes[box].add_to_dependency_graph(self.nodes[other_box],
-                                                        self.dependency_graph)
-        self.propagate_escapes()
-
-    def propagate_escapes(self):
-        # XXX find efficient algorithm, we're too fried for that by now
-        done = False
-        while not done:
-            done = True
-            for instnode, fieldnode in self.dependency_graph:
-                if instnode.escaped:  ## and not instnode.virtualized:
-                    if not fieldnode.escaped:
-                        fieldnode.escaped = True
-                        done = False
-
-    def intersect_input_and_output(self):
-        # Step (3)
-        self.recursively_find_escaping_values()
-        jump = self.loop.operations[-1]
-        assert jump.opnum == rop.JUMP
-        specnodes = []
-        for i in range(len(self.loop.inputargs)):
-            enternode = self.nodes[self.loop.inputargs[i]]
-            leavenode = self.getnode(jump.args[i])
-            specnodes.append(enternode.intersect(leavenode, self.nodes))
-        self.specnodes = specnodes
-
-    def expanded_version_of(self, boxlist):
-        newboxlist = []
-        assert len(boxlist) == len(self.specnodes)
-        for i in range(len(boxlist)):
-            box = boxlist[i]
-            specnode = self.specnodes[i]
-            specnode.expand_boxlist(self.nodes[box], newboxlist)
-        return newboxlist
-
-    def prepare_rebuild_ops(self, instnode, rebuild_ops, memo, box=None):
-        if box is None:
-            box = instnode.source
-        if not isinstance(box, Box):
-            return box
-        if box in memo:
-            return box
-        if instnode.virtual:
-            ld = instnode.cls.source
-            if self.cpu.is_oo and isinstance(ld, ConstObj):
-                # it's probably a ootype new
-                cls = ld.getobj()
-                typedescr = self.cpu.class_sizes[cls] # XXX this is probably not rpython
-                op = ResOperation(rop.NEW_WITH_VTABLE, [ld], box,
-                                  descr=typedescr)
-            else:
-                assert not self.cpu.is_oo
-                vtable = ld.getint()
-                if self.cpu.translate_support_code:
-                    vtable_addr = self.cpu.cast_int_to_adr(vtable)
-                    size = self.cpu.class_sizes[vtable_addr]
-                else:
-                    size = self.cpu.class_sizes[vtable]
-                op = ResOperation(rop.NEW_WITH_VTABLE, [ld], box,
-                                  descr=size)
-            rebuild_ops.append(op)
-            memo[box] = None
-            for ofs, node in instnode.curfields.items():
-                fieldbox = self.prepare_rebuild_ops(node, rebuild_ops, memo)
-                assert isinstance(ofs, AbstractDescr)
-                op = ResOperation(rop.SETFIELD_GC, [box, fieldbox],
-                                  None, descr=ofs)
-                rebuild_ops.append(op)
-            return box
-        memo[box] = None
-        return box
-
-    def optimize_guard(self, op):
-        # Make a list of operations to run to rebuild the unoptimized objects.
-        rebuild_ops = []
-        memo = {}
-        assert len(op.suboperations) == 1
-        op_fail = op.suboperations[0]
-        assert op_fail.opnum == rop.FAIL
-        for box in op_fail.args:
-            if isinstance(box, Const):
-                continue
-            self.prepare_rebuild_ops(self.nodes[box], rebuild_ops, memo, box)
-
-        newboxes = []
-        for box in op_fail.args:
-            if box in self.nodes:
-                box = self.nodes[box].source
-            newboxes.append(box)
-        op_fail.args = newboxes
-        # NB. we mutate op_fail in-place above.  That's bad.  Hopefully
-        # it does not really matter because no-one is going to look again
-        # at its unoptimized version.  We cannot really clone it because of
-        # how the rest works (e.g. it is returned by cpu.execute_operations()).
-        rebuild_ops.append(op_fail)
-        op1 = op.clone()
-        op1.args = self.new_arguments(op1)
-        op1.suboperations = rebuild_ops
-        op.optimized = op1
-        return op1
-
-    def new_arguments(self, op):
-        newboxes = []
-        for box in op.args:
-            if isinstance(box, Box):
-                instnode = self.nodes[box]
-                assert not instnode.virtual
-                box = instnode.source
-            newboxes.append(box)
-        return newboxes
-
-    def optimize_getfield(self, instnode, ofs, box):
-        assert isinstance(ofs, AbstractValue)
-        if instnode.virtual:
-            assert ofs in instnode.curfields
-            return True # this means field is never actually
-        return False
-
-    def optimize_setfield(self, instnode, ofs, valuenode, valuebox):
-        assert isinstance(ofs, AbstractValue)
-        if instnode.virtual: ## or instnode.virtualized:
-            instnode.curfields[ofs] = valuenode
-            return True
-        else:
-            assert not valuenode.virtual
-            return False
-            # we never perform this operation here, note
-
-    def optimize_loop(self):
-        self._allow_automatic_node_creation = False
-        newoperations = []
-        exception_might_have_happened = False
-        if self.loop.inputargs is not None:
-            # closing a loop
-            assert len(self.loop.inputargs) == len(self.specnodes)
-            for i in range(len(self.specnodes)):
-                box = self.loop.inputargs[i]
-                self.specnodes[i].mutate_nodes(self.nodes[box])
-            newinputargs = self.expanded_version_of(self.loop.inputargs)
-        else:
-            # making a bridge
-            newinputargs = None
-        #
-        for op in self.loop.operations:
-            opnum = op.opnum
-            if opnum == rop.JUMP:
-                args = self.expanded_version_of(op.args)
-                for arg in args:
-                    if arg in self.nodes:
-                        assert not self.nodes[arg].virtual
-                op = op.clone()
-                op.args = args
-                newoperations.append(op)
-                break
-            elif opnum == rop.GUARD_NO_EXCEPTION:
-                if not exception_might_have_happened:
-                    continue
-                exception_might_have_happened = False
-                newoperations.append(self.optimize_guard(op))
-                continue
-            elif opnum == rop.GUARD_EXCEPTION:
-                newoperations.append(self.optimize_guard(op))
-                continue
-            elif (opnum == rop.GUARD_TRUE or
-                  opnum == rop.GUARD_FALSE):
-                instnode = self.nodes[op.args[0]]
-                if instnode.const:
-                    continue
-                newoperations.append(self.optimize_guard(op))
-                continue
-            elif opnum == rop.GUARD_CLASS:
-                instnode = self.nodes[op.args[0]]
-                if instnode.cls is not None:
-                    assert op.args[1].equals(instnode.cls.source)
-                    continue
-                instnode.cls = InstanceNode(op.args[1])
-                newoperations.append(self.optimize_guard(op))
-                continue
-            elif opnum == rop.GUARD_VALUE:
-                instnode = self.nodes[op.args[0]]
-                assert isinstance(op.args[1], Const)
-                if instnode.const:
-                    continue
-                instnode.const = True
-                newoperations.append(self.optimize_guard(op))
-                continue
-            elif opnum == rop.GETFIELD_GC:
-                instnode = self.nodes[op.args[0]]
-                if self.optimize_getfield(instnode, op.descr, op.result):
-                    continue
-                # otherwise we need this getfield, but it does not
-                # invalidate caches
-            elif opnum == rop.GETFIELD_GC_PURE:
-                instnode = self.nodes[op.args[0]]
-                if not instnode.const:
-                    if self.optimize_getfield(instnode, op.descr, op.result):
-                        continue
-            elif opnum == rop.NEW_WITH_VTABLE:
-                # self.nodes[op.result] keeps the value from Steps (1,2)
-                instnode = self.nodes[op.result]
-                instnode.curfields = r_dict(av_eq, av_hash)
-                if not instnode.escaped:
-                    instnode.virtual = True
-                    assert instnode.cls is not None
-                    continue
-            elif opnum == rop.SETFIELD_GC:
-                instnode = self.nodes[op.args[0]]
-                valuenode = self.nodes[op.args[1]]
-                ofs = op.descr
-                if self.optimize_setfield(instnode, ofs, valuenode, op.args[1]):
-                    continue
-            elif (opnum == rop.OOISNULL or
-                  opnum == rop.OONONNULL):
-                instnode = self.getnode(op.args[0])
-                # we know the result is constant if instnode is a virtual,
-                # or known to be non-zero.
-                if instnode.virtual or instnode.is_nonzero():
-                    box = op.result
-                    instnode = InstanceNode(box.constbox())
-                    self.nodes[box] = instnode
-                    continue
-            elif (opnum == rop.OOIS or
-                  opnum == rop.OOISNOT):
-                instnode_x = self.getnode(op.args[0])
-                instnode_y = self.getnode(op.args[1])
-                # we know the result is constant in one of these 5 cases:
-                if (instnode_x.virtual or    # x is a virtual (even if y isn't)
-                    instnode_y.virtual or    # y is a virtual (even if x isn't)
-                    # x != NULL and y == NULL
-                    (instnode_x.is_nonzero() and instnode_y.is_zero()) or
-                    # x == NULL and y != NULL
-                    (instnode_x.is_zero() and instnode_y.is_nonzero()) or
-                    # x == NULL and y == NULL
-                    (instnode_x.is_zero() and instnode_y.is_zero())):
-                    #
-                    box = op.result
-                    instnode = InstanceNode(box.constbox())
-                    self.nodes[box] = instnode
-                    continue
-            # default handling of arguments and return value
-            op = op.clone()
-            op.args = self.new_arguments(op)
-            if op.is_always_pure():
-                for box in op.args:
-                    if isinstance(box, Box):
-                        break
-                else:
-                    # all constant arguments: constant-fold away
-                    box = op.result
-                    assert box is not None
-                    instnode = InstanceNode(box.constbox())
-                    self.nodes[box] = instnode
-                    continue
-            if op.can_raise():
-                exception_might_have_happened = True
-            box = op.result
-            if box is not None:
-                instnode = InstanceNode(box)
-                self.nodes[box] = instnode
-            newoperations.append(op)
-        #
-        self.loop.specnodes = self.specnodes
-        self.loop.inputargs = newinputargs
-        self.loop.operations = newoperations
-
-    def match_exactly(self, old_loop):
-        assert len(old_loop.specnodes) == len(self.specnodes)
-        for i in range(len(self.specnodes)):
-            old_specnode = old_loop.specnodes[i]
-            new_specnode = self.specnodes[i]
-            if not old_specnode.equals(new_specnode):
-                return False
-        return True
-
-    def match(self, old_loop):
-        jump_op = self.loop.operations[-1]
-        assert jump_op.opnum == rop.JUMP
-        assert len(old_loop.specnodes) == len(jump_op.args)
-        for i in range(len(old_loop.specnodes)):
-            old_specnode = old_loop.specnodes[i]
-            new_instnode = self.getnode(jump_op.args[i])
-            if not old_specnode.matches(new_instnode):
-                return False
-        return True
-
-    def adapt_for_match(self, old_loop):
-        jump_op = self.loop.operations[-1]
-        assert jump_op.opnum == rop.JUMP
-        self.specnodes = old_loop.specnodes
-        for i in range(len(old_loop.specnodes)):
-            old_specnode = old_loop.specnodes[i]
-            new_instnode = self.getnode(jump_op.args[i])
-            old_specnode.adapt_to(new_instnode, None)
-
-# ---------------------------------------------------------------
-
-def partition(array, left, right):
-    last_item = array[right]
-    pivot = last_item.sort_key()
-    storeindex = left
-    for i in range(left, right):
-        if array[i].sort_key() <= pivot:
-            array[i], array[storeindex] = array[storeindex], array[i]
-            storeindex += 1
-    # Move pivot to its final place
-    array[storeindex], array[right] = last_item, array[storeindex]
-    return storeindex
-
-def quicksort(array, left, right):
-    # sort array[left:right+1] (i.e. bounds included)
-    if right > left:
-        pivotnewindex = partition(array, left, right)
-        quicksort(array, left, pivotnewindex - 1)
-        quicksort(array, pivotnewindex + 1, right)
+    def find_nodes_GETFIELD_GC_PURE(self, op):
+        self.find_nodes_GETFIELD_GC(op)
+
+    def find_nodes_GUARD_CLASS(self, op):
+        pass    # prevent the default handling
+
+    def find_nodes_JUMP(self, op):
+        pass    # prevent the default handling
+
+find_nodes_ops = _findall(PerfectSpecializationFinder, 'find_nodes_')
+perfect_specialization_finder = PerfectSpecializationFinder()
 
-def sort_descrs(lst):
-    quicksort(lst, 0, len(lst)-1)
+# ____________________________________________________________

Copied: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimize.py (from r66241, pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimize4.py)
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimize4.py	(original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimize.py	Wed Jul 15 21:17:49 2009
@@ -8,10 +8,10 @@
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr,
                                          Const, ConstAddr, TreeLoop)
-from pypy.jit.metainterp.optimize4 import PerfectSpecializer
-from pypy.jit.metainterp.specnode4 import (FixedClassSpecNode,
-                                           NotSpecNode,
-                                           VirtualInstanceSpecNode)
+from pypy.jit.metainterp.optimize import perfect_specialization_finder
+from pypy.jit.metainterp.specnode import (FixedClassSpecNode,
+                                          NotSpecNode,
+                                          VirtualInstanceSpecNode)
 
 cpu = runner.LLtypeCPU(None)
 
@@ -80,25 +80,6 @@
         opnum = getattr(rop, opname.upper())
     return resoperation.ResOperation(opnum, args, result, descr)
 
-
-class CheckPerfectSpecializer(PerfectSpecializer):
-    def optimize_loop(self):
-        PerfectSpecializer.optimize_loop(self)
-        check_operations(self.loop.inputargs, self.loop.operations)
-
-def check_operations(inputargs, operations, indent=' |'):
-    seen = dict.fromkeys(inputargs)
-    for op in operations:
-        print indent, op
-        for x in op.args:
-            assert x in seen or isinstance(x, Const)
-        assert op.descr is None or isinstance(op.descr, history.AbstractDescr)
-        if op.is_guard():
-            check_operations(seen.keys(), op.suboperations, indent+'    ')
-        if op.result is not None:
-            seen[op.result] = True
-    assert operations[-1].opnum in (rop.FAIL, rop.JUMP)
-
 # ____________________________________________________________
 
 class A:
@@ -126,6 +107,7 @@
         ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], n2,
                      size_of_node),
         ResOperation('setfield_gc', [n2, v2], None, ofs_value),
+        ResOperation('setfield_gc', [n2, n2], None, ofs_next),
         ResOperation('jump', [sum2, n2], None),
         ]
 
@@ -136,849 +118,15 @@
     set_guard(ops[0], [])
 
 def test_A_find_nodes():
-    spec = CheckPerfectSpecializer(Loop(A.inputargs, A.ops))
-    spec.find_nodes()
-    assert spec.nodes[A.sum] is not spec.nodes[A.sum2]
-    assert spec.nodes[A.n1] is not spec.nodes[A.n2]
-    assert spec.nodes[A.n1].cls.source.value == node_vtable_adr
-    assert not spec.nodes[A.n1].escaped
-    assert spec.nodes[A.n2].cls.source.value == node_vtable_adr
-    assert not spec.nodes[A.n2].escaped
-
-    assert len(spec.nodes[A.n1].curfields) == 0
-    assert spec.nodes[A.n1].origfields[A.ofs_value] is spec.nodes[A.v]
-    assert len(spec.nodes[A.n2].origfields) == 0
-    assert spec.nodes[A.n2].curfields[A.ofs_value] is spec.nodes[A.v2]
-
-def test_A_intersect_input_and_output():
-    spec = CheckPerfectSpecializer(Loop(A.inputargs, A.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    assert len(spec.specnodes) == 2
-    spec_sum, spec_n = spec.specnodes
-    assert isinstance(spec_sum, NotSpecNode)
-    assert isinstance(spec_n, VirtualInstanceSpecNode)
-    assert spec_n.known_class.value == node_vtable_adr
-    assert spec_n.fields[0][0] == A.ofs_value
-    assert isinstance(spec_n.fields[0][1], NotSpecNode)
-
-def test_A_optimize_loop():
-    spec = CheckPerfectSpecializer(Loop(A.inputargs, A.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    assert spec.loop.inputargs == [A.sum, A.v]
-    equaloplists(spec.loop.operations, [
-        ResOperation('int_sub', [A.v, ConstInt(1)], A.v2),
-        ResOperation('int_add', [A.sum, A.v], A.sum2),
-        ResOperation('jump', [A.sum2, A.v2], None),
-        ])
-
-# ____________________________________________________________
-
-class B:
-    locals().update(A.__dict__)    # :-)
-    inputargs = [sum, n1]
-    ops = [
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('escape', [n1], None),
-        ResOperation('getfield_gc', [n1], v, ofs_value),
-        ResOperation('int_sub', [v, ConstInt(1)], v2),
-        ResOperation('int_add', [sum, v], sum2),
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], n2,
-                     size_of_node),
-        ResOperation('setfield_gc', [n2, v2], None, ofs_value),
-        ResOperation('escape', [n2], None),    # <== escaping
-        ResOperation('jump', [sum2, n2], None),
-        ]
-    set_guard(ops[0], [])
-
-def test_B_find_nodes():
-    spec = CheckPerfectSpecializer(Loop(B.inputargs, B.ops))
-    spec.find_nodes()
-    assert spec.nodes[B.n1].cls.source.value == node_vtable_adr
-    assert spec.nodes[B.n1].escaped
-    assert spec.nodes[B.n2].cls.source.value == node_vtable_adr
-    assert spec.nodes[B.n2].escaped
-
-def test_B_intersect_input_and_output():
-    spec = CheckPerfectSpecializer(Loop(B.inputargs, B.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    assert len(spec.specnodes) == 2
-    spec_sum, spec_n = spec.specnodes
-    assert isinstance(spec_sum, NotSpecNode)
-    assert type(spec_n) is FixedClassSpecNode
-    assert spec_n.known_class.value == node_vtable_adr
-
-def test_B_optimize_loop():
-    spec = CheckPerfectSpecializer(Loop(B.inputargs, B.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    assert spec.loop.inputargs == [B.sum, B.n1]
-    equaloplists(spec.loop.operations, [
-        # guard_class is gone
-        ResOperation('escape', [B.n1], None),
-        ResOperation('getfield_gc', [B.n1], B.v, B.ofs_value),
-        ResOperation('int_sub', [B.v, ConstInt(1)], B.v2),
-        ResOperation('int_add', [B.sum, B.v], B.sum2),
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], B.n2,
-                     B.size_of_node),
-        ResOperation('setfield_gc', [B.n2, B.v2], None, B.ofs_value),
-        ResOperation('escape', [B.n2], None),   # <== escaping
-        ResOperation('jump', [B.sum2, B.n2], None),
-        ])
-
-# ____________________________________________________________
-
-class C:
-    locals().update(A.__dict__)    # :-)
-    inputargs = [sum, n1]
-    ops = [
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('escape', [n1], None),    # <== escaping
-        ResOperation('getfield_gc', [n1], v, ofs_value),
-        ResOperation('int_sub', [v, ConstInt(1)], v2),
-        ResOperation('int_add', [sum, v], sum2),
-        ResOperation('escape', [n1], None),    # <== escaping
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], n2,
-                     size_of_node),
-        ResOperation('setfield_gc', [n2, v2], None, ofs_value),
-        ResOperation('jump', [sum2, n2], None),
-        ]
-    set_guard(ops[0], [])
-
-def test_C_find_nodes():
-    spec = CheckPerfectSpecializer(Loop(C.inputargs, C.ops))
-    spec.find_nodes()
-    assert spec.nodes[C.n1].cls.source.value == node_vtable_adr
-    assert spec.nodes[C.n1].escaped
-    assert spec.nodes[C.n2].cls.source.value == node_vtable_adr
-
-def test_C_intersect_input_and_output():
-    spec = CheckPerfectSpecializer(Loop(C.inputargs, C.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    assert spec.nodes[C.n2].escaped
-    assert len(spec.specnodes) == 2
-    spec_sum, spec_n = spec.specnodes
-    assert isinstance(spec_sum, NotSpecNode)
-    assert type(spec_n) is FixedClassSpecNode
-    assert spec_n.known_class.value == node_vtable_adr
-
-def test_C_optimize_loop():
-    spec = CheckPerfectSpecializer(Loop(C.inputargs, C.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    assert spec.loop.inputargs == [C.sum, C.n1]
-    equaloplists(spec.loop.operations, [
-        # guard_class is gone
-        ResOperation('escape', [C.n1], None),   # <== escaping
-        ResOperation('getfield_gc', [C.n1], C.v, C.ofs_value),
-        ResOperation('int_sub', [C.v, ConstInt(1)], C.v2),
-        ResOperation('int_add', [C.sum, C.v], C.sum2),
-        ResOperation('escape', [C.n1], None),   # <== escaping
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], C.n2,
-                     C.size_of_node),
-        ResOperation('setfield_gc', [C.n2, C.v2], None, C.ofs_value),
-        ResOperation('jump', [C.sum2, C.n2], None),
-        ])
-
-# ____________________________________________________________
-
-class D:
-    locals().update(A.__dict__)    # :-)
-    inputargs = [sum, n1]
-    ops = [
-        ResOperation('guard_class', [n1, ConstAddr(node2_vtable, cpu)], None),
-        # the only difference is different vtable  ^^^^^^^^^^^^
-        ResOperation('getfield_gc', [n1], v, ofs_value),
-        ResOperation('int_sub', [v, ConstInt(1)], v2),
-        ResOperation('int_add', [sum, v], sum2),
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], n2,
-                     size_of_node),
-        ResOperation('setfield_gc', [n2, v2], None, ofs_value),
-        ResOperation('jump', [sum2, n2], None),
-        ]
-
-def test_D_intersect_input_and_output():
-    py.test.skip("nowadays, this compiles, just without making a virtual")
-    spec = CheckPerfectSpecializer(Loop(D.inputargs, D.ops))
-    spec.find_nodes()
-    py.test.raises(CancelInefficientLoop, spec.intersect_input_and_output)
-
-# ____________________________________________________________
-
-class E:
-    locals().update(A.__dict__)    # :-)
-    inputargs = [sum, n1]
-    ops = [
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('getfield_gc', [n1], v, ofs_value),
-        ResOperation('int_sub', [v, ConstInt(1)], v2),
-        ResOperation('int_add', [sum, v], sum2),
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], n2,
-                     size_of_node),
-        ResOperation('setfield_gc', [n2, v2], None, ofs_value),
-        ResOperation('guard_true', [v2], None),
-        ResOperation('jump', [sum2, n2], None),
-        ]
-    set_guard(ops[0], [])
-    set_guard(ops[-2], [sum2, n2])
-
-def test_E_optimize_loop():
-    spec = CheckPerfectSpecializer(Loop(E.inputargs, E.ops), cpu=cpu)
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    assert spec.loop.inputargs == [E.sum, E.v]
-    equaloplists(spec.loop.operations, [
-        # guard_class is gone
-        ResOperation('int_sub', [E.v, ConstInt(1)], E.v2),
-        ResOperation('int_add', [E.sum, E.v], E.sum2),
-        ResOperation('guard_true', [E.v2], None),
-        ResOperation('jump', [E.sum2, E.v2], None),
-        ])
-    guard_op = spec.loop.operations[-2]
-    assert guard_op.getopname() == 'guard_true'
-    _, n2 = guard_op.suboperations[-1].args
-    equaloplists(guard_op.suboperations, [
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable_adr, cpu)], n2,
-                     E.size_of_node),
-        ResOperation('setfield_gc', [n2, E.v2], None, E.ofs_value),
-        ResOperation('fail', [E.sum2, n2], None),
-        ])
-
-##def test_E_rebuild_after_failure():
-##    spec = CheckPerfectSpecializer(Loop(E.inputargs, E.ops), cpu=cpu)
-##    spec.find_nodes()
-##    spec.intersect_input_and_output()
-##    spec.optimize_loop()
-##    guard_op = spec.loop.operations[-2]
-##    v_sum_b = BoxInt(13)
-##    v_v_b = BoxInt(14)
-##    history = History(cpu)
-##    newboxes = rebuild_boxes_from_guard_failure(guard_op, cpu, history,
-##                                                [v_sum_b, v_v_b])
-##    assert len(newboxes) == 2
-##    assert newboxes[0] == v_sum_b
-##    p = newboxes[1].getptr(lltype.Ptr(NODE))
-##    assert p.value == 14
-##    assert len(history.operations) == 2
-##    assert ([op.getopname() for op in history.operations] ==
-##            ['new_with_vtable', 'setfield_gc'])
-
-# ____________________________________________________________
-
-class F:
-    locals().update(A.__dict__)    # :-)
-    nextnode = lltype.malloc(NODE)
-    nextnode.value = 32
-    n3 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, nextnode))
-    vbool1 = BoxInt(1)
-    vbool2 = BoxInt(0)
-    vbool3 = BoxInt(1)
-    inputargs = [sum, n1, n3]
-    ops = [
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('getfield_gc', [n1], v, ofs_value),
-        ResOperation('int_sub', [v, ConstInt(1)], v2),
-        ResOperation('int_add', [sum, v], sum2),
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], n2,
-                     size_of_node),
-        ResOperation('setfield_gc', [n2, v2], None, ofs_value),
-        ResOperation('ooisnot', [n2, n3], vbool1),
-        ResOperation('guard_true', [vbool1], None),
-        ResOperation('ooisnull', [n2], vbool2),
-        ResOperation('guard_false', [vbool2], None),
-        ResOperation('oononnull', [n3], vbool3),
-        ResOperation('guard_true', [vbool3], None),        
-        ResOperation('jump', [sum2, n2, n3], None),
-        ]
-    set_guard(ops[0], [])
-    set_guard(ops[-2], [sum2, n2, n3])
-    set_guard(ops[-4], [sum2, n2, n3])
-    set_guard(ops[-6], [sum2, n2, n3])
-
-def test_F_find_nodes():
-    spec = CheckPerfectSpecializer(Loop(F.inputargs, F.ops))
-    spec.find_nodes()
-    assert not spec.nodes[F.n1].escaped
-    assert not spec.nodes[F.n2].escaped
-
-def test_F_optimize_loop():
-    spec = CheckPerfectSpecializer(Loop(F.inputargs, F.ops), cpu=cpu)
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    assert spec.nodes[F.n3].escaped
-    spec.optimize_loop()
-    assert spec.loop.inputargs == [F.sum, F.v, F.n3]
-    equaloplists(spec.loop.operations, [
-            ResOperation('int_sub', [F.v, ConstInt(1)], F.v2),
-            ResOperation('int_add', [F.sum, F.v], F.sum2),
-            ResOperation('oononnull', [F.n3], F.vbool3),
-            ResOperation('guard_true', [F.vbool3], None),        
-            ResOperation('jump', [F.sum2, F.v2, F.n3], None),
-        ])
-
-class F2:
-    locals().update(A.__dict__)    # :-)
-    node2 = lltype.malloc(NODE)
-    node3 = lltype.malloc(NODE)
-    node4 = lltype.malloc(NODE)
-    n2 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, node2))
-    n3 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, node3))
-    n4 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, node4))
-    vbool1 = BoxInt(0)
-    inputargs = [n2, n3]
-    ops = [
-        ResOperation('oois', [n2, n3], vbool1),
-        ResOperation('guard_true', [vbool1], None),
-        ResOperation('escape', [], n4),
-        ResOperation('jump', [n2, n4], None),
-        ]
-    set_guard(ops[-3], [n2])
-
-def test_F2_optimize_loop():
-    spec = CheckPerfectSpecializer(Loop(F2.inputargs, F2.ops), cpu=cpu)
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    equaloplists(spec.loop.operations, F2.ops)
-
-# ____________________________________________________________
-
-class G:
-    locals().update(A.__dict__)    # :-)
-    v3 = BoxInt(123)
-    v4 = BoxInt(124)
-    inputargs = [sum, n1]
-    ops = [
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('getfield_gc', [n1], v, ofs_value),
-        ResOperation('int_sub', [v, ConstInt(1)], v2),
-        ResOperation('int_add', [sum, v], sum2),
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], n2,
-                     size_of_node),
-        ResOperation('setfield_gc', [n2, ConstInt(123)], None, ofs_value),
-        ResOperation('getfield_gc', [n2], v3, ofs_value),
-        ResOperation('int_add', [v3, ConstInt(1)], v4),
-        ResOperation('setfield_gc', [n2, v4], None, ofs_value),
-        ResOperation('guard_true', [v2], None),
-        ResOperation('jump', [sum2, n2], None),
-        ]
-    set_guard(ops[0], [])
-    set_guard(ops[-2], [sum2, n2])
-
-def test_G_optimize_loop():
-    spec = CheckPerfectSpecializer(Loop(G.inputargs, G.ops), cpu=cpu)
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    assert spec.loop.inputargs == [G.sum, G.v]
-    equaloplists(spec.loop.operations, [
-        # guard_class is gone
-        ResOperation('int_sub', [G.v, ConstInt(1)], G.v2),
-        ResOperation('int_add', [G.sum, G.v], G.sum2),
-        ResOperation('guard_true', [G.v2], None),
-        ResOperation('jump', [G.sum2, ConstInt(124)], None),
-        ])
-    guard_op = spec.loop.operations[-2]
-    assert guard_op.getopname() == 'guard_true'
-    _, n2 = guard_op.suboperations[-1].args
-    equaloplists(guard_op.suboperations, [
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], n2,
-                     G.size_of_node),
-        ResOperation('setfield_gc', [n2, ConstInt(124)], None, G.ofs_value),
-        ResOperation('fail', [G.sum2, n2], None),
-        ])
-
-# ____________________________________________________________
-
-class H:
-    locals().update(A.__dict__)    # :-)
-    #
-    containernode = lltype.malloc(NODE)
-    containernode.next = lltype.malloc(NODE)
-    containernode.next.value = 20
-    n0 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, containernode))
-    n1 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, containernode.next))
-    nextnode = lltype.malloc(NODE)
-    nextnode.value = 19
-    n2 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, nextnode))
-    v = BoxInt(containernode.next.value)
-    v2 = BoxInt(nextnode.value)
-    inputargs = [n0]
-    ops = [
-        ResOperation('getfield_gc', [n0], n1, ofs_next),
-        ResOperation('getfield_gc', [n1], v, ofs_value),
-        ResOperation('int_sub', [v, ConstInt(1)], v2),
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], n2,
-                     size_of_node),
-        ResOperation('setfield_gc', [n2, v2], None, ofs_value),
-        ResOperation('setfield_gc', [n0, n2], None, ofs_next),
-        ResOperation('jump', [n0], None),
-        ]
-
-def test_H_intersect_input_and_output():
-    spec = CheckPerfectSpecializer(Loop(H.inputargs, H.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    assert spec.nodes[H.n0].escaped
-    assert spec.nodes[H.n1].escaped
-    assert spec.nodes[H.n2].escaped
-
-# ____________________________________________________________
-
-class I:
-    locals().update(A.__dict__)    # :-)
-    #
-    containernode = lltype.malloc(NODE)
-    containernode.next = lltype.malloc(NODE)
-    containernode.next.value = 20
-    n0 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, containernode))
-    nextnode = lltype.malloc(NODE)
-    nextnode.value = 19
-    n2 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, nextnode))
-    inputargs = [n0]
-    ops = [
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], n2,
-                     size_of_node),
-        ResOperation('setfield_gc', [n2, n0], None, ofs_next),
-        ResOperation('jump', [n2], None),
-        ]
-
-def test_I_intersect_input_and_output():
-    spec = CheckPerfectSpecializer(Loop(I.inputargs, I.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    assert spec.nodes[I.n0].escaped
-    assert spec.nodes[I.n2].escaped
-
-# ____________________________________________________________
-
-class J:
-    locals().update(A.__dict__)    # :-)
-    #
-    containernode = lltype.malloc(NODE)
-    containernode.next = lltype.malloc(NODE)
-    containernode.next.value = 20
-    n0 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, containernode))
-    nextnode = lltype.malloc(NODE)
-    nextnode.value = 19
-    n2 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, nextnode))
-    n1 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, nextnode))
-    inputargs = [n0]
-    ops = [
-        ResOperation('getfield_gc', [n0], n1, ofs_next),
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], n2,
-                     size_of_node),
-        ResOperation('setfield_gc', [n2, n1], None, ofs_next),
-        ResOperation('jump', [n2], None),
-        ]
-
-def test_J_intersect_input_and_output():
-    spec = CheckPerfectSpecializer(Loop(J.inputargs, J.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    assert not spec.nodes[J.n0].escaped
-    assert spec.nodes[J.n1].escaped
-    assert not spec.nodes[J.n2].escaped
-
-# ____________________________________________________________
-
-class K0:
-    locals().update(A.__dict__)    # :-)
-    sum3 = BoxInt(3)
-    v3 = BoxInt(4)
-    inputargs = [sum, n1]
-    ops = [
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('getfield_gc', [n1], v, ofs_value),
-        ResOperation('int_sub', [v, ConstInt(1)], v2),
-        ResOperation('int_add', [sum, v], sum2),
-        ResOperation('getfield_gc', [n1], v3, ofs_value),
-        ResOperation('int_add', [sum2, v3], sum3),
-        ResOperation('escape', [n1], None),
-        ResOperation('jump', [sum3, n1], None),
-        ]
-
-def test_K0_optimize_loop():
-    py.test.skip("Disabled")
-    spec = CheckPerfectSpecializer(Loop(K0.inputargs, K0.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    v4 = spec.loop.operations[-1].args[-1]
-    assert spec.loop.inputargs == [K0.sum, K0.n1, K0.v]
-    equaloplists(spec.loop.operations, [
-        ResOperation('int_sub', [K0.v, ConstInt(1)], K0.v2),
-        ResOperation('int_add', [K0.sum, K0.v], K0.sum2),
-        ResOperation('int_add', [K0.sum2, K0.v], K0.sum3),
-        ResOperation('escape', [K0.n1], None),
-        ResOperation('getfield_gc', [K0.n1], v4, K0.ofs_value),
-        ResOperation('jump', [K0.sum3, K0.n1, v4], None),
-    ])
-
-
-class K1:
-    locals().update(A.__dict__)    # :-)
-    sum3 = BoxInt(3)
-    v3 = BoxInt(4)
-    inputargs = [sum, n1]
-    ops = [
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('getfield_gc', [n1], v, ofs_value),
-        ResOperation('int_sub', [v, ConstInt(1)], v2),
-        ResOperation('int_add', [sum, v], sum2),
-        ResOperation('setfield_gc', [n1, sum], None, ofs_value),
-        ResOperation('getfield_gc', [n1], v3, ofs_value),
-        ResOperation('int_add', [sum2, v3], sum3),
-        ResOperation('escape', [n1], None),
-        ResOperation('jump', [sum3, n1], None),
-        ]
-
-def test_K1_optimize_loop():
-    py.test.skip("Disabled")
-    spec = CheckPerfectSpecializer(Loop(K1.inputargs, K1.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    v4 = spec.loop.operations[-1].args[-1]
-    assert spec.loop.inputargs == [K1.sum, K1.n1, K1.v]
-    equaloplists(spec.loop.operations, [
-        ResOperation('int_sub', [K1.v, ConstInt(1)], K1.v2),
-        ResOperation('int_add', [K1.sum, K1.v], K1.sum2),
-        ResOperation('int_add', [K1.sum2, K1.sum], K1.sum3),
-        ResOperation('setfield_gc', [K1.n1, K1.sum], None, K1.ofs_value),
-        ResOperation('escape', [K1.n1], None),
-        ResOperation('getfield_gc', [K1.n1], v4, K1.ofs_value),
-        ResOperation('jump', [K1.sum3, K1.n1, v4], None),
-    ])
-
-
-class K:
-    locals().update(A.__dict__)    # :-)
-    sum3 = BoxInt(3)
-    v3 = BoxInt(4)
-    inputargs = [sum, n1]
-    ops = [
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('getfield_gc', [n1], v, ofs_value),
-        ResOperation('int_sub', [v, ConstInt(1)], v2),
-        ResOperation('int_add', [sum, v], sum2),
-        ResOperation('getfield_gc', [n1], v3, ofs_value),
-        ResOperation('int_add', [sum2, v3], sum3),
-        ResOperation('jump', [sum3, n1], None),
-        ]
-
-def test_K_optimize_loop():
-    py.test.skip("Disabled")
-    spec = CheckPerfectSpecializer(Loop(K.inputargs, K.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    assert spec.loop.inputargs == [K.sum, K.n1, K.v]
-    equaloplists(spec.loop.operations, [
-        ResOperation('int_sub', [K.v, ConstInt(1)], K.v2),
-        ResOperation('int_add', [K.sum, K.v], K.sum2),
-        ResOperation('int_add', [K.sum2, K.v], K.sum3),
-        ResOperation('jump', [K.sum3, K.n1, K.v], None),
-    ])
-
-# ____________________________________________________________
-
-class L:
-    locals().update(A.__dict__)    # :-)
-    sum3 = BoxInt(3)
-    v3 = BoxInt(4)
-    inputargs = [sum, n1]
-    ops = [
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('getfield_gc', [n1], v, ofs_value),
-        ResOperation('int_sub', [v, ConstInt(1)], v2),
-        ResOperation('int_add', [sum, v], sum2),
-        ResOperation('escape', [n1], None),
-        ResOperation('getfield_gc', [n1], v3, ofs_value),
-        ResOperation('int_add', [sum2, v3], sum3),
-        ResOperation('jump', [sum3, n1], None),
-        ]
-
-def test_L_optimize_loop():
-    py.test.skip("Disabled")
-    spec = CheckPerfectSpecializer(Loop(L.inputargs, L.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    assert spec.loop.inputargs == [L.sum, L.n1, L.v]
-    equaloplists(spec.loop.operations, [
-        ResOperation('int_sub', [L.v, ConstInt(1)], L.v2),
-        ResOperation('int_add', [L.sum, L.v], L.sum2),
-        ResOperation('escape', [L.n1], None),
-        ResOperation('getfield_gc', [L.n1], L.v3, L.ofs_value),
-        ResOperation('int_add', [L.sum2, L.v3], L.sum3),
-        ResOperation('jump', [L.sum3, L.n1, L.v3], None),
-    ])
-
-# ____________________________________________________________
-
-class M:
-    locals().update(A.__dict__)    # :-)
-    sum3 = BoxInt(3)
-    v3 = BoxInt(4)
-    inputargs = [sum, n1]
-    ops = [
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('getfield_gc', [n1], v, ofs_value),
-        ResOperation('int_sub', [v, ConstInt(1)], v2),
-        ResOperation('int_add', [sum, v], sum2),
-        ResOperation('escape', [n1], None),
-        ResOperation('jump', [sum2, n1], None),
-        ]
-
-def test_M_optimize_loop():
-    py.test.skip("Disabled")
-    spec = CheckPerfectSpecializer(Loop(M.inputargs, M.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    v4 = spec.loop.operations[-1].args[-1]
-    assert spec.loop.inputargs == [M.sum, M.n1, M.v]
-    equaloplists(spec.loop.operations, [
-        ResOperation('int_sub', [M.v, ConstInt(1)], M.v2),
-        ResOperation('int_add', [M.sum, M.v], M.sum2),
-        ResOperation('escape', [M.n1], None),
-        ResOperation('getfield_gc', [M.n1], v4, M.ofs_value),
-        ResOperation('jump', [M.sum2, M.n1, v4], None),
-    ])
-
-# ____________________________________________________________
-
-class N:
-    locals().update(A.__dict__)    # :-)
-    sum3 = BoxInt(3)
-    v3 = BoxInt(4)
-    inputargs = [sum, n1]
-    ops = [
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('getfield_gc', [n1], v, ofs_value),
-        ResOperation('int_sub', [v, ConstInt(1)], v2),
-        ResOperation('int_add', [sum, v], sum2),
-        ResOperation('escape', [n1], None),
-        ResOperation('jump', [sum2, n1], None),
-        ]
-
-def test_N_optimize_loop():
-    py.test.skip("Disabled")
-    spec = CheckPerfectSpecializer(Loop(N.inputargs, N.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    v4 = spec.loop.operations[-1].args[-1]
-    assert spec.loop.inputargs == [N.sum, N.n1, N.v]
-    equaloplists(spec.loop.operations, [
-        ResOperation('int_sub', [N.v, ConstInt(1)], N.v2),
-        ResOperation('int_add', [N.sum, N.v], N.sum2),
-        ResOperation('escape', [N.n1], None),
-        ResOperation('getfield_gc', [N.n1], v4, N.ofs_value),
-        ResOperation('jump', [N.sum2, N.n1, v4], None),
-    ])
-
-# ____________________________________________________________
-
-class O1:
-    locals().update(A.__dict__)    # :-)
-    inputargs = []
-    ops = [
-        ResOperation('escape', [], n1),
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('jump', [], None),
-        ]
-    set_guard(ops[-3], [])
-    set_guard(ops[-2], [])
-
-def test_O1_optimize_loop():
-    spec = CheckPerfectSpecializer(Loop(O1.inputargs, O1.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    assert spec.loop.inputargs == []
-    equaloplists(spec.loop.operations, [
-        ResOperation('escape', [], O1.n1),
-        # only the first guard_class is left
-        ResOperation('guard_class', [O1.n1, ConstAddr(node_vtable, cpu)],
-                     None),
-        ResOperation('jump', [], None),
-    ])
-
-# ____________________________________________________________
-
-class O2:
-    locals().update(A.__dict__)    # :-)
-    v1 = BoxInt(1)
-    inputargs = []
-    ops = [
-        ResOperation('escape', [], n1),
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('oononnull', [n1], v1),
-        ResOperation('guard_true', [v1], None),
-        ResOperation('jump', [], None),
-        ]
-    set_guard(ops[-4], [])
-    set_guard(ops[-2], [])
-
-def test_O2_optimize_loop():
-    spec = CheckPerfectSpecializer(Loop(O2.inputargs, O2.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    assert spec.loop.inputargs == []
-    equaloplists(spec.loop.operations, [
-        ResOperation('escape', [], O2.n1),
-        ResOperation('guard_class', [O2.n1, ConstAddr(node_vtable, cpu)],
-                     None),
-        # the oononnull and guard_true are gone, because we know they
-        # return True -- as there was already a guard_class done on n1
-        ResOperation('jump', [], None),
-    ])
-
-# ____________________________________________________________
-
-class O3:
-    locals().update(A.__dict__)    # :-)
-    v1 = BoxInt(1)
-    inputargs = []
-    ops = [
-        ResOperation('escape', [], n1),
-        ResOperation('guard_class', [n1, ConstAddr(node_vtable, cpu)], None),
-        ResOperation('oois', [n1, ConstPtr(lltype.nullptr(llmemory.GCREF.TO))],
-                             v1),
-        ResOperation('guard_false', [v1], None),
-        ResOperation('jump', [], None),
-        ]
-    set_guard(ops[-4], [])
-    set_guard(ops[-2], [])
-
-def test_O3_optimize_loop():
-    spec = CheckPerfectSpecializer(Loop(O3.inputargs, O3.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    assert spec.loop.inputargs == []
-    equaloplists(spec.loop.operations, [
-        ResOperation('escape', [], O3.n1),
-        ResOperation('guard_class', [O3.n1, ConstAddr(node_vtable, cpu)],
-                     None),
-        # the oois and guard_false are gone, because we know they
-        # return False -- as there was already a guard_class done on n1
-        ResOperation('jump', [], None),
-    ])
-
-# ____________________________________________________________
-
-class P:
-    locals().update(A.__dict__)    # :-)
-    thirdnode = lltype.malloc(NODE)
-    n3 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, thirdnode))
-    f = BoxInt(0)   # False
-    inputargs = [n1, n3]
-    ops = [
-        ResOperation('getfield_gc', [n3], v, ofs_value),
-        ResOperation('setfield_gc', [n1, ConstInt(1)], None, ofs_value),
-        ResOperation('getfield_gc', [n3], v2, ofs_value),
-        ResOperation('int_eq', [v, v2], f),
-        ResOperation('guard_false', [f], None),
-        ResOperation('getfield_gc', [n1], n2, ofs_next),
-        ResOperation('jump', [n2, n3], None),
-        ]
-    set_guard(ops[-3], [])
-
-def test_P_optimize_loop():
-    spec = CheckPerfectSpecializer(Loop(P.inputargs, P.ops))
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    # Optimization should not remove any operation.
-    # If it does, then aliasing is not correctly detected.
-    # It is ok to reorder just the 'getfield_gc[n1], n2' operation,
-    # but the three remaining getfields/setfields *must* be in that order.
-    equaloplists(spec.loop.operations, P.ops)
-
-# ____________________________________________________________
-
-class Q:
-    locals().update(A.__dict__)    # :-)
-    inputargs = [sum]
-    ops = [
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], n1,
-                     size_of_node),
-        ResOperation('setfield_gc', [n1, sum], None, ofs_value),
-        ResOperation('getfield_gc', [n1], sum2, ofs_value),
-        ResOperation('guard_true', [sum2], None),
-        ResOperation('int_sub', [sum, ConstInt(1)], v),
-        ResOperation('jump', [v], None),
-        ]
-    set_guard(ops[-3], [sum])
-
-def test_Q_optimize_loop():
-    spec = CheckPerfectSpecializer(Loop(Q.inputargs, Q.ops), cpu=cpu)
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    equaloplists(spec.loop.operations, [
-        ResOperation('guard_true', [Q.sum], None),
-        ResOperation('int_sub', [Q.sum, ConstInt(1)], Q.v),
-        ResOperation('jump', [Q.v], None),
-        ])
-
-# ____________________________________________________________
-
-class R:
-    locals().update(A.__dict__)    # :-)
-    inputargs = [sum]
-    ops = [
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], n1,
-                     size_of_node),
-        ResOperation('int_is_true', [sum], n1nz),
-        ResOperation('guard_true', [n1nz], None),
-        ResOperation('new_with_vtable', [ConstAddr(node_vtable, cpu)], n2,
-                     size_of_node),
-        ResOperation('setfield_gc', [n1, n2], None, ofs_next),
-        ResOperation('int_sub', [sum, ConstInt(1)], sum2),
-        ResOperation('jump', [sum2], None),
-        ]
-    set_guard(ops[2], [n1])
-
-def test_R_find_nodes():
-    spec = CheckPerfectSpecializer(Loop(R.inputargs, R.ops), cpu=cpu)
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-
-# ____________________________________________________________
-
-class S:
-    locals().update(A.__dict__)    # :-)
-    n1subnode = lltype.malloc(NODE2)
-    n2subnode = lltype.malloc(NODE2)
-    n1sub = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, n1subnode))
-    n2sub = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, n2subnode))
-    inputargs = [n1sub]
-    ops = [
-        ResOperation('guard_class', [n1sub, ConstAddr(node2_vtable, cpu)],
-                     None),
-        ResOperation('escape', [], n2sub),
-        ResOperation('jump', [n2sub], None),
-        ]
-    set_guard(ops[0], [n1sub])
-
-def test_S_find_nodes():
-    py.test.skip("in-progress")
-    spec = CheckPerfectSpecializer(Loop(S.inputargs, S.ops), cpu=cpu)
-    spec.find_nodes()
-    spec.intersect_input_and_output()
-    spec.optimize_loop()
-    equaloplists(spec.loop.operations, S.ops)
+    perfect_specialization_finder.find_nodes(Loop(A.inputargs, A.ops))
+    nodes = perfect_specialization_finder.nodes
+    assert A.sum in nodes
+    assert A.sum2 not in nodes
+    assert nodes[A.n1] is not nodes[A.n2]
+    assert not nodes[A.n1].escaped
+    assert not nodes[A.n2].escaped
+
+    assert not nodes[A.n1].curfields
+    assert nodes[A.n1].origfields[A.ofs_value] is nodes[A.v]
+    assert not nodes[A.n2].origfields
+    assert nodes[A.n2].curfields[A.ofs_next] is nodes[A.n2]



More information about the Pypy-commit mailing list