123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- """Computes dominator trees for control-flow graphs."""
- from collections import defaultdict
- import modelverse_jit.cfg_ir as cfg_ir
- def sort_postorder(entry_point):
- """Produces a postorder traversal of the graph with the given block as entry point."""
- processed = set()
- results = []
- def __sort_postorder_step(block):
- if block in processed:
- return
- processed.add(block)
- for branch in block.flow.branches():
- __sort_postorder_step(branch.block)
- results.append(block)
- __sort_postorder_step(entry_point)
- return results
- class DominatorTree(object):
- """A data structure that represents a dominator tree."""
- def __init__(self, immediate_dominators):
- self.immediate_dominators = immediate_dominators
- self.dominator_sets = {}
- def get_immediate_dominator(self, block):
- """Gets the given block's immediate dominator."""
- return self.immediate_dominators[block]
- def get_dominators(self, block):
- """Gets the given block's set of all dominators."""
- if block in self.dominator_sets:
- return self.dominator_sets
- else:
- idom = self.get_immediate_dominator(block)
- if idom == block:
- results = set([block])
- else:
- results = set(self.get_dominators(idom))
- results.add(block)
- self.dominator_sets[block] = results
- return results
- def dominates_block(self, dominator, dominated):
- """Tests if the first block dominates the second."""
- return dominator in self.get_dominators(dominated)
- def dominates_instruction(self, dominator, dominated):
- """Tests if the first instruction dominates the second."""
- dominator_block = dominator.block
- dominated_block = dominated.block
- if dominator_block == dominated_block:
- return dominator.definition_index < dominated.definition_index
- else:
- return self.dominates_block(dominator_block, dominated_block)
- # The algorithms below are based on "A Simple, Fast Dominance Algorithm" by
- # Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
- # (http://www.cs.rice.edu/~keith/Embed/dom.pdf)
- def intersect_immediate_dominators(block1, block2, idoms, postorder_nums):
- """Computes the intersection of the given blocks' immediate dominators."""
- finger1 = block1
- finger2 = block2
- while finger1 != finger2:
- while postorder_nums[finger1] < postorder_nums[finger2]:
- finger1 = idoms[finger1]
- while postorder_nums[finger2] < postorder_nums[finger1]:
- finger2 = idoms[finger2]
- return finger1
- def get_immediate_dominators(entry_point):
- """Computes the immediate dominators of the control-flow graph defined by the given entry
- point."""
- predecessor_map = cfg_ir.get_all_predecessor_blocks(entry_point)
- idoms = {}
- postorder_sort = sort_postorder(entry_point)
- postorder_nums = {}
- for i, elem in enumerate(postorder_sort):
- postorder_nums[elem] = i
- idoms[elem] = None
- idoms[entry_point] = entry_point
- changed = True
- while changed:
- changed = False
- for block in reversed(postorder_sort):
- if block == entry_point:
- continue
- new_idom = None
- for pred in predecessor_map[block]:
- assert pred in postorder_nums
- if new_idom is None:
- new_idom = pred
- elif idoms[pred] is not None:
- new_idom = intersect_immediate_dominators(pred, new_idom, idoms, postorder_nums)
- if idoms[block] is not new_idom:
- idoms[block] = new_idom
- changed = True
- return idoms
- def get_dominator_tree(entry_point):
- """Constructs the dominator tree for the control-flow graph defined by the given entry point."""
- return DominatorTree(get_immediate_dominators(entry_point))
|