dataflow.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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. self.in_set = set([])
  11. self.out_set = set([])
  12. self.gen_set = set([])
  13. self.kill_set = set([])
  14. def add_edge_to(self, block):
  15. if block not in self.edges_to:
  16. self.edges_to.append(block)
  17. block.edges_from.append(self)
  18. def set_dominates(self, block):
  19. if block not in self.dominates:
  20. self.dominates.append(block)
  21. block.dominated_by.append(self)
  22. def create_gen_kill(self, defs):
  23. used = set()
  24. self_defs = {}
  25. # Get the last of each definition series and put in in the `def' set
  26. self.gen_set = set()
  27. for s in reversed(self):
  28. for reg in s.get_def():
  29. if reg not in self_defs:
  30. self_defs[reg] = s.sid
  31. self.gen_set.add(s.sid)
  32. # Generate kill set
  33. self.kill_set = set()
  34. for reg, statement_ids in defs.iteritems():
  35. if reg in self_defs:
  36. add = statement_ids - set([self_defs[reg]])
  37. else:
  38. add = statement_ids
  39. self.kill_set |= add
  40. def defs(blocks):
  41. # Collect definitions of all registers
  42. defs = {}
  43. for b in blocks:
  44. for s in b:
  45. for reg in s.get_def():
  46. if reg not in defs:
  47. defs[reg] = set([s.sid])
  48. else:
  49. defs[reg].add(s.sid)
  50. return defs
  51. def reaching_definitions(blocks):
  52. """Generate the `in' and `out' sets of the given blocks using the iterative
  53. algorithm from the slides."""
  54. defs = defs(blocks)
  55. for b in blocks:
  56. b.create_gen_kill(defs)
  57. b.out_set = b.gen_set
  58. change = True
  59. while change:
  60. change = False
  61. for b in blocks:
  62. b.in_set = set()
  63. for pred in b.edges_from:
  64. b.in_set |= pred.out_set
  65. oldout = copy(p.out_set)
  66. p.out_set = b.gen_set | (b.in_set - b.kill_set)
  67. if b.out_set != oldout:
  68. change = True
  69. def pred(n, known=[]):
  70. """Recursively find all predecessors of a node."""
  71. direct = filter(lambda b: b not in known, n.edges_from)
  72. p = copy(direct)
  73. for ancestor in direct:
  74. p += pred(ancestor, direct)
  75. return p
  76. def find_leaders(statements):
  77. """Determine the leaders, which are:
  78. 1. The first statement.
  79. 2. Any statement that is the target of a jump.
  80. 3. Any statement that follows directly follows a jump."""
  81. leaders = [0]
  82. jump_target_labels = []
  83. # Append statements following jumps and save jump target labels
  84. for i, statement in enumerate(statements[1:]):
  85. if statement.is_jump():
  86. leaders.append(i + 2)
  87. jump_target_labels.append(statement[-1])
  88. # Append jump targets
  89. for i, statement in enumerate(statements[1:]):
  90. if i + 1 not in leaders \
  91. and statement.is_label() \
  92. and statement.name in jump_target_labels:
  93. leaders.append(i + 1)
  94. leaders.sort()
  95. return leaders
  96. def find_basic_blocks(statements):
  97. """Divide a statement list into basic blocks. Returns a list of basic
  98. blocks, which are also statement lists."""
  99. leaders = find_leaders(statements)
  100. blocks = []
  101. for i in range(len(leaders) - 1):
  102. blocks.append(BasicBlock(statements[leaders[i]:leaders[i + 1]]))
  103. blocks.append(BasicBlock(statements[leaders[-1]:]))
  104. return blocks
  105. def generate_flow_graph(blocks):
  106. """Add flow graph edge administration of an ordered sequence of basic
  107. blocks."""
  108. for i, b in enumerate(blocks):
  109. last_statement = b[-1]
  110. if last_statement.is_jump():
  111. target = last_statement.jump_target()
  112. # Compare the target to all leading labels, add an edge if the
  113. # label matches the jump target
  114. for other in blocks:
  115. if other[0].is_label(target):
  116. b.add_edge_to(other)
  117. # A branch instruction also creates an edge to the next block
  118. if last_statement.is_branch() and i < len(blocks) - 1:
  119. b.add_edge_to(blocks[i + 1])
  120. elif i < len(blocks) - 1:
  121. b.add_edge_to(blocks[i + 1])
  122. #def generate_dominator_tree(nodes):
  123. # """Add dominator administration to the given flow graph nodes."""
  124. # # Dominator of the start node is the start itself
  125. # nodes[0].dom = set([nodes[0]])
  126. #
  127. # # For all other nodes, set all nodes as the dominators
  128. # for n in nodes[1:]:
  129. # n.dom = set(copy(nodes))
  130. #
  131. # def pred(n, known=[]):
  132. # """Recursively find all predecessors of a node."""
  133. # direct = filter(lambda x: x not in known, n.edges_from)
  134. # p = copy(direct)
  135. #
  136. # for ancestor in direct:
  137. # p += pred(ancestor, direct)
  138. #
  139. # return p
  140. #
  141. # # Iteratively eliminate nodes that are not dominators
  142. # changed = True
  143. #
  144. # while changed:
  145. # changed = False
  146. #
  147. # for n in nodes[1:]:
  148. # old_dom = n.dom
  149. # intersection = lambda p1, p2: p1.dom & p2.dom
  150. # n.dom = set([n]) | reduce(intersection, pred(n), set([]))
  151. #
  152. # if n.dom != old_dom:
  153. # changed = True
  154. #
  155. # def idom(d, n):
  156. # """Check if d immediately dominates n."""
  157. # for b in n.dom:
  158. # if b != d and b != n and b in n.dom:
  159. # return False
  160. #
  161. # return True
  162. #
  163. # # Build tree using immediate dominators
  164. # for n in nodes:
  165. # for d in n.dom:
  166. # if idom(d, n):
  167. # d.set_dominates(n)
  168. # break
  169. class Dag:
  170. def __init__(self, block):
  171. """Create the Directed Acyclic Graph of all binary operations in a
  172. basic block."""
  173. self.nodes = []
  174. for s in block:
  175. if s.is_command('move') or s.is_monop():
  176. rd, rs = s
  177. y = self.find_reg_node(rs)
  178. self.find_op_node(s.name, rd, y)
  179. elif s.is_binop():
  180. rd, rs, rt = s
  181. y = self.find_reg_node(rs)
  182. z = self.find_reg_node(rt)
  183. self.find_op_node(s.name, rd, y, z)
  184. def find_reg_node(self, reg):
  185. for n in self.nodes:
  186. if reg in n.reg:
  187. return n
  188. node = DagLeaf(reg)
  189. self.nodes.append(node)
  190. return node
  191. def find_op_node(self, op, rd, *args):
  192. for n in self.nodes:
  193. if not isinstance(n, DagLeaf) and n.op == op and n.nodes == args:
  194. n.labels.append(rd)
  195. return n
  196. node = DagNode(op, rd, *args)
  197. self.nodes.append(node)
  198. return node
  199. class DagNode:
  200. def __init__(self, op, label, *args):
  201. self.op = op
  202. self.labels = [label]
  203. self.nodes = args
  204. class DagLeaf:
  205. def __init__(self, reg):
  206. self.reg = reg