Przeglądaj źródła

Merge branch 'master' of github.com:taddeus/peephole

Richard Torenvliet 14 lat temu
rodzic
commit
15bbae4381
5 zmienionych plików z 109 dodań i 60 usunięć
  1. 8 4
      report/report.tex
  2. 39 22
      src/optimize/redundancies.py
  3. 3 1
      src/program.py
  4. 5 3
      tests/test_dataflow.py
  5. 54 30
      tests/test_optimize.py

+ 8 - 4
report/report.tex

@@ -246,14 +246,18 @@ the generated Assembly code.
 The writer expects a list of statements, so first the blocks have to be
 The writer expects a list of statements, so first the blocks have to be
 concatenated again into a list. After this is done, the list is passed on to
 concatenated again into a list. After this is done, the list is passed on to
 the writer, which writes the instructions back to Assembly and saves the file
 the writer, which writes the instructions back to Assembly and saves the file
-so we can let xgcc compile it. We also write the original statements to a file,
-so differences in tabs, spaces and newlines do not show up when we check the
-differences between the optimized and non-optimized files.
+so we can let xgcc compile it. The original statements can also written to a
+file, so differences in tabs, spaces and newlines do not show up when checking
+the differences between the optimized and non-optimized files.
 
 
 \subsection{Execution}
 \subsection{Execution}
 
 
 To execute the optimizer, the following command can be given:\\
 To execute the optimizer, the following command can be given:\\
-\texttt{./main <original file> <optimized file> <rewritten original file>}
+\texttt{./main.py <original file> <optimized file> <rewritten original file>}\\
+There is also a script available that runs the optimizer and automatically
+starts the program \emph{meld}. In meld it is easy to visually compare the
+original file and the optimized file. The command to execute this script is:\\
+\texttt{./run <benchmark name (e.g. whet)>}\\
 
 
 \section{Testing}
 \section{Testing}
 
 

+ 39 - 22
src/optimize/redundancies.py

@@ -123,29 +123,46 @@ def add_lw(add, statements):
 
 
             return True
             return True
 
 
-
 def remove_redundant_jumps(statements):
 def remove_redundant_jumps(statements):
+    """Remove jump if label follows immediately."""
+    changed = False
+        
+    statements.reset()
+    while not statements.end():
+        s = statements.read()
+
+        #     j $Lx     ->             $Lx:
+        # $Lx:
+        if s.is_command('j'):
+            following = statements.peek()
+            
+            if following.is_label(s[0]):
+                statements.replace(1, [])
+                changed = True
+                    
+    return True
+                        
+def remove_redundant_branch_jumps(statements):
     """Optimize statement sequences on a global level."""
     """Optimize statement sequences on a global level."""
-    old_len = -1
-
-    while old_len != len(statements):
-        old_len = len(statements)
-
-        while not statements.end():
-            s = statements.read()
-
-            #     beq/bne ..., $Lx      ->      bne/beq ..., $Ly
-            #     j $Ly                     $Lx:
-            # $Lx:
-            if s.is_command('beq', 'bne'):
-                following = statements.peek(2)
-
-                if len(following) == 2:
-                    j, label = following
-
-                    if j.is_command('j') and label.is_label(s[2]):
-                        s.name = 'bne' if s.is_command('beq') else 'beq'
-                        s[2] = j[0]
-                        statements.replace(3, [s, label])
+    changed = False
 
 
     statements.reset()
     statements.reset()
+    while not statements.end():
+        s = statements.read()
+
+        #     beq/bne ..., $Lx      ->      bne/beq ..., $Ly
+        #     j $Ly                     $Lx:
+        # $Lx:
+        if s.is_command('beq', 'bne'):
+            following = statements.peek(2)
+
+            if len(following) == 2:
+                j, label = following
+
+                if j.is_command('j') and label.is_label(s[2]):
+                    s.name = 'bne' if s.is_command('beq') else 'beq'
+                    s[2] = j[0]
+                    statements.replace(3, [s, label])
+                    changed = True
+                        
+    return changed

+ 3 - 1
src/program.py

@@ -1,6 +1,7 @@
 from statement import Statement as S, Block
 from statement import Statement as S, Block
 from dataflow import find_basic_blocks, generate_flow_graph
 from dataflow import find_basic_blocks, generate_flow_graph
-from optimize.redundancies import remove_redundant_jumps, remove_redundancies
+from optimize.redundancies import remove_redundant_jumps, remove_redundancies,\
+        remove_redundant_branch_jumps
 from optimize.advanced import eliminate_common_subexpressions, \
 from optimize.advanced import eliminate_common_subexpressions, \
         fold_constants, copy_propagation, eliminate_dead_code
         fold_constants, copy_propagation, eliminate_dead_code
 from writer import write_statements
 from writer import write_statements
@@ -63,6 +64,7 @@ class Program(Block):
     def optimize_global(self):
     def optimize_global(self):
         """Optimize on a global level."""
         """Optimize on a global level."""
         remove_redundant_jumps(self)
         remove_redundant_jumps(self)
+        remove_redundant_branch_jumps(self)
 
 
     def optimize_blocks(self):
     def optimize_blocks(self):
         """Optimize on block level. Keep executing all optimizations until no
         """Optimize on block level. Keep executing all optimizations until no

+ 5 - 3
tests/test_dataflow.py

@@ -20,9 +20,11 @@ class TestDataflow(unittest.TestCase):
 
 
     def test_find_basic_blocks(self):
     def test_find_basic_blocks(self):
         s = self.statements
         s = self.statements
-        self.assertEqual(map(lambda b: b.statements, find_basic_blocks(s)), \
-                [B(s[:2]).statements, B(s[2:4]).statements, \
-                 B(s[4:]).statements])
+        self.assertEqual(
+                map(lambda b: b.statements, find_basic_blocks(s)[:-1]),
+                [B(s[:2]).statements, B(s[2:4]).statements,
+                    B(s[4:]).statements]
+        )
 
 
     def test_generate_flow_graph_simple(self):
     def test_generate_flow_graph_simple(self):
         b1 = B([S('command', 'foo'), S('command', 'j', 'b2')])
         b1 = B([S('command', 'foo'), S('command', 'j', 'b2')])

+ 54 - 30
tests/test_optimize.py

@@ -1,6 +1,7 @@
 import unittest
 import unittest
 
 
-from src.optimize.redundancies import remove_redundancies, remove_redundant_jumps
+from src.optimize.redundancies import remove_redundancies, \
+    remove_redundant_jumps, remove_redundant_branch_jumps
 from src.program import Program
 from src.program import Program
 from src.statement import Statement as S, Block as B
 from src.statement import Statement as S, Block as B
 
 
@@ -172,72 +173,95 @@ class TestOptimize(unittest.TestCase):
         self.assertEquals(block.statements, arguments)
         self.assertEquals(block.statements, arguments)
         self.assertEquals(block2.statements, arguments2)
         self.assertEquals(block2.statements, arguments2)
         self.assertEquals(block3.statements, arguments3)
         self.assertEquals(block3.statements, arguments3)
+        
+    def test_optimize_block_move_move_true(self):
+        block = B([self.foo,
+                   S('command', 'move', '$regA', '$regB'),
+                   S('command', 'move', '$regB', '$regA'),
+                   self.bar])
+        remove_redundancies(block)
 
 
-    def test_remove_redundant_jumps_beq_j_true(self):
+        self.assertEquals(block.statements, [self.foo,
+                   S('command', 'move', '$regA', '$regB'),
+                   self.bar])
+
+    def test_optimize_block_mov_mov_false(self):
+        arguments = [self.foo, \
+                     S('command', 'move', '$regA', '$regB'), \
+                     S('command', 'move', '$regB', '$regC'), \
+                     self.bar]
+        block = B(arguments)
+        remove_redundancies(block)
+
+        self.assertEquals(block.statements, arguments)
+        
+    def test_remove_redundant_jumps_true(self):
+        block = B([self.foo,
+                   S('command', 'j', '$L1'),
+                   S('label', '$L1'),
+                   self.bar])
+        
+        remove_redundant_jumps(block)
+       
+        self.assertEqual(block.statements, [self.foo, 
+                                             S('label', '$L1'),
+                                             self.bar])
+                                             
+    def test_remove_redundant_jumps_false(self):
+        arguments = [self.foo,
+                   S('command', 'j', '$L1'),
+                   S('label', '$L2'),
+                   self.bar]
+        block = B(arguments)
+                   
+        remove_redundant_jumps(block)
+       
+        self.assertEqual(block.statements, arguments)
+        
+    def test_remove_redundant_branch_jumps_beq_j_true(self):
         block = B([self.foo,
         block = B([self.foo,
                    S('command', 'beq', '$regA', '$regB', '$Lx'),
                    S('command', 'beq', '$regA', '$regB', '$Lx'),
                    S('command', 'j', '$Ly'),
                    S('command', 'j', '$Ly'),
                    S('label', '$Lx'),
                    S('label', '$Lx'),
                    self.bar])
                    self.bar])
-        remove_redundant_jumps(block)
+        remove_redundant_branch_jumps(block)
 
 
         self.assertEquals(block.statements, [self.foo,
         self.assertEquals(block.statements, [self.foo,
                    S('command', 'bne', '$regA', '$regB', '$Ly'),
                    S('command', 'bne', '$regA', '$regB', '$Ly'),
                    S('label', '$Lx'),
                    S('label', '$Lx'),
                    self.bar])
                    self.bar])
 
 
-    def test_remove_redundant_jumps_beq_j_false(self):
+    def test_remove_redundant_branch_jumps_beq_j_false(self):
         arguments = [self.foo, \
         arguments = [self.foo, \
                      S('command', 'beq', '$regA', '$regB', '$Lz'), \
                      S('command', 'beq', '$regA', '$regB', '$Lz'), \
                      S('command', 'j', '$Ly'), \
                      S('command', 'j', '$Ly'), \
                      S('label', '$Lx'), \
                      S('label', '$Lx'), \
                      self.bar]
                      self.bar]
         block = B(arguments)
         block = B(arguments)
-        remove_redundant_jumps(block)
+        remove_redundant_branch_jumps(block)
 
 
         self.assertEquals(block.statements, arguments)
         self.assertEquals(block.statements, arguments)
 
 
-    def test_remove_redundant_jumps_bne_j_true(self):
+    def test_remove_redundant_branch_jumps_bne_j_true(self):
         block = B([self.foo,
         block = B([self.foo,
                    S('command', 'bne', '$regA', '$regB', '$Lx'),
                    S('command', 'bne', '$regA', '$regB', '$Lx'),
                    S('command', 'j', '$Ly'),
                    S('command', 'j', '$Ly'),
                    S('label', '$Lx'),
                    S('label', '$Lx'),
                    self.bar])
                    self.bar])
-        remove_redundant_jumps(block)
+        remove_redundant_branch_jumps(block)
 
 
         self.assertEquals(block.statements, [self.foo,
         self.assertEquals(block.statements, [self.foo,
                    S('command', 'beq', '$regA', '$regB', '$Ly'),
                    S('command', 'beq', '$regA', '$regB', '$Ly'),
                    S('label', '$Lx'),
                    S('label', '$Lx'),
                    self.bar])
                    self.bar])
 
 
-    def test_remove_redundant_jumps_bne_j_false(self):
+    def test_remove_redundant_branch_jumps_bne_j_false(self):
         arguments = [self.foo, \
         arguments = [self.foo, \
                      S('command', 'bne', '$regA', '$regB', '$Lz'), \
                      S('command', 'bne', '$regA', '$regB', '$Lz'), \
                      S('command', 'j', '$Ly'), \
                      S('command', 'j', '$Ly'), \
                      S('label', '$Lx'), \
                      S('label', '$Lx'), \
                      self.bar]
                      self.bar]
         block = B(arguments)
         block = B(arguments)
-        remove_redundant_jumps(block)
-
-        self.assertEquals(block.statements, arguments)
-
-    def test_optimize_block_move_move_true(self):
-        block = B([self.foo,
-                   S('command', 'move', '$regA', '$regB'),
-                   S('command', 'move', '$regB', '$regA'),
-                   self.bar])
-        remove_redundancies(block)
-
-        self.assertEquals(block.statements, [self.foo,
-                   S('command', 'move', '$regA', '$regB'),
-                   self.bar])
-
-    def test_optimize_block_mov_mov_false(self):
-        arguments = [self.foo, \
-                     S('command', 'move', '$regA', '$regB'), \
-                     S('command', 'move', '$regB', '$regC'), \
-                     self.bar]
-        block = B(arguments)
-        remove_redundancies(block)
+        remove_redundant_branch_jumps(block)
 
 
         self.assertEquals(block.statements, arguments)
         self.assertEquals(block.statements, arguments)