Browse Source

Implement redundant check-local-exists definition elision

jonathanvdc 8 years ago
parent
commit
1b22d28a37
2 changed files with 57 additions and 3 deletions
  1. 15 0
      kernel/modelverse_jit/cfg_ir.py
  2. 42 3
      kernel/modelverse_jit/cfg_optimization.py

+ 15 - 0
kernel/modelverse_jit/cfg_ir.py

@@ -568,6 +568,21 @@ def is_literal_def(def_or_value):
     """Tests if the given value is a literal or a definition with an underlying literal."""
     return apply_to_value(is_literal, def_or_value)
 
+def is_value_def(def_or_value, class_or_type_or_tuple=Value):
+    """Tests if the given definition or value is a value of the given type."""
+    if isinstance(def_or_value, Definition):
+        return is_value_def(def_or_value.value, class_or_type_or_tuple)
+    else:
+        return isinstance(def_or_value, class_or_type_or_tuple)
+
+def get_def_variable(def_or_value):
+    """Gets the 'variable' attribute of the given value, or the underlying value of the given
+       definition, whichever is appropriate."""
+    if isinstance(def_or_value, Definition):
+        return get_def_variable(def_or_value.value)
+    else:
+        return def_or_value.variable
+
 def get_literal_value(value):
     """Gets the value of the given literal value."""
     return value.literal

+ 42 - 3
kernel/modelverse_jit/cfg_optimization.py

@@ -1,6 +1,8 @@
 """Optimizes and analyzes CFG-IR."""
 
+from collections import defaultdict
 import modelverse_jit.cfg_ir as cfg_ir
+import modelverse_jit.cfg_dominators as cfg_dominators
 
 def get_directly_reachable_blocks(block):
     """Gets the set of all blocks that can be reached by taking a single branch from the
@@ -58,13 +60,50 @@ def optimize_flow(block):
             block.flow = block.flow.branch.block.flow
             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
+    for block in get_reachable_blocks(entry_point):
+        yield block
+
 def optimize_graph_flow(entry_point):
     """Optimizes all flow instructions in the graph defined by the given entry point."""
-    all_blocks = set(get_reachable_blocks(entry_point))
-    all_blocks.add(entry_point)
-    for block in all_blocks:
+    for block in get_all_blocks(entry_point):
         optimize_flow(block)
 
+def elide_local_checks(entry_point):
+    """Tries to elide redundant checks on local variables."""
+    # The plan here is to replace all check-local-exists defs by literals if
+    # they are either dominated by an appropriate declare-local or not reachable
+    # from a declare-local.
+    local_checks = defaultdict(set)
+    local_defs = defaultdict(set)
+    for block in get_all_blocks(entry_point):
+        for definition in block.definitions:
+            if cfg_ir.is_value_def(definition, cfg_ir.CheckLocalExists):
+                local_checks[cfg_ir.get_def_variable(definition).node_id].add(definition)
+            elif cfg_ir.is_value_def(definition, cfg_ir.DeclareLocal):
+                local_defs[cfg_ir.get_def_variable(definition).node_id].add(definition)
+
+    dominator_tree = cfg_dominators.get_dominator_tree(entry_point)
+    reachable_blocks = get_all_reachable_blocks(entry_point)
+    for (variable, all_checks) in local_checks.items():
+        for check in all_checks:
+            is_reachable = False
+            for local_def in local_defs[variable]:
+                if dominator_tree.dominates_instruction(local_def, check):
+                    # Check is dominated by a definition. Replace it by a 'True' literal.
+                    check.redefine(cfg_ir.Literal(True))
+                    break
+                elif check.block in reachable_blocks[local_def.block]:
+                    is_reachable = True
+
+            if not is_reachable:
+                # Check cannot be reached from any definition. Replace it by a 'False' literal.
+                check.redefine(cfg_ir.Literal(False))
+
 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)