[pypy-svn] r74049 - in pypy/branch/blackhole-improvement/pypy/jit/codewriter: . test

arigo at codespeak.net arigo at codespeak.net
Sun Apr 25 11:38:54 CEST 2010


Author: arigo
Date: Sun Apr 25 11:38:53 2010
New Revision: 74049

Modified:
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/format.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_flatten.py
Log:
Add SwitchDictDescr to handle large switches.


Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py	Sun Apr 25 11:38:53 2010
@@ -42,6 +42,9 @@
     def __iter__(self):
         return iter(self.content)
 
+class SwitchDictDescr(AbstractDescr):
+    "Get a 'dict' attribute mapping integer values to bytecode positions."
+
 KINDS = ['int', 'ref', 'float']
 
 # ____________________________________________________________
@@ -126,12 +129,15 @@
 
     def insert_exits(self, block):
         if len(block.exits) == 1:
+            # A single link, fall-through
             link = block.exits[0]
             assert link.exitcase is None
             self.make_link(link)
+        #
         elif len(block.exits) == 2 and (
                 isinstance(block.exitswitch, tuple) or
                 block.exitswitch.concretetype == lltype.Bool):
+            # Two exit links with a boolean condition
             linkfalse, linktrue = block.exits
             if linkfalse.llexitcase == True:
                 linkfalse, linktrue = linktrue, linkfalse
@@ -151,14 +157,40 @@
             # false path:
             self.emitline(Label(linkfalse))
             self.make_link(linkfalse)
+        #
         else:
+            # A switch.
+            #
+            def emitdefaultpath():
+                if block.exits[-1].exitcase == 'default':
+                    self.make_link(block.exits[-1])
+                else:
+                    self.emitline('unreachable')
+            #
             switches = [link for link in block.exits
                         if link.exitcase != 'default']
-            if len(switches) >= 5 and isinstance(block.exitswitch.concretetype,
-                                                 lltype.Primitive):
-                XXX
+            switches.sort(key=lambda link: link.llexitcase)
+            kind = getkind(block.exitswitch.concretetype)
+            if len(switches) >= 5 and kind == 'int':
+                # A large switch on an integer, implementable efficiently
+                # with the help of a SwitchDictDescr
+                switchdict = SwitchDictDescr()
+                switchdict._labels = []
+                self.emitline('switch', self.getcolor(block.exitswitch),
+                                        switchdict)
+                emitdefaultpath()
+                #
+                for switch in switches:
+                    key = lltype.cast_primitive(lltype.Signed,
+                                                switch.llexitcase)
+                    switchdict._labels.append((key, TLabel(switch)))
+                    # emit code for that path
+                    self.emitline(Label(switch))
+                    self.make_link(switch)
+            #
             else:
-                kind = getkind(block.exitswitch.concretetype)
+                # A switch with several possible answers, though not too
+                # many of them -- a chain of int_eq comparisons is fine
                 assert kind == 'int'    # XXX
                 for switch in switches:
                     # make the case described by 'switch'
@@ -172,10 +204,7 @@
                     # finally, emit the label for the "non-taken" path
                     self.emitline(Label(switch))
                 #
-                if block.exits[-1].exitcase == 'default':
-                    self.make_link(block.exits[-1])
-                else:
-                    self.emitline('unreachable')
+                emitdefaultpath()
 
     def insert_renamings(self, link):
         renamings = {}

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/format.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/format.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/format.py	Sun Apr 25 11:38:53 2010
@@ -1,7 +1,7 @@
 import py
 from pypy.objspace.flow.model import Constant
 from pypy.jit.codewriter.flatten import SSARepr, Label, TLabel, Register
-from pypy.jit.codewriter.flatten import ListOfKind
+from pypy.jit.codewriter.flatten import ListOfKind, SwitchDictDescr
 from pypy.jit.metainterp.history import AbstractDescr
 
 
@@ -19,19 +19,19 @@
             return getlabelname(x)
         elif isinstance(x, ListOfKind):
             return '%s[%s]' % (x.kind[0].upper(), ', '.join(map(repr, x)))
+        elif isinstance(x, SwitchDictDescr):
+            return '<SwitchDictDescr %s>' % (
+                ', '.join(['%s:%s' % (key, getlabelname(lbl))
+                           for key, lbl in x._labels]))
         elif isinstance(x, AbstractDescr):
             return '%r' % (x,)
         else:
             return '<unknown object: %r>' % (x,)
     #
     seenlabels = {}
-    for asm in ssarepr.insns:
-        for x in asm:
-            if isinstance(x, TLabel):
-                seenlabels[x.name] = -1
     labelcount = [0]
     def getlabelname(lbl):
-        if seenlabels[lbl.name] == -1:
+        if lbl.name not in seenlabels:
             labelcount[0] += 1
             seenlabels[lbl.name] = labelcount[0]
         return 'L%d' % seenlabels[lbl.name]

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_flatten.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_flatten.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_flatten.py	Sun Apr 25 11:38:53 2010
@@ -176,3 +176,29 @@
             L3:
             int_return $42
         """)
+
+    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
+            return -1
+        self.encoding_test(f, [65], """
+            switch %i0, <SwitchDictDescr 1:L1, 2:L2, 3:L3, 4:L4, 5:L5, 6:L6>
+            int_return $-1
+            L1:
+            int_return $61
+            L2:
+            int_return $511
+            L3:
+            int_return $-22
+            L4:
+            int_return $81
+            L5:
+            int_return $17
+            L6:
+            int_return $54
+        """)



More information about the Pypy-commit mailing list