]> granicus.if.org Git - python/commitdiff
Update the peephole optimizer to remove more dead code (jumps after returns)
authorNeal Norwitz <nnorwitz@gmail.com>
Sat, 14 Oct 2006 21:33:38 +0000 (21:33 +0000)
committerNeal Norwitz <nnorwitz@gmail.com>
Sat, 14 Oct 2006 21:33:38 +0000 (21:33 +0000)
and inline jumps to returns.

Lib/test/test_peepholer.py
Misc/NEWS
Python/import.c
Python/peephole.c

index 4385a84c1fbf255f4c21d36f50e6acabf6c81f1d..02b04e071fef2f5b29282dd928e814d2aa969dac 100644 (file)
@@ -161,6 +161,41 @@ class TestTranforms(unittest.TestCase):
         self.assert_('(None)' not in asm)
         self.assertEqual(asm.split().count('RETURN_VALUE'), 1)
 
+    def test_elim_jump_to_return(self):
+        # JUMP_FORWARD to RETURN -->  RETURN
+        def f(cond, true_value, false_value):
+            return true_value if cond else false_value
+        asm = disassemble(f)
+        self.assert_('JUMP_FORWARD' not in asm)
+        self.assert_('JUMP_ABSOLUTE' not in asm)
+        self.assertEqual(asm.split().count('RETURN_VALUE'), 2)
+
+    def test_elim_jump_after_return1(self):
+        # Eliminate dead code: jumps immediately after returns can't be reached
+        def f(cond1, cond2):
+            if cond1: return 1
+            if cond2: return 2
+            while 1:
+                return 3
+            while 1:
+                if cond1: return 4
+                return 5
+            return 6
+        asm = disassemble(f)
+        self.assert_('JUMP_FORWARD' not in asm)
+        self.assert_('JUMP_ABSOLUTE' not in asm)
+        self.assertEqual(asm.split().count('RETURN_VALUE'), 6)
+
+    def test_elim_jump_after_return2(self):
+        # Eliminate dead code: jumps immediately after returns can't be reached
+        def f(cond1, cond2):
+            while 1:
+                if cond1: return 4
+        asm = disassemble(f)
+        self.assert_('JUMP_FORWARD' not in asm)
+        # There should be one jump for the while loop.
+        self.assertEqual(asm.split().count('JUMP_ABSOLUTE'), 1)
+        self.assertEqual(asm.split().count('RETURN_VALUE'), 2)
 
 
 def test_main(verbose=None):
index cd21eea4b5a67fa907434e3bf4ca7f83ddd2371d..9800a9b396c6f493baac8b86906f2227e28a4441 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 2.6 alpha 1?
 Core and builtins
 -----------------
 
+- Update the peephole optimizer to remove more dead code (jumps after returns)
+  and inline unconditional jumps to returns.
+
 - Bug #1545497: when given an explicit base, int() did ignore NULs
   embedded in the string to convert.
 
index a90729ae25920d600cd0f867f6425e4a4dd92268..45c5507aa9f79b53b9b9dc1c4c85655286715d77 100644 (file)
@@ -65,9 +65,10 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
        Python 2.5c1: 62121 (fix wrong lnotab with for loops and
                                    storing constants that should have been removed)
        Python 2.5c2: 62131 (fix wrong code: for x, in ... in listcomp/genexp)
+       Python 2.6a0: 62141 (peephole optimizations)
 .
 */
-#define MAGIC (62131 | ((long)'\r'<<16) | ((long)'\n'<<24))
+#define MAGIC (62141 | ((long)'\r'<<16) | ((long)'\n'<<24))
 
 /* Magic word as global; note that _PyImport_Init() can change the
    value of this global to accommodate for alterations of how the
index 1d94319a3927e126270697d1b60a28466f522090..f2fe6cebcfdd3fc573b4b38f15b4ab1058ee8335 100644 (file)
@@ -523,6 +523,13 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
                        case SETUP_EXCEPT:
                        case SETUP_FINALLY:
                                tgt = GETJUMPTGT(codestr, i);
+                               /* Replace JUMP_* to a RETURN into just a RETURN */
+                               if (UNCONDITIONAL_JUMP(opcode) &&
+                                   codestr[tgt] == RETURN_VALUE) {
+                                       codestr[i] = RETURN_VALUE;
+                                       memset(codestr+i+1, NOP, 2);
+                                       continue;
+                               }
                                if (!UNCONDITIONAL_JUMP(codestr[tgt]))
                                        continue;
                                tgttgt = GETJUMPTGT(codestr, tgt);
@@ -540,12 +547,16 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
                                goto exitUnchanged;
 
                                /* Replace RETURN LOAD_CONST None RETURN with just RETURN */
+                               /* Remove unreachable JUMPs after RETURN */
                        case RETURN_VALUE:
-                               if (i+4 >= codelen  ||
-                                   codestr[i+4] != RETURN_VALUE         ||
-                                   !ISBASICBLOCK(blocks,i,5))
+                               if (i+4 >= codelen)
                                        continue;
-                               memset(codestr+i+1, NOP, 4);
+                               if (codestr[i+4] == RETURN_VALUE &&
+                                   ISBASICBLOCK(blocks,i,5))
+                                       memset(codestr+i+1, NOP, 4);
+                               else if (UNCONDITIONAL_JUMP(codestr[i+1]) &&
+                                        ISBASICBLOCK(blocks,i,4))
+                                       memset(codestr+i+1, NOP, 3);
                                break;
                }
        }