Ejemplo n.º 1
0
 def _start_new_block(self, offset):
     oldblock = self.current_block
     self.insert_block(offset)
     # Ensure the last block is terminated
     if oldblock is not None and not oldblock.is_terminated:
         # Handle ending try block.
         tryblk = self.dfainfo.active_try_block
         # If there's an active try-block and the handler block is live.
         if tryblk is not None and tryblk["end"] in self.cfa.graph.nodes():
             # We are in a try-block, insert a branch to except-block.
             # This logic cannot be in self._end_current_block()
             # because we the non-raising next block-offset.
             branch = ir.Branch(
                 cond=self.get("$exception_check"),
                 truebr=tryblk["end"],
                 falsebr=offset,
                 loc=self.loc,
             )
             oldblock.append(branch)
         # Handle normal case
         else:
             jmp = ir.Jump(offset, loc=self.loc)
             oldblock.append(jmp)
     # Get DFA block info
     self.dfainfo = self.dfa.infos[self.current_block_offset]
     self.assigner = Assigner()
     # Check out-of-scope syntactic-block
     while self.syntax_blocks:
         if offset >= self.syntax_blocks[-1].exit:
             self.syntax_blocks.pop()
         else:
             break
Ejemplo n.º 2
0
    def op_FOR_ITER(self, inst, iterator, pair, indval, pred):
        """
        Assign new block other this instruction.
        """
        assert inst.offset in self.blocks, "FOR_ITER must be block head"

        # Emit code
        val = self.get(iterator)

        pairval = ir.Expr.iternext(value=val, loc=self.loc)
        self.store(pairval, pair)

        iternext = ir.Expr.pair_first(value=self.get(pair), loc=self.loc)
        self.store(iternext, indval)

        isvalid = ir.Expr.pair_second(value=self.get(pair), loc=self.loc)
        self.store(isvalid, pred)

        # Conditional jump
        br = ir.Branch(
            cond=self.get(pred),
            truebr=inst.next,
            falsebr=inst.get_jump_target(),
            loc=self.loc,
        )
        self.current_block.append(br)
Ejemplo n.º 3
0
 def _op_JUMP_IF(self, inst, pred, iftrue):
     brs = {
         True: inst.get_jump_target(),
         False: inst.next,
     }
     truebr = brs[iftrue]
     falsebr = brs[not iftrue]
     bra = ir.Branch(cond=self.get(pred), truebr=truebr, falsebr=falsebr,
                     loc=self.loc)
     self.current_block.append(bra)
Ejemplo n.º 4
0
 def test_branch(self):
     a = ir.Branch(self.var_a, 1, 2, self.loc1)
     b = ir.Branch(self.var_a, 1, 2, self.loc1)
     c = ir.Branch(self.var_a, 1, 2, self.loc2)
     d = ir.Branch(self.var_b, 1, 2, self.loc1)
     e = ir.Branch(self.var_a, 2, 2, self.loc1)
     f = ir.Branch(self.var_a, 1, 3, self.loc1)
     self.check(a, same=[b, c], different=[d, e, f])
Ejemplo n.º 5
0
    def replace_target(term, src, dst):
        def replace(target):
            return (dst if target == src else target)

        if isinstance(term, ir.Branch):
            return ir.Branch(cond=term.cond,
                             truebr=replace(term.truebr),
                             falsebr=replace(term.falsebr),
                             loc=term.loc)
        elif isinstance(term, ir.Jump):
            return ir.Jump(target=replace(term.target), loc=term.loc)
        else:
            assert not term.get_targets()
            return term
Ejemplo n.º 6
0
    def _op_JUMP_IF(self, inst, pred, iftrue):
        brs = {
            True: inst.get_jump_target(),
            False: inst.next,
        }
        truebr = brs[iftrue]
        falsebr = brs[not iftrue]

        name = "bool%s" % (inst.offset)
        gv_fn = ir.Global("bool", bool, loc=self.loc)
        self.store(value=gv_fn, name=name)

        callres = ir.Expr.call(self.get(name), (self.get(pred),), (),
                               loc=self.loc)

        pname = "$%spred" % (inst.offset)
        predicate = self.store(value=callres, name=pname)
        bra = ir.Branch(cond=predicate, truebr=truebr, falsebr=falsebr,
                        loc=self.loc)
        self.current_block.append(bra)
Ejemplo n.º 7
0
def _fix_multi_exit_blocks(func_ir, exit_nodes, *, split_condition=None):
    """Modify the FunctionIR to create a single common exit node given the
    original exit nodes.

    Parameters
    ----------
    func_ir :
        The FunctionIR. Mutated inplace.
    exit_nodes :
        The original exit nodes. A sequence of block keys.
    split_condition : callable or None
        If not None, it is a callable with the signature
        `split_condition(statement)` that determines if the `statement` is the
        splitting point (e.g. `POP_BLOCK`) in an exit node.
        If it's None, the exit node is not split.
    """

    # Convert the following:
    #
    #     |           |
    # +-------+   +-------+
    # | exit0 |   | exit1 |
    # +-------+   +-------+
    #     |           |
    # +-------+   +-------+
    # | after0|   | after1|
    # +-------+   +-------+
    #     |           |
    #
    # To roughly:
    #
    #     |           |
    # +-------+   +-------+
    # | exit0 |   | exit1 |
    # +-------+   +-------+
    #     |           |
    #     +-----+-----+
    #           |
    #      +---------+
    #      | common  |
    #      +---------+
    #           |
    #       +-------+
    #       | post  |
    #       +-------+
    #           |
    #     +-----+-----+
    #     |           |
    # +-------+   +-------+
    # | after0|   | after1|
    # +-------+   +-------+

    blocks = func_ir.blocks
    # Getting the scope
    any_blk = min(func_ir.blocks.values())
    scope = any_blk.scope
    # Getting the maximum block label
    max_label = max(func_ir.blocks) + 1
    # Define the new common block for the new exit.
    common_block = ir.Block(any_blk.scope, loc=ir.unknown_loc)
    common_label = max_label
    max_label += 1
    blocks[common_label] = common_block
    # Define the new block after the exit.
    post_block = ir.Block(any_blk.scope, loc=ir.unknown_loc)
    post_label = max_label
    max_label += 1
    blocks[post_label] = post_block

    # Adjust each exit node
    remainings = []
    for i, k in enumerate(exit_nodes):
        blk = blocks[k]

        # split the block if needed
        if split_condition is not None:
            for pt, stmt in enumerate(blk.body):
                if split_condition(stmt):
                    break
        else:
            # no splitting
            pt = -1

        before = blk.body[:pt]
        after = blk.body[pt:]
        remainings.append(after)

        # Add control-point variable to mark which exit block this is.
        blk.body = before
        loc = blk.loc
        blk.body.append(
            ir.Assign(value=ir.Const(i, loc=loc),
                      target=scope.get_or_define("$cp", loc=loc),
                      loc=loc))
        # Replace terminator with a jump to the common block
        assert not blk.is_terminated
        blk.body.append(ir.Jump(common_label, loc=ir.unknown_loc))

    if split_condition is not None:
        # Move the splitting statement to the common block
        common_block.body.append(remainings[0][0])
    assert not common_block.is_terminated
    # Append jump from common block to post block
    common_block.body.append(ir.Jump(post_label, loc=loc))

    # Make if-else tree to jump to target
    remain_blocks = []
    for remain in remainings:
        remain_blocks.append(max_label)
        max_label += 1

    switch_block = post_block
    loc = ir.unknown_loc
    for i, remain in enumerate(remainings):
        match_expr = scope.redefine("$cp_check", loc=loc)
        match_rhs = scope.redefine("$cp_rhs", loc=loc)

        # Do comparison to match control-point variable to the exit block
        switch_block.body.append(
            ir.Assign(value=ir.Const(i, loc=loc), target=match_rhs, loc=loc), )

        # Add assignment for the comparison
        switch_block.body.append(
            ir.Assign(value=ir.Expr.binop(
                fn=operator.eq,
                lhs=scope.get("$cp"),
                rhs=match_rhs,
                loc=loc,
            ),
                      target=match_expr,
                      loc=loc), )

        # Insert jump to the next case
        [jump_target] = remain[-1].get_targets()
        switch_block.body.append(
            ir.Branch(match_expr, jump_target, remain_blocks[i], loc=loc), )
        switch_block = ir.Block(scope=scope, loc=loc)
        blocks[remain_blocks[i]] = switch_block

    # Add the final jump
    switch_block.body.append(ir.Jump(jump_target, loc=loc))

    return func_ir, common_label