[pypy-svn] r62294 - in pypy/branch/pyjitpl5/pypy/jit: backend/llgraph metainterp metainterp/test tl

arigo at codespeak.net arigo at codespeak.net
Sun Mar 1 15:11:42 CET 2009


Author: arigo
Date: Sun Mar  1 15:11:41 2009
New Revision: 62294

Added:
   pypy/branch/pyjitpl5/pypy/jit/metainterp/resoperation.py   (contents, props changed)
Modified:
   pypy/branch/pyjitpl5/pypy/jit/backend/llgraph/runner.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/history.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/optimize.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_basic.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_vable_optimize.py
   pypy/branch/pyjitpl5/pypy/jit/tl/pypyjit.py
   pypy/branch/pyjitpl5/pypy/jit/tl/pypyjit_child.py
Log:
- add the "switch_dict" operation
- fixes to optimize.py
- move the ResOperation class to its own file


Modified: pypy/branch/pyjitpl5/pypy/jit/backend/llgraph/runner.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/backend/llgraph/runner.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/backend/llgraph/runner.py	Sun Mar  1 15:11:41 2009
@@ -176,7 +176,7 @@
         if resbox is not None:
             resboxes.append(resbox)
         operations = [
-            history.MergePoint('merge_point', valueboxes, None),
+            history.ResOperation('merge_point', valueboxes, None),
             history.ResOperation(opname, valueboxes, resbox),
             history.ResOperation('return', resboxes, None),
             ]

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/codewriter.py	Sun Mar  1 15:11:41 2009
@@ -80,6 +80,10 @@
         self.bytecode_for_address = bytecode_for_address
         self.dict = None
 
+
+class SwitchDict(history.AbstractValue):
+    "Get a 'dict' attribute mapping integer values to bytecode positions."
+
 # ____________________________________________________________
 
 
@@ -233,6 +237,7 @@
 
         labelpos = {}
         code = assemble(labelpos, self.codewriter.metainterp, self.assembler)
+        self.resolve_switch_targets(labelpos)
         self.bytecode.setup(code, self.constants)
 
         self.bytecode._source = self.assembler
@@ -335,13 +340,24 @@
             self.minimize_variables()
             switches = [link for link in block.exits
                         if link.exitcase != 'default']
+            if len(switches) >= 6 and isinstance(block.exitswitch.concretetype,
+                                                 lltype.Primitive):
+                switchdict = SwitchDict()
+                switchdict._maps = {}
+                for link in switches:
+                    key = lltype.cast_primitive(lltype.Signed, link.llexitcase)
+                    switchdict._maps[key] = link
+                self.emit("switch_dict",
+                          self.var_position(block.exitswitch),
+                          self.get_position(switchdict))
+            else:
+                self.emit("switch",
+                          self.var_position(block.exitswitch))
+                self.emit_list([self.const_position(link.llexitcase)
+                                for link in switches])
+                self.emit_list([tlabel(link) for link in switches])
             renamings = [self.insert_renaming(link.args)
                          for link in switches]
-            self.emit("switch",
-                      self.var_position(block.exitswitch))
-            self.emit_list([self.const_position(link.llexitcase)
-                            for link in switches])
-            self.emit_list([tlabel(link) for link in switches])
             if block.exits[-1].exitcase == 'default':
                 link = block.exits[-1]
                 self.emit(*self.insert_renaming(link.args))
@@ -356,11 +372,18 @@
         self.dont_minimize_variables += 1
         handler = object()
         renamings = []
-        for link in exception_exits:
+        for i, link in enumerate(exception_exits):
             args_without_last_exc = [v for v in link.args
                                        if (v is not link.last_exception and
                                            v is not link.last_exc_value)]
-            renamings.append(self.insert_renaming(args_without_last_exc))
+            if (link.exitcase is Exception and
+                not args_without_last_exc and link.target.operations == () and
+                len(link.target.inputargs) == 2):
+                # stop at the catch-and-reraise-every-exception branch, if any
+                exception_exits = exception_exits[:i]
+                break
+            renamings.append(self.insert_renaming(args_without_last_exc,
+                                                  force=True))
         self.pending_exception_handlers.append((handler, exception_exits,
                                                 renamings))
         self.emit("setup_exception_block",
@@ -394,7 +417,7 @@
                 self.emit("put_last_exc_value", i)
         self.make_bytecode_block(link.target)
 
-    def insert_renaming(self, args):
+    def insert_renaming(self, args, force=False):
         args = [v for v in args if v.concretetype is not lltype.Void]
         if len(args) >= MAX_MAKE_NEW_VARS:
             code = ["make_new_vars", len(args)]
@@ -402,18 +425,33 @@
             code = ["make_new_vars_%d" % len(args)]
         for v in args:
             code.append(self.var_position(v))
+        if (not force and len(args) == self.free_vars and
+            code[len(code)-len(args):] == range(0, self.free_vars*2, 2)):
+            return []     # no-op
         return code
 
     def minimize_variables(self):
         if self.dont_minimize_variables:
             return
         block, index = self.current_position
-        vars = self.vars_alive_through_op(block, index)
+        allvars = self.vars_alive_through_op(block, index)
+        seen = {}       # {position: unique Variable} without Voids
+        unique = {}     # {Variable: unique Variable} without Voids
+        for v in allvars:
+            if v.concretetype is not lltype.Void:
+                pos = self.var_position(v)
+                seen.setdefault(pos, v)
+                unique[v] = seen[pos]
+        vars = seen.items()
+        vars.sort()
+        vars = [v1 for pos, v1 in vars]
         self.emit(*self.insert_renaming(vars))
         self.free_vars = 0
         self.var_positions.clear()
-        for v in vars:
-            self.register_var(v, verbose=False)
+        for v1 in vars:
+            self.register_var(v1, verbose=False)
+        for v, v1 in unique.items():
+            self.var_positions[v] = self.var_positions[v1]
 
     def vars_alive_through_op(self, block, index):
         """Returns the list of variables that are really used by or after
@@ -790,6 +828,13 @@
         self.emit(len(l))
         self.emit(*l)
 
+    def resolve_switch_targets(self, labelpos):
+        for sd in self.constants:
+            if isinstance(sd, SwitchDict):
+                sd.dict = {}
+                for key, link in sd._maps.items():
+                    sd.dict[key] = labelpos[link]
+
 # ____________________________________________________________
 
 class label(object):

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/history.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/history.py	Sun Mar  1 15:11:41 2009
@@ -5,6 +5,9 @@
 from pypy.tool.uid import uid
 from pypy.conftest import option
 
+from pypy.jit.metainterp import resoperation as rop
+from pypy.jit.metainterp.resoperation import ResOperation
+
 import py
 from pypy.tool.ansi_print import ansi_log
 log = py.log.Producer('compiler')

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/optimize.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/optimize.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/optimize.py	Sun Mar  1 15:11:41 2009
@@ -99,6 +99,7 @@
         self.virtual = False
         self.virtualized = False
         self.const = const
+        self.nonzero = False     # NB. never set to True so far
         self.cls = None
         self.origfields = {}
         self.curfields = {}
@@ -108,6 +109,12 @@
         #self.origsize = -1
         #self.cursize  = -1
 
+    def is_nonzero(self):
+        return self.cls is not None or self.nonzero
+
+    def is_zero(self):
+        return self.const and not self.source.getptr_base()
+
     def escape_if_startbox(self, memo):
         if self in memo:
             return
@@ -764,26 +771,25 @@
             elif opname == 'ooisnull' or opname == 'oononnull':
                 instnode = self.getnode(op.args[0])
                 # we know the result is constant if instnode is a virtual,
-                # or if we already checked the class of the object before
-                if instnode.virtual or instnode.cls is not None:
+                # a constant, or known to be non-zero.
+                if instnode.virtual or instnode.const or instnode.is_nonzero():
                     box = op.result
                     instnode = InstanceNode(box.constbox(), const=True)
                     self.nodes[box] = instnode
                     continue
-                # XXX we could also do a bit better by marking on the
-                # InstanceNode that we compared it with NULL already
             elif opname == 'oois' or opname == '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 4 cases:
+                # 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)
-                    (instnode_x.cls is not None and     # we checked cls x and
-                     instnode_y.const and               # y is the const NULL
-                     not instnode_y.source.getptr_base()) or
-                    (instnode_y.cls is not None and     # we checked cls y and
-                     instnode_x.const and               # x is the const NULL
-                     not instnode_x.source.getptr_base())):
+                    # 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(), const=True)
                     self.nodes[box] = instnode

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/pyjitpl.py	Sun Mar  1 15:11:41 2009
@@ -296,13 +296,22 @@
     @arguments("orgpc", "box", "constargs", "jumptargets")
     def opimpl_switch(self, pc, valuebox, constargs, jumptargets):
         box = self.implement_guard_value(pc, valuebox)
-        # XXX implement dictionary for speedups at some point
         for i in range(len(constargs)):
             casebox = constargs[i]
             if box.equals(casebox):
                 self.pc = jumptargets[i]
                 break
 
+    @arguments("orgpc", "box", "constbox")
+    def opimpl_switch_dict(self, pc, valuebox, switchdict):
+        box = self.implement_guard_value(pc, valuebox)
+        search_value = box.getint()
+        assert isinstance(switchdict, codewriter.SwitchDict)
+        try:
+            self.pc = switchdict.dict[search_value]
+        except KeyError:
+            pass
+
     @arguments("constbox")
     def opimpl_new(self, sizebox):
         self.execute('new', [sizebox], 'ptr')
@@ -574,7 +583,8 @@
 
     @arguments()
     def opimpl_reraise(self):
-        xxx
+        return self.metainterp.finishframe_exception(self.exception_box,
+                                                     self.exc_value_box)
 
     # ------------------------------
 

Added: pypy/branch/pyjitpl5/pypy/jit/metainterp/resoperation.py
==============================================================================
--- (empty file)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/resoperation.py	Sun Mar  1 15:11:41 2009
@@ -0,0 +1,40 @@
+
+class ResOperation(object):
+    """The central ResOperation class, representing one operation."""
+
+    # for 'merge_point'
+    specnodes = None
+    key = None
+
+    # for 'jump' and 'guard_*'
+    jump_target = None
+
+    # for 'guard_*'
+    counter = 0
+    storage_info = None
+    liveboxes = None
+
+    def __init__(self, opname, args, result):
+        self.opname = opname
+        self.args = list(args)
+        self.result = result
+
+    def __repr__(self):
+        if self.result is not None:
+            sres = repr(self.result) + ' = '
+        else:
+            sres = ''
+        result = '%s%s(%s)' % (sres, self.opname,
+                               ', '.join(map(repr, self.args)))
+        if self.liveboxes is not None:
+            result = '%s [%s]' % (result, ', '.join(map(repr, self.liveboxes)))
+        return result
+
+    def clone(self):
+        op = ResOperation(self.opname, self.args, self.result)
+        op.specnodes = self.specnodes
+        op.key = self.key
+        return op
+
+# ____________________________________________________________
+

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_basic.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_basic.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_basic.py	Sun Mar  1 15:11:41 2009
@@ -282,6 +282,21 @@
         assert res == 210
         self.check_history_(getfield_gc=0)
 
+    def test_switch_dict(self):
+        def f(x):
+            if   x == 1: return 61
+            elif x == 2: return 511
+            elif x == 3: return -22
+            elif x == 4: return 81
+            elif x == 5: return 17
+            elif x == 6: return 54
+            elif x == 7: return 987
+            elif x == 8: return -12
+            elif x == 9: return 321
+            return -1
+        res = self.interp_operations(f, [5])
+        assert res == 17
+
 
 class TestOOtype(BasicTests, OOJitMixin):
     pass

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_vable_optimize.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_vable_optimize.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_vable_optimize.py	Sun Mar  1 15:11:41 2009
@@ -5,7 +5,7 @@
 from pypy.rpython.lltypesystem.rvirtualizable2 import VirtualizableAccessor
 from pypy.jit.backend.llgraph import runner
 from pypy.jit.metainterp import heaptracker
-from pypy.jit.metainterp.history import (ResOperation, MergePoint, Jump,
+from pypy.jit.metainterp.history import (ResOperation,
                                          ConstInt, ConstAddr, BoxInt, BoxPtr)
 from pypy.jit.metainterp.optimize import (PerfectSpecializer,
                                           VirtualizableSpecNode,
@@ -82,7 +82,7 @@
     v2 = BoxInt(nextnode.value)
     sum2 = BoxInt(0 + frame.node.value)
     ops = [
-        MergePoint('merge_point', [sum, fr], None),
+        ResOperation('merge_point', [sum, fr], None),
         ResOperation('guard_nonvirtualized', [fr, ConstAddr(xy_vtable, cpu),
                                               ConstInt(ofs_node)], None),
         ResOperation('getfield_gc', [fr, ConstInt(ofs_node)], n1),
@@ -93,7 +93,7 @@
                                          ConstAddr(node_vtable, cpu)], n2),
         ResOperation('setfield_gc', [n2, ConstInt(ofs_value), v2], None),
         ResOperation('setfield_gc', [fr, ConstInt(ofs_node), n2], None),
-        Jump('jump', [sum2, fr], None),
+        ResOperation('jump', [sum2, fr], None),
         ]
     ops[1].vdesc = xy_desc
 
@@ -118,10 +118,10 @@
     spec.intersect_input_and_output()
     spec.optimize_loop()
     equaloplists(spec.loop.operations, [
-        MergePoint('merge_point', [A.sum, A.fr, A.v], None),
+        ResOperation('merge_point', [A.sum, A.fr, A.v], None),
         ResOperation('int_sub', [A.v, ConstInt(1)], A.v2),
         ResOperation('int_add', [A.sum, A.v], A.sum2),
-        Jump('jump', [A.sum2, A.fr, A.v2], None),
+        ResOperation('jump', [A.sum2, A.fr, A.v2], None),
     ])
 
 # ____________________________________________________________
@@ -139,12 +139,12 @@
     n1 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, frame.node))
     v = BoxInt(13)
     ops = [
-        MergePoint('merge_point', [fr], None),
+        ResOperation('merge_point', [fr], None),
         ResOperation('guard_nonvirtualized', [fr, ConstAddr(xy_vtable, cpu),
                                               ConstInt(ofs_node)], None),
         ResOperation('getfield_gc', [fr, ConstInt(ofs_node)], n1),
         ResOperation('getfield_gc', [n1, ConstInt(ofs_value)], v),
-        Jump('jump', [fr], None),
+        ResOperation('jump', [fr], None),
         ]
     ops[1].vdesc = xy_desc
 
@@ -168,7 +168,7 @@
     v2 = BoxInt(13)
     sizebox = ConstInt(cpu.sizeof(NODE))
     ops = [
-        MergePoint('merge_point', [fr], None),
+        ResOperation('merge_point', [fr], None),
         ResOperation('guard_nonvirtualized', [fr, ConstAddr(xy_vtable, cpu),
                                               ConstInt(ofs_node)], None),
         #
@@ -181,7 +181,7 @@
         ResOperation('guard_class', [n2, ConstAddr(node_vtable, cpu)], None),
         ResOperation('getfield_gc', [n2, ConstInt(ofs_value)], v2),
         #
-        Jump('jump', [fr], None),
+        ResOperation('jump', [fr], None),
         ]
     ops[1].vdesc = xy_desc
 
@@ -212,7 +212,7 @@
     v2 = BoxInt(13)
     l = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, frame.node))
     ops = [
-        MergePoint('merge_point', [fr], None),
+        ResOperation('merge_point', [fr], None),
         ResOperation('guard_nonvirtualized', [fr, ConstAddr(xy_vtable, cpu),
                                               ConstInt(ofs_node)], None),
         #
@@ -220,7 +220,7 @@
         ResOperation('guard_builtin', [l, SomeDescr()], None),
         ResOperation('getitem', [None, l, ConstInt(0)], v2),
         ResOperation('setitem', [None, l, ConstInt(0), v2], None),
-        Jump('jump', [fr], None),
+        ResOperation('jump', [fr], None),
         ]
     ops[1].vdesc = xy_desc
 

Modified: pypy/branch/pyjitpl5/pypy/jit/tl/pypyjit.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/tl/pypyjit.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/tl/pypyjit.py	Sun Mar  1 15:11:41 2009
@@ -17,8 +17,8 @@
 config.objspace.allworkingmodules = False
 config.objspace.usemodules.pypyjit = True
 set_pypy_opt_level(config, level='0')
-config.objspace.std.multimethods = 'doubledispatch'
-multimethod.Installer = multimethod.InstallerVersion1
+config.objspace.std.multimethods = 'mrd'
+multimethod.Installer = multimethod.InstallerVersion2
 print config
 
 

Modified: pypy/branch/pyjitpl5/pypy/jit/tl/pypyjit_child.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/tl/pypyjit_child.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/tl/pypyjit_child.py	Sun Mar  1 15:11:41 2009
@@ -23,7 +23,7 @@
 #     Consts -- make sure that these Consts are not stored, or else
 #     remove them entirely
 #
-#   - dead operation removal: e.g. line 158
+#   - dead operation removal: e.g. unused 'getfield_gc' (line 158)
 
 
 def run_child(glob, loc):



More information about the Pypy-commit mailing list