def find_natural_loops(func, cfg=None): """Return a loop nesting forest for the given function ([Loop])""" cfg = cfg or cfa.cfg(func) dominators = cfa.compute_dominators(func, cfg) loops = [] loop_stack = [] for block in func.blocks: ### Look for incoming back-edge for pred in cfg.predecessors(block): if block in dominators[pred]: # We dominate an incoming block, this means there is a # back-edge (pred, block) loop_stack.append(Loop([block])) ### Populate Loop if loop_stack: loop = loop_stack[-1] head = loop.blocks[0] if head in dominators[block] and head != block: # Dominated by loop header, add loop.blocks.append(block) if head in cfg[block]: loop_stack.pop() if loop_stack: # update outer loop loop_stack[-1].blocks.extend(loop.blocks) loop_stack[-1].children.append(loop) else: # outermost loop, add to forest loops.append(loop) assert not loop_stack return loops
def verify_block_order(func): """Verify block order according to dominator tree""" from pykit.analysis import cfa flow = cfa.cfg(func) dominators = cfa.compute_dominators(func, flow) visited = set() for block in func.blocks: visited.add(block.name) for dominator in dominators[block.name]: if dominator not in visited: raise VerifyError("Dominator %s does not precede block %s" % ( dominator, block.name))