| 187 | |
| 188 | @dataclass |
| 189 | class Uop: |
| 190 | name: str |
| 191 | context: parser.Context | None |
| 192 | annotations: list[str] |
| 193 | stack: StackEffect |
| 194 | caches: list[CacheEntry] |
| 195 | local_stores: list[lexer.Token] |
| 196 | body: BlockStmt |
| 197 | properties: Properties |
| 198 | _size: int = -1 |
| 199 | implicitly_created: bool = False |
| 200 | replicated = range(0) |
| 201 | replicates: "Uop | None" = None |
| 202 | # Size of the instruction(s), only set for uops containing the INSTRUCTION_SIZE macro |
| 203 | instruction_size: int | None = None |
| 204 | |
| 205 | def dump(self, indent: str) -> None: |
| 206 | print( |
| 207 | indent, self.name, ", ".join(self.annotations) if self.annotations else "" |
| 208 | ) |
| 209 | print(indent, self.stack, ", ".join([str(c) for c in self.caches])) |
| 210 | self.properties.dump(" " + indent) |
| 211 | |
| 212 | @property |
| 213 | def size(self) -> int: |
| 214 | if self._size < 0: |
| 215 | self._size = sum(c.size for c in self.caches) |
| 216 | return self._size |
| 217 | |
| 218 | def why_not_viable(self) -> str | None: |
| 219 | if self.name == "_SAVE_RETURN_OFFSET": |
| 220 | return None # Adjusts next_instr, but only in tier 1 code |
| 221 | if "INSTRUMENTED" in self.name: |
| 222 | return "is instrumented" |
| 223 | if "replaced" in self.annotations: |
| 224 | return "is replaced" |
| 225 | if self.name in ("INTERPRETER_EXIT", "JUMP_BACKWARD"): |
| 226 | return "has tier 1 control flow" |
| 227 | if self.properties.needs_this: |
| 228 | return "uses the 'this_instr' variable" |
| 229 | if len([c for c in self.caches if c.name != "unused"]) > 2: |
| 230 | return "has too many cache entries" |
| 231 | if self.properties.error_with_pop and self.properties.error_without_pop: |
| 232 | return "has both popping and not-popping errors" |
| 233 | return None |
| 234 | |
| 235 | def is_viable(self) -> bool: |
| 236 | return self.why_not_viable() is None |
| 237 | |
| 238 | def is_super(self) -> bool: |
| 239 | for tkn in self.body.tokens(): |
| 240 | if tkn.kind == "IDENTIFIER" and tkn.text == "oparg1": |
| 241 | return True |
| 242 | return False |
| 243 | |
| 244 | |
| 245 | class Label: |