|
@@ -0,0 +1,181 @@
|
|
|
|
+"""Defines control flow graph IR data structures."""
|
|
|
|
+
|
|
|
|
+# Let's just agree to disagree on map vs list comprehensions, pylint.
|
|
|
|
+# pylint: disable=I0011,W0141
|
|
|
|
+
|
|
|
|
+class SharedCounter(object):
|
|
|
|
+ """Defines a shared counter."""
|
|
|
|
+ def __init__(self):
|
|
|
|
+ self.index = 0
|
|
|
|
+
|
|
|
|
+ def next_value(self):
|
|
|
|
+ """Gets the next value for this counter."""
|
|
|
|
+ result = self.index
|
|
|
|
+ self.index += 1
|
|
|
|
+ return result
|
|
|
|
+
|
|
|
|
+class BasicBlock(object):
|
|
|
|
+ """Represents a basic block."""
|
|
|
|
+ def __init__(self, counter):
|
|
|
|
+ self.parameters = []
|
|
|
|
+ self.definitions = []
|
|
|
|
+ self.counter = counter
|
|
|
|
+ self.index = counter.next_value()
|
|
|
|
+ self.flow = UnreachableFlow()
|
|
|
|
+
|
|
|
|
+ def append_parameter(self, parameter):
|
|
|
|
+ """Appends a parameter to this basic block."""
|
|
|
|
+ result = Definition(self.counter.next_value(), parameter)
|
|
|
|
+ self.parameters.append(result)
|
|
|
|
+ return result
|
|
|
|
+
|
|
|
|
+ def prepend_definition(self, value):
|
|
|
|
+ """Defines the given value in this basic block."""
|
|
|
|
+ result = Definition(self.counter.next_value(), value)
|
|
|
|
+ self.definitions.insert(0, result)
|
|
|
|
+ return result
|
|
|
|
+
|
|
|
|
+ def append_definition(self, value):
|
|
|
|
+ """Defines the given value in this basic block."""
|
|
|
|
+ result = Definition(self.counter.next_value(), value)
|
|
|
|
+ self.definitions.append(result)
|
|
|
|
+ return result
|
|
|
|
+
|
|
|
|
+ def remove_definition(self, definition):
|
|
|
|
+ """Removes the given definition from this basic block."""
|
|
|
|
+ return self.definitions.remove(definition)
|
|
|
|
+
|
|
|
|
+ def __str__(self):
|
|
|
|
+ return '\n'.join(map(str, self.definitions + [self.flow]))
|
|
|
|
+
|
|
|
|
+class Definition(object):
|
|
|
|
+ """Maps a value to a variable."""
|
|
|
|
+ def __init__(self, index, value):
|
|
|
|
+ self.index = index
|
|
|
|
+ self.value = value
|
|
|
|
+
|
|
|
|
+ def redefine(self, new_value):
|
|
|
|
+ """Tweaks this definition to take on the given new value."""
|
|
|
|
+ self.value = new_value
|
|
|
|
+
|
|
|
|
+ def __str__(self):
|
|
|
|
+ return '$%d = %s' % (self.index, str(self.value))
|
|
|
|
+
|
|
|
|
+class Instruction(object):
|
|
|
|
+ """Represents an instruction."""
|
|
|
|
+ def get_dependencies(self):
|
|
|
|
+ """Gets all definitions and instructions on which this instruction depends."""
|
|
|
|
+ raise NotImplementedError()
|
|
|
|
+
|
|
|
|
+ def get_all_dependencies(self):
|
|
|
|
+ """Gets all definitions and instructions on which this instruction depends,
|
|
|
|
+ along with any dependencies of dependencies."""
|
|
|
|
+ results = list(self.get_dependencies())
|
|
|
|
+ for item in results:
|
|
|
|
+ results.extend(item.get_all_dependencies())
|
|
|
|
+
|
|
|
|
+ return results
|
|
|
|
+
|
|
|
|
+class Branch(Instruction):
|
|
|
|
+ """Represents a branch from one basic block to another."""
|
|
|
|
+ def __init__(self, block, arguments):
|
|
|
|
+ self.block = block
|
|
|
|
+ self.arguments = arguments
|
|
|
|
+
|
|
|
|
+ def get_dependencies(self):
|
|
|
|
+ """Gets all definitions and instructions on which this instruction depends."""
|
|
|
|
+ return self.arguments
|
|
|
|
+
|
|
|
|
+class FlowInstruction(Instruction):
|
|
|
|
+ """Represents a control flow instruction which terminates a basic block."""
|
|
|
|
+ def branches(self):
|
|
|
|
+ """Gets a list of basic blocks targeted by this flow instruction."""
|
|
|
|
+ raise NotImplementedError()
|
|
|
|
+
|
|
|
|
+class JumpFlow(FlowInstruction):
|
|
|
|
+ """Represents a control flow instruction which jumps directly to a basic block."""
|
|
|
|
+ def __init__(self, branch):
|
|
|
|
+ FlowInstruction.__init__(self)
|
|
|
|
+ self.branch = branch
|
|
|
|
+
|
|
|
|
+ def get_dependencies(self):
|
|
|
|
+ """Gets all definitions and instructions on which this instruction depends."""
|
|
|
|
+ return self.branches()
|
|
|
|
+
|
|
|
|
+ def branches(self):
|
|
|
|
+ """Gets a list of basic blocks targeted by this flow instruction."""
|
|
|
|
+ return [self.branch]
|
|
|
|
+
|
|
|
|
+class SelectFlow(FlowInstruction):
|
|
|
|
+ """Represents a control flow instruction which jumps to one of two basic blocks depending
|
|
|
|
+ on whether a condition is truthy or not."""
|
|
|
|
+ def __init__(self, condition, if_branch, else_branch):
|
|
|
|
+ FlowInstruction.__init__(self)
|
|
|
|
+ self.condition = condition
|
|
|
|
+ self.if_branch = if_branch
|
|
|
|
+ self.else_branch = else_branch
|
|
|
|
+
|
|
|
|
+ def get_dependencies(self):
|
|
|
|
+ """Gets all definitions and instructions on which this instruction depends."""
|
|
|
|
+ return [self.condition] + self.branches()
|
|
|
|
+
|
|
|
|
+ def branches(self):
|
|
|
|
+ """Gets a list of basic blocks targeted by this flow instruction."""
|
|
|
|
+ return [self.if_branch, self.else_branch]
|
|
|
|
+
|
|
|
|
+class ReturnFlow(FlowInstruction):
|
|
|
|
+ """Represents a control flow instruction which terminates the execution of the current
|
|
|
|
+ function and returns a value."""
|
|
|
|
+ def __init__(self, value):
|
|
|
|
+ FlowInstruction.__init__(self)
|
|
|
|
+ self.value = value
|
|
|
|
+
|
|
|
|
+ def get_dependencies(self):
|
|
|
|
+ """Gets all definitions and instructions on which this instruction depends."""
|
|
|
|
+ return [self.value]
|
|
|
|
+
|
|
|
|
+ def branches(self):
|
|
|
|
+ """Gets a list of basic blocks targeted by this flow instruction."""
|
|
|
|
+ return []
|
|
|
|
+
|
|
|
|
+class UnreachableFlow(FlowInstruction):
|
|
|
|
+ """Represents a control flow instruction which is unreachable."""
|
|
|
|
+ def get_dependencies(self):
|
|
|
|
+ """Gets all definitions and instructions on which this instruction depends."""
|
|
|
|
+ return []
|
|
|
|
+
|
|
|
|
+ def branches(self):
|
|
|
|
+ """Gets a list of basic blocks targeted by this flow instruction."""
|
|
|
|
+ return []
|
|
|
|
+
|
|
|
|
+class Value(Instruction):
|
|
|
|
+ """A value: an instruction that produces some result."""
|
|
|
|
+ def get_dependencies(self):
|
|
|
|
+ """Gets all definitions and instructions on which this instruction depends."""
|
|
|
|
+ raise NotImplementedError()
|
|
|
|
+
|
|
|
|
+class BlockParameter(Value):
|
|
|
|
+ """A basic block parameter."""
|
|
|
|
+ def get_dependencies(self):
|
|
|
|
+ """Gets all definitions and instructions on which this instruction depends."""
|
|
|
|
+ return []
|
|
|
|
+
|
|
|
|
+class FunctionParameter(Value):
|
|
|
|
+ """A function parameter."""
|
|
|
|
+ def __init__(self, name):
|
|
|
|
+ Value.__init__(self)
|
|
|
|
+ self.name = name
|
|
|
|
+
|
|
|
|
+ def get_dependencies(self):
|
|
|
|
+ """Gets all definitions and instructions on which this instruction depends."""
|
|
|
|
+ return []
|
|
|
|
+
|
|
|
|
+class Literal(Value):
|
|
|
|
+ """A literal value."""
|
|
|
|
+ def __init__(self, literal):
|
|
|
|
+ Value.__init__(self)
|
|
|
|
+ self.literal = literal
|
|
|
|
+
|
|
|
|
+ def get_dependencies(self):
|
|
|
|
+ """Gets all definitions and instructions on which this instruction depends."""
|
|
|
|
+ return []
|