Skip to content

Commit

Permalink
[mypyc] Provide an easier way to define IR-to-IR transforms (#16998)
Browse files Browse the repository at this point in the history
This makes it easy to define simple IR-to-IR transforms by subclassing
`IRTansform` and overriding some visit methods.

Add an implementation of a simple copy propagation optimization as an
example.

This will be used by the implementation of mypyc/mypyc#854, and this can
also be used for various optimizations.

The IR transform preserves the identities of ops that are not modified.
This means that the old IR is no longer valid after the transform, but
the transform can be fast since we don't need to allocate many objects
if only a small subset of ops will be modified by a transform.
  • Loading branch information
JukkaL authored Mar 9, 2024
1 parent e0ad952 commit c94d8e3
Show file tree
Hide file tree
Showing 7 changed files with 904 additions and 17 deletions.
13 changes: 6 additions & 7 deletions mypyc/codegen/emitmodule.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
from mypyc.irbuild.prepare import load_type_map
from mypyc.namegen import NameGenerator, exported_name
from mypyc.options import CompilerOptions
from mypyc.transform.copy_propagation import do_copy_propagation
from mypyc.transform.exceptions import insert_exception_handling
from mypyc.transform.refcount import insert_ref_count_opcodes
from mypyc.transform.uninit import insert_uninit_checks
Expand Down Expand Up @@ -225,18 +226,16 @@ def compile_scc_to_ir(
if errors.num_errors > 0:
return modules

# Insert uninit checks.
for module in modules.values():
for fn in module.functions:
# Insert uninit checks.
insert_uninit_checks(fn)
# Insert exception handling.
for module in modules.values():
for fn in module.functions:
# Insert exception handling.
insert_exception_handling(fn)
# Insert refcount handling.
for module in modules.values():
for fn in module.functions:
# Insert refcount handling.
insert_ref_count_opcodes(fn)
# Perform copy propagation optimization.
do_copy_propagation(fn, compiler_options)

return modules

Expand Down
6 changes: 2 additions & 4 deletions mypyc/irbuild/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ def __init__(
options: CompilerOptions,
singledispatch_impls: dict[FuncDef, list[RegisterImplInfo]],
) -> None:
self.builder = LowLevelIRBuilder(current_module, errors, mapper, options)
self.builder = LowLevelIRBuilder(errors, options)
self.builders = [self.builder]
self.symtables: list[dict[SymbolNode, SymbolTarget]] = [{}]
self.runtime_args: list[list[RuntimeArg]] = [[]]
Expand Down Expand Up @@ -1111,9 +1111,7 @@ def flatten_classes(self, arg: RefExpr | TupleExpr) -> list[ClassIR] | None:
def enter(self, fn_info: FuncInfo | str = "") -> None:
if isinstance(fn_info, str):
fn_info = FuncInfo(name=fn_info)
self.builder = LowLevelIRBuilder(
self.current_module, self.errors, self.mapper, self.options
)
self.builder = LowLevelIRBuilder(self.errors, self.options)
self.builder.set_module(self.module_name, self.module_path)
self.builders.append(self.builder)
self.symtables.append({})
Expand Down
8 changes: 2 additions & 6 deletions mypyc/irbuild/ll_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@
short_int_rprimitive,
str_rprimitive,
)
from mypyc.irbuild.mapper import Mapper
from mypyc.irbuild.util import concrete_arg_kind
from mypyc.options import CompilerOptions
from mypyc.primitives.bytes_ops import bytes_compare
Expand Down Expand Up @@ -220,12 +219,8 @@


class LowLevelIRBuilder:
def __init__(
self, current_module: str, errors: Errors, mapper: Mapper, options: CompilerOptions
) -> None:
self.current_module = current_module
def __init__(self, errors: Errors | None, options: CompilerOptions) -> None:
self.errors = errors
self.mapper = mapper
self.options = options
self.args: list[Register] = []
self.blocks: list[BasicBlock] = []
Expand Down Expand Up @@ -2394,6 +2389,7 @@ def _create_dict(self, keys: list[Value], values: list[Value], line: int) -> Val
return self.call_c(dict_new_op, [], line)

def error(self, msg: str, line: int) -> None:
assert self.errors is not None, "cannot generate errors in this compiler phase"
self.errors.error(msg, self.module_path, line)


Expand Down
Loading

0 comments on commit c94d8e3

Please sign in to comment.