Explorar el Código

Merged conflicts.

Taddeus Kroes hace 14 años
padre
commit
ab33ab8652

+ 1 - 0
benchmarks/optimized/.gitignore

@@ -0,0 +1 @@
+*.s

+ 1 - 2
benchmarks/optimized/acron.s

@@ -180,7 +180,6 @@ $L5:
 	addu	$3,$16,$17
 	addu	$3,$16,$17
 	addu	$2,$3,$2
 	addu	$2,$3,$2
 	sw	$2,24($fp)
 	sw	$2,24($fp)
-	lw	$2,24($fp)
 	beq	$2,$0,$L8
 	beq	$2,$0,$L8
 	lw	$2,24($fp)
 	lw	$2,24($fp)
 	li	$3,0x00000003		# 3
 	li	$3,0x00000003		# 3
@@ -410,4 +409,4 @@ $L27:
 	lw	$fp,24($sp)
 	lw	$fp,24($sp)
 	addu	$sp,$sp,32
 	addu	$sp,$sp,32
 	j	$31
 	j	$31
-	.end	main
+	.end	main

+ 57 - 0
report/report.tex

@@ -116,6 +116,50 @@ This is a less efficient method then the dag, but because the basic blocks are
 in general not very large and the execution time of the optimizer is not a
 in general not very large and the execution time of the optimizer is not a
 primary concern, this is not a big problem.
 primary concern, this is not a big problem.
 
 
+\subsubsection*{Fold constants}
+
+
+
+\subsubsection*{Copy propagation}
+
+Copy propagation `unpacks' a move instruction, by replacing its destination
+address with its source address in the code following the move instruction.
+
+This is not a direct optimization, but this does allow for a more effective
+dead code elimination.
+
+The code of the block is checked linearly. When a move operation is
+encountered, the source and destination address of this move are stored. When
+a normal operation with a source and a destination address are found, a number
+of checks are performed.
+
+The first check is whether the destination address is stored as a destination
+address of a move instruction. If so, this move instruction is no longer valid,
+so the optimizations can not be done. Otherwise, continue with the second
+check.
+
+In the second check, the source address is compared to the destination
+addresses of all still valid move operations. If these are the same, in the
+current operation the found source address is replaced with the source address
+of the move operation.
+
+An example would be the following:
+\begin{verbatim}
+move $regA, $regB           move $regA, $regB
+...                         ...
+Code not writing $regA, ->  ...
+$regB                       ...
+...                         ...
+addu $regC, $regA, ...      addu $regC, $regB, ...
+\end{verbatim}
+This code shows that \texttt{\$regA} is replaced with \texttt{\$regB}. This
+way, the move instruction might have become useless, and it will then be
+removed by the dead code elimination.
+
+\subsubsection*{Algebraic transformations}
+
+
+
 \section{Implementation}
 \section{Implementation}
 
 
 We decided to implement the optimization in Python. We chose this programming
 We decided to implement the optimization in Python. We chose this programming
@@ -240,6 +284,7 @@ addu $regC, $regB, 4        move $regC, $regD
 
 
 # Constant folding
 # Constant folding
 
 
+
 # Copy propagation
 # Copy propagation
 move $regA, $regB           move $regA, $regB
 move $regA, $regB           move $regA, $regB
 ...                         ...
 ...                         ...
@@ -247,5 +292,17 @@ Code not writing $regA, ->  ...
 $regB                       ...
 $regB                       ...
 ...                         ...
 ...                         ...
 addu $regC, $regA, ...      addu $regC, $regB, ...
 addu $regC, $regA, ...      addu $regC, $regB, ...
+
+
+# Algebraic transformations
+addu $regA, $regB, 0    ->  move $regA, $regB
+
+subu $regA, $regB, 0    ->  move $regA, $regB
+
+mult $regA, $regB, 1    ->  move $regA, $regB
+
+mult $regA, $regB, 0    ->  li   $regA, 0
+
+mult $regA, $regB, 2    ->  sll  $regA, $regB, 1
 \end{verbatim}
 \end{verbatim}
 \end{document}
 \end{document}

+ 4 - 3
src/optimize/__init__.py

@@ -3,7 +3,7 @@ from src.dataflow import find_basic_blocks
 from redundancies import remove_redundant_jumps, move_1, move_2, move_3, \
 from redundancies import remove_redundant_jumps, move_1, move_2, move_3, \
         move_4, load, shift, add
         move_4, load, shift, add
 from advanced import eliminate_common_subexpressions, fold_constants, \
 from advanced import eliminate_common_subexpressions, fold_constants, \
-        copy_propagation
+        copy_propagation, algebraic_transformations
 
 
 
 
 def remove_redundancies(block):
 def remove_redundancies(block):
@@ -31,7 +31,8 @@ def optimize_block(block):
     while remove_redundancies(block) \
     while remove_redundancies(block) \
             | eliminate_common_subexpressions(block) \
             | eliminate_common_subexpressions(block) \
             | fold_constants(block) \
             | fold_constants(block) \
-            | copy_propagation(block):
+            | copy_propagation(block)\
+            | algebraic_transformations(block):
         pass
         pass
 
 
 
 
@@ -40,7 +41,7 @@ def optimize(statements, verbose=0):
     optimization functions."""
     optimization functions."""
     # Optimize on a global level
     # Optimize on a global level
     o = len(statements)
     o = len(statements)
-    optimize_global(statements)
+    remove_redundant_jumps(statements)
     g = len(statements)
     g = len(statements)
 
 
     # Optimize basic blocks
     # Optimize basic blocks

+ 29 - 17
src/optimize/advanced.py

@@ -1,5 +1,5 @@
 from src.statement import Statement as S
 from src.statement import Statement as S
-
+from math import log
 
 
 def reg_dead_in(var, context):
 def reg_dead_in(var, context):
     """Check if a register is `dead' in a given list of statements."""
     """Check if a register is `dead' in a given list of statements."""
@@ -182,10 +182,16 @@ def fold_constants(block):
 
 
 def copy_propagation(block):
 def copy_propagation(block):
     """
     """
-    Replace a variable with its original variable after a move if possible, by
-    walking through the code, storing move operations and checking whether it
-    changes or whether a variable can be replaced. This way, the move statement
-    might be a target for dead code elimination.
+    Unpack a move instruction, by replacing its destination
+    address with its source address in the code following the move instruction.
+    This way, the move statement might be a target for dead code elimination.
+
+    move $regA, $regB           move $regA, $regB
+    ...                         ...
+    Code not writing $regA, ->  ...
+    $regB                       ...
+    ...                         ...
+    addu $regC, $regA, ...      addu $regC, $regB, ...
     """
     """
     moves_from = []
     moves_from = []
     moves_to = []
     moves_to = []
@@ -233,25 +239,31 @@ def copy_propagation(block):
 def algebraic_transformations(block):
 def algebraic_transformations(block):
     """
     """
     Change ineffective or useless algebraic transformations. Handled are:
     Change ineffective or useless algebraic transformations. Handled are:
-    - x = x + 0 -> remove
-    - x = x - 0 -> remove
-    - x = x * 1 -> remove
-    - x = x * 2 -> x = x << 1
+    - x = y + 0 -> x = y
+    - x = y - 0 -> x = y
+    - x = y * 1 -> x = y
+    - x = y * 0 -> x = 0
+    - x = y * 2 -> x = x << 1
     """
     """
     changed = False
     changed = False
 
 
     while not block.end():
     while not block.end():
-        changed = True
         s = block.read()
         s = block.read()
 
 
         if (s.is_command('addu') or s.is_command('subu')) and s[2] == 0:
         if (s.is_command('addu') or s.is_command('subu')) and s[2] == 0:
-            block.replace(1, [])
+            block.replace(1, [S('command', 'move', s[0], s[1])])
+            changed = True
         elif s.is_command('mult') and s[2] == 1:
         elif s.is_command('mult') and s[2] == 1:
-            block.replace(1, [])
-        elif s.is_command('mult') and s[2] == 2:
-            new_command = S(['command', 'sll', s[0], s[1], 1])
-            block.replace(1, [new_command])
-        else:
-            changed = False
+            block.replace(1, [S('command', 'move', s[0], s[1])])
+            changed = True
+        elif s.is_command('mult') and s[2] == 0:
+            block.replace(1, [S('command', 'li', '$1', to_hex(0))])
+            changed = True
+        elif s.is_command('mult'):
+            shift_amount = log(s[2], 2)
+            if shift_amount.is_integer():
+                new_command = S('command', 'sll', s[0], s[1], shift_amount)
+                block.replace(1, [new_command])
+                changed = True
 
 
     return changed
     return changed

+ 78 - 2
tests/test_optimize_advanced.py

@@ -90,8 +90,84 @@ class TestOptimizeAdvanced(unittest.TestCase):
         block = B([self.foo,
         block = B([self.foo,
                    S('command', 'addu', '$1', '$2', 0),
                    S('command', 'addu', '$1', '$2', 0),
                    self.bar])
                    self.bar])
+        self.assertTrue(algebraic_transformations(block))
+        self.assertEqual(block.statements, [self.foo,
+                         S('command', 'move', '$1', '$2'),
+                         self.bar])
+
+    def test_algebraic_transforms_add1(self):
+        arguments = [self.foo,
+                   S('command', 'addu', '$1', '$2', 1),
+                   self.bar]
+        block = B(arguments)
+
+        self.assertFalse(algebraic_transformations(block))
+        self.assertEqual(block.statements, arguments)
+
+    def test_algebraic_transforms_sub0(self):
+        block = B([self.foo,
+                   S('command', 'subu', '$1', '$2', 0),
+                   self.bar])
+
+        self.assertTrue(algebraic_transformations(block))
+        self.assertEqual(block.statements, [self.foo,
+                         S('command', 'move', '$1', '$2'),
+                         self.bar])
+
+    def test_algebraic_transforms_sub1(self):
+        arguments = [self.foo,
+                   S('command', 'subu', '$1', '$2', 1),
+                   self.bar]
+        block = B(arguments)
+
+        self.assertFalse(algebraic_transformations(block))
+        self.assertEqual(block.statements, arguments)
+
+    def test_algebraic_transforms_mult0(self):
+        block = B([self.foo,
+                   S('command', 'mult', '$1', '$2', 0),
+                   self.bar])
+
+        self.assertTrue(algebraic_transformations(block))
+        self.assertEqual(block.statements, [self.foo,
+                         S('command', 'li', '$1', '0x00000000'),
+                         self.bar])
+
+    def test_algebraic_transforms_mult1(self):
+        block = B([self.foo,
+                   S('command', 'mult', '$1', '$2', 1),
+                   self.bar])
+
+        self.assertTrue(algebraic_transformations(block))
+        self.assertEqual(block.statements, [self.foo,
+                         S('command', 'move', '$1', '$2'),
+                         self.bar])
+
+    def test_algebraic_transforms_mult2(self):
+        block = B([self.foo,
+                   S('command', 'mult', '$1', '$2', 2),
+                   self.bar])
 
 
-#        self.assertTrue(copy_propagation(block))
-        algebraic_transformations(block)
+        self.assertTrue(algebraic_transformations(block))
         self.assertEqual(block.statements, [self.foo,
         self.assertEqual(block.statements, [self.foo,
+                         S('command', 'sll', '$1', '$2', 1),
+                         self.bar])
+
+    def test_algebraic_transforms_mult16(self):
+        block = B([self.foo,
+                   S('command', 'mult', '$1', '$2', 16),
                    self.bar])
                    self.bar])
+
+        self.assertTrue(algebraic_transformations(block))
+        self.assertEqual(block.statements, [self.foo,
+                         S('command', 'sll', '$1', '$2', 4),
+                         self.bar])
+
+    def test_algebraic_transforms_mult3(self):
+        arguments = [self.foo,
+                     S('command', 'mult', '$1', '$2', 3),
+                     self.bar]
+        block = B(arguments)
+
+        self.assertFalse(algebraic_transformations(block))
+        self.assertEqual(block.statements, arguments)