cfg_ir.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. """Defines control flow graph IR data structures."""
  2. # Let's just agree to disagree on map vs list comprehensions, pylint.
  3. # pylint: disable=I0011,W0141
  4. class SharedCounter(object):
  5. """Defines a shared counter."""
  6. def __init__(self):
  7. self.index = 0
  8. def next_value(self):
  9. """Gets the next value for this counter."""
  10. result = self.index
  11. self.index += 1
  12. return result
  13. class BasicBlock(object):
  14. """Represents a basic block."""
  15. def __init__(self, counter):
  16. self.parameters = []
  17. self.definitions = []
  18. self.counter = counter
  19. self.index = counter.next_value()
  20. self.flow = UnreachableFlow()
  21. def append_parameter(self, parameter):
  22. """Appends a parameter to this basic block."""
  23. result = Definition(self.counter.next_value(), parameter)
  24. self.parameters.append(result)
  25. return result
  26. def prepend_definition(self, value):
  27. """Defines the given value in this basic block."""
  28. result = Definition(self.counter.next_value(), value)
  29. self.definitions.insert(0, result)
  30. return result
  31. def append_definition(self, value):
  32. """Defines the given value in this basic block."""
  33. result = Definition(self.counter.next_value(), value)
  34. self.definitions.append(result)
  35. return result
  36. def remove_definition(self, definition):
  37. """Removes the given definition from this basic block."""
  38. return self.definitions.remove(definition)
  39. def __str__(self):
  40. prefix = '!%d(%s):' % (self.index, ', '.join(map(str, self.parameters)))
  41. return '\n'.join(
  42. [prefix] +
  43. [' ' * 4 + str(item) for item in self.definitions + [self.flow]])
  44. class Definition(object):
  45. """Maps a value to a variable."""
  46. def __init__(self, index, value):
  47. self.index = index
  48. self.value = value
  49. def redefine(self, new_value):
  50. """Tweaks this definition to take on the given new value."""
  51. self.value = new_value
  52. def ref_str(self):
  53. """Gets a string that represents a reference to this definition."""
  54. return '$%d' % self.index
  55. def __str__(self):
  56. return '$%d = %s' % (self.index, str(self.value))
  57. class Instruction(object):
  58. """Represents an instruction."""
  59. def get_dependencies(self):
  60. """Gets all definitions and instructions on which this instruction depends."""
  61. raise NotImplementedError()
  62. def get_all_dependencies(self):
  63. """Gets all definitions and instructions on which this instruction depends,
  64. along with any dependencies of dependencies."""
  65. results = list(self.get_dependencies())
  66. for item in results:
  67. results.extend(item.get_all_dependencies())
  68. return results
  69. class Branch(Instruction):
  70. """Represents a branch from one basic block to another."""
  71. def __init__(self, block, arguments):
  72. self.block = block
  73. self.arguments = arguments
  74. def get_dependencies(self):
  75. """Gets all definitions and instructions on which this instruction depends."""
  76. return self.arguments
  77. def __str__(self):
  78. return '!%d(%s)' % (self.block.index, ', '.join(map(str, self.arguments)))
  79. class FlowInstruction(Instruction):
  80. """Represents a control flow instruction which terminates a basic block."""
  81. def branches(self):
  82. """Gets a list of basic blocks targeted by this flow instruction."""
  83. raise NotImplementedError()
  84. class JumpFlow(FlowInstruction):
  85. """Represents a control flow instruction which jumps directly to a basic block."""
  86. def __init__(self, branch):
  87. FlowInstruction.__init__(self)
  88. self.branch = branch
  89. def get_dependencies(self):
  90. """Gets all definitions and instructions on which this instruction depends."""
  91. return self.branches()
  92. def branches(self):
  93. """Gets a list of basic blocks targeted by this flow instruction."""
  94. return [self.branch]
  95. def __str__(self):
  96. return 'jump %s' % self.branch
  97. class SelectFlow(FlowInstruction):
  98. """Represents a control flow instruction which jumps to one of two basic blocks depending
  99. on whether a condition is truthy or not."""
  100. def __init__(self, condition, if_branch, else_branch):
  101. FlowInstruction.__init__(self)
  102. self.condition = condition
  103. self.if_branch = if_branch
  104. self.else_branch = else_branch
  105. def get_dependencies(self):
  106. """Gets all definitions and instructions on which this instruction depends."""
  107. return [self.condition] + self.branches()
  108. def branches(self):
  109. """Gets a list of basic blocks targeted by this flow instruction."""
  110. return [self.if_branch, self.else_branch]
  111. def __str__(self):
  112. return 'select %s, %s, %s' % (self.condition.ref_str(), self.if_branch, self.else_branch)
  113. class ReturnFlow(FlowInstruction):
  114. """Represents a control flow instruction which terminates the execution of the current
  115. function and returns a value."""
  116. def __init__(self, value):
  117. FlowInstruction.__init__(self)
  118. self.value = value
  119. def get_dependencies(self):
  120. """Gets all definitions and instructions on which this instruction depends."""
  121. return [self.value]
  122. def branches(self):
  123. """Gets a list of basic blocks targeted by this flow instruction."""
  124. return []
  125. def __str__(self):
  126. return 'return %s' % self.value.ref_str()
  127. class UnreachableFlow(FlowInstruction):
  128. """Represents a control flow instruction which is unreachable."""
  129. def get_dependencies(self):
  130. """Gets all definitions and instructions on which this instruction depends."""
  131. return []
  132. def branches(self):
  133. """Gets a list of basic blocks targeted by this flow instruction."""
  134. return []
  135. def __str__(self):
  136. return 'unreachable'
  137. class Value(Instruction):
  138. """A value: an instruction that produces some result."""
  139. def get_dependencies(self):
  140. """Gets all definitions and instructions on which this instruction depends."""
  141. raise NotImplementedError()
  142. class BlockParameter(Value):
  143. """A basic block parameter."""
  144. def get_dependencies(self):
  145. """Gets all definitions and instructions on which this instruction depends."""
  146. return []
  147. def __str__(self):
  148. return 'block-parameter'
  149. class FunctionParameter(Value):
  150. """A function parameter."""
  151. def __init__(self, name):
  152. Value.__init__(self)
  153. self.name = name
  154. def get_dependencies(self):
  155. """Gets all definitions and instructions on which this instruction depends."""
  156. return []
  157. def __str__(self):
  158. return 'func-parameter %s' % self.name
  159. class Literal(Value):
  160. """A literal value."""
  161. def __init__(self, literal):
  162. Value.__init__(self)
  163. self.literal = literal
  164. def get_dependencies(self):
  165. """Gets all definitions and instructions on which this instruction depends."""
  166. return []
  167. def __str__(self):
  168. return 'literal %s' % self.literal