Ajout du smart allocator .... disfonctionnel
This commit is contained in:
parent
2c50bbaaa0
commit
0a8c02ec83
@ -11,10 +11,15 @@ TODO:
|
||||
- Explain any design choices you may have made.
|
||||
- Do not forget to remove all debug traces from your code!
|
||||
|
||||
|
||||
|
||||
# Test design
|
||||
|
||||
TODO: give the main objectives of your tests.
|
||||
|
||||
# Known bugs
|
||||
|
||||
TODO: bugs you could not fix (if any).
|
||||
There was an issue with the subject, because we implemented «smart moves» in ExitSSA, we had to replace
|
||||
temporaries at the exit of the SSA. So when the SSA is exited, some temporaries are already replaced
|
||||
with real data locations (that is, the instructions that comes from the reduction
|
||||
of phi-statements.
|
||||
|
||||
@ -29,12 +29,6 @@ class AllInMemAllocator(Allocator):
|
||||
if(isinstance(arg, Temporary)):
|
||||
after.append(RiscV.sd(subst[arg],self._fdata._pool.get_alloced_loc(arg)))
|
||||
|
||||
|
||||
# TODO (Exercise 7): compute before,after,args.
|
||||
# TODO (Exercise 7): iterate over old_args, check which argument
|
||||
# TODO (Exercise 7): is a temporary (e.g. isinstance(..., Temporary)),
|
||||
# TODO (Exercise 7): and if so, generate ld/sd accordingly. Replace the
|
||||
# TODO (Exercise 7): temporary with S[1], S[2] or S[3] physical registers.
|
||||
try:
|
||||
new_instr = old_instr.substitute(subst)
|
||||
except Exception:
|
||||
|
||||
@ -10,10 +10,11 @@ from Lib.Graphes import DiGraph
|
||||
from Lib.CFG import Block, BlockInstr, CFG
|
||||
from Lib.Operands import (
|
||||
Register, DataLocation,
|
||||
Temporary)
|
||||
Temporary, TemporaryPool)
|
||||
from Lib.Statement import AbsoluteJump
|
||||
from Lib.Terminator import BranchingTerminator, Return
|
||||
from Lib.PhiNode import PhiNode
|
||||
from TP05.SequentializeMoves import sequentialize_moves
|
||||
|
||||
|
||||
def generate_moves_from_phis(phis: List[PhiNode], parent: Block) -> List[BlockInstr]:
|
||||
@ -32,6 +33,31 @@ def generate_moves_from_phis(phis: List[PhiNode], parent: Block) -> List[BlockIn
|
||||
return moves
|
||||
|
||||
|
||||
def generate_moves_from_phis_smart(pool: TemporaryPool, phis: List[PhiNode], parent: Block) -> List[BlockInstr]:
|
||||
"""
|
||||
`generate_moves_from_phis_smart(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 function is working with smart allocation, unlike its «dump» counterpart
|
||||
that makes allocations in no particular order.
|
||||
|
||||
This is an helper function called during SSA exit.
|
||||
"""
|
||||
moves: List[Tuple[DataLocation,DataLocation]] = []
|
||||
plabel = parent.get_label()
|
||||
for phi in phis:
|
||||
if(plabel in phi.used()):
|
||||
src = phi.var
|
||||
dest = phi.used()[plabel]
|
||||
if(isinstance(src,Temporary)):
|
||||
src = pool.get_alloced_loc(src)
|
||||
if(isinstance(dest,Temporary)):
|
||||
dest = pool.get_alloced_loc(dest)
|
||||
assert(isinstance(dest,DataLocation))
|
||||
moves.append((dest,src))
|
||||
realmoves = sequentialize_moves(set(moves))
|
||||
return realmoves
|
||||
|
||||
|
||||
def exit_ssa(cfg: CFG, is_smart: bool) -> None:
|
||||
"""
|
||||
`exit_ssa(cfg)` replaces phi nodes with move instructions to exit SSA form.
|
||||
@ -44,7 +70,7 @@ def exit_ssa(cfg: CFG, is_smart: bool) -> None:
|
||||
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)
|
||||
moves = generate_moves_from_phis_smart(cfg.fdata._pool,phis, p) if is_smart else generate_moves_from_phis(phis, p)
|
||||
if(len(moves)==0):
|
||||
continue
|
||||
# Creating the block
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
from typing import List, Set, Tuple
|
||||
from Lib.Errors import MiniCInternalError
|
||||
from Lib import RiscV
|
||||
from Lib.Graphes import DiGraph
|
||||
from Lib.CFG import BlockInstr
|
||||
from Lib.Operands import (Register, DataLocation, S)
|
||||
from Lib.Operands import (Offset, Register, DataLocation, S)
|
||||
|
||||
|
||||
def generate_smart_move(dest: DataLocation, src: DataLocation) -> List[BlockInstr]:
|
||||
@ -12,8 +13,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]
|
||||
if(isinstance(dest,Offset) and isinstance(src,Offset)):
|
||||
# We read the source in tmp and write it to destination
|
||||
instr.append(RiscV.ld(tmp,src))
|
||||
instr.append(RiscV.sd(tmp,dest))
|
||||
elif(isinstance(dest,Offset) and isinstance(src,Register)):
|
||||
# We write the register to destination
|
||||
instr.append(RiscV.sd(src,dest))
|
||||
elif(isinstance(dest,Register) and isinstance(src,Offset)):
|
||||
# We read the source into the register
|
||||
instr.append(RiscV.ld(dest,src))
|
||||
elif(isinstance(dest,Register) and isinstance(src,Register)):
|
||||
# Classic move
|
||||
instr.append(RiscV.mv(src,dest))
|
||||
else:
|
||||
raise MiniCInternalError("Cannot generate smart move from parameters that are no Offset or Register:",src,dest)
|
||||
return instr
|
||||
|
||||
|
||||
@ -39,13 +54,33 @@ def sequentialize_moves(parallel_moves: Set[Tuple[DataLocation, DataLocation]]
|
||||
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")
|
||||
head = vars_without_successor.pop()
|
||||
while(head is not None):
|
||||
preds = move_graph.pred(head)
|
||||
if(len(preds)==0):
|
||||
head = None
|
||||
else:
|
||||
pred = preds.pop()
|
||||
moves.append((pred,head))
|
||||
move_graph.delete_vertex(head)
|
||||
head = pred
|
||||
|
||||
# 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")
|
||||
if(len(cycle)==1):
|
||||
# No moves to do
|
||||
pass
|
||||
else:
|
||||
head = cycle[0]
|
||||
moves.append((head,tmp))
|
||||
while True:
|
||||
pred = move_graph.pred(head).pop()
|
||||
if(pred==cycle[0]):
|
||||
break
|
||||
moves.append((pred,head))
|
||||
head = pred
|
||||
moves.append((tmp,head))
|
||||
# Transform the moves to do in actual RiscV instructions
|
||||
moves_instr: List[BlockInstr] = []
|
||||
for dest, src in moves:
|
||||
|
||||
@ -28,13 +28,44 @@ class SmartAllocator(Allocator):
|
||||
before: List[Instruction] = []
|
||||
after: List[Instruction] = []
|
||||
subst: Dict[Operand, 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
|
||||
|
||||
old_args = old_instr.args()
|
||||
numreg = 1
|
||||
for arg in old_args:
|
||||
if(isinstance(arg, Temporary)): # Else we don't change anything
|
||||
dest = self._fdata._pool.get_alloced_loc(arg)
|
||||
if(isinstance(dest,Register)):
|
||||
# We use the provided register
|
||||
subst[arg] = dest
|
||||
elif(isinstance(dest,Offset)):
|
||||
# We use a s register in which we will read|write
|
||||
subst[arg] = S[numreg]
|
||||
numreg += 1
|
||||
else:
|
||||
raise MiniCInternalError("Unsupported dataLocation for smart replace")
|
||||
for arg in old_instr.used():
|
||||
if(isinstance(arg, Temporary)):
|
||||
# If the argument has an Offset substitution
|
||||
if(isinstance(self._fdata._pool.get_alloced_loc(arg),Offset)):
|
||||
# We have to read it from memory
|
||||
before.append(RiscV.ld(subst[arg],self._fdata._pool.get_alloced_loc(arg)))
|
||||
for arg in old_instr.defined():
|
||||
if(isinstance(arg, Temporary)):
|
||||
# If the argument has an Offset substitution
|
||||
if(isinstance(self._fdata._pool.get_alloced_loc(arg),Offset)):
|
||||
# We have to write them after to memory
|
||||
after.append(RiscV.sd(subst[arg],self._fdata._pool.get_alloced_loc(arg)))
|
||||
|
||||
# And now return the new list!
|
||||
instr = old_instr.substitute(subst)
|
||||
return before + [instr] + after
|
||||
|
||||
|
||||
print(old_instr,"->",before,subst,after)
|
||||
try:
|
||||
new_instr = old_instr.substitute(subst)
|
||||
except Exception:
|
||||
# We have an instruction that doesn't need substitution
|
||||
return [old_instr]
|
||||
return before + [new_instr] + after
|
||||
|
||||
def prepare(self) -> None:
|
||||
"""
|
||||
Perform all preparatory steps related to smart register allocation:
|
||||
@ -70,7 +101,17 @@ 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 st,varz in self._liveness._liveout.items():
|
||||
for x in varz:
|
||||
if(isinstance(x,Temporary)):
|
||||
# First condition
|
||||
for y in varz:
|
||||
if x!=y and isinstance(y,Temporary):
|
||||
self._igraph.add_edge((x,y))
|
||||
# Second/third condition
|
||||
for y in st.defined():
|
||||
if x!=y and isinstance(y,Temporary): # x is alive after x definition
|
||||
self._igraph.add_edge((x,y))
|
||||
|
||||
def smart_alloc(self) -> None:
|
||||
"""
|
||||
@ -92,7 +133,16 @@ 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
|
||||
moreColors_alloc_dict: Dict[int, DataLocation] = dict()
|
||||
|
||||
for var,col in coloringreg.items():
|
||||
if(col<len(GP_REGS)):
|
||||
alloc_dict[var] = GP_REGS[col]
|
||||
else:
|
||||
if(not col in moreColors_alloc_dict):
|
||||
moreColors_alloc_dict[col] = self._fdata.fresh_offset()
|
||||
alloc_dict[var] = moreColors_alloc_dict[col]
|
||||
|
||||
if self._debug:
|
||||
print("Allocation:")
|
||||
print(alloc_dict)
|
||||
|
||||
40
MiniC/TP05/tests/students/testEq-min.c
Normal file
40
MiniC/TP05/tests/students/testEq-min.c
Normal file
@ -0,0 +1,40 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main() {
|
||||
|
||||
// Testing ==
|
||||
if( 11 == 11 ){
|
||||
println_int(61);
|
||||
}else{
|
||||
println_int(420);
|
||||
}
|
||||
if( -22 == -22 ){
|
||||
println_int(62);
|
||||
}else{
|
||||
println_int(420);
|
||||
}
|
||||
if( true == true ){
|
||||
println_int(63);
|
||||
}else{
|
||||
println_int(420);
|
||||
}
|
||||
if( true == false ){
|
||||
println_int(420);
|
||||
}else{
|
||||
println_int(64);
|
||||
}
|
||||
if( false == false ){
|
||||
println_int(65);
|
||||
}else{
|
||||
println_int(420);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
// 61
|
||||
// 62
|
||||
// 63
|
||||
// 64
|
||||
// 65
|
||||
Loading…
x
Reference in New Issue
Block a user