TP05b (buggy)
This commit is contained in:
parent
9e371fb015
commit
d668ab98aa
@ -6,14 +6,14 @@ Functions to convert a CFG out of SSA Form.
|
||||
from typing import cast, List
|
||||
from Lib import RiscV
|
||||
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.Terminator import BranchingTerminator, Return
|
||||
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
|
||||
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.
|
||||
"""
|
||||
# (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 [
|
||||
RiscV.mv(
|
||||
phi.defined()[0],
|
||||
phi.get_srcs()[parent.get_label()]
|
||||
) for phi in phis if parent.get_label() in phi.get_srcs()
|
||||
phi.var,
|
||||
phi.get_srcs()[lbl]
|
||||
) 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:
|
||||
# Add the block containing 'moves' to 'cfg'
|
||||
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)
|
||||
|
||||
# Update parent terminator
|
||||
|
@ -1,6 +1,6 @@
|
||||
from typing import Dict, Set, Tuple
|
||||
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.PhiNode import PhiNode
|
||||
|
||||
@ -35,16 +35,41 @@ class LivenessSSA:
|
||||
|
||||
def livein_at_instruction(self, block: Block, pos: int, var: Temporary) -> None:
|
||||
"""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:
|
||||
"""Backward propagation of liveness information at the end of an instruction."""
|
||||
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:
|
||||
"""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]]]:
|
||||
"""
|
||||
@ -67,7 +92,9 @@ class LivenessSSA:
|
||||
|
||||
def conflict_on_phis(self) -> None:
|
||||
"""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
|
||||
"""Print live out sets at each instruction, group by block, useful for debugging!"""
|
||||
|
@ -18,8 +18,22 @@ def generate_smart_move(dest: DataLocation, src: DataLocation) -> List[BlockInst
|
||||
This is an helper function for `sequentialize_moves`.
|
||||
"""
|
||||
instr: List[BlockInstr] = []
|
||||
# TODO Compute the moves (Lab 5b, Exercise 4)
|
||||
raise NotImplementedError("generate_smart_move")
|
||||
tmp: Register = S[1]
|
||||
|
||||
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
|
||||
|
||||
|
||||
@ -40,18 +54,27 @@ def sequentialize_moves(parallel_moves: Set[Tuple[DataLocation, DataLocation]]
|
||||
# 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 vetices without successors
|
||||
# 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:
|
||||
# TODO Remove the leaves iteratively (Lab 5b, Exercise 4)
|
||||
raise NotImplementedError("sequentialize_moves: leaves")
|
||||
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:
|
||||
# TODO Handle each cycle (Lab 5b, Exercise 4)
|
||||
raise NotImplementedError("sequentialize_moves: cycles")
|
||||
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:
|
||||
|
@ -1,11 +1,12 @@
|
||||
from typing import List, Dict
|
||||
from Lib.Errors import MiniCInternalError
|
||||
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.FunctionData import FunctionData
|
||||
from Lib import RiscV
|
||||
from Lib.Graphes import Graph # For Graph coloring utility functions
|
||||
from TP05.SequentializeMoves import generate_smart_move
|
||||
|
||||
|
||||
class SmartAllocator(Allocator):
|
||||
@ -28,9 +29,27 @@ class SmartAllocator(Allocator):
|
||||
before: List[Instruction] = []
|
||||
after: List[Instruction] = []
|
||||
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).
|
||||
raise NotImplementedError("Smart Replace (lab5)") # TODO
|
||||
|
||||
for arg in old_instr.defined():
|
||||
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!
|
||||
instr = old_instr.with_args(new_args)
|
||||
return before + [instr] + after
|
||||
@ -70,7 +89,12 @@ class SmartAllocator(Allocator):
|
||||
# Iterate over self._liveness._liveout (dictionary containing all
|
||||
# live out temporaries for each instruction), and for each conflict use
|
||||
# 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:
|
||||
"""
|
||||
@ -79,6 +103,7 @@ class SmartAllocator(Allocator):
|
||||
|
||||
Precondition: the interference graph _igraph must have been built.
|
||||
"""
|
||||
regs = list(GP_REGS) # Get a writable copy
|
||||
# Checking the interference graph has been built
|
||||
if not self._igraph:
|
||||
raise MiniCInternalError("Empty interference graph in the Smart Allocator")
|
||||
@ -92,7 +117,15 @@ class SmartAllocator(Allocator):
|
||||
alloc_dict: Dict[Temporary, DataLocation] = dict()
|
||||
# Use the coloring `coloringreg` to fill `alloc_dict`.
|
||||
# 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:
|
||||
print("Allocation:")
|
||||
print(alloc_dict)
|
||||
|
Loading…
Reference in New Issue
Block a user