Explorar o código

Debugged Dead Code Elimination.

Taddeus Kroes %!s(int64=14) %!d(string=hai) anos
pai
achega
c8dba202e4
Modificáronse 3 ficheiros con 67 adicións e 22 borrados
  1. 38 18
      src/optimize/advanced.py
  2. 10 0
      src/statement.py
  3. 19 4
      tests/test_optimize_advanced.py

+ 38 - 18
src/optimize/advanced.py

@@ -1,8 +1,25 @@
 from src.statement import Statement as S
 
 
-def create_variable():
-    return '$15'
+def reg_dead_in(var, context):
+    """Check if a register is `dead' in a given list of statements."""
+    # TODO: Finish
+    for s in context:
+        if s.defines(var) or s.uses(var):
+            return False
+
+    return True
+
+
+def find_free_reg(context):
+    """Find a temporary register that is free in a given list of statements."""
+    for i in xrange(8):
+        tmp = '$t%d' % i
+
+        if reg_dead_in(tmp, context):
+            return tmp
+
+    raise Exception('No temporary register is available.')
 
 
 def eliminate_common_subexpressions(block):
@@ -44,19 +61,22 @@ def eliminate_common_subexpressions(block):
                 # Replace a similar expression by a move instruction
                 if s2.name == s.name and s2[1:] == args:
                     if not new_reg:
-                        new_reg = create_variable()
+                        new_reg = find_free_reg(block[:pointer])
 
                     block.replace(1, [S('command', 'move', s2[0], new_reg)])
                     last = block.pointer
 
-            # Insert an additional expression with a new destination address
-            if last:
-                block.insert(S('command', s.name, [new_reg] + args), last)
-                found = True
-
             # Reset pointer to and continue from the original statement
             block.pointer = pointer
 
+            if last:
+                # Insert an additional expression with a new destination address
+                block.insert(S('command', s.name, *([new_reg] + args)), last)
+
+                # Replace the original expression with a move statement
+                block.replace(1, [S('command', 'move', s[0], new_reg)])
+                found = True
+
     block.reverse_statements()
 
     return found
@@ -139,7 +159,7 @@ def fold_constants(block):
                 if s.name == 'div':
                     result = to_hex(rs_val / rt_val)
 
-                block.replace(1, [S('command', 'li', result)])
+                block.replace(1, [S('command', 'li', rd, result)])
                 register[rd] = result
                 found = True
             elif rt_known:
@@ -186,7 +206,7 @@ def copy_propagation(block):
                     break
         elif len(s) == 3 and s[0] in moves_to:
             # The result gets overwritten, so remove the data from the list.
-            i = 0            
+            i = 0
             while i  < len(moves_to):
                 if moves_to[i] == s[0]:
                     del moves_to[i]
@@ -200,16 +220,16 @@ def copy_propagation(block):
                 if s[1] == moves_to[i]:
                     s[1] = moves_from[i]
                     break
-                
+
                 if s[2] == moves_to[i]:
                     s[2] = moves_from[i]
                     break
-            
+
             changed = True
-                          
+
     return changed
-    
-    
+
+
 def algebraic_transformations(block):
     """
     Change ineffective or useless algebraic transformations. Handled are:
@@ -219,11 +239,11 @@ def algebraic_transformations(block):
     - x = x * 2 -> x = x << 1
     """
     changed = False
-    
+
     while not block.end():
         changed = True
         s = block.read()
-        
+
         if (s.is_command('addu') or s.is_command('subu')) and s[2] == 0:
             block.replace(1, [])
         elif s.is_command('mult') and s[2] == 1:
@@ -233,5 +253,5 @@ def algebraic_transformations(block):
             block.replace(1, [new_command])
         else:
             changed = False
-            
+
     return changed

+ 10 - 0
src/statement.py

@@ -88,6 +88,16 @@ class Statement:
 
         return self[-1]
 
+    def defines(self, reg):
+        """Check if this statement defines the given register."""
+        # TODO: Finish
+        return (self.is_load() or self.is_arith()) and self[0] == reg
+
+    def uses(self, reg):
+        """Check if this statement uses the given register."""
+        # TODO: Finish
+        return (self.is_load() or self.is_arith()) and reg in self[1:]
+
 
 class Block:
     def __init__(self, statements=[]):

+ 19 - 4
tests/test_optimize_advanced.py

@@ -1,4 +1,5 @@
 import unittest
+from copy import copy
 
 from src.optimize.advanced import eliminate_common_subexpressions, \
         fold_constants, copy_propagation, algebraic_transformations
@@ -15,8 +16,22 @@ class TestOptimizeAdvanced(unittest.TestCase):
         del self.foo
         del self.bar
 
-    def test_eliminate_common_subexpressions(self):
-        pass
+    def test_eliminate_common_subexpressions_simple(self):
+        b = B([S('command', 'addu', '$regC', '$regA', '$regB'),
+               S('command', 'addu', '$regD', '$regA', '$regB')])
+        e = [S('command', 'addu', '$t0', '$regA', '$regB'), \
+             S('command', 'move', '$regC', '$t0'), \
+             S('command', 'move', '$regD', '$t0')]
+        eliminate_common_subexpressions(b)
+        self.assertEqual(b.statements, e)
+
+    def test_eliminate_common_subexpressions_assigned(self):
+        b = B([S('command', 'addu', '$regC', '$regA', '$regB'),
+               S('command', 'li', '$regA', '0x00000001'),
+               S('command', 'addu', '$regD', '$regA', '$regB')])
+        e = copy(b.statements)
+        eliminate_common_subexpressions(b)
+        self.assertEqual(b.statements, e)
 
     def test_fold_constants(self):
         pass
@@ -70,12 +85,12 @@ class TestOptimizeAdvanced(unittest.TestCase):
         block = B(arguments)
         self.assertFalse(copy_propagation(block))
         self.assertEqual(block.statements, arguments)
-        
+
     def test_algebraic_transforms_add0(self):
         block = B([self.foo,
                    S('command', 'addu', '$1', '$2', 0),
                    self.bar])
-                   
+
 #        self.assertTrue(copy_propagation(block))
         algebraic_transformations(block)
         self.assertEqual(block.statements, [self.foo,