forked from M-Labs/artiq
Add a dominator analysis.
This commit is contained in:
parent
224a93fde3
commit
603d49dffa
|
@ -0,0 +1 @@
|
|||
from .domination import DominatorTree
|
|
@ -0,0 +1,48 @@
|
|||
"""
|
||||
:class:`DominatorTree` computes the dominance relation over
|
||||
control flow graphs.
|
||||
|
||||
See http://www.cs.colostate.edu/~mstrout/CS553/slides/lecture04.pdf.
|
||||
"""
|
||||
|
||||
from functools import reduce, cmp_to_key
|
||||
|
||||
# Key Idea
|
||||
# If a node dominates all
|
||||
# predecessors of node n, then it
|
||||
# also dominates node n
|
||||
class DominatorTree:
|
||||
def __init__(self, func):
|
||||
entry = func.get_entry()
|
||||
|
||||
self.dominated_by = { entry: {entry} }
|
||||
for block in func.basic_blocks:
|
||||
if block != entry:
|
||||
self.dominated_by[block] = set(func.basic_blocks)
|
||||
|
||||
predecessors = {block: block.predecessors() for block in func.basic_blocks}
|
||||
while True:
|
||||
changed = False
|
||||
|
||||
for block in func.basic_blocks:
|
||||
if block == entry:
|
||||
continue
|
||||
|
||||
if not any(predecessors[block]):
|
||||
# Unreachable blocks are dominated by everything
|
||||
continue
|
||||
|
||||
new_dominated_by = {block}.union(
|
||||
reduce(lambda a, b: a.intersection(b),
|
||||
(self.dominated_by[pred] for pred in predecessors[block])))
|
||||
if new_dominated_by != self.dominated_by[block]:
|
||||
self.dominated_by[block] = new_dominated_by
|
||||
changed = True
|
||||
|
||||
if not changed:
|
||||
break
|
||||
|
||||
def in_domination_order(self):
|
||||
blocks = list(self.dominated_by.keys())
|
||||
blocks.sort(key=cmp_to_key(lambda a, b: a in self.dominated_by[b]))
|
||||
return blocks
|
|
@ -335,6 +335,9 @@ class BasicBlock(NamedValue):
|
|||
|
||||
return "\n".join(lines)
|
||||
|
||||
def __repr__(self):
|
||||
return "<BasicBlock '{}'>".format(self.name)
|
||||
|
||||
class Argument(NamedValue):
|
||||
"""
|
||||
A function argument.
|
||||
|
@ -383,6 +386,13 @@ class Function:
|
|||
basic_block._detach()
|
||||
self.basic_blocks.remove(basic_block)
|
||||
|
||||
def get_entry(self):
|
||||
assert any(self.basic_blocks)
|
||||
return self.basic_blocks[0]
|
||||
|
||||
def instructions(self):
|
||||
for basic_block in self.basic_blocks:
|
||||
yield from iter(basic_block.instructions)
|
||||
|
||||
def __str__(self):
|
||||
printer = types.TypePrinter()
|
||||
|
|
Loading…
Reference in New Issue