def insert_ref_count_opcodes(ir: FuncIR) -> None: """Insert reference count inc/dec opcodes to a function. This is the entry point to this module. """ cfg = get_cfg(ir.blocks) borrowed = set(reg for reg in ir.env.regs() if reg.is_borrowed) args = set(reg for reg in ir.env.regs() if ir.env.indexes[reg] < len(ir.args)) regs = [reg for reg in ir.env.regs() if isinstance(reg, Register)] live = analyze_live_regs(ir.blocks, cfg) borrow = analyze_borrowed_arguments(ir.blocks, cfg, borrowed) defined = analyze_must_defined_regs(ir.blocks, cfg, args, regs) cache = {} # type: BlockCache for block in ir.blocks[:]: if isinstance(block.ops[-1], (Branch, Goto)): insert_branch_inc_and_decrefs(block, cache, ir.blocks, live.before, borrow.before, borrow.after, defined.after, ir.env) transform_block(block, live.before, live.after, borrow.before, defined.after, ir.env) # Find all the xdecs we inserted and note the registers down as # needing to be initialized. for block in ir.blocks: for op in block.ops: if isinstance(op, DecRef) and op.is_xdec: ir.env.vars_needing_init.add(op.src) cleanup_cfg(ir.blocks)
def insert_uninit_checks(ir: FuncIR) -> None: # Remove dead blocks from the CFG, which helps avoid spurious # checks due to unused error handling blocks. cleanup_cfg(ir.blocks) cfg = get_cfg(ir.blocks) args = set(reg for reg in ir.env.regs() if ir.env.indexes[reg] < len(ir.args)) must_defined = analyze_must_defined_regs(ir.blocks, cfg, args, ir.env.regs()) ir.blocks = split_blocks_at_uninits(ir.env, ir.blocks, must_defined.before)