[pypy-svn] r46616 - in pypy/dist/pypy/translator: c/test cli jvm oosupport

antocuni at codespeak.net antocuni at codespeak.net
Sat Sep 15 11:35:03 CEST 2007


Author: antocuni
Date: Sat Sep 15 11:35:03 2007
New Revision: 46616

Modified:
   pypy/dist/pypy/translator/c/test/test_backendoptimized.py
   pypy/dist/pypy/translator/cli/function.py
   pypy/dist/pypy/translator/jvm/generator.py
   pypy/dist/pypy/translator/jvm/node.py
   pypy/dist/pypy/translator/oosupport/function.py
Log:
use jvm's tableswitch to implement numeric switch.



Modified: pypy/dist/pypy/translator/c/test/test_backendoptimized.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_backendoptimized.py	(original)
+++ pypy/dist/pypy/translator/c/test/test_backendoptimized.py	Sat Sep 15 11:35:03 2007
@@ -104,6 +104,34 @@
         for x in (0,1,2,3,9,27,48, -9):
             assert fn(x) == f(x)
 
+    def test_int_switch_nonsparse(self):
+        def f(x):
+            if x == 1:
+                return 9
+            elif x == 2:
+                return 27
+            elif x == 3:
+                return 3
+            return 0
+        codegenerator = self.CodeGenerator()
+        fn = codegenerator.getcompiled(f, [int])
+        for x in (0,1,2,3,9,27,48, -9):
+            assert fn(x) == f(x)
+
+    def test_int_switch_nonsparse_neg(self):
+        def f(x):
+            if x == -1:
+                return 9
+            elif x == 2:
+                return 27
+            elif x == 3:
+                return 3
+            return 0
+        codegenerator = self.CodeGenerator()
+        fn = codegenerator.getcompiled(f, [int])
+        for x in (0,1,2,3,9,27,48, -9):
+            assert fn(x) == f(x)
+
     def test_uint_switch(self):
         def f(x):
             if x == r_uint(3):

Modified: pypy/dist/pypy/translator/cli/function.py
==============================================================================
--- pypy/dist/pypy/translator/cli/function.py	(original)
+++ pypy/dist/pypy/translator/cli/function.py	Sat Sep 15 11:35:03 2007
@@ -166,28 +166,10 @@
             self.render_numeric_switch_naive(block)
             return
 
-        cases = {}
-        naive = False
-        for link in block.exits:
-            if link.exitcase == "default":
-                default = link, self.next_label('switch')
-            else:
-                if block.exitswitch.concretetype in (ootype.Char, ootype.UniChar):
-                    value = ord(link.exitcase)
-                else:
-                    value = link.exitcase
-                if value < 0:
-                    naive = True
-                    break
-                cases[value] = link, self.next_label('switch')
-
-        try:
-            max_case = max(cases.keys())
-        except ValueError:
-            max_case = 0
-        if max_case > 3*len(cases) + 10: # the switch is very sparse, better to use the naive version
-            naive = True
+        cases, min_case, max_case, default = self._collect_switch_cases(block)
+        is_sparse = self._is_sparse_switch(cases, min_case, max_case)
 
+        naive = (min_case < 0) or is_sparse
         if naive:
             self.render_numeric_switch_naive(block)
             return
@@ -202,12 +184,6 @@
         for link, lbl in cases.itervalues():
             self.render_switch_case(link, lbl)
 
-    def render_switch_case(self, link, label):
-        target_label = self._get_block_name(link.target)
-        self.set_label(label)
-        self._setup_link(link)
-        self.generator.branch_unconditionally(target_label)
-
     # Those parts of the generator interface that are function
     # specific
 

Modified: pypy/dist/pypy/translator/jvm/generator.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/generator.py	(original)
+++ pypy/dist/pypy/translator/jvm/generator.py	Sat Sep 15 11:35:03 2007
@@ -1380,6 +1380,7 @@
         return self.curfunc.instr_counter
 
     def emit_tableswitch(self, low, lbls, default):
-        pass
-
-        
+        self.curclass.out('    tableswitch %d\n' % low)
+        for label in lbls:
+            self.curclass.out('        %s\n' % label.jasmin_syntax())
+        self.curclass.out('        default: %s\n' % default.jasmin_syntax())

Modified: pypy/dist/pypy/translator/jvm/node.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/node.py	(original)
+++ pypy/dist/pypy/translator/jvm/node.py	Sat Sep 15 11:35:03 2007
@@ -35,6 +35,7 @@
      push_constant
 
 import pypy.translator.jvm.generator as jvmgen
+from pypy.translator.jvm.log import log
 
 class Node(object):
     def set_db(self, db):
@@ -327,6 +328,33 @@
                 self.ilasm.store(link.last_exc_value)
             self._setup_link(link)
 
+    def render_numeric_switch(self, block):
+        if block.exitswitch.concretetype in (ootype.SignedLongLong, ootype.UnsignedLongLong):
+            # TODO: it could be faster to check is the values fit in
+            # 32bit, and perform a cast in that case
+            self.render_numeric_switch_naive(block)
+            return
+
+        cases, min_case, max_case, default = self._collect_switch_cases(block)
+        is_sparse = self._is_sparse_switch(cases, min_case, max_case)
+
+        if is_sparse:
+            log.WARNING('TODO: use lookupswitch to render sparse numeric_switches')
+            self.render_numeric_switch_naive(block)
+            return
+
+        targets = []
+        for i in xrange(min_case, max_case+1):
+            link, lbl = cases.get(i, default)
+            targets.append(lbl)
+
+        self.generator.load(block.exitswitch)
+        self.generator.emit_tableswitch(min_case, targets, default[1])
+        
+        self.render_switch_case(*default)
+        for link, lbl in cases.itervalues():
+            self.render_switch_case(link, lbl)
+
     def render_return_block(self, block):
         return_var = block.inputargs[0]
         return_ty = self.db.lltype_to_cts(return_var.concretetype)

Modified: pypy/dist/pypy/translator/oosupport/function.py
==============================================================================
--- pypy/dist/pypy/translator/oosupport/function.py	(original)
+++ pypy/dist/pypy/translator/oosupport/function.py	Sat Sep 15 11:35:03 2007
@@ -227,6 +227,37 @@
         log.WARNING("The default version of render_numeric_switch is *slow*: please override it in the backend")
         self.render_numeric_switch_naive(block)
 
+    def _collect_switch_cases(self, block):
+        cases = {}
+        for link in block.exits:
+            if link.exitcase == "default":
+                default = link, self.next_label('switch')
+            else:
+                if block.exitswitch.concretetype in (ootype.Char, ootype.UniChar):
+                    value = ord(link.exitcase)
+                else:
+                    value = link.exitcase
+                cases[value] = link, self.next_label('switch')
+
+        values = cases.keys()
+        try:
+            min_case = min(values)
+            max_case = max(values)
+        except ValueError:
+            min_case = max_case = 0
+        return cases, min_case, max_case, default
+
+    def _is_sparse_switch(self, cases, min_case, max_case):
+        if max_case-min_case > 3*len(cases) + 10: # the switch is very sparse, better to use the naive version
+            return True
+        return False
+
+    def render_switch_case(self, link, label):
+        target_label = self._get_block_name(link.target)
+        self.set_label(label)
+        self._setup_link(link)
+        self.generator.branch_unconditionally(target_label)
+
     def render_numeric_switch_naive(self, block):
         for link in block.exits:
             target_label = self._get_block_name(link.target)



More information about the Pypy-commit mailing list