Ver Fonte

Started implementing Dead Code elimination.

Taddeus Kroes há 14 anos atrás
pai
commit
ccaa52ac41
4 ficheiros alterados com 73 adições e 21 exclusões
  1. 3 2
      src/optimize/__init__.py
  2. 38 1
      src/optimize/advanced.py
  3. 30 16
      src/statement.py
  4. 2 2
      tests/test_statement.py

+ 3 - 2
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, algebraic_transformations
+        copy_propagation, algebraic_transformations, eliminate_dead_code
 
 
 
 
 def remove_redundancies(block):
 def remove_redundancies(block):
@@ -32,7 +32,8 @@ def optimize_block(block):
             | eliminate_common_subexpressions(block) \
             | eliminate_common_subexpressions(block) \
             | fold_constants(block) \
             | fold_constants(block) \
             | copy_propagation(block)\
             | copy_propagation(block)\
-            | algebraic_transformations(block):
+            | algebraic_transformations(block) \
+            | eliminate_dead_code(block):
         pass
         pass
 
 
 
 

+ 38 - 1
src/optimize/advanced.py

@@ -40,7 +40,7 @@ def eliminate_common_subexpressions(block):
                             y = u
                             y = u
 
 
     The algorithm used is as follows:
     The algorithm used is as follows:
-    - Traverse through the statements in reverse order.
+    - Traverse through the statements.
     - If the statement can be possibly be eliminated, walk further collecting
     - If the statement can be possibly be eliminated, walk further collecting
       all other occurrences of the expression until one of the arguments is
       all other occurrences of the expression until one of the arguments is
       assigned in a statement, or the start of the block has been reached.
       assigned in a statement, or the start of the block has been reached.
@@ -292,3 +292,40 @@ def algebraic_transformations(block):
                     changed = True
                     changed = True
 
 
     return changed
     return changed
+
+
+def eliminate_dead_code(block):
+    """
+    Dead code elimination:
+    TODO: example...
+
+    The algorithm used is as follows:
+    - Traverse through the statements in reverse order.
+    - If the statement definition is dead, remove it. A variable is dead if it
+      is not used in the rest of the block, and is not in the `out' set of the
+      block.
+    """
+    # TODO: Finish
+    changed = False
+
+    block.reverse_statements()
+    unused = set()
+
+    while not block.end():
+        s = block.read()
+
+        for reg in s.get_def():
+            if reg in unused:
+                # Statement is redefined later, so this statement is useless
+                s.remove = True
+                #print 'reg %s is in %s, remove:' % (reg, unused), \
+                #        block.pointer - 1, s
+            else:
+                unused.add(reg)
+
+        unused -= set(s.get_use())
+
+    block.apply_filter(lambda s: not hasattr(s, 'remove'))
+    block.reverse_statements()
+
+    return changed

+ 30 - 16
src/statement.py

@@ -71,8 +71,11 @@ class Statement:
     def is_arith(self):
     def is_arith(self):
         """Check if the statement is an arithmetic operation."""
         """Check if the statement is an arithmetic operation."""
         return self.is_command() \
         return self.is_command() \
-               and re.match('^s(ll|rl|ra)|(add|sub|mflo|abs|neg|slt|sqrt)' \
-                            + '(u|\.s|\.d)?$', self.name)
+               and re.match('^s(ll|rl|ra)'
+                            + '|(mfhi|mflo|abs|neg|and|[xn]?or)'
+                            + '|(add|sub|slt)u?'
+                            + '|(add|sub|mult|div|abs|neg|sqrt|c)\.[sd]$', \
+                            self.name)
 
 
     def is_monop(self):
     def is_monop(self):
         """Check if the statement is an unary operation."""
         """Check if the statement is an unary operation."""
@@ -89,31 +92,42 @@ class Statement:
 
 
         return self[-1]
         return self[-1]
 
 
-    def defines(self, reg):
-        """Check if this statement defines the given register."""
+    def get_def(self):
         # TODO: Finish
         # TODO: Finish
-        return (self.is_load() or self.is_arith()) and self[0] == reg
+        if self.is_load() or self.is_arith():
+            return self[:1]
 
 
-    def uses(self, reg):
-        """Check if this statement uses the given register."""
-        # TODO: Finish
-        if self.is_arith():
-            return reg in self[1:]
+        return []
 
 
-        if self.is_command('move'):
-            return self[1] == reg
+    def get_use(self):
+        # TODO: Finish with ALL the available commands!
+        use = []
 
 
-        if self.is_command('lw', 'sb', 'sw', 'dsw'):
+        if self.is_binop():
+            use += self[1:]
+        elif self.is_command('move'):
+            use.append(self[1])
+        elif self.is_command('lw', 'sb', 'sw', 'dsw', 's.s', 's.d'):
             m = re.match('^\d+\(([^)]+)\)$', self[1])
             m = re.match('^\d+\(([^)]+)\)$', self[1])
 
 
             if m:
             if m:
-                return m.group(1) == reg
+                use.append(m.group(1))
 
 
             # 'sw' also uses its first argument
             # 'sw' also uses its first argument
             if self.name in ['sw', 'dsw']:
             if self.name in ['sw', 'dsw']:
-                return self[0] == reg
+                use.append(self[0])
+        elif len(self) == 2:  # FIXME: temporary fix, manually add all commands
+            use.append(self[1])
 
 
-        return False
+        return use
+
+    def defines(self, reg):
+        """Check if this statement defines the given register."""
+        return reg in self.get_def()
+
+    def uses(self, reg):
+        """Check if this statement uses the given register."""
+        return reg in self.get_use()
 
 
 
 
 class Block:
 class Block:

+ 2 - 2
tests/test_statement.py

@@ -90,6 +90,6 @@ class TestStatement(unittest.TestCase):
         self.assertFalse(S('label', 'lw').is_load())
         self.assertFalse(S('label', 'lw').is_load())
 
 
     def test_is_arith(self):
     def test_is_arith(self):
-        self.assertTrue(S('command', 'add', '$1', '$2', '$3').is_arith())
+        self.assertTrue(S('command', 'addu', '$1', '$2', '$3').is_arith())
         self.assertFalse(S('command', 'foo').is_arith())
         self.assertFalse(S('command', 'foo').is_arith())
-        self.assertFalse(S('label', 'add').is_arith())
+        self.assertFalse(S('label', 'addu').is_arith())