(
blocks: list[BasicBlock],
env: ClassIR,
to_spill: set[Value],
live: AnalysisResult[Value],
self_reg: Register,
)
| 32 | |
| 33 | |
| 34 | def spill_regs( |
| 35 | blocks: list[BasicBlock], |
| 36 | env: ClassIR, |
| 37 | to_spill: set[Value], |
| 38 | live: AnalysisResult[Value], |
| 39 | self_reg: Register, |
| 40 | ) -> list[BasicBlock]: |
| 41 | env_reg: Value |
| 42 | for op in blocks[0].ops: |
| 43 | if isinstance(op, GetAttr) and op.attr == "__mypyc_env__": |
| 44 | env_reg = op |
| 45 | break |
| 46 | else: |
| 47 | # Environment has been merged into generator object |
| 48 | env_reg = self_reg |
| 49 | |
| 50 | spill_locs = {} |
| 51 | for i, val in enumerate(to_spill): |
| 52 | name = f"{TEMP_ATTR_NAME}2_{i}" |
| 53 | env.attributes[name] = val.type |
| 54 | if val.type.error_overlap: |
| 55 | # We can safely treat as always initialized, since the type has no pointers. |
| 56 | # This way we also don't need to manage the defined attribute bitfield. |
| 57 | env._always_initialized_attrs.add(name) |
| 58 | spill_locs[val] = name |
| 59 | |
| 60 | for block in blocks: |
| 61 | ops = block.ops |
| 62 | block.ops = [] |
| 63 | |
| 64 | for i, op in enumerate(ops): |
| 65 | to_decref = [] |
| 66 | |
| 67 | if isinstance(op, IncRef) and op.src in spill_locs: |
| 68 | raise AssertionError("not sure what to do with an incref of a spill...") |
| 69 | if isinstance(op, DecRef) and op.src in spill_locs: |
| 70 | # When we decref a spilled value, we turn that into |
| 71 | # NULLing out the attribute, but only if the spilled |
| 72 | # value is not live *when we include yields in the |
| 73 | # CFG*. (The original decrefs are computed without that.) |
| 74 | # |
| 75 | # We also skip a decref is the env register is not |
| 76 | # live. That should only happen when an exception is |
| 77 | # being raised, so everything should be handled there. |
| 78 | if op.src not in live.after[block, i] and env_reg in live.after[block, i]: |
| 79 | # Skip the DecRef but null out the spilled location |
| 80 | null = LoadErrorValue(op.src.type) |
| 81 | block.ops.extend([null, SetAttr(env_reg, spill_locs[op.src], null, op.line)]) |
| 82 | continue |
| 83 | |
| 84 | if ( |
| 85 | any(src in spill_locs for src in op.sources()) |
| 86 | # N.B: IS_ERROR should be before a spill happens |
| 87 | # XXX: but could we have a regular branch? |
| 88 | and not (isinstance(op, Branch) and op.op == Branch.IS_ERROR) |
| 89 | ): |
| 90 | new_sources: list[Value] = [] |
| 91 | stolen = op.stolen() |
no test coverage detected
searching dependent graphs…