58 lines
2.2 KiB
Python
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}')")
|