| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- from copy import copy
- from statement import Block
- class BasicBlock(Block):
- def __init__(self, statements=[], dummy=False):
- Block.__init__(self, statements)
- self.edges_to = []
- self.edges_from = []
- self.dominates = []
- self.dominated_by = []
- self.dummy = dummy
- def add_edge_to(self, block):
- if block not in self.edges_to:
- self.edges_to.append(block)
- block.edges_from.append(self)
- def set_dominates(self, block):
- if block not in self.dominates:
- self.dominates.append(block)
- block.dominated_by.append(self)
- def find_leaders(statements, return_jump_targets=False):
- """
- - Determine the leaders, which are:
- 1. The first statement.
- 2. Any statement that is the target of a jump.
- 3. Any statement that follows directly follows a jump.
- - To determine the leaders, a list of known jump targets is created. This
- list can also be returned for later use.
- """
- leaders = [0]
- jump_targets = []
- # Append statements following jumps and save jump target labels
- for i, statement in enumerate(statements[1:]):
- if statement.is_jump():
- leaders.append(i + 2)
- jump_targets.append(statement[-1])
- # Append jump targets
- for i, statement in enumerate(statements[1:]):
- if i + 1 not in leaders \
- and statement.is_label() \
- and statement.name in jump_targets:
- leaders.append(i + 1)
- leaders.sort()
- return (leaders, jump_targets) if return_jump_targets else leaders
- def find_basic_blocks(statements, return_jump_targets=False):
- """Divide a statement list into basic blocks. Returns a list of basic
- blocks, which are also statement lists."""
- leaders, jump_targets = find_leaders(statements, True)
- blocks = []
- for i in xrange(len(leaders) - 1):
- blocks.append(BasicBlock(statements[leaders[i]:leaders[i + 1]]))
- blocks.append(BasicBlock(statements[leaders[-1]:]))
- # Add a target block for unknown jump targets
- #blocks.append(BasicBlock([], dummy=True))
- return (blocks, jump_targets) if return_jump_targets else blocks
- def generate_flow_graph(blocks):
- """Add flow graph edge administration of an ordered sequence of basic
- blocks."""
- #dummy_block = blocks[-1]
- for i, b in enumerate(blocks):
- last_statement = b[-1]
- if last_statement.is_jump():
- target = last_statement.jump_target()
- # Compare the target to all leading labels, add an edge if the
- # label matches the jump target
- #target_found = False
- for other in blocks:
- if other[0].is_label(target):
- b.add_edge_to(other)
- #target_found = True
- # If the jump target is outside the program, add an edge to the
- # dummy block
- #if not target_found:
- # b.add_edge_to(dummy_block)
- # A branch and jump-and-line instruction also creates an edge to
- # the next block
- if (last_statement.is_branch() or last_statement.name == 'jal') \
- and i < len(blocks) - 1:
- b.add_edge_to(blocks[i + 1])
- elif i < len(blocks) - 1:
- b.add_edge_to(blocks[i + 1])
- def pred(block, known=[]):
- """Recursively find all predecessors of a node."""
- direct = filter(lambda b: b != block and b not in known, block.edges_from)
- p = copy(direct)
- for predecessor in direct:
- p += pred(predecessor, known + direct)
- return p
- return p
- def succ(block, known=[]):
- """Recursively find all successors of a node."""
- direct = filter(lambda b: b != block and b not in known, block.edges_to)
- s = copy(direct)
- for successor in direct:
- s += succ(successor, known + direct)
- return s
- return s
|