dataflow.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. from copy import copy
  2. from statement import Block
  3. class BasicBlock(Block):
  4. edges_to = []
  5. edges_from = []
  6. dominates = []
  7. dominated_by = []
  8. def add_edge_to(self, block):
  9. self.edges_to.append(block)
  10. block.edges_from.append(self)
  11. def set_dominates(self, block):
  12. self.dominates.append(block)
  13. block.dominated_by.append(self)
  14. def get_gen(self):
  15. pass
  16. def get_kill(self):
  17. pass
  18. def get_in(self):
  19. pass
  20. def get_out(self):
  21. pass
  22. def find_leaders(statements):
  23. """Determine the leaders, which are:
  24. 1. The first statement.
  25. 2. Any statement that is the target of a jump.
  26. 3. Any statement that follows directly follows a jump."""
  27. leaders = [0]
  28. jump_target_labels = []
  29. # Append statements following jumps and save jump target labels
  30. for i, statement in enumerate(statements[1:]):
  31. if statement.is_jump():
  32. leaders.append(i + 2)
  33. jump_target_labels.append(statement[-1])
  34. # Append jump targets
  35. for i, statement in enumerate(statements[1:]):
  36. if i + 1 not in leaders \
  37. and statement.is_label() \
  38. and statement.name in jump_target_labels:
  39. leaders.append(i + 1)
  40. leaders.sort()
  41. return leaders
  42. def find_basic_blocks(statements):
  43. """Divide a statement list into basic blocks. Returns a list of basic
  44. blocks, which are also statement lists."""
  45. leaders = find_leaders(statements)
  46. blocks = []
  47. for i in range(len(leaders) - 1):
  48. blocks.append(BasicBlock(statements[leaders[i]:leaders[i + 1]]))
  49. blocks.append(BasicBlock(statements[leaders[-1]:]))
  50. return blocks
  51. def generate_flow_graph(blocks):
  52. """Add flow graph edge administration of an ordered sequence of basic
  53. blocks."""
  54. for b in blocks:
  55. last_statement = b[-1]
  56. if last_statement.is_jump():
  57. target = last_statement.jump_target()
  58. # Compare the target to all leading labels, add an edge if the
  59. # label matches the jump target
  60. for other in blocks:
  61. if other[0].is_label(target):
  62. b.add_edge_to(other)
  63. def generate_dominator_tree(nodes):
  64. """Add dominator administration to the given flow graph nodes."""
  65. # Dominator of the start node is the start itself
  66. nodes[0].dom = set([nodes[0]])
  67. # For all other nodes, set all nodes as the dominators
  68. for n in nodes[1:]:
  69. n.dom = set(copy(nodes))
  70. def pred(n, known=[]):
  71. """Recursively find all predecessors of a node."""
  72. direct = filter(lambda x: x not in known, n.edges_from)
  73. p = copy(direct)
  74. for ancestor in direct:
  75. p += pred(ancestor, direct)
  76. return p
  77. # Iteratively eliminate nodes that are not dominators
  78. changed = True
  79. while changed:
  80. changed = False
  81. for n in nodes[1:]:
  82. old_dom = n.dom
  83. intersection = lambda p1, p2: p1.dom & p2.dom
  84. n.dom = set([n]) | reduce(intersection, pred(n), set([]))
  85. if n.dom != old_dom:
  86. changed = True
  87. def idom(d, n):
  88. """Check if d immediately dominates n."""
  89. for b in n.dom:
  90. if b != d and b != n and b in n.dom:
  91. return False
  92. return True
  93. # Build tree using immediate dominators
  94. for n in nodes:
  95. for d in n.dom:
  96. if idom(d, n):
  97. d.set_dominates(n)
  98. break
  99. # statements = parse_file(...)
  100. # b = find_basic_blocks(statements)
  101. # generate_flow_graph(b) # nodes now have edges
  102. # generate_dominator_tree(b) # nodes now have dominators