A "low-level" IR builder class. LowLevelIRBuilder provides core abstractions we use for constructing IR as well as a number of higher-level ones (accessing attributes, calling functions and methods, and coercing between types, for example). The core principle of the low-level I
| 250 | |
| 251 | |
| 252 | class LowLevelIRBuilder: |
| 253 | """A "low-level" IR builder class. |
| 254 | |
| 255 | LowLevelIRBuilder provides core abstractions we use for constructing |
| 256 | IR as well as a number of higher-level ones (accessing attributes, |
| 257 | calling functions and methods, and coercing between types, for |
| 258 | example). |
| 259 | |
| 260 | The core principle of the low-level IR builder is that all of its |
| 261 | facilities operate solely on the mypyc IR level and not the mypy AST |
| 262 | level---it has *no knowledge* of mypy types or expressions. |
| 263 | |
| 264 | The mypyc.irbuilder.builder.IRBuilder class wraps an instance of this |
| 265 | class and provides additional functionality to transform mypy AST nodes |
| 266 | to IR. |
| 267 | """ |
| 268 | |
| 269 | def __init__(self, errors: Errors | None, options: CompilerOptions) -> None: |
| 270 | self.errors = errors |
| 271 | self.options = options |
| 272 | self.args: list[Register] = [] |
| 273 | self.blocks: list[BasicBlock] = [] |
| 274 | # Stack of except handler entry blocks |
| 275 | self.error_handlers: list[BasicBlock | None] = [None] |
| 276 | # Values that we need to keep alive as long as we have borrowed |
| 277 | # temporaries. Use flush_keep_alives() to mark the end of the live range. |
| 278 | self.keep_alives: list[Value] = [] |
| 279 | |
| 280 | def set_module(self, module_name: str, module_path: str) -> None: |
| 281 | """Set the name and path of the current module.""" |
| 282 | self.module_name = module_name |
| 283 | self.module_path = module_path |
| 284 | |
| 285 | # Basic operations |
| 286 | |
| 287 | def add(self, op: Op) -> Value: |
| 288 | """Add an op.""" |
| 289 | assert not self.blocks[-1].terminated, "Can't add to finished block" |
| 290 | self.blocks[-1].ops.append(op) |
| 291 | return op |
| 292 | |
| 293 | def assign(self, lvalue: Register, rvalue: Value | int) -> None: |
| 294 | if isinstance(rvalue, int): |
| 295 | rvalue = Integer(rvalue, lvalue.type) |
| 296 | self.add(Assign(lvalue, rvalue)) |
| 297 | |
| 298 | def goto(self, target: BasicBlock) -> None: |
| 299 | """Add goto to a basic block.""" |
| 300 | if not self.blocks[-1].terminated: |
| 301 | self.add(Goto(target)) |
| 302 | |
| 303 | def activate_block(self, block: BasicBlock) -> None: |
| 304 | """Add a basic block and make it the active one (target of adds).""" |
| 305 | if self.blocks: |
| 306 | assert self.blocks[-1].terminated |
| 307 | |
| 308 | block.error_handler = self.error_handlers[-1] |
| 309 | self.blocks.append(block) |
no outgoing calls
searching dependent graphs…