瀏覽代碼

Started implementing Dead Code elimination.

Taddeus Kroes 14 年之前
父節點
當前提交
ccaa52ac41
共有 4 個文件被更改,包括 73 次插入21 次删除
  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, \
         move_4, load, shift, add
 from advanced import eliminate_common_subexpressions, fold_constants, \
-        copy_propagation, algebraic_transformations
+        copy_propagation, algebraic_transformations, eliminate_dead_code
 
 
 def remove_redundancies(block):
@@ -32,7 +32,8 @@ def optimize_block(block):
             | eliminate_common_subexpressions(block) \
             | fold_constants(block) \
             | copy_propagation(block)\
-            | algebraic_transformations(block):
+            | algebraic_transformations(block) \
+            | eliminate_dead_code(block):
         pass
 
 

+ 38 - 1
src/optimize/advanced.py

@@ -40,7 +40,7 @@ def eliminate_common_subexpressions(block):
                             y = u
 
     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
       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.
@@ -292,3 +292,40 @@ def algebraic_transformations(block):
                     changed = True
 
     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):
         """Check if the statement is an arithmetic operation."""
         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):
         """Check if the statement is an unary operation."""
@@ -89,31 +92,42 @@ class Statement:
 
         return self[-1]
 
-    def defines(self, reg):
-        """Check if this statement defines the given register."""
+    def get_def(self):
         # 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])
 
             if m:
-                return m.group(1) == reg
+                use.append(m.group(1))
 
             # 'sw' also uses its first argument
             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:

+ 2 - 2
tests/test_statement.py

@@ -90,6 +90,6 @@ class TestStatement(unittest.TestCase):
         self.assertFalse(S('label', 'lw').is_load())
 
     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('label', 'add').is_arith())
+        self.assertFalse(S('label', 'addu').is_arith())