瀏覽代碼

Optimize repeated reads in CFG IR

jonathanvdc 8 年之前
父節點
當前提交
540c727d10
共有 2 個文件被更改,包括 109 次插入2 次删除
  1. 97 2
      kernel/modelverse_jit/cfg_ir.py
  2. 12 0
      kernel/modelverse_jit/cfg_optimization.py

+ 97 - 2
kernel/modelverse_jit/cfg_ir.py

@@ -132,6 +132,15 @@ class Definition(object):
         else:
             return self.value.get_all_dependencies()
 
+    def get_all_filtered_dependencies(self, function):
+        """Gets all definitions and instructions on which this instruction depends,
+           along with any dependencies of instruction dependencies. Dependency trees
+           are filtered by a Boolean-returning function."""
+        if isinstance(self.value, Definition):
+            return list(filter(function, [self.value]))
+        else:
+            return self.value.get_all_filtered_dependencies(function)
+
     def has_side_effects(self):
         """Tests if this definition produces any side-effects."""
         return self.value.has_side_effects()
@@ -171,6 +180,17 @@ class Instruction(object):
 
         return results
 
+    def get_all_filtered_dependencies(self, function):
+        """Gets all definitions and instructions on which this instruction depends,
+           along with any dependencies of instruction dependencies. Dependency trees
+           are filtered by a Boolean-returning function."""
+        results = list(filter(function, self.get_dependencies()))
+        for item in results:
+            if not isinstance(item, Definition):
+                results.extend(item.get_all_filtered_dependencies(function))
+
+        return results
+
 class Branch(Instruction):
     """Represents a branch from one basic block to another."""
     def __init__(self, block, arguments=None):
@@ -464,9 +484,25 @@ class DirectFunctionCall(Value):
         """Gets all definitions and instructions on which this instruction depends."""
         return [val for _, val in self.argument_list]
 
+    def format_calling_convention_tuple(self):
+        """Formats this direct function call's extended calling convention tuple.
+           The result is a formatted string that consists of a calling convention,
+           and optionally information that pertains to whether the function returns
+           a value and has side-effects."""
+        if self.has_side_effects() and self.has_value():
+            return repr(self.calling_convention)
+
+        contents = [repr(self.calling_convention)]
+        if not self.has_side_effects():
+            contents.append('pure')
+        if not self.has_value():
+            contents.append('void')
+
+        return '(%s)' % ', '.join(contents)
+
     def __str__(self):
-        return 'direct-call %r %s(%s)' % (
-            self.calling_convention,
+        return 'direct-call %s %s(%s)' % (
+            self.format_calling_convention_tuple(),
             self.target_name,
             ', '.join(['%s=%s' % (key, val.ref_str()) for key, val in self.argument_list]))
 
@@ -879,3 +915,62 @@ def get_trivial_phi_value(parameter_def, values):
                 return None
 
     return result
+
+def match_and_rewrite(entry_point, match_def, match_use, rewrite_def, rewrite_use):
+    """Matches and rewrites chains of definitions and uses in the graph defined by
+       the given entry point."""
+    ineligible_defs = set()
+    used_defs = defaultdict(set)
+    all_blocks = list(get_all_blocks(entry_point))
+    connected_defs = defaultdict(set)
+
+    # Figure out which defs and which uses match.
+    for block in all_blocks:
+        for definition in block.definitions + [block.flow]:
+            is_def_of_def = False
+            if isinstance(definition, Definition):
+                if isinstance(definition.value, Definition):
+                    is_def_of_def = True
+                    connected_defs[definition].add(definition.value)
+                    connected_defs[definition.value].add(definition)
+                elif not match_def(definition):
+                    ineligible_defs.add(definition)
+            else:
+                ineligible_defs.add(definition)
+
+            if not is_def_of_def:
+                for dependency in definition.get_all_filtered_dependencies(
+                        lambda dep: not isinstance(dep, Branch)):
+                    if (isinstance(dependency, Definition)
+                            and dependency not in ineligible_defs):
+                        if match_use(definition, dependency):
+                            used_defs[definition].add(dependency)
+                        else:
+                            ineligible_defs.add(dependency)
+
+        for branch in block.flow.branches():
+            for param, arg in zip(branch.block.parameters, branch.arguments):
+                connected_defs[arg].add(param)
+                connected_defs[param].add(arg)
+
+    def spread_ineligible(ineligible_definition):
+        """Spreads 'ineligible' to all connected definitions."""
+        for connected in connected_defs[ineligible_definition]:
+            if connected not in ineligible_defs:
+                ineligible_defs.add(connected)
+                spread_ineligible(connected)
+
+    ineligible_roots = list(ineligible_defs)
+    for root in ineligible_roots:
+        spread_ineligible(root)
+
+    # Replace defs and uses.
+    for block in all_blocks:
+        for definition in block.definitions + [block.flow]:
+            if (definition not in ineligible_defs
+                    and not isinstance(definition.value, Definition)):
+                rewrite_def(definition)
+
+            for dependency in used_defs[definition]:
+                if dependency not in ineligible_defs:
+                    rewrite_use(definition, dependency)

+ 12 - 0
kernel/modelverse_jit/cfg_optimization.py

@@ -343,6 +343,17 @@ def expand_indirect_definitions(entry_point):
 
         block.flow = __expand_indirect_defs(block.flow)
 
+def optimize_reads(entry_point):
+    """Tries to replace repeated reads by a single read."""
+    cfg_ir.match_and_rewrite(
+        entry_point,
+        lambda _: True,
+        lambda use_def, _: cfg_ir.is_value_def(use_def, cfg_ir.Read),
+        lambda def_def:
+        def_def.redefine(
+            cfg_ir.Read(def_def.insert_before(def_def.value))),
+        lambda use_def, def_def: use_def.redefine(def_def))
+
 def optimize(entry_point, jit):
     """Optimizes the control-flow graph defined by the given entry point.
        A potentially altered entry point is returned."""
@@ -353,6 +364,7 @@ def optimize(entry_point, jit):
     entry_point = cfg_ssa_construction.construct_ssa_form(entry_point)
     optimize_calls(entry_point, jit)
     yield [("CALL_ARGS", [inline_constants, (entry_point,)])]
+    optimize_reads(entry_point)
     simplify_values(entry_point)
     eliminate_unused_definitions(entry_point)
     optimize_graph_flow(entry_point)