Exemple #1
0
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
Exemple #2
0
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
Exemple #3
0
def sccp(func, constantfolder=None):
    """
    Perform Sparse conditional constant propagation. The idea is to have two
    queues, one for blocks and one for SSA variables (Ops).
    Blocks must be processed whole, which is a dense operation. Subsequent
    changes to live code are then sparse operations using the SSA info.

    When reaching the end of a block started by a CFG edge,
    we add new edges iff we have an unconditional branch. After all, we are
    executing optimistically, which means we cannot tell whether the
    destination blocks are live.

    Note that we can perform no modifications until after the algorithm
    terminates, since the cells are only correct after termination.

    Returns
    =======
    constmap: A dict mapping Ops to Consts
    deadblock: A set of dead basic blocks
    """
    # Object that folds operations with constant inputs
    constantfolder = constantfolder or ConstantFolder()

    # Mapping of CFG edges (block1, block2) to indicate whether there exists
    # some runtime path from block1 to block2. Blocks without any incoming
    # runtime path are not explored.
    executable = defaultdict(bool)

    # Control flow graph (networkx.DiGraph)
    cfg = cfa.cfg(func)

    cfedges = deque([(None, func.startblock)]) # remaining cfg edges
    ssavars = deque()           # SSA edges: (Op, Op)
    cells   = defaultdict(cell) # Cells holding lattice values
    processed = set()           # Set of processed blocks

    # Initialize all constants in cells
    vmap(partial(initialize, cells), func)

    while cfedges or ssavars:
        if cfedges:
            src, dst = cfedges.popleft()
            if not executable[src, dst]:
                # Process each block only once for each predecessor
                executable[src, dst] = True
                # process_phis(dst, constantfolder, cells, ssavars)
                if dst not in processed:
                    # This is the first time we visit this block, process body
                    processed.add(dst)
                    process_body(constantfolder, dst, cfg, cells, ssavars, cfedges)

        else:
            defop, op = ssavars.popleft()
            if executable[defop.block, op.block]:
                # Only handle live code !
                process_expr(constantfolder, op, cells, ssavars)

    deadblocks = set(func.blocks) - processed
    return deadblocks, cells, cfg
Exemple #4
0
def sccp(func, constantfolder=None):
    """
    Perform Sparse conditional constant propagation. The idea is to have two
    queues, one for blocks and one for SSA variables (Ops).
    Blocks must be processed whole, which is a dense operation. Subsequent
    changes to live code are then sparse operations using the SSA info.

    When reaching the end of a block started by a CFG edge,
    we add new edges iff we have an unconditional branch. After all, we are
    executing optimistically, which means we cannot tell whether the
    destination blocks are live.

    Note that we can perform no modifications until after the algorithm
    terminates, since the cells are only correct after termination.

    Returns
    =======
    constmap: A dict mapping Ops to Consts
    deadblock: A set of dead basic blocks
    """
    # Mapping of CFG edges (block1, block2) to indicate whether there exists
    # some runtime path from block1 to block2. Blocks without any incoming
    # runtime path are not explored.
    executable = defaultdict(bool)

    # Object that folds operations with constant inputs
    constantfolder = constantfolder or SCCPFolder(executable)

    # Control flow graph (networkx.DiGraph)
    cfg = cfa.cfg(func)

    cfedges = deque([(None, func.startblock)]) # remaining cfg edges
    ssavars = deque()           # SSA edges: (Op, Op)
    cells   = defaultdict(cell) # Cells holding lattice values
    processed = set()           # Set of processed blocks

    # Initialize all constants in cells
    vmap(partial(initialize, cells), func)

    while cfedges or ssavars:
        if cfedges:
            src, dst = cfedges.popleft()
            if not executable[src, dst]:
                # Process each block only once for each predecessor
                executable[src, dst] = True
                # process_phis(dst, constantfolder, cells, ssavars)
                if dst not in processed:
                    # This is the first time we visit this block, process body
                    processed.add(dst)
                    process_body(constantfolder, dst, cfg, cells, ssavars, cfedges)

        else:
            defop, op = ssavars.popleft()
            if executable[defop.block, op.block]:
                # Only handle live code !
                process_expr(constantfolder, op, cells, ssavars)

    deadblocks = set(func.blocks) - processed
    return deadblocks, cells, cfg
Exemple #5
0
    def test_cfg(self):
        mod = from_c(source)
        f = mod.get_function('func_simple')
        verify(f)
        flow = cfa.cfg(f)

        cond_block = findop(f, 'cbranch').block
        self.assertEqual(len(flow[cond_block]), 2)
Exemple #6
0
    def test_cfg(self):
        mod = from_c(source)
        f = mod.get_function('func_simple')
        verify(f)
        flow = cfa.cfg(f)

        cond_block = findop(f, 'cbranch').block
        self.assertEqual(len(flow[cond_block]), 2)
Exemple #7
0
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))
Exemple #8
0
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))
Exemple #9
0
def update_outdated_incoming_blocks(func, candidates):
    """
    Update phi nodes in blocks previously containing 'exc_catch'. 'exc_setup'
    may span many blocks, and none, or only a subset of those blocks may be
    actual predecessors.
    """
    cfg = cfa.cfg(func)
    for block in candidates:
        preds = cfg.predecessors(block)
        for op in block.leaders:
            if op.opcode == 'phi':
                blocks, values = op.args
                newblocks = [block for block in blocks if block in preds]
                newvalues = [val for block, val in zip(blocks, values)
                                     if block in preds]
                assert len(newblocks) == len(preds), (op.block, newblocks,
                                                      preds, blocks)
                op.set_args([newblocks, newvalues])
Exemple #10
0
def update_outdated_incoming_blocks(func, candidates):
    """
    Update phi nodes in blocks previously containing 'exc_catch'. 'exc_setup'
    may span many blocks, and none, or only a subset of those blocks may be
    actual predecessors.
    """
    cfg = cfa.cfg(func)
    for block in candidates:
        preds = cfg.predecessors(block)
        for op in block.leaders:
            if op.opcode == 'phi':
                blocks, values = op.args
                newblocks = [block for block in blocks if block in preds]
                newvalues = [
                    val for block, val in zip(blocks, values) if block in preds
                ]
                assert len(newblocks) == len(preds), (op.block, newblocks,
                                                      preds, blocks)
                op.set_args([newblocks, newvalues])
Exemple #11
0
def dataflow(func, env, sync_context=True):
    """
    Move all allocas to the start block and then use pykit's SSA pass.
    We can move all allocas since all our objects are immutable
    """
    allocas = [op for op in func.ops if op.opcode == 'alloca']
    cfa.move_allocas(func, allocas)

    CFG = cfa.cfg(func)
    phis = cfa.ssa(func, CFG)

    if sync_context:
        context = env['flypy.typing.context']
        for phi, alloc in phis.iteritems():
            type = context[alloc]
            context[phi] = type
            for arg in phi.args[1]:
                if isinstance(arg, Undef):
                    context[arg] = type
Exemple #12
0
def dataflow(func, env, sync_context=True):
    """
    Move all allocas to the start block and then use pykit's SSA pass.
    We can move all allocas since all our objects are immutable
    """
    allocas = [op for op in func.ops if op.opcode == 'alloca']
    cfa.move_allocas(func, allocas)

    CFG = cfa.cfg(func)
    phis = cfa.ssa(func, CFG)

    if sync_context:
        context = env['flypy.typing.context']
        for phi, alloc in phis.iteritems():
            type = context[alloc]
            context[phi] = type
            for arg in phi.args[1]:
                if isinstance(arg, Undef):
                    context[arg] = type
Exemple #13
0
    def test_ssa(self):
        mod = from_c(source)
        f = mod.get_function('func_simple')
        verify(f)
        self.assertEqual(opcodes(f.startblock),
                         ['alloca', 'store', 'load', 'gt', 'cbranch'])

        # SSA
        CFG = cfa.cfg(f)
        cfa.ssa(f, CFG)

        assert len(f.blocks) == 4
        blocks = list(f.blocks)
        self.assertEqual(opcodes(blocks[0]), ['gt', 'cbranch'])
        self.assertEqual(opcodes(blocks[1]), ['jump'])
        self.assertEqual(opcodes(blocks[2]), ['jump'])
        self.assertEqual(opcodes(blocks[3]), ['phi', 'ret'])

        phi = findop(f, 'phi')
        iblocks, ivals = phi.args
        self.assertEqual(sorted(iblocks), sorted([blocks[1], blocks[2]]))
        self.assertEqual(len(ivals), 2)
Exemple #14
0
    def test_ssa(self):
        mod = from_c(source)
        f = mod.get_function('func_simple')
        verify(f)
        self.assertEqual(opcodes(f.startblock),
                         ['alloca', 'store', 'load', 'gt', 'cbranch'])

        # SSA
        CFG = cfa.cfg(f)
        cfa.ssa(f, CFG)

        assert len(f.blocks) == 4
        blocks = list(f.blocks)
        self.assertEqual(opcodes(blocks[0]), ['gt', 'cbranch'])
        self.assertEqual(opcodes(blocks[1]), ['jump'])
        self.assertEqual(opcodes(blocks[2]), ['jump'])
        self.assertEqual(opcodes(blocks[3]), ['phi', 'convert', 'ret'])

        phi = findop(f, 'phi')
        iblocks, ivals = phi.args
        self.assertEqual(sorted(iblocks), sorted([blocks[1], blocks[2]]))
        self.assertEqual(len(ivals), 2)
Exemple #15
0
def run(func, env):
    cfg = cfa.cfg(func)
    deadblocks = cfa.find_dead_blocks(func, cfg)
    cfa.delete_blocks(func, cfg, deadblocks)
Exemple #16
0
def dump_cfg(func, env, fancy):
    CFG = cfa.cfg(func)
    viz.dump(CFG.nx, os.path.expanduser("~/cfg.dot"))
Exemple #17
0
def run(func, env):
    cfg = cfa.cfg(func)
    deadblocks = cfa.find_dead_blocks(func, cfg)
    cfa.delete_blocks(func, cfg, deadblocks)
Exemple #18
0
def reg2mem(func, env=None):
    cfg = cfa.cfg(func, exceptions=False)  # ignore exc_setup
    split_critical_edges(func, cfg, find_phis(func))
    vars, loads = generate_copies(func, find_phis(func))
    return vars, loads
Exemple #19
0
def reg2mem(func, env=None):
    cfg = cfa.cfg(func, exceptions=False) # ignore exc_setup
    split_critical_edges(func, cfg, find_phis(func))
    vars, loads = generate_copies(func, find_phis(func))
    return vars, loads
Exemple #20
0
def dump_cfg(func, env, fancy):
    CFG = cfa.cfg(func)
    viz.dump(CFG.nx, os.path.expanduser("~/cfg.dot"))