75 lines
2.7 KiB
Python
75 lines
2.7 KiB
Python
"""
|
|
CAP, SSA Intro, Elimination and Optimisations
|
|
Functions to convert a CFG out of SSA Form.
|
|
"""
|
|
|
|
from typing import cast, List, Set, Tuple
|
|
from Lib.Errors import MiniCInternalError
|
|
from Lib import RiscV
|
|
from Lib.Graphes import DiGraph
|
|
from Lib.CFG import Block, BlockInstr, CFG
|
|
from Lib.Operands import (
|
|
Register, DataLocation,
|
|
Temporary)
|
|
from Lib.Statement import AbsoluteJump
|
|
from Lib.Terminator import BranchingTerminator, Return
|
|
from Lib.PhiNode import PhiNode
|
|
|
|
|
|
def generate_moves_from_phis(phis: List[PhiNode], parent: Block) -> List[BlockInstr]:
|
|
"""
|
|
`generate_moves_from_phis(phis, parent)` builds a list of move instructions
|
|
to be inserted in a new block between `parent` and the block with phi nodes
|
|
`phis`.
|
|
|
|
This is an helper function called during SSA exit.
|
|
"""
|
|
moves: List[BlockInstr] = []
|
|
plabel = parent.get_label()
|
|
for phi in phis:
|
|
if(plabel in phi.used()):
|
|
moves.append(RiscV.mv(phi.var,phi.used()[plabel]))
|
|
return moves
|
|
|
|
|
|
def exit_ssa(cfg: CFG, is_smart: bool) -> None:
|
|
"""
|
|
`exit_ssa(cfg)` replaces phi nodes with move instructions to exit SSA form.
|
|
|
|
`is_smart` is set to true when smart register allocation is enabled (Lab 5b).
|
|
"""
|
|
for b in cfg.get_blocks():
|
|
phis = cast(List[PhiNode], b._phis) # Use cast for Pyright
|
|
b._phis = [] # Remove all phi nodes in the block
|
|
blabel = b.get_label()
|
|
parents: List[Block] = b.get_in().copy() # Copy as we modify it by adding blocks
|
|
for p in parents:
|
|
moves = generate_moves_from_phis(phis, p)
|
|
if(len(moves)==0):
|
|
continue
|
|
# Creating the block
|
|
ilabel = cfg.fdata.fresh_label(p.get_label().name+"_to_"+b.get_label().name)
|
|
i = Block(ilabel,moves,AbsoluteJump(blabel))
|
|
# Add the block
|
|
cfg.add_block(i)
|
|
# Changing the jumps
|
|
ot = p.get_terminator()
|
|
if(isinstance(ot,BranchingTerminator)):
|
|
if(ot.label_then == blabel):
|
|
ot.label_then = ilabel
|
|
if(ot.label_else == blabel):
|
|
ot.label_else = ilabel
|
|
elif(isinstance(ot,AbsoluteJump)):
|
|
assert(ot.label == blabel)
|
|
ot = AbsoluteJump(ilabel)
|
|
elif(isinstance(ot,Return)):
|
|
raise MiniCInternalError("Malformed CFG, cannot have a return in a parent block")
|
|
else:
|
|
raise MiniCInternalError("I don't know of this terminator type:",type(ot))
|
|
p.set_terminator(ot) # This instruction might be useless
|
|
# Moving from p -> b to p -> i -> b
|
|
cfg.remove_edge(p,b)
|
|
cfg.add_edge(p,i)
|
|
cfg.add_edge(i,b)
|
|
|