TP05b (buggy)

This commit is contained in:
augustin64 2024-11-25 21:57:16 +01:00
parent 9e371fb015
commit d668ab98aa
4 changed files with 127 additions and 25 deletions

View File

@ -6,14 +6,14 @@ Functions to convert a CFG out of SSA Form.
from typing import cast, List from typing import cast, List
from Lib import RiscV from Lib import RiscV
from Lib.CFG import Block, BlockInstr, CFG from Lib.CFG import Block, BlockInstr, CFG
from Lib.Operands import Temporary from Lib.Operands import Temporary, DataLocation
from Lib.Statement import AbsoluteJump, Label from Lib.Statement import AbsoluteJump, Label
from Lib.Terminator import BranchingTerminator, Return from Lib.Terminator import BranchingTerminator, Return
from Lib.PhiNode import PhiNode from Lib.PhiNode import PhiNode
from TP05.SequentializeMoves import sequentialize_moves from TP05.SequentializeMoves import sequentialize_moves, generate_smart_move
def generate_moves_from_phis(phis: List[PhiNode], parent: Block) -> List[BlockInstr]: def generate_moves_from_phis(phis: List[PhiNode], parent: Block, is_smart: bool=False) -> List[BlockInstr]:
""" """
`generate_moves_from_phis(phis, parent)` builds a list of move instructions `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 to be inserted in a new block between `parent` and the block with phi nodes
@ -22,11 +22,30 @@ def generate_moves_from_phis(phis: List[PhiNode], parent: Block) -> List[BlockIn
This is an helper function called during SSA exit. This is an helper function called during SSA exit.
""" """
# (Lab 5a, Exercise 6) # (Lab 5a, Exercise 6)
lbl = parent.get_label()
if is_smart:
parallel_moves: set[tuple[DataLocation, DataLocation]] = set()
moves: List[BlockInstr] = []
for phi in phis:
if lbl not in phi.get_srcs():
continue
src = phi.get_srcs()[lbl]
if isinstance(src, Temporary) or isinstance(phi.var, Temporary):
loc1, loc2 = phi.var, src
if isinstance(loc1, Temporary):
loc1 = loc1.get_alloced_loc()
if isinstance(loc2, Temporary):
loc2 = loc2.get_alloced_loc()
moves += generate_smart_move(loc1, cast(DataLocation, loc2))
else:
src = phi.get_srcs()[lbl]
parallel_moves.add((phi.var, cast(DataLocation, src)))
return sequentialize_moves(parallel_moves)+moves
return [ return [
RiscV.mv( RiscV.mv(
phi.defined()[0], phi.var,
phi.get_srcs()[parent.get_label()] phi.get_srcs()[lbl]
) for phi in phis if parent.get_label() in phi.get_srcs() ) for phi in phis if lbl in phi.get_srcs()
] ]
@ -43,7 +62,7 @@ def exit_ssa(cfg: CFG, is_smart: bool) -> None:
for parent in parents: for parent in parents:
# Add the block containing 'moves' to 'cfg' # Add the block containing 'moves' to 'cfg'
moves_label = cfg.fdata.fresh_label("merge_phi") moves_label = cfg.fdata.fresh_label("merge_phi")
block_moves = Block(moves_label, generate_moves_from_phis(phis, parent), AbsoluteJump(b.get_label())) block_moves = Block(moves_label, generate_moves_from_phis(phis, parent, is_smart=is_smart), AbsoluteJump(b.get_label()))
cfg.add_block(block_moves) cfg.add_block(block_moves)
# Update parent terminator # Update parent terminator

View File

@ -1,6 +1,6 @@
from typing import Dict, Set, Tuple from typing import Dict, Set, Tuple
from Lib.Operands import Temporary from Lib.Operands import Temporary
from Lib.Statement import Statement, regset_to_string from Lib.Statement import Statement, regset_to_string, Instru3A
from Lib.CFG import Block, CFG from Lib.CFG import Block, CFG
from Lib.PhiNode import PhiNode from Lib.PhiNode import PhiNode
@ -35,16 +35,41 @@ class LivenessSSA:
def livein_at_instruction(self, block: Block, pos: int, var: Temporary) -> None: def livein_at_instruction(self, block: Block, pos: int, var: Temporary) -> None:
"""Backward propagation of liveness information at the beginning of an instruction.""" """Backward propagation of liveness information at the beginning of an instruction."""
raise NotImplementedError("LivenessSSA") # TODO (Lab 5b, Exercise 1) instr = block.get_all_statements()[pos]
if isinstance(instr, PhiNode) and var in instr.srcs.values():
bpred = self._cfg.get_block(
next(lbl for lbl, value in instr.srcs.items() if value == var)
)
self.liveout_at_block(bpred, var)
elif pos == 0:
for bpred in block.get_in():
self.liveout_at_block(bpred, var)
else:
self.liveout_at_instruction(block, pos-1, var)
def liveout_at_instruction(self, block: Block, pos: int, var: Temporary) -> None: def liveout_at_instruction(self, block: Block, pos: int, var: Temporary) -> None:
"""Backward propagation of liveness information at the end of an instruction.""" """Backward propagation of liveness information at the end of an instruction."""
instr = block.get_all_statements()[pos] instr = block.get_all_statements()[pos]
raise NotImplementedError("LivenessSSA") # TODO (Lab 5b, Exercise 1)
self._liveout[block, instr].add(var)
if var in instr.defined():
#self._seen[block].add(var)
return
self.livein_at_instruction(block, pos, var)
#self._seen[block].add(var)
def liveout_at_block(self, block: Block, var: Temporary) -> None: def liveout_at_block(self, block: Block, var: Temporary) -> None:
"""Backward propagation of liveness information at the end of a block.""" """Backward propagation of liveness information at the end of a block."""
raise NotImplementedError("LivenessSSA") # TODO (Lab 5b, Exercise 1) if var not in self._seen[block]:
self._seen[block].add(var)
self.liveout_at_instruction(block, len(block.get_all_statements())-1, var)
def gather_uses(self) -> Dict[Temporary, Set[Tuple[Block, int]]]: def gather_uses(self) -> Dict[Temporary, Set[Tuple[Block, int]]]:
""" """
@ -67,7 +92,9 @@ class LivenessSSA:
def conflict_on_phis(self) -> None: def conflict_on_phis(self) -> None:
"""Ensures that variables defined by φ instructions are in conflict with one-another.""" """Ensures that variables defined by φ instructions are in conflict with one-another."""
raise NotImplementedError("LivenessSSA") # TODO (Lab 5b, Exercise 1) for block in self._cfg.get_blocks():
for phinode in block.get_phis():
self._liveout[block, phinode] = set([v for v in phinode.used() if isinstance(v, Temporary)])
def print_map_in_out(self) -> None: # pragma: no cover def print_map_in_out(self) -> None: # pragma: no cover
"""Print live out sets at each instruction, group by block, useful for debugging!""" """Print live out sets at each instruction, group by block, useful for debugging!"""

View File

@ -18,8 +18,22 @@ def generate_smart_move(dest: DataLocation, src: DataLocation) -> List[BlockInst
This is an helper function for `sequentialize_moves`. This is an helper function for `sequentialize_moves`.
""" """
instr: List[BlockInstr] = [] instr: List[BlockInstr] = []
# TODO Compute the moves (Lab 5b, Exercise 4) tmp: Register = S[1]
raise NotImplementedError("generate_smart_move")
match dest, src:
case Register(), Register():
if dest != src:
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 return instr
@ -40,18 +54,27 @@ def sequentialize_moves(parallel_moves: Set[Tuple[DataLocation, DataLocation]]
# List for the sequentialized moves to do # List for the sequentialized moves to do
# Convention: in moves we put (dest, src) for each move # Convention: in moves we put (dest, src) for each move
moves: List[Tuple[DataLocation, DataLocation]] = [] moves: List[Tuple[DataLocation, DataLocation]] = []
# First iteratively remove all the vetices without successors # First iteratively remove all the vertices without successors
vars_without_successor = {src vars_without_successor = {src
for src, dests in move_graph.neighbourhoods() for src, dests in move_graph.neighbourhoods()
if len(dests) == 0} if len(dests) == 0}
while vars_without_successor: while vars_without_successor:
# TODO Remove the leaves iteratively (Lab 5b, Exercise 4) var = vars_without_successor.pop()
raise NotImplementedError("sequentialize_moves: leaves") 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 # Then handle the cycles
cycles: List = move_graph.connected_components() cycles: List = move_graph.connected_components()
for cycle in cycles: for cycle in cycles:
# TODO Handle each cycle (Lab 5b, Exercise 4) previous = tmp
raise NotImplementedError("sequentialize_moves: cycles") for var in reversed(cycle):
moves.append((previous, var))
previous = var
moves.append((previous, tmp))
# Transform the moves to do in actual RiscV instructions # Transform the moves to do in actual RiscV instructions
moves_instr: List[BlockInstr] = [] moves_instr: List[BlockInstr] = []
for dest, src in moves: for dest, src in moves:

View File

@ -1,11 +1,12 @@
from typing import List, Dict from typing import List, Dict
from Lib.Errors import MiniCInternalError from Lib.Errors import MiniCInternalError
from Lib.Operands import Temporary, Operand, S, Offset, DataLocation, GP_REGS from Lib.Operands import Temporary, Operand, S, Offset, DataLocation, GP_REGS
from Lib.Statement import Instruction from Lib.Statement import Instruction, Instru3A
from Lib.Allocator import Allocator from Lib.Allocator import Allocator
from Lib.FunctionData import FunctionData from Lib.FunctionData import FunctionData
from Lib import RiscV from Lib import RiscV
from Lib.Graphes import Graph # For Graph coloring utility functions from Lib.Graphes import Graph # For Graph coloring utility functions
from TP05.SequentializeMoves import generate_smart_move
class SmartAllocator(Allocator): class SmartAllocator(Allocator):
@ -28,9 +29,27 @@ class SmartAllocator(Allocator):
before: List[Instruction] = [] before: List[Instruction] = []
after: List[Instruction] = [] after: List[Instruction] = []
new_args: List[Operand] = [] new_args: List[Operand] = []
# TODO (lab5): Compute before, after, subst. This is similar to what
# TODO (lab5): replace from the Naive and AllInMem Allocators do (Lab 4). for arg in old_instr.defined():
raise NotImplementedError("Smart Replace (lab5)") # TODO match arg:
case Offset():
after.append(RiscV.sd(S[3], arg))
new_args.append(S[3])
case Temporary():
new_args.append(arg.get_alloced_loc())
case _: # Contains Register()
new_args.append(arg)
for i, arg in enumerate(old_instr.used(), 1):
match arg:
case Offset():
before.append(RiscV.ld(S[i], arg))
new_args.append(S[i])
case Temporary():
new_args.append(arg.get_alloced_loc())
case _: # Contains Register()
new_args.append(arg)
# And now return the new list! # And now return the new list!
instr = old_instr.with_args(new_args) instr = old_instr.with_args(new_args)
return before + [instr] + after return before + [instr] + after
@ -70,7 +89,12 @@ class SmartAllocator(Allocator):
# Iterate over self._liveness._liveout (dictionary containing all # Iterate over self._liveness._liveout (dictionary containing all
# live out temporaries for each instruction), and for each conflict use # live out temporaries for each instruction), and for each conflict use
# self._igraph.add_edge((t1, t2)) to add the corresponding edge. # self._igraph.add_edge((t1, t2)) to add the corresponding edge.
raise NotImplementedError("build_interference_graph (lab5)") # TODO for (block, statement), vars in self._liveness._liveout.items():
for t1 in list(vars)+statement.defined():
for t2 in vars:
if t1 == t2:
continue
self._igraph.add_edge((t1, t2))
def smart_alloc(self) -> None: def smart_alloc(self) -> None:
""" """
@ -79,6 +103,7 @@ class SmartAllocator(Allocator):
Precondition: the interference graph _igraph must have been built. Precondition: the interference graph _igraph must have been built.
""" """
regs = list(GP_REGS) # Get a writable copy
# Checking the interference graph has been built # Checking the interference graph has been built
if not self._igraph: if not self._igraph:
raise MiniCInternalError("Empty interference graph in the Smart Allocator") raise MiniCInternalError("Empty interference graph in the Smart Allocator")
@ -92,7 +117,15 @@ class SmartAllocator(Allocator):
alloc_dict: Dict[Temporary, DataLocation] = dict() alloc_dict: Dict[Temporary, DataLocation] = dict()
# Use the coloring `coloringreg` to fill `alloc_dict`. # Use the coloring `coloringreg` to fill `alloc_dict`.
# Our version is less than 5 lines of code. # Our version is less than 5 lines of code.
raise NotImplementedError("Allocation based on graph coloring (lab5)") # TODO color_dict: Dict[int, DataLocation] = dict()
for temp in self._fdata._pool.get_all_temps():
if coloringreg[temp] not in color_dict:
color_dict[coloringreg[temp]] = (
regs.pop() if len(regs) > 0 else
self._fdata.fresh_offset()
)
alloc_dict[temp] = color_dict[coloringreg[temp]]
if self._debug: if self._debug:
print("Allocation:") print("Allocation:")
print(alloc_dict) print(alloc_dict)