dataflow.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. from copy import copy
  2. from statement import Block
  3. class BasicBlock(Block):
  4. def __init__(self, statements=[]):
  5. Block.__init__(self, statements)
  6. self.edges_to = []
  7. self.edges_from = []
  8. self.dominates = []
  9. self.dominated_by = []
  10. def add_edge_to(self, block):
  11. if block not in self.edges_to:
  12. self.edges_to.append(block)
  13. block.edges_from.append(self)
  14. def set_dominates(self, block):
  15. if block not in self.dominates:
  16. self.dominates.append(block)
  17. block.dominated_by.append(self)
  18. def get_gen(self):
  19. pass
  20. def get_kill(self):
  21. pass
  22. def get_in(self):
  23. pass
  24. def get_out(self):
  25. pass
  26. def find_leaders(statements):
  27. """Determine the leaders, which are:
  28. 1. The first statement.
  29. 2. Any statement that is the target of a jump.
  30. 3. Any statement that follows directly follows a jump."""
  31. leaders = [0]
  32. jump_target_labels = []
  33. # Append statements following jumps and save jump target labels
  34. for i, statement in enumerate(statements[1:]):
  35. if statement.is_jump():
  36. leaders.append(i + 2)
  37. jump_target_labels.append(statement[-1])
  38. # Append jump targets
  39. for i, statement in enumerate(statements[1:]):
  40. if i + 1 not in leaders \
  41. and statement.is_label() \
  42. and statement.name in jump_target_labels:
  43. leaders.append(i + 1)
  44. leaders.sort()
  45. return leaders
  46. def find_basic_blocks(statements):
  47. """Divide a statement list into basic blocks. Returns a list of basic
  48. blocks, which are also statement lists."""
  49. leaders = find_leaders(statements)
  50. blocks = []
  51. for i in range(len(leaders) - 1):
  52. blocks.append(BasicBlock(statements[leaders[i]:leaders[i + 1]]))
  53. blocks.append(BasicBlock(statements[leaders[-1]:]))
  54. return blocks
  55. def generate_flow_graph(blocks):
  56. """Add flow graph edge administration of an ordered sequence of basic
  57. blocks."""
  58. for i, b in enumerate(blocks):
  59. last_statement = b[-1]
  60. if last_statement.is_jump():
  61. target = last_statement.jump_target()
  62. # Compare the target to all leading labels, add an edge if the
  63. # label matches the jump target
  64. for other in blocks:
  65. if other[0].is_label(target):
  66. b.add_edge_to(other)
  67. # A branch instruction also creates an edge to the next block
  68. if last_statement.is_branch() and i < len(blocks) - 1:
  69. b.add_edge_to(blocks[i + 1])
  70. elif i < len(blocks) - 1:
  71. b.add_edge_to(blocks[i + 1])
  72. #def generate_dominator_tree(nodes):
  73. # """Add dominator administration to the given flow graph nodes."""
  74. # # Dominator of the start node is the start itself
  75. # nodes[0].dom = set([nodes[0]])
  76. #
  77. # # For all other nodes, set all nodes as the dominators
  78. # for n in nodes[1:]:
  79. # n.dom = set(copy(nodes))
  80. #
  81. # def pred(n, known=[]):
  82. # """Recursively find all predecessors of a node."""
  83. # direct = filter(lambda x: x not in known, n.edges_from)
  84. # p = copy(direct)
  85. #
  86. # for ancestor in direct:
  87. # p += pred(ancestor, direct)
  88. #
  89. # return p
  90. #
  91. # # Iteratively eliminate nodes that are not dominators
  92. # changed = True
  93. #
  94. # while changed:
  95. # changed = False
  96. #
  97. # for n in nodes[1:]:
  98. # old_dom = n.dom
  99. # intersection = lambda p1, p2: p1.dom & p2.dom
  100. # n.dom = set([n]) | reduce(intersection, pred(n), set([]))
  101. #
  102. # if n.dom != old_dom:
  103. # changed = True
  104. #
  105. # def idom(d, n):
  106. # """Check if d immediately dominates n."""
  107. # for b in n.dom:
  108. # if b != d and b != n and b in n.dom:
  109. # return False
  110. #
  111. # return True
  112. #
  113. # # Build tree using immediate dominators
  114. # for n in nodes:
  115. # for d in n.dom:
  116. # if idom(d, n):
  117. # d.set_dominates(n)
  118. # break
  119. class Dag:
  120. def __init__(self, block):
  121. """Create the Directed Acyclic Graph of all binary operations in a
  122. basic block."""
  123. self.nodes = []
  124. for s in block:
  125. if s.is_command('move') or s.is_monop():
  126. rd, rs = s
  127. y = self.find_reg_node(rs)
  128. self.find_op_node(s.name, rd, y)
  129. elif s.is_binop():
  130. rd, rs, rt = s
  131. y = self.find_reg_node(rs)
  132. z = self.find_reg_node(rt)
  133. self.find_op_node(s.name, rd, y, z)
  134. def find_reg_node(self, reg):
  135. for n in self.nodes:
  136. if reg in n.reg:
  137. return n
  138. node = DagLeaf(reg)
  139. self.nodes.append(node)
  140. return node
  141. def find_op_node(self, op, rd, *args):
  142. for n in self.nodes:
  143. if n.op == op and n.nodes == args:
  144. n.labels.append(rd)
  145. return n
  146. node = DagNode(op, rd, *args)
  147. self.nodes.append(node)
  148. return node
  149. class DagNode:
  150. def __init__(self, op, label, *args):
  151. self.op = op
  152. self.labels = [label]
  153. self.nodes = args
  154. class DagLeaf:
  155. def __init__(self, reg):
  156. self.reg = reg