compiler/compiler/optimizations/register_allocation.py

58 lines
2.2 KiB
Python

from .. import ir
from ..errors import CompilationError
from ..logger import Logger
logger = Logger(__name__)
class RegisterAllocation:
"""
Rules:
Read After Write: write (a) MUST be before read (b)
Read After Read: order does not matter
Write After Read: write (b) MUST be after read (a)
Write After Write: order should be preserved
This means we must allocate a new register on its first u
"""
def __init__(self, intermediate_representation: list[ir.IRItem]):
self.intermediate_representation = intermediate_representation
self.used_registers: dict[int, bool] = {}
for register in ir.IRRegister.registers:
self.used_registers[register] = True
def alloc_register(self) -> int:
for register, free in self.used_registers.items():
if free:
self.used_registers[register] = False
return register
def free_register(self, identifier: int):
self.used_registers[identifier] = True
def analyze(self):
for i, item in enumerate(self.intermediate_representation):
if not isinstance(item, ir.IRAction):
raise CompilationError(item.location, f"Expected an action, got {item}")
action: ir.IRAction = item
for assignable in (action.reads + action.writes):
if not isinstance(assignable, ir.IRRegister):
continue
register: ir.IRRegister = assignable
sorted_users = register.sorted_users
# This is the first use, allocate a new register
if sorted_users[0].ir_location.line == i:
logger.debug(f"Try to allocate new register for virtual register '{register}'")
new_register = self.alloc_register()
register.real = new_register
logger.debug(f"Allocated new register '{new_register}' for virtual register '{register}'")
if sorted_users[-1].ir_location.line == i:
self.free_register(register.real)
logger.debug(f"Freed register '{register.real}' (was last used by virt. register '{register}')")