"""Transform IR to lower-level ops.

Higher-level ops are used in earlier compiler passes, as they make
various analyses, optimizations and transforms easier to implement.
Later passes use lower-level ops, as they are easier to generate code
from, and they help with lower-level optimizations.

Lowering of various primitive ops is implemented in the mypyc.lower
package.
"""

from __future__ import annotations

from mypyc.ir.func_ir import FuncIR
from mypyc.ir.ops import PrimitiveOp, Value
from mypyc.irbuild.ll_builder import LowLevelIRBuilder
from mypyc.lower.registry import lowering_registry
from mypyc.options import CompilerOptions
from mypyc.transform.ir_transform import IRTransform


def lower_ir(ir: FuncIR, options: CompilerOptions) -> None:
    builder = LowLevelIRBuilder(None, options)
    visitor = LoweringVisitor(builder)
    visitor.transform_blocks(ir.blocks)
    ir.blocks = builder.blocks


class LoweringVisitor(IRTransform):
    def visit_primitive_op(self, op: PrimitiveOp) -> Value | None:
        # The lowering implementation functions of various primitive ops are stored
        # in a registry, which is populated using function decorators. The name
        # of op (such as "int_eq") is used as the key.
        lower_fn = lowering_registry[op.desc.name]
        return lower_fn(self.builder, op.args, op.line)
