Browse Source

Implement dead code elimination for CFGs

jonathanvdc 8 years ago
parent
commit
004bcdc1e5
2 changed files with 57 additions and 1 deletions
  1. 10 1
      kernel/modelverse_jit/cfg_ir.py
  2. 47 0
      kernel/modelverse_jit/cfg_optimization.py

+ 10 - 1
kernel/modelverse_jit/cfg_ir.py

@@ -95,6 +95,15 @@ class Definition(object):
         """Updates this definition's index in the block that defines it."""
         self.definition_index = new_definition_index
 
+    def get_all_dependencies(self):
+        """Gets all definitions and instructions on which this definition depends,
+           along with any dependencies of instruction dependencies."""
+        return self.value.get_all_dependencies()
+
+    def has_side_effects(self):
+        """Tests if this definition produces any side-effects."""
+        return self.value.has_side_effects()
+
     def ref_str(self):
         """Gets a string that represents a reference to this definition."""
         return '$%d' % self.index
@@ -110,7 +119,7 @@ class Instruction(object):
 
     def get_all_dependencies(self):
         """Gets all definitions and instructions on which this instruction depends,
-           along with any dependencies of dependencies."""
+           along with any dependencies of instruction dependencies."""
         results = list(self.get_dependencies())
         for item in results:
             results.extend(item.get_all_dependencies())

+ 47 - 0
kernel/modelverse_jit/cfg_optimization.py

@@ -60,6 +60,17 @@ def optimize_flow(block):
             block.flow = block.flow.branch.block.flow
             changed = True
 
+        # Branches to blocks which contain nothing but a jump can be replaced by branches
+        # to the jump's target.
+        for branch in block.flow.branches():
+            if (is_empty_block(branch.block)
+                    and branch.block is not block
+                    and isinstance(branch.block.flow, cfg_ir.JumpFlow)):
+                new_branch = branch.block.flow.branch
+                branch.block = new_branch.block
+                branch.arguments = new_branch.arguments
+                changed = True
+
 def get_all_blocks(entry_point):
     """Gets all basic blocks in the control-flow graph defined by the given entry point."""
     yield entry_point
@@ -102,8 +113,44 @@ def elide_local_checks(entry_point):
                 # Check cannot be reached from any definition. Replace it by a 'False' literal.
                 check.redefine(cfg_ir.Literal(False))
 
+def eliminate_unused_definitions(entry_point):
+    """Tries to eliminate unused definitions in the control-flow graphb defined by the
+       given entry point."""
+    def_dependencies = {}
+    root_defs = set()
+    for block in get_all_blocks(entry_point):
+        for definition in block.definitions:
+            def_dependencies[definition] = set(
+                [dep for dep in definition.get_all_dependencies()
+                 if isinstance(dep, cfg_ir.Definition)])
+            if definition.has_side_effects():
+                root_defs.add(definition)
+
+        for dep in block.flow.get_all_dependencies():
+            if isinstance(dep, cfg_ir.Definition):
+                root_defs.add(dep)
+
+    live_defs = set()
+    def __mark_live(definition):
+        if definition in live_defs:
+            return
+
+        live_defs.add(definition)
+        if definition in def_dependencies:
+            for dep in def_dependencies[definition]:
+                __mark_live(dep)
+
+    for root in root_defs:
+        __mark_live(root)
+
+    dead_defs = set.difference(set(def_dependencies.keys()), live_defs)
+    for dead_def in dead_defs:
+        dead_def.block.remove_definition(dead_def)
+
 def optimize(entry_point):
     """Optimizes the control-flow graph defined by the given entry point."""
     optimize_graph_flow(entry_point)
     elide_local_checks(entry_point)
     optimize_graph_flow(entry_point)
+    eliminate_unused_definitions(entry_point)
+    optimize_graph_flow(entry_point)