def after_branch_decrefs(label: Label, pre_live: AnalysisDict, source_borrowed: Set[Register], source_live_regs: Set[Register], env: Environment) -> List[Op]: target_pre_live = pre_live[label, 0] decref = source_live_regs - target_pre_live - source_borrowed if decref: return [DecRef(reg, env.types[reg]) for reg in sorted(decref)] return []
def add_block(decincs: DecIncs, cache: BlockCache, blocks: List[BasicBlock], label: BasicBlock) -> BasicBlock: decs, incs = decincs if not decs and not incs: return label # TODO: be able to share *partial* results if (label, decincs) in cache: return cache[label, decincs] block = BasicBlock() blocks.append(block) block.ops.extend(DecRef(reg, is_xdec=xdec) for reg, xdec in decs) block.ops.extend(IncRef(reg) for reg in incs) block.ops.append(Goto(label)) cache[label, decincs] = block return block
def transform_block(block: BasicBlock, pre_live: AnalysisDict[Register], post_live: AnalysisDict[Register], pre_borrow: AnalysisDict[Register], env: Environment) -> None: old_ops = block.ops ops = [] # type: List[Op] for i, op in enumerate(old_ops): key = (block.label, i) if isinstance(op, (Assign, Cast, Box)): # These operations just copy/steal a reference and don't create new # references. if op.src in post_live[key] or op.src in pre_borrow[key]: ops.append(IncRef(op.src, env.types[op.src])) if (op.dest not in pre_borrow[key] and op.dest in pre_live[key]): ops.append(DecRef(op.dest, env.types[op.dest])) ops.append(op) if op.dest not in post_live[key]: ops.append(DecRef(op.dest, env.types[op.dest])) elif isinstance(op, RegisterOp): # These operations construct a new reference. tmp_reg = None # type: Optional[Register] if (op.dest not in pre_borrow[key] and op.dest in pre_live[key]): if op.dest not in op.sources(): ops.append(DecRef(op.dest, env.types[op.dest])) else: tmp_reg = env.add_temp(env.types[op.dest]) ops.append(Assign(tmp_reg, op.dest)) ops.append(op) for src in op.unique_sources(): # Decrement source that won't be live afterwards. if src not in post_live[key] and src not in pre_borrow[key]: if src != op.dest: ops.append(DecRef(src, env.types[src])) if op.dest is not None and op.dest not in post_live[key]: ops.append(DecRef(op.dest, env.types[op.dest])) if tmp_reg is not None: ops.append(DecRef(tmp_reg, env.types[tmp_reg])) elif isinstance(op, Return) and op.reg in pre_borrow[key]: # The return op returns a new reference. ops.append(IncRef(op.reg, env.types[op.reg])) ops.append(op) else: ops.append(op) block.ops = ops
def test_dec_ref_tuple_nested(self) -> None: self.assert_emit(DecRef(self.tt), 'CPyTagged_DecRef(cpy_r_tt.f0.f0);')
def test_dec_ref(self) -> None: self.assert_emit(DecRef(self.m), "CPyTagged_DecRef(cpy_r_m);")
def maybe_append_dec_ref(ops: List[Op], dest: Value, defined: 'AnalysisDict[Value]', key: Tuple[BasicBlock, int]) -> None: if dest.type.is_refcounted: ops.append(DecRef(dest, is_xdec=is_maybe_undefined(defined[key], dest)))
def maybe_append_dec_ref(ops: List[Op], dest: Value) -> None: if dest.type.is_refcounted: ops.append(DecRef(dest))
def test_dec_ref_tuple_nested(self) -> None: tuple_type = TupleRType( [TupleRType([IntRType(), BoolRType()]), BoolRType()]) self.assert_emit(DecRef(self.m, tuple_type), 'CPyTagged_DecRef(cpy_r_m.f0.f0);')