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 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
|
||||||
|
@ -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!"""
|
||||||
|
@ -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:
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user