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)
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<BasicBlock '{}'>".format(self.name)
|
||||||
|
|
||||||
class Argument(NamedValue):
|
class Argument(NamedValue):
|
||||||
"""
|
"""
|
||||||
A function argument.
|
A function argument.
|
||||||
|
@ -383,6 +386,13 @@ class Function:
|
||||||
basic_block._detach()
|
basic_block._detach()
|
||||||
self.basic_blocks.remove(basic_block)
|
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):
|
def __str__(self):
|
||||||
printer = types.TypePrinter()
|
printer = types.TypePrinter()
|
||||||
|
|
Loading…
Reference in New Issue