Browse Source

Introduce the concept of bidirectional dependencies in CFG IR, define cfg_ir.CreateEdge

jonathanvdc 8 years ago
parent
commit
ff2cea223f
2 changed files with 52 additions and 3 deletions
  1. 42 2
      kernel/modelverse_jit/cfg_ir.py
  2. 10 1
      kernel/modelverse_jit/cfg_optimization.py

+ 42 - 2
kernel/modelverse_jit/cfg_ir.py

@@ -149,6 +149,11 @@ class Definition(object):
         """Tells if this definition produces a result that is not None."""
         return self.value.has_value()
 
+    def has_bidirectional_dependencies(self):
+        """Tells if this instruction's dependencies are bidirectional."""
+        return (not isinstance(self.value, Definition)
+                and self.value.has_bidirectional_dependencies())
+
     def insert_before(self, value):
         """Inserts the given value or definition before this definition."""
         return self.block.insert_definition_before(self, value)
@@ -218,6 +223,10 @@ class FlowInstruction(Instruction):
         """Gets a list of basic blocks targeted by this flow instruction."""
         raise NotImplementedError()
 
+    def has_bidirectional_dependencies(self):
+        """Tells if this instruction's dependencies are bidirectional."""
+        return False
+
     def has_side_effects(self):
         """Tells if this instruction has side-effects."""
         # All flow-instructions have side-effects!
@@ -349,6 +358,11 @@ class Value(Instruction):
         """Tells if this instruction has side-effects."""
         return False
 
+    def has_bidirectional_dependencies(self):
+        """Tells if this value has bidirectional dependencies: if so, then all dependencies
+           of this node on another node are also dependencies of that node on this node."""
+        return False
+
     def ref_str(self):
         """Gets a string that represents this value."""
         return str(self)
@@ -558,8 +572,9 @@ class DeallocateRootNode(Value):
         """Tells if this value produces a result that is not None."""
         return False
 
-    def has_side_effects(self):
-        """Tells if this instruction has side-effects."""
+    def has_bidirectional_dependencies(self):
+        """Tells if this value has bidirectional dependencies: if so, then all dependencies
+           of this node on another node are also dependencies of that node on this node."""
         return True
 
     def __str__(self):
@@ -750,6 +765,31 @@ class CreateNode(Value):
     def __str__(self):
         return 'create-node %s' % (self.value.ref_str())
 
+class CreateEdge(Value):
+    """A value that creates a new edge."""
+    def __init__(self, source, target):
+        Value.__init__(self)
+        self.source = source
+        assert isinstance(source, Definition)
+        self.target = target
+        assert isinstance(target, Definition)
+
+    def get_dependencies(self):
+        """Gets all definitions and instructions on which this instruction depends."""
+        return [self.source, self.target]
+
+    def create(self, new_dependencies):
+        """Creates an instruction of this type from the given set of dependencies."""
+        return CreateEdge(*new_dependencies)
+
+    def has_bidirectional_dependencies(self):
+        """Tells if this value has bidirectional dependencies: if so, then all dependencies
+           of this node on another node are also dependencies of that node on this node."""
+        return True
+
+    def __str__(self):
+        return 'create-edge %s, %s' % (self.source.ref_str(), self.target.ref_str())
+
 class Binary(Value):
     """A value that applies a binary operator to two other values."""
     def __init__(self, lhs, operator, rhs):

+ 10 - 1
kernel/modelverse_jit/cfg_optimization.py

@@ -126,11 +126,18 @@ def eliminate_unused_definitions(entry_point):
        given entry point."""
     def_dependencies = defaultdict(set)
     root_defs = set()
+    # Gather dependencies.
     for block in cfg_ir.get_all_blocks(entry_point):
         for definition in block.parameters + block.definitions:
+            all_dependencies = list(definition.get_all_dependencies())
             def_dependencies[definition].update(
-                [dep for dep in definition.get_all_dependencies()
+                [dep for dep in all_dependencies
                  if isinstance(dep, cfg_ir.Definition)])
+
+            if len(all_dependencies) > 0 and definition.has_bidirectional_dependencies():
+                for dep in all_dependencies:
+                    def_dependencies[dep].add(definition)
+
             if definition.has_side_effects():
                 root_defs.add(definition)
 
@@ -142,6 +149,7 @@ def eliminate_unused_definitions(entry_point):
                 for param, arg in zip(dep.block.parameters, dep.arguments):
                     def_dependencies[param].add(arg)
 
+    # Figure out which definitions are live.
     live_defs = set()
     def __mark_live(definition):
         if definition in live_defs:
@@ -155,6 +163,7 @@ def eliminate_unused_definitions(entry_point):
     for root in root_defs:
         __mark_live(root)
 
+    # Remove all dead definitions.
     dead_defs = set.difference(set(def_dependencies.keys()), live_defs)
     dead_phis = set()
     for dead_def in dead_defs: