Insert inc_refs and/or dec_refs after a branch/goto. Add dec_refs for registers that become dead after a branch. Add inc_refs for registers that become unborrowed after a branch or goto. Branches are special as the true and false targets may have a different live and borrowed regis
(
block: BasicBlock,
cache: BlockCache,
blocks: list[BasicBlock],
pre_live: AnalysisDict[Value],
pre_borrow: AnalysisDict[Value],
post_borrow: AnalysisDict[Value],
post_must_defined: AnalysisDict[Value],
ordering: dict[Value, int],
)
| 159 | |
| 160 | |
| 161 | def insert_branch_inc_and_decrefs( |
| 162 | block: BasicBlock, |
| 163 | cache: BlockCache, |
| 164 | blocks: list[BasicBlock], |
| 165 | pre_live: AnalysisDict[Value], |
| 166 | pre_borrow: AnalysisDict[Value], |
| 167 | post_borrow: AnalysisDict[Value], |
| 168 | post_must_defined: AnalysisDict[Value], |
| 169 | ordering: dict[Value, int], |
| 170 | ) -> None: |
| 171 | """Insert inc_refs and/or dec_refs after a branch/goto. |
| 172 | |
| 173 | Add dec_refs for registers that become dead after a branch. |
| 174 | Add inc_refs for registers that become unborrowed after a branch or goto. |
| 175 | |
| 176 | Branches are special as the true and false targets may have a different |
| 177 | live and borrowed register sets. Add new blocks before the true/false target |
| 178 | blocks that tweak reference counts. |
| 179 | |
| 180 | Example where we need to add an inc_ref: |
| 181 | |
| 182 | def f(a: int) -> None |
| 183 | if a: |
| 184 | a = 1 |
| 185 | return a # a is borrowed if condition is false and unborrowed if true |
| 186 | """ |
| 187 | prev_key = (block, len(block.ops) - 1) |
| 188 | source_live_regs = pre_live[prev_key] |
| 189 | source_borrowed = post_borrow[prev_key] |
| 190 | source_defined = post_must_defined[prev_key] |
| 191 | |
| 192 | term = block.terminator |
| 193 | for i, target in enumerate(term.targets()): |
| 194 | # HAX: After we've checked against an error value the value we must not touch the |
| 195 | # refcount since it will be a null pointer. The correct way to do this would be |
| 196 | # to perform data flow analysis on whether a value can be null (or is always |
| 197 | # null). |
| 198 | omitted: Iterable[Value] |
| 199 | if isinstance(term, Branch) and term.op == Branch.IS_ERROR and i == 0: |
| 200 | omitted = (term.value,) |
| 201 | else: |
| 202 | omitted = () |
| 203 | |
| 204 | decs = after_branch_decrefs( |
| 205 | target, pre_live, source_defined, source_borrowed, source_live_regs, ordering, omitted |
| 206 | ) |
| 207 | incs = after_branch_increfs(target, pre_live, pre_borrow, source_borrowed, ordering) |
| 208 | term.set_target(i, add_block(decs, incs, cache, blocks, target)) |
| 209 | |
| 210 | |
| 211 | def after_branch_decrefs( |
no test coverage detected
searching dependent graphs…