85 lines
3.1 KiB
Python
85 lines
3.1 KiB
Python
"""
|
|
CAP, SSA Intro, Elimination and Optimisations
|
|
Helper functions to convert a CFG out of SSA Form
|
|
for the Smart Allocator.
|
|
"""
|
|
|
|
from typing import List, Set, Tuple
|
|
from Lib import RiscV
|
|
from Lib.Graphes import DiGraph
|
|
from Lib.CFG import BlockInstr
|
|
from Lib.Operands import Register, Offset, DataLocation, S
|
|
|
|
|
|
def generate_smart_move(dest: DataLocation, src: DataLocation) -> List[BlockInstr]:
|
|
"""
|
|
Generate a list of move, store and load instructions, depending on
|
|
whether the operands are registers or memory locations.
|
|
This is an helper function for `sequentialize_moves`.
|
|
"""
|
|
instr: List[BlockInstr] = []
|
|
tmp: Register = S[1]
|
|
|
|
match dest, src:
|
|
case Register(), Register():
|
|
instr.append(RiscV.mv(dest, src))
|
|
case Register(), Offset():
|
|
instr.append(RiscV.ld(dest, src))
|
|
case Offset(), Register():
|
|
instr.append(RiscV.sd(src, dest))
|
|
case Offset(), Offset():
|
|
instr.append(RiscV.ld(tmp, src))
|
|
instr.append(RiscV.sd(tmp, dest))
|
|
case _, _:
|
|
raise ValueError(f"Unsupported operands {type(dest)} <- {type(src)}")
|
|
|
|
return instr
|
|
|
|
|
|
def sequentialize_moves(parallel_moves: Set[Tuple[DataLocation, DataLocation]]
|
|
) -> List[BlockInstr]:
|
|
"""
|
|
Take a set of parallel moves represented as (destination, source) pairs,
|
|
and return a list of sequential moves which respect the cycles.
|
|
Use the register `tmp` S2 for the cycles.
|
|
Return a corresponding list of RiscV instructions.
|
|
This is an helper function called during SSA exit.
|
|
"""
|
|
tmp: Register = S[2] # S2 is not a general purpose register
|
|
# Build the graph of the moves
|
|
move_graph: DiGraph = DiGraph()
|
|
for dest, src in parallel_moves:
|
|
move_graph.add_edge((src, dest))
|
|
# List for the sequentialized moves to do
|
|
# Convention: in moves we put (dest, src) for each move
|
|
moves: List[Tuple[DataLocation, DataLocation]] = []
|
|
# First iteratively remove all the vertices without successors
|
|
vars_without_successor = {src
|
|
for src, dests in move_graph.neighbourhoods()
|
|
if len(dests) == 0}
|
|
while vars_without_successor:
|
|
var = vars_without_successor.pop()
|
|
for src in move_graph.pred(var):
|
|
moves.append((var, src))
|
|
dests = [dests for sr, dests in move_graph.neighbourhoods() if sr == src][0]
|
|
if len(dests) == 1:
|
|
vars_without_successor.add(src)
|
|
|
|
move_graph.delete_vertex(var)
|
|
# Then handle the cycles
|
|
cycles: List = move_graph.connected_components()
|
|
for cycle in cycles:
|
|
if len(cycle) == 1:
|
|
continue
|
|
previous = tmp
|
|
for var in reversed(cycle):
|
|
moves.append((previous, var))
|
|
previous = var
|
|
moves.append((previous, tmp))
|
|
# Transform the moves to do in actual RiscV instructions
|
|
moves_instr: List[BlockInstr] = []
|
|
for dest, src in moves:
|
|
instrs = generate_smart_move(dest, src)
|
|
moves_instr.extend(instrs)
|
|
return moves_instr
|