Find attributes that are always initialized in some basic blocks. The analysis results are expected to be up-to-date for the blocks. Return a set of always defined attributes.
(
blocks: list[BasicBlock],
self_reg: Register,
all_attrs: set[str],
maybe_defined: AnalysisResult[str],
maybe_undefined: AnalysisResult[str],
dirty: AnalysisResult[None],
)
| 190 | |
| 191 | |
| 192 | def find_always_defined_attributes( |
| 193 | blocks: list[BasicBlock], |
| 194 | self_reg: Register, |
| 195 | all_attrs: set[str], |
| 196 | maybe_defined: AnalysisResult[str], |
| 197 | maybe_undefined: AnalysisResult[str], |
| 198 | dirty: AnalysisResult[None], |
| 199 | ) -> set[str]: |
| 200 | """Find attributes that are always initialized in some basic blocks. |
| 201 | |
| 202 | The analysis results are expected to be up-to-date for the blocks. |
| 203 | |
| 204 | Return a set of always defined attributes. |
| 205 | """ |
| 206 | attrs = all_attrs.copy() |
| 207 | for block in blocks: |
| 208 | for i, op in enumerate(block.ops): |
| 209 | # If an attribute we *read* may be undefined, it isn't always defined. |
| 210 | if isinstance(op, GetAttr) and op.obj is self_reg: |
| 211 | if op.attr in maybe_undefined.before[block, i]: |
| 212 | attrs.discard(op.attr) |
| 213 | # If an attribute we *set* may be sometimes undefined and |
| 214 | # sometimes defined, don't consider it always defined. Unlike |
| 215 | # the get case, it's fine for the attribute to be undefined. |
| 216 | # The set operation will then be treated as initialization. |
| 217 | if isinstance(op, SetAttr) and op.obj is self_reg: |
| 218 | if ( |
| 219 | op.attr in maybe_undefined.before[block, i] |
| 220 | and op.attr in maybe_defined.before[block, i] |
| 221 | ): |
| 222 | attrs.discard(op.attr) |
| 223 | # Treat an op that might run arbitrary code as an "exit" |
| 224 | # in terms of the analysis -- we can't do any inference |
| 225 | # afterwards reliably. |
| 226 | if dirty.after[block, i]: |
| 227 | if not dirty.before[block, i]: |
| 228 | attrs = attrs & ( |
| 229 | maybe_defined.after[block, i] - maybe_undefined.after[block, i] |
| 230 | ) |
| 231 | break |
| 232 | if isinstance(op, ControlOp): |
| 233 | for target in op.targets(): |
| 234 | # Gotos/branches can also be "exits". |
| 235 | if not dirty.after[block, i] and dirty.before[target, 0]: |
| 236 | attrs = attrs & ( |
| 237 | maybe_defined.after[target, 0] - maybe_undefined.after[target, 0] |
| 238 | ) |
| 239 | return attrs |
| 240 | |
| 241 | |
| 242 | def find_sometimes_defined_attributes( |
no test coverage detected
searching dependent graphs…