TP05b : Optimize two register swap, update README

This commit is contained in:
augustin64 2024-11-25 23:50:51 +01:00
parent d91c1df685
commit a30f035d06
7 changed files with 41 additions and 17 deletions

View File

@ -1,21 +1,30 @@
# MiniC Compiler # MiniC Compiler
LAB5a (Control Flow Graph in SSA Form) & LAB5b (Smart Register Allocation), CAP 2022-23 LAB5a (Control Flow Graph in SSA Form) & LAB5b (Smart Register Allocation), CAP 2023-24
# Authors # Authors
YOUR NAME HERE Augustin LUCAS
# Contents # Contents
TODO: Extension implemented : Optimizing swap
- Explain any design choices you may have made. - Cycles of size 1 : skip
- Do not forget to remove all debug traces from your code! - Cycles of size 2 : use 3 XOR operations to swap the registers values without any temporary register use
- Did you implement an extension?
# Test design # Test design
TODO: give the main objectives of your tests. No tests were added since some of the `students`' tests from lab4 still failed to execute properly.
# Known bugs # Known bugs
TODO: bugs you could not fix (if any). Failing tests:
- `./TP04/tests/students/ext-for-fortran/test_imbricated_for.c`
- `./TP04/tests/students/ext-for-fortran/test_for.c`
- `./TP04/tests/students/base/test_nested_while.c`
- `./TP04/tests/students/base/test_fibonacci.c`
- `./TP04/tests/provided/dataflow/df03.c`
The bug seems to be related to the handling of Offsets because a lot more tests will fail if temporaries are only assigned to memory (no registers).
This can be done by commenting `TP05/SmartAllocator.py:124`.
This seems to affect `while` and `for` loops as well as regular variables (because variables may not be stored/loaded correctly).

View File

@ -1,5 +1,5 @@
# MiniC Compiler # MiniC Compiler
LAB5 (smart code generation), MIF08 / CAP 2022-23 LAB5 (smart code generation), MIF08 / CAP 2023-24
# Authors # Authors

View File

@ -1,5 +1,5 @@
# MiniC Compiler # MiniC Compiler
LAB4 (simple code generation), MIF08 / CAP 2022-23 LAB4 (simple code generation), MIF08 / CAP 2023-24
# Authors # Authors

View File

@ -1,5 +1,5 @@
# MiniC Compiler # MiniC Compiler
LAB6 (code generation for functions), MIF08 / CAP 2022-23 LAB6 (code generation for functions), MIF08 / CAP 2023-24
# Authors # Authors

View File

@ -1,5 +1,5 @@
# MiniC interpreter and typer # MiniC interpreter and typer
LAB3, MIF08 / CAP / CS444 2022-23 LAB3, MIF08 / CAP / CS444 2023-24
# Authors # Authors

View File

@ -69,7 +69,7 @@ class LivenessSSA:
if var not in self._seen[block]: if var not in self._seen[block]:
self._seen[block].add(var) self._seen[block].add(var)
self.liveout_at_instruction(block, len(block.get_all_statements())-1, 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]]]:
""" """

View File

@ -19,7 +19,7 @@ def generate_smart_move(dest: DataLocation, src: DataLocation) -> List[BlockInst
""" """
instr: List[BlockInstr] = [] instr: List[BlockInstr] = []
tmp: Register = S[1] tmp: Register = S[1]
match dest, src: match dest, src:
case Register(), Register(): case Register(), Register():
instr.append(RiscV.mv(dest, src)) instr.append(RiscV.mv(dest, src))
@ -36,6 +36,15 @@ def generate_smart_move(dest: DataLocation, src: DataLocation) -> List[BlockInst
return instr return instr
def swap_registers(r1: Register, r2: Register) -> List[BlockInstr]:
"""Swap two registers"""
return [
RiscV.xor(r1, r1, r2),
RiscV.xor(r2, r1, r2),
RiscV.xor(r1, r1, r2)
]
def sequentialize_moves(parallel_moves: Set[Tuple[DataLocation, DataLocation]] def sequentialize_moves(parallel_moves: Set[Tuple[DataLocation, DataLocation]]
) -> List[BlockInstr]: ) -> List[BlockInstr]:
""" """
@ -52,7 +61,7 @@ def sequentialize_moves(parallel_moves: Set[Tuple[DataLocation, DataLocation]]
move_graph.add_edge((src, dest)) move_graph.add_edge((src, dest))
# 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] | BlockInstr] = []
# First iteratively remove all the vertices 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()
@ -71,6 +80,9 @@ def sequentialize_moves(parallel_moves: Set[Tuple[DataLocation, DataLocation]]
for cycle in cycles: for cycle in cycles:
if len(cycle) == 1: if len(cycle) == 1:
continue continue
if len(cycle) == 2 and isinstance(cycle[0], Register) and isinstance(cycle[1], Register):
moves += swap_registers(*cycle)
continue
previous = tmp previous = tmp
for var in reversed(cycle): for var in reversed(cycle):
moves.append((previous, var)) moves.append((previous, var))
@ -78,7 +90,10 @@ def sequentialize_moves(parallel_moves: Set[Tuple[DataLocation, DataLocation]]
moves.append((previous, tmp)) 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 val in moves:
instrs = generate_smart_move(dest, src) if isinstance(val, BlockInstr):
moves_instr.append(val)
continue
instrs = generate_smart_move(*val)
moves_instr.extend(instrs) moves_instr.extend(instrs)
return moves_instr return moves_instr