|
@@ -49,23 +49,31 @@ class BasicBlock(object):
|
|
|
self.renumber_definitions()
|
|
|
return result
|
|
|
|
|
|
- def insert_definition_before(self, anchor, value):
|
|
|
- """Inserts the second definition or value before the first definition."""
|
|
|
- index = None
|
|
|
+ def __get_def_index_for_insert(self, anchor):
|
|
|
for i, definition in enumerate(self.definitions):
|
|
|
if definition.definition_index == anchor.definition_index:
|
|
|
- index = i
|
|
|
+ return i
|
|
|
|
|
|
- if index is None:
|
|
|
- raise ValueError(
|
|
|
- 'Cannot insert a definition because the anchor '
|
|
|
- 'is not defined in this block.')
|
|
|
+ raise ValueError(
|
|
|
+ 'Cannot insert a definition because the anchor '
|
|
|
+ 'is not defined in this block.')
|
|
|
|
|
|
+ def insert_definition_before(self, anchor, value):
|
|
|
+ """Inserts the second definition or value before the first definition."""
|
|
|
+ index = self.__get_def_index_for_insert(anchor)
|
|
|
result = self.create_definition(value)
|
|
|
self.definitions.insert(index, result)
|
|
|
self.renumber_definitions()
|
|
|
return result
|
|
|
|
|
|
+ def insert_definition_after(self, anchor, value):
|
|
|
+ """Inserts the second definition or value after the first definition."""
|
|
|
+ index = self.__get_def_index_for_insert(anchor)
|
|
|
+ result = self.create_definition(value)
|
|
|
+ self.definitions.insert(index + 1, result)
|
|
|
+ self.renumber_definitions()
|
|
|
+ return result
|
|
|
+
|
|
|
def append_definition(self, value):
|
|
|
"""Defines the given value in this basic block."""
|
|
|
result = self.create_definition(value)
|
|
@@ -158,6 +166,10 @@ class Definition(object):
|
|
|
"""Inserts the given value or definition before this definition."""
|
|
|
return self.block.insert_definition_before(self, value)
|
|
|
|
|
|
+ def insert_after(self, value):
|
|
|
+ """Inserts the given value or definition after this definition."""
|
|
|
+ return self.block.insert_definition_after(self, value)
|
|
|
+
|
|
|
def ref_str(self):
|
|
|
"""Gets a string that represents a reference to this definition."""
|
|
|
return '$%d' % self.index
|
|
@@ -464,6 +476,9 @@ JIT_CALLING_CONVENTION = 'jit'
|
|
|
MACRO_POSITIONAL_CALLING_CONVENTION = 'macro-positional'
|
|
|
"""The calling convention for well-known functions that are expanded as macros during codegen."""
|
|
|
|
|
|
+MACRO_IO_CALLING_CONVENTION = 'macro-io'
|
|
|
+"""The calling convention 'input' and 'output'."""
|
|
|
+
|
|
|
PRINT_MACRO_NAME = 'print'
|
|
|
"""The name of the 'print' macro."""
|
|
|
|
|
@@ -479,13 +494,22 @@ READ_DICT_KEYS_MACRO_NAME = 'read_dict_keys'
|
|
|
REVERSE_LIST_MACRO_NAME = 'reverse_list'
|
|
|
"""The name of the list reversal macro."""
|
|
|
|
|
|
+GC_PROTECT_MACRO_NAME = 'gc_protect'
|
|
|
+"""The name of the macro that unconditionally protects its first argument from the GC by
|
|
|
+ drawing an edge between it and the second argument."""
|
|
|
+
|
|
|
+MAYBE_GC_PROTECT_MACRO_NAME = 'maybe_gc_protect'
|
|
|
+"""The name of the macro that protects its first argument from the GC by drawing an edge between
|
|
|
+ it and the second argument, but only if that first argument is not None."""
|
|
|
+
|
|
|
class DirectFunctionCall(Value):
|
|
|
"""A value that is the result of a direct function call."""
|
|
|
def __init__(
|
|
|
self, target_name, argument_list,
|
|
|
calling_convention=JIT_CALLING_CONVENTION,
|
|
|
has_value=True,
|
|
|
- has_side_effects=True):
|
|
|
+ has_side_effects=True,
|
|
|
+ has_bidirectional_dependencies=False):
|
|
|
Value.__init__(self)
|
|
|
self.target_name = target_name
|
|
|
assert all([isinstance(val, Definition) for _, val in argument_list])
|
|
@@ -493,6 +517,7 @@ class DirectFunctionCall(Value):
|
|
|
self.calling_convention = calling_convention
|
|
|
self.has_value_val = has_value
|
|
|
self.has_side_effects_val = has_side_effects
|
|
|
+ self.has_bidirectional_deps_val = has_bidirectional_dependencies
|
|
|
|
|
|
def has_side_effects(self):
|
|
|
"""Tells if this instruction has side-effects."""
|
|
@@ -502,13 +527,18 @@ class DirectFunctionCall(Value):
|
|
|
"""Tells if this value produces a result that is not None."""
|
|
|
return self.has_value_val
|
|
|
|
|
|
+ def has_bidirectional_dependencies(self):
|
|
|
+ """Tells if this value has bidirectional dependencies."""
|
|
|
+ return self.has_bidirectional_deps_val
|
|
|
+
|
|
|
def create(self, new_dependencies):
|
|
|
"""Creates an instruction of this type from the given set of dependencies."""
|
|
|
return DirectFunctionCall(
|
|
|
self.target_name,
|
|
|
[(name, new_val)
|
|
|
for new_val, (name, _) in zip(new_dependencies, self.argument_list)],
|
|
|
- self.calling_convention, self.has_value_val, self.has_side_effects_val)
|
|
|
+ self.calling_convention, self.has_value_val, self.has_side_effects_val,
|
|
|
+ self.has_bidirectional_deps_val)
|
|
|
|
|
|
def get_dependencies(self):
|
|
|
"""Gets all definitions and instructions on which this instruction depends."""
|
|
@@ -519,7 +549,9 @@ class DirectFunctionCall(Value):
|
|
|
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():
|
|
|
+ if (self.has_side_effects()
|
|
|
+ and self.has_value()
|
|
|
+ and not self.has_bidirectional_dependencies()):
|
|
|
return repr(self.calling_convention)
|
|
|
|
|
|
contents = [repr(self.calling_convention)]
|
|
@@ -527,6 +559,8 @@ class DirectFunctionCall(Value):
|
|
|
contents.append('pure')
|
|
|
if not self.has_value():
|
|
|
contents.append('void')
|
|
|
+ if self.has_bidirectional_dependencies():
|
|
|
+ contents.append('two-way-dependencies')
|
|
|
|
|
|
return '(%s)' % ', '.join(contents)
|
|
|
|
|
@@ -827,14 +861,40 @@ def create_output(argument):
|
|
|
"""Creates a value that outputs the specified argument."""
|
|
|
return DirectFunctionCall(
|
|
|
OUTPUT_MACRO_NAME, [('argument', argument)],
|
|
|
- calling_convention=MACRO_POSITIONAL_CALLING_CONVENTION,
|
|
|
+ calling_convention=MACRO_IO_CALLING_CONVENTION,
|
|
|
has_value=False)
|
|
|
|
|
|
def create_input():
|
|
|
"""Creates a value that pops a value from the input queue."""
|
|
|
return DirectFunctionCall(
|
|
|
INPUT_MACRO_NAME, [],
|
|
|
- calling_convention=MACRO_POSITIONAL_CALLING_CONVENTION)
|
|
|
+ calling_convention=MACRO_IO_CALLING_CONVENTION)
|
|
|
+
|
|
|
+def create_gc_protect(protected_value, root):
|
|
|
+ """Creates a value that protects the first from the GC by drawing an
|
|
|
+ edge between it and the given root."""
|
|
|
+ return DirectFunctionCall(
|
|
|
+ GC_PROTECT_MACRO_NAME, [
|
|
|
+ ('protected_value', protected_value),
|
|
|
+ ('root', root)
|
|
|
+ ],
|
|
|
+ calling_convention=MACRO_POSITIONAL_CALLING_CONVENTION,
|
|
|
+ has_value=False, has_side_effects=False,
|
|
|
+ has_bidirectional_dependencies=True)
|
|
|
+
|
|
|
+def create_conditional_gc_protect(protected_value, root):
|
|
|
+ """Creates a value that protects the first from the GC by drawing an
|
|
|
+ edge between it and the given root, but only if the protected value
|
|
|
+ is not None."""
|
|
|
+ return DirectFunctionCall(
|
|
|
+ MAYBE_GC_PROTECT_MACRO_NAME, [
|
|
|
+ ('condition', protected_value),
|
|
|
+ ('protected_value', protected_value),
|
|
|
+ ('root', root)
|
|
|
+ ],
|
|
|
+ calling_convention=MACRO_POSITIONAL_CALLING_CONVENTION,
|
|
|
+ has_value=False, has_side_effects=False,
|
|
|
+ has_bidirectional_dependencies=True)
|
|
|
|
|
|
def get_def_value(def_or_value):
|
|
|
"""Returns the given value, or the underlying value of the given definition, whichever is
|
|
@@ -953,6 +1013,26 @@ def get_trivial_phi_value(parameter_def, values):
|
|
|
|
|
|
return result
|
|
|
|
|
|
+def find_all_def_uses(entry_point):
|
|
|
+ """Finds all uses of all definitions in the given entry point.
|
|
|
+ A (definition to list of users map, definition to defining block map)
|
|
|
+ tuple is returned."""
|
|
|
+ all_blocks = list(get_all_blocks(entry_point))
|
|
|
+
|
|
|
+ # Find all definition users for each definition.
|
|
|
+ def_users = defaultdict(list)
|
|
|
+ def_blocks = {}
|
|
|
+ for block in all_blocks:
|
|
|
+ for parameter_def in block.parameters:
|
|
|
+ def_blocks[parameter_def] = block
|
|
|
+ for definition in block.definitions + [block.flow]:
|
|
|
+ def_blocks[definition] = block
|
|
|
+ for dependency in definition.get_all_dependencies():
|
|
|
+ if not isinstance(dependency, Branch):
|
|
|
+ def_users[dependency].append(definition)
|
|
|
+
|
|
|
+ return def_users, def_blocks
|
|
|
+
|
|
|
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."""
|