cfg_dominators.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. """Computes dominator trees for control-flow graphs."""
  2. from collections import defaultdict
  3. import modelverse_jit.cfg_ir as cfg_ir
  4. def sort_postorder(entry_point):
  5. """Produces a postorder traversal of the graph with the given block as entry point."""
  6. processed = set()
  7. results = []
  8. def __sort_postorder_step(block):
  9. if block in processed:
  10. return
  11. processed.add(block)
  12. for branch in block.flow.branches():
  13. __sort_postorder_step(branch.block)
  14. results.append(block)
  15. __sort_postorder_step(entry_point)
  16. return results
  17. class DominatorTree(object):
  18. """A data structure that represents a dominator tree."""
  19. def __init__(self, immediate_dominators):
  20. self.immediate_dominators = immediate_dominators
  21. self.dominator_sets = {}
  22. def get_immediate_dominator(self, block):
  23. """Gets the given block's immediate dominator."""
  24. return self.immediate_dominators[block]
  25. def get_dominators(self, block):
  26. """Gets the given block's set of all dominators."""
  27. if block in self.dominator_sets:
  28. return self.dominator_sets
  29. else:
  30. idom = self.get_immediate_dominator(block)
  31. if idom == block:
  32. results = set([block])
  33. else:
  34. results = set(self.get_dominators(idom))
  35. results.add(block)
  36. self.dominator_sets[block] = results
  37. return results
  38. def dominates_block(self, dominator, dominated):
  39. """Tests if the first block dominates the second."""
  40. return dominator in self.get_dominators(dominated)
  41. def dominates_instruction(self, dominator, dominated):
  42. """Tests if the first instruction dominates the second."""
  43. dominator_block = dominator.block
  44. dominated_block = dominated.block
  45. if dominator_block == dominated_block:
  46. return dominator.definition_index < dominated.definition_index
  47. else:
  48. return self.dominates_block(dominator_block, dominated_block)
  49. # The algorithms below are based on "A Simple, Fast Dominance Algorithm" by
  50. # Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
  51. # (http://www.cs.rice.edu/~keith/Embed/dom.pdf)
  52. def intersect_immediate_dominators(block1, block2, idoms, postorder_nums):
  53. """Computes the intersection of the given blocks' immediate dominators."""
  54. finger1 = block1
  55. finger2 = block2
  56. while finger1 != finger2:
  57. while postorder_nums[finger1] < postorder_nums[finger2]:
  58. finger1 = idoms[finger1]
  59. while postorder_nums[finger2] < postorder_nums[finger1]:
  60. finger2 = idoms[finger2]
  61. return finger1
  62. def get_immediate_dominators(entry_point):
  63. """Computes the immediate dominators of the control-flow graph defined by the given entry
  64. point."""
  65. predecessor_map = cfg_ir.get_all_predecessor_blocks(entry_point)
  66. idoms = {}
  67. postorder_sort = sort_postorder(entry_point)
  68. postorder_nums = {}
  69. for i, elem in enumerate(postorder_sort):
  70. postorder_nums[elem] = i
  71. idoms[elem] = None
  72. idoms[entry_point] = entry_point
  73. changed = True
  74. while changed:
  75. changed = False
  76. for block in reversed(postorder_sort):
  77. if block == entry_point:
  78. continue
  79. new_idom = None
  80. for pred in predecessor_map[block]:
  81. assert pred in postorder_nums
  82. if new_idom is None:
  83. new_idom = pred
  84. elif idoms[pred] is not None:
  85. new_idom = intersect_immediate_dominators(pred, new_idom, idoms, postorder_nums)
  86. if idoms[block] is not new_idom:
  87. idoms[block] = new_idom
  88. changed = True
  89. return idoms
  90. def get_dominator_tree(entry_point):
  91. """Constructs the dominator tree for the control-flow graph defined by the given entry point."""
  92. return DominatorTree(get_immediate_dominators(entry_point))