From 49092057f8ee2505d21ffde78879c6f3d77ff39f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Di=20Guardia?= Date: Tue, 11 Oct 2022 17:07:00 +0200 Subject: [PATCH] Commit TP4b --- MiniC/Lib/CFG.py | 272 ++++++++++++++++ MiniC/Lib/Terminator.py | 133 ++++++++ MiniC/MiniCC.py | 9 +- MiniC/TP04/BuildCFG.py | 111 +++++++ MiniC/TP04/LinearizeCFG.py | 43 +++ MiniC/TP04/tests/provided/dataflow/df00.c | 13 + MiniC/TP04/tests/provided/dataflow/df01.c | 15 + MiniC/TP04/tests/provided/dataflow/df02.c | 14 + MiniC/TP04/tests/provided/dataflow/df03.c | 18 ++ MiniC/TP04/tests/provided/dataflow/df04.c | 16 + MiniC/TP04/tests/provided/dataflow/df05.c | 14 + MiniC/TP04/tp4b.pdf | Bin 0 -> 91522 bytes PLANNING.md | 10 +- docs/_modules/Lib/Allocator.html | 2 + docs/_modules/Lib/CFG.html | 377 ++++++++++++++++++++++ docs/_modules/Lib/Errors.html | 2 + docs/_modules/Lib/FunctionData.html | 2 + docs/_modules/Lib/LinearCode.html | 2 + docs/_modules/Lib/Operands.html | 18 +- docs/_modules/Lib/RiscV.html | 2 + docs/_modules/Lib/Statement.html | 9 +- docs/_modules/Lib/Terminator.html | 238 ++++++++++++++ docs/_modules/index.html | 4 + docs/_sources/api/Lib.CFG.rst.txt | 7 + docs/_sources/api/Lib.Terminator.rst.txt | 7 + docs/_sources/api/Lib.rst.txt | 2 + docs/_sources/index.rst.txt | 8 + docs/api/Lib.Allocator.html | 16 +- docs/api/Lib.CFG.html | 300 +++++++++++++++++ docs/api/Lib.Errors.html | 14 +- docs/api/Lib.FunctionData.html | 38 +-- docs/api/Lib.LinearCode.html | 58 ++-- docs/api/Lib.Operands.html | 186 +++++++---- docs/api/Lib.RiscV.html | 82 ++--- docs/api/Lib.Statement.html | 308 +++++++++--------- docs/api/Lib.Terminator.html | 228 +++++++++++++ docs/api/Lib.html | 4 + docs/api/modules.html | 4 + docs/genindex.html | 198 +++++++++++- docs/index.html | 9 + docs/objects.inv | Bin 1199 -> 1566 bytes docs/py-modindex.html | 12 + docs/search.html | 2 + docs/searchindex.js | 2 +- 44 files changed, 2480 insertions(+), 329 deletions(-) create mode 100644 MiniC/Lib/CFG.py create mode 100644 MiniC/Lib/Terminator.py create mode 100644 MiniC/TP04/BuildCFG.py create mode 100644 MiniC/TP04/LinearizeCFG.py create mode 100644 MiniC/TP04/tests/provided/dataflow/df00.c create mode 100644 MiniC/TP04/tests/provided/dataflow/df01.c create mode 100644 MiniC/TP04/tests/provided/dataflow/df02.c create mode 100644 MiniC/TP04/tests/provided/dataflow/df03.c create mode 100644 MiniC/TP04/tests/provided/dataflow/df04.c create mode 100644 MiniC/TP04/tests/provided/dataflow/df05.c create mode 100644 MiniC/TP04/tp4b.pdf create mode 100644 docs/_modules/Lib/CFG.html create mode 100644 docs/_modules/Lib/Terminator.html create mode 100644 docs/_sources/api/Lib.CFG.rst.txt create mode 100644 docs/_sources/api/Lib.Terminator.rst.txt create mode 100644 docs/api/Lib.CFG.html create mode 100644 docs/api/Lib.Terminator.html diff --git a/MiniC/Lib/CFG.py b/MiniC/Lib/CFG.py new file mode 100644 index 0000000..3937259 --- /dev/null +++ b/MiniC/Lib/CFG.py @@ -0,0 +1,272 @@ +""" +Classes for a RiscV CFG: :py:class:`CFG` for the CFG itself, +and :py:class:`Block` for its basic blocks. +""" + +from graphviz import Digraph # for dot output +from typing import cast, Any, Dict, List, Set, Iterator + +from Lib.Errors import MiniCInternalError +from Lib.Operands import (Operand, Immediate, Function, A0) +from Lib.Statement import ( + Statement, Instru3A, Label, + AbsoluteJump, ConditionalJump, Comment +) +from Lib.Terminator import ( + Terminator, BranchingTerminator, Return) +from Lib.FunctionData import (FunctionData, _iter_statements, _print_code) + + +BlockInstr = Instru3A | Comment + + +class Block: + """ + A basic block of a :py:class:`CFG` is made of three main parts: + + - a start :py:class:`label ` that uniquely identifies the block in the CFG + - the main body of the block, a list of instructions + (excluding labels, jumps and branching instructions) + - a :py:class:`terminator ` + that represents the final jump or branching instruction of the block, + and points to the successors of the block. + See the documentation for :py:class:`Lib.Terminator.Terminator` for further explanations. + """ + + _terminator: Terminator + _label: Label + _phis: List[Statement] + _instructions: List[BlockInstr] + _in: List['Block'] + _gen: Set + _kill: Set + + def __init__(self, label: Label, insts: List[BlockInstr], terminator: Terminator): + self._label = label + self._instructions = insts + self._in = [] + self._phis = [] + self._terminator = terminator + self._gen = set() + self._kill = set() + + def __str__(self): + instr = [i for i in self._instructions if not isinstance(i, Comment)] + instr_str = '\n'.join(map(str, instr)) + s = '{}:\n\n{}'.format(self._label, instr_str) + return s + + def to_dot(self) -> str: # pragma: no cover + """Outputs all statements of the block as a string.""" + # dot is weird: lines ending with \l instead of \n are left-aligned. + NEWLINE = '\\l ' + instr = [] + instr += self._phis + instr += [i for i in self._instructions if not isinstance(i, Comment)] + instr += [self.get_terminator()] + instr_str = NEWLINE.join(map(str, instr)) + s = '{}:{}{}\\l'.format(self._label, NEWLINE, instr_str) + return s + + def __repr__(self): + return str(self._label) + + def get_body(self) -> List[BlockInstr]: + """Return the statements in the body of the block (no phi-node nor the terminator).""" + return self._instructions + + def get_all_statements(self) -> List[Statement]: + """ + Return all statements of the block + (including phi-nodes and the terminator, but not the label of the block). + """ + return (self._phis + + cast(List[Statement], self._instructions) + + [self.get_terminator()]) + + def get_label(self) -> Label: + """Return the label of the block.""" + return self._label + + def get_in(self) -> List['Block']: + """Return the list of blocks with an edge to the considered block.""" + return self._in + + def get_terminator(self) -> Terminator: + """Return the terminator of the block.""" + return self._terminator + + def set_terminator(self, term: Terminator) -> None: + """Set the terminator of the block.""" + self._terminator = term + + def iter_statements(self, f) -> None: + """Iterate over instructions. + For each real instruction i (not label or comment), replace it + with the list of instructions given by f(i). + + Assume there is no phi-node. + """ + assert (self._phis == []) + new_statements = _iter_statements(self._instructions, f) + end_statements = f(self.get_terminator()) + if len(end_statements) >= 1 and isinstance(end_statements[-1], Terminator): + new_terminator = end_statements.pop(-1) + self._instructions = new_statements + end_statements + self.set_terminator(new_terminator) + else: + raise MiniCInternalError( + "Block.iter_statements: Invalid replacement for terminator {}:\n {}" + .format(self.get_terminator(), end_statements)) + + def add_instruction(self, instr: BlockInstr) -> None: + """Add an instruction to the body of the block.""" + self._instructions.append(instr) + + +class CFG: + """ + A complete control-flow graph representing a function. + This class is mainly made of a list of basic :py:class:`Block`, + a label indicating the :py:meth:`entry point of the function `, + and an :py:meth:`exit label `. + + As with linear code, metadata about the function can be found + in the :py:attr:`fdata` member variable. + """ + + _start: Label + _end: Label + _blocks: Dict[Label, Block] + + #: Metadata about the function represented by this CFG + fdata: FunctionData + + def __init__(self, fdata: FunctionData): + self._blocks = {} + self.fdata = fdata + self._init_blks() + self._end = self.fdata.fresh_label("end") + + def _init_blks(self) -> None: + """Add a block for division by 0.""" + # Label for the address of the error message + # This address is added by print_code + label_div_by_zero_msg = Label(self.fdata._label_div_by_zero.name + "_msg") + blk = Block(self.fdata._label_div_by_zero, [ + Instru3A("la", A0, label_div_by_zero_msg), + Instru3A("call", Function("println_string")), + Instru3A("li", A0, Immediate(1)), + Instru3A("call", Function("exit")), + ], terminator=Return()) + self.add_block(blk) + + def get_start(self) -> Label: + """Return the entry label of the CFG.""" + return self._start + + def set_start(self, start: Label) -> None: + """Set the entry label of the CFG.""" + assert (start in self._blocks) + self._start = start + + def get_end(self) -> Label: + """Return the exit label of the CFG.""" + return self._end + + def add_block(self, blk: Block) -> None: + """Add a new block to the CFG.""" + self._blocks[blk._label] = blk + + def get_block(self, name: Label) -> Block: + """Return the block with label `name`.""" + return self._blocks[name] + + def get_blocks(self) -> List[Block]: + """Return all the blocks.""" + return [b for b in self._blocks.values()] + + def get_entries(self) -> List[Block]: + """Return all the blocks with no predecessors.""" + return [b for b in self._blocks.values() if not b.get_in()] + + def add_edge(self, src: Block, dest: Block) -> None: + """Add the edge src -> dest in the control flow graph.""" + dest.get_in().append(src) + # assert (dest.get_label() in src.get_terminator().targets()) + + def remove_edge(self, src: Block, dest: Block) -> None: + """Remove the edge src -> dest in the control flow graph.""" + dest.get_in().remove(src) + # assert (dest.get_label() not in src.get_terminator().targets()) + + def out_blocks(self, block: Block) -> List[Block]: + """ + Return the list of blocks in the CFG targeted by + the Terminator of Block block. + """ + return [self.get_block(dest) for dest in block.get_terminator().targets()] + + def gather_defs(self) -> Dict[Any, Set[Block]]: + """ + Return a dictionary associating variables to all the blocks + containing one of their definitions. + """ + defs: Dict[Operand, Set[Block]] = dict() + for b in self.get_blocks(): + for i in b.get_all_statements(): + for v in i.defined(): + if v not in defs: + defs[v] = {b} + else: + defs[v].add(b) + return defs + + def iter_statements(self, f) -> None: + """Apply f to all instructions in all the blocks.""" + for b in self.get_blocks(): + b.iter_statements(f) + + def linearize_naive(self) -> Iterator[Statement]: + """ + Linearize the given control flow graph as a list of instructions. + Naive procedure that adds jumps everywhere. + """ + for label, block in self._blocks.items(): + yield label + for i in block._instructions: + yield i + match block.get_terminator(): + case BranchingTerminator() as j: + # In case of conditional jump, add the missing edge + yield ConditionalJump(j.cond, j.op1, j.op2, j.label_then) + yield AbsoluteJump(j.label_else) + case AbsoluteJump() as j: + yield AbsoluteJump(j.label) + case Return(): + yield AbsoluteJump(self.get_end()) + + def print_code(self, output, linearize=(lambda cfg: list(cfg.linearize_naive())), + comment=None) -> None: + """Print the linearization of the CFG.""" + statements = linearize(self) + _print_code(statements, self.fdata, output, init_label=self._start, + fin_label=self._end, fin_div0=False, comment=comment) + + def print_dot(self, filename, DF=None, view=False) -> None: # pragma: no cover + """Print the CFG as a graph.""" + graph = Digraph() + # nodes + for name, blk in self._blocks.items(): + if DF is not None: + print(str(name), blk._label) + df_str = "{}" if blk not in DF or not len(DF[blk]) else str(DF[blk]) + df_lab = blk.to_dot() + "\n\nDominance frontier:\n" + df_str + else: + df_lab = blk.to_dot() + graph.node(str(blk._label), label=df_lab, shape='rectangle') + # edges + for name, blk in self._blocks.items(): + for child in blk.get_terminator().targets(): + graph.edge(str(blk._label), str(child)) + graph.render(filename, view=view) diff --git a/MiniC/Lib/Terminator.py b/MiniC/Lib/Terminator.py new file mode 100644 index 0000000..5ae5d1e --- /dev/null +++ b/MiniC/Lib/Terminator.py @@ -0,0 +1,133 @@ +""" +MIF08, CAP, CFG library - Terminators. + +Each :py:class:`block ` of a :py:class:`CFG ` +ends with a branching instruction called a terminator. +There are three kinds of terminators: + +- :py:class:`Lib.Statement.AbsoluteJump` is a non-conditional jump + to another block of the CFG +- :py:class:`BranchingTerminator` is a conditional branching + instruction with two successor blocks. + Unlike the class :py:class:`ConditionalJump ` + that was used in :py:class:`LinearCode `, + both successor labels have to be specified. +- :py:class:`Return` marks the end of the function + +During the construction of the CFG, :py:func:`jump2terminator` builds +a terminator for each extracted chunk of instructions. +""" + +from dataclasses import dataclass +from typing import List, Dict +from Lib.Errors import MiniCInternalError +from Lib.Operands import Operand, Renamer, Temporary, Condition +from Lib.Statement import AbsoluteJump, ConditionalJump, Instruction, Label, Statement + + +@dataclass(unsafe_hash=True) +class Return(Statement): + """A terminator that marks the end of the function.""" + + def __str__(self): + return ("return") + + def printIns(self, stream): + print("return", file=stream) + + def targets(self) -> List[Label]: + """Return the labels targetted by the Return terminator.""" + return [] + + def args(self) -> List[Operand]: + return [] + + def rename(self, renamer: Renamer): + pass + + def substitute(self, subst: Dict[Operand, Operand]): + if subst != {}: + raise Exception( + "substitute: No possible substitution on instruction {}" + .format(self)) + return self + + +@dataclass(init=False) +class BranchingTerminator(Instruction): + """A terminating statement with a condition.""" + + #: The condition of the branch + cond: Condition + #: The destination label if the condition is true + label_then: Label + #: The destination label if the condition is false + label_else: Label + #: The first operand of the condition + op1: Operand + #: The second operand of the condition + op2: Operand + _read_only = True + + def __init__(self, cond: Condition, op1: Operand, op2: Operand, + label_then: Label, label_else: Label): + self.cond = cond + self.label_then = label_then + self.label_else = label_else + self.op1 = op1 + self.op2 = op2 + self.ins = str(self.cond) + + def args(self) -> List[Operand]: + return [self.op1, self.op2, self.label_then, self.label_else] + + def targets(self) -> List[Label]: + """Return the labels targetted by the Branching terminator.""" + return [self.label_then, self.label_else] + + def rename(self, renamer: Renamer): + if isinstance(self.op1, Temporary): + self.op1 = renamer.replace(self.op1) + if isinstance(self.op2, Temporary): + self.op2 = renamer.replace(self.op2) + + def substitute(self, subst: Dict[Operand, Operand]): + for op in subst: + if op not in self.args(): + raise Exception( + "substitute: Operand {} is not present in instruction {}" + .format(op, self)) + op1 = subst.get(self.op1, self.op1) if isinstance(self.op1, Temporary) \ + else self.op1 + op2 = subst.get(self.op2, self.op2) if isinstance(self.op2, Temporary) \ + else self.op2 + return BranchingTerminator(self.cond, op1, op2, self.label_then, self.label_else) + + def __hash__(self): + return hash(super) + + +Terminator = Return | AbsoluteJump | BranchingTerminator + + +def jump2terminator(j: ConditionalJump | AbsoluteJump | None, + next_label: Label | None) -> Terminator: + """ + Construct the Terminator associated to the potential jump j + to the potential label next_label. + """ + match j: + case ConditionalJump(): + if (next_label is None): + raise MiniCInternalError( + "jump2terminator: Missing secondary label for instruction {}" + .format(j)) + label_else = next_label + return BranchingTerminator(j.cond, j.op1, j.op2, j.label, label_else) + case AbsoluteJump(): + return AbsoluteJump(label=j.label) + case None: + if next_label: + return AbsoluteJump(next_label) + else: + return Return() diff --git a/MiniC/MiniCC.py b/MiniC/MiniCC.py index 4c785f2..d82787c 100644 --- a/MiniC/MiniCC.py +++ b/MiniC/MiniCC.py @@ -216,7 +216,14 @@ liveness file not found for {}.".format(form)) s = "{}.{}.exitssa.dot".format(basename, code.fdata.get_name()) print("CFG after SSA:", s) code.print_dot(s, view=True) - code.print_code(output, comment=comment) + from Lib.LinearCode import LinearCode # type: ignore[import] + if isinstance(code, LinearCode): + code.print_code(output, comment=comment) + else: + from Lib.CFG import CFG # type: ignore[import] + from TP04.LinearizeCFG import linearize # type: ignore[import] + assert (isinstance(code, CFG)) + code.print_code(output, linearize=linearize, comment=comment) if debug: visitor3.printSymbolTable() diff --git a/MiniC/TP04/BuildCFG.py b/MiniC/TP04/BuildCFG.py new file mode 100644 index 0000000..7e4d384 --- /dev/null +++ b/MiniC/TP04/BuildCFG.py @@ -0,0 +1,111 @@ +""" +CAP, CodeGeneration, CFG construction from linear code +""" + +from typing import List +from Lib.Errors import MiniCInternalError +from Lib.FunctionData import FunctionData +from Lib.LinearCode import LinearCode, CodeStatement +from Lib.Statement import ( + Instru3A, Comment, Label, AbsoluteJump, ConditionalJump +) +from Lib.Terminator import jump2terminator +from Lib.CFG import Block, BlockInstr, CFG + + +def find_leaders(instructions: List[CodeStatement]) -> List[int]: + """ + Find the leaders in the given list of instructions as linear code. + Returns a list of indices in the instruction list whose first is 0 and + last is len(instructions) + """ + leaders: List[int] = [0] + # TODO fill leaders (Lab4b, Exercise 3) + # The final "ret" is also a form of jump + leaders.append(len(instructions)) + return leaders + + +def separate_with_leaders(instructions: List[CodeStatement], + leaders: List[int]) -> List[List[CodeStatement]]: + """ + Partition the lists instructions into a list containing for + elements the lists of statements between indices + leaders[i] (included) and leaders[i+1] (excluded). + + If leaders[i] = leaders[i+1], do not add the empty list. + """ + chunks: List[List[CodeStatement]] = [] + for i in range(0, len(leaders)-1): + start = leaders[i] + end = leaders[i+1] + if start != end: + # Avoid corner-cases when a label immediately follows a jump + chunks.append(instructions[start:end]) + return chunks + + +def prepare_chunk(pre_chunk: List[CodeStatement], fdata: FunctionData) -> tuple[ + Label, ConditionalJump | AbsoluteJump | None, List[BlockInstr]]: + """ + Extract the potential label (respectively jump) + at the start (respectively end) of the list instrs_chunk, + and return the tuple with this label, this jump and the + rest of instrs_chunk. + + If there is no label at the start then return a fresh label instead, + thanks to fdata (use `fdata.fresh_label(fdata._name)` for instance). + If there is no jump at the end, return None instead. + + Raise an error if there is a label not in first position in pre_chunk, + or a jump not in last position. + """ + label = None + jump = None + inner_statements: List[CodeStatement] = pre_chunk + # Extract the first instruction from inner_statements if it is a label, or create a fresh one + raise NotImplementedError() # TODO (Lab4b, Exercise 3) + # Extract the last instruction from inner_statements if it is a jump, or do nothing + raise NotImplementedError() # TODO (Lab4b, Exercise 3) + # Check that there is no other label or jump left in inner_statements + l: List[BlockInstr] = [] + for i in inner_statements: + match i: + case AbsoluteJump() | ConditionalJump(): + raise MiniCInternalError( + "prepare_chunk: Jump {} not in last position of a chunk" + .format(i)) + case Label(): + raise MiniCInternalError( + "prepare_chunk: Label {} not in first position of a chunk" + .format(i)) + case Instru3A() | Comment(): + l.append(i) + return (label, jump, l) + + +def build_cfg(linCode: LinearCode) -> CFG: + """Extract the blocks from the linear code and add them to the CFG.""" + fdata = linCode.fdata + cfg = CFG(fdata) + instructions = linCode.get_instructions() + # 1. Identify Leaders + leaders = find_leaders(instructions) + # 2. Extract Chunks of Instructions + pre_chunks: List[List[CodeStatement]] = separate_with_leaders(instructions, leaders) + chunks: List[tuple[Label, ConditionalJump | AbsoluteJump | None, List[BlockInstr]]] = [ + prepare_chunk(pre_chunk, fdata) for pre_chunk in pre_chunks] + # 3. Build the Blocks + next_label = None + for (label, jump, block_instrs) in reversed(chunks): + term = jump2terminator(jump, next_label) + block = Block(label, block_instrs, term) + cfg.add_block(block) + next_label = label + # 4. Fill the edges + for block in cfg.get_blocks(): + for dest in cfg.out_blocks(block): + cfg.add_edge(block, dest) + # 5. Identify the entry label of the CFG + cfg.set_start(chunks[0][0]) + return cfg diff --git a/MiniC/TP04/LinearizeCFG.py b/MiniC/TP04/LinearizeCFG.py new file mode 100644 index 0000000..d3f185e --- /dev/null +++ b/MiniC/TP04/LinearizeCFG.py @@ -0,0 +1,43 @@ +""" +CAP, CodeGeneration, CFG linearization to a list of statements +""" + +from typing import List, Set + +from Lib.Statement import ( + Statement, AbsoluteJump, ConditionalJump +) +from Lib.Terminator import (Return, BranchingTerminator) +from Lib.CFG import Block + + +def ordered_blocks_list(cfg) -> List[Block]: + """ + Compute a list of blocks with optimized ordering for linearization. + """ + # TODO (Lab4b, Extension) + return cfg.get_blocks() + + +def linearize(cfg) -> List[Statement]: + """ + Linearize the given control flow graph as a list of instructions. + """ + # TODO (Lab 4b, Exercise 5) + l: List[Statement] = [] # Linearized CFG + blocks: List[Block] = ordered_blocks_list(cfg) + for j, block in enumerate(blocks): + # 1. Add the label of the block to the linearization + l.append(block.get_label()) + # 2. Add the body of the block to the linearization + l.extend(block.get_body()) + # 3. Add the terminator of the block to the linearization + match block.get_terminator(): + case BranchingTerminator() as j: + l.append(ConditionalJump(j.cond, j.op1, j.op2, j.label_then)) + l.append(AbsoluteJump(j.label_else)) + case AbsoluteJump() as j: + l.append(AbsoluteJump(j.label)) + case Return(): + l.append(AbsoluteJump(cfg.get_end())) + return l diff --git a/MiniC/TP04/tests/provided/dataflow/df00.c b/MiniC/TP04/tests/provided/dataflow/df00.c new file mode 100644 index 0000000..1ce157a --- /dev/null +++ b/MiniC/TP04/tests/provided/dataflow/df00.c @@ -0,0 +1,13 @@ +#include "printlib.h" + +int main() { + + int n,u; + n=6; + println_int(n); + + return 0; +} + +// EXPECTED +// 6 \ No newline at end of file diff --git a/MiniC/TP04/tests/provided/dataflow/df01.c b/MiniC/TP04/tests/provided/dataflow/df01.c new file mode 100644 index 0000000..acbf660 --- /dev/null +++ b/MiniC/TP04/tests/provided/dataflow/df01.c @@ -0,0 +1,15 @@ +#include "printlib.h" + +int main() { + + int n,u,v; + n=6; + u=12; + v=n+u; + println_int(v); + + return 0; +} + +// EXPECTED +// 18 \ No newline at end of file diff --git a/MiniC/TP04/tests/provided/dataflow/df02.c b/MiniC/TP04/tests/provided/dataflow/df02.c new file mode 100644 index 0000000..55282c9 --- /dev/null +++ b/MiniC/TP04/tests/provided/dataflow/df02.c @@ -0,0 +1,14 @@ +#include "printlib.h" + +int main() { + + int n,v; + bool u; + n=6; + u=12>n; + println_bool(1 1) + { + n = n - 1; + u = u + n; + } + println_int(u); + return 0; +} + +// EXPECTED +// 15 \ No newline at end of file diff --git a/MiniC/TP04/tests/provided/dataflow/df04.c b/MiniC/TP04/tests/provided/dataflow/df04.c new file mode 100644 index 0000000..638a3a8 --- /dev/null +++ b/MiniC/TP04/tests/provided/dataflow/df04.c @@ -0,0 +1,16 @@ +#include "printlib.h" + +int main() +{ + + int x, y; + x = 2; + if (x < 4) + x = 4; + else + x = 5; + + return 0; +} + +// EXPECTED \ No newline at end of file diff --git a/MiniC/TP04/tests/provided/dataflow/df05.c b/MiniC/TP04/tests/provided/dataflow/df05.c new file mode 100644 index 0000000..ccee7fb --- /dev/null +++ b/MiniC/TP04/tests/provided/dataflow/df05.c @@ -0,0 +1,14 @@ +#include "printlib.h" + +int main() +{ + int x; + x = 0; + while (x < 4) + { + x = x + 1; + } + return 0; +} + +// EXPECTED \ No newline at end of file diff --git a/MiniC/TP04/tp4b.pdf b/MiniC/TP04/tp4b.pdf new file mode 100644 index 0000000000000000000000000000000000000000..644881d0e9c1a64e7e2d16f802882d39a50b5157 GIT binary patch literal 91522 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

ehcK6+U$!T@^-+E=kB4j7I&s;p=*(XVl7r{4I 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 z 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 library - Function data

  • Linear intermediate representation
  • Temporary allocation
  • +
  • Control Flow Graph - CFG and Basic blocks
  • +
  • Control Flow Graph - Terminators
  • diff --git a/docs/_modules/Lib/CFG.html b/docs/_modules/Lib/CFG.html new file mode 100644 index 0000000..bc7a4cd --- /dev/null +++ b/docs/_modules/Lib/CFG.html @@ -0,0 +1,377 @@ + + + + + + Lib.CFG — MiniC documentation + + + + + + + + + + + + + + + +
    + + +
    + +
    +
    +
    + +
    +
    +
    +
    + +

    Source code for Lib.CFG

    +"""
    +Classes for a RiscV CFG: :py:class:`CFG` for the CFG itself,
    +and :py:class:`Block` for its basic blocks.
    +"""
    +
    +from graphviz import Digraph  # for dot output
    +from typing import cast, Any, Dict, List, Set, Iterator
    +
    +from Lib.Errors import MiniCInternalError
    +from Lib.Operands import (Operand, Immediate, Function, A0)
    +from Lib.Statement import (
    +    Statement, Instru3A, Label,
    +    AbsoluteJump, ConditionalJump, Comment
    +)
    +from Lib.Terminator import (
    +    Terminator, BranchingTerminator, Return)
    +from Lib.FunctionData import (FunctionData, _iter_statements, _print_code)
    +
    +
    +BlockInstr = Instru3A | Comment
    +
    +
    +
    [docs]class Block: + """ + A basic block of a :py:class:`CFG` is made of three main parts: + + - a start :py:class:`label <Lib.Statement.Label>` that uniquely identifies the block in the CFG + - the main body of the block, a list of instructions + (excluding labels, jumps and branching instructions) + - a :py:class:`terminator <Lib.Terminator.Terminator>` + that represents the final jump or branching instruction of the block, + and points to the successors of the block. + See the documentation for :py:class:`Lib.Terminator.Terminator` for further explanations. + """ + + _terminator: Terminator + _label: Label + _phis: List[Statement] + _instructions: List[BlockInstr] + _in: List['Block'] + _gen: Set + _kill: Set + + def __init__(self, label: Label, insts: List[BlockInstr], terminator: Terminator): + self._label = label + self._instructions = insts + self._in = [] + self._phis = [] + self._terminator = terminator + self._gen = set() + self._kill = set() + + def __str__(self): + instr = [i for i in self._instructions if not isinstance(i, Comment)] + instr_str = '\n'.join(map(str, instr)) + s = '{}:\n\n{}'.format(self._label, instr_str) + return s + +
    [docs] def to_dot(self) -> str: # pragma: no cover + """Outputs all statements of the block as a string.""" + # dot is weird: lines ending with \l instead of \n are left-aligned. + NEWLINE = '\\l ' + instr = [] + instr += self._phis + instr += [i for i in self._instructions if not isinstance(i, Comment)] + instr += [self.get_terminator()] + instr_str = NEWLINE.join(map(str, instr)) + s = '{}:{}{}\\l'.format(self._label, NEWLINE, instr_str) + return s
    + + def __repr__(self): + return str(self._label) + +
    [docs] def get_body(self) -> List[BlockInstr]: + """Return the statements in the body of the block (no phi-node nor the terminator).""" + return self._instructions
    + +
    [docs] def get_all_statements(self) -> List[Statement]: + """ + Return all statements of the block + (including phi-nodes and the terminator, but not the label of the block). + """ + return (self._phis + + cast(List[Statement], self._instructions) + + [self.get_terminator()])
    + +
    [docs] def get_label(self) -> Label: + """Return the label of the block.""" + return self._label
    + +
    [docs] def get_in(self) -> List['Block']: + """Return the list of blocks with an edge to the considered block.""" + return self._in
    + +
    [docs] def get_terminator(self) -> Terminator: + """Return the terminator of the block.""" + return self._terminator
    + +
    [docs] def set_terminator(self, term: Terminator) -> None: + """Set the terminator of the block.""" + self._terminator = term
    + +
    [docs] def iter_statements(self, f) -> None: + """Iterate over instructions. + For each real instruction i (not label or comment), replace it + with the list of instructions given by f(i). + + Assume there is no phi-node. + """ + assert (self._phis == []) + new_statements = _iter_statements(self._instructions, f) + end_statements = f(self.get_terminator()) + if len(end_statements) >= 1 and isinstance(end_statements[-1], Terminator): + new_terminator = end_statements.pop(-1) + self._instructions = new_statements + end_statements + self.set_terminator(new_terminator) + else: + raise MiniCInternalError( + "Block.iter_statements: Invalid replacement for terminator {}:\n {}" + .format(self.get_terminator(), end_statements))
    + +
    [docs] def add_instruction(self, instr: BlockInstr) -> None: + """Add an instruction to the body of the block.""" + self._instructions.append(instr)
    + + +
    [docs]class CFG: + """ + A complete control-flow graph representing a function. + This class is mainly made of a list of basic :py:class:`Block`, + a label indicating the :py:meth:`entry point of the function <get_start>`, + and an :py:meth:`exit label <get_end>`. + + As with linear code, metadata about the function can be found + in the :py:attr:`fdata` member variable. + """ + + _start: Label + _end: Label + _blocks: Dict[Label, Block] + + #: Metadata about the function represented by this CFG + fdata: FunctionData + + def __init__(self, fdata: FunctionData): + self._blocks = {} + self.fdata = fdata + self._init_blks() + self._end = self.fdata.fresh_label("end") + + def _init_blks(self) -> None: + """Add a block for division by 0.""" + # Label for the address of the error message + # This address is added by print_code + label_div_by_zero_msg = Label(self.fdata._label_div_by_zero.name + "_msg") + blk = Block(self.fdata._label_div_by_zero, [ + Instru3A("la", A0, label_div_by_zero_msg), + Instru3A("call", Function("println_string")), + Instru3A("li", A0, Immediate(1)), + Instru3A("call", Function("exit")), + ], terminator=Return()) + self.add_block(blk) + +
    [docs] def get_start(self) -> Label: + """Return the entry label of the CFG.""" + return self._start
    + +
    [docs] def set_start(self, start: Label) -> None: + """Set the entry label of the CFG.""" + assert (start in self._blocks) + self._start = start
    + +
    [docs] def get_end(self) -> Label: + """Return the exit label of the CFG.""" + return self._end
    + +
    [docs] def add_block(self, blk: Block) -> None: + """Add a new block to the CFG.""" + self._blocks[blk._label] = blk
    + +
    [docs] def get_block(self, name: Label) -> Block: + """Return the block with label `name`.""" + return self._blocks[name]
    + +
    [docs] def get_blocks(self) -> List[Block]: + """Return all the blocks.""" + return [b for b in self._blocks.values()]
    + +
    [docs] def get_entries(self) -> List[Block]: + """Return all the blocks with no predecessors.""" + return [b for b in self._blocks.values() if not b.get_in()]
    + +
    [docs] def add_edge(self, src: Block, dest: Block) -> None: + """Add the edge src -> dest in the control flow graph.""" + dest.get_in().append(src)
    + # assert (dest.get_label() in src.get_terminator().targets()) + +
    [docs] def remove_edge(self, src: Block, dest: Block) -> None: + """Remove the edge src -> dest in the control flow graph.""" + dest.get_in().remove(src)
    + # assert (dest.get_label() not in src.get_terminator().targets()) + +
    [docs] def out_blocks(self, block: Block) -> List[Block]: + """ + Return the list of blocks in the CFG targeted by + the Terminator of Block block. + """ + return [self.get_block(dest) for dest in block.get_terminator().targets()]
    + +
    [docs] def gather_defs(self) -> Dict[Any, Set[Block]]: + """ + Return a dictionary associating variables to all the blocks + containing one of their definitions. + """ + defs: Dict[Operand, Set[Block]] = dict() + for b in self.get_blocks(): + for i in b.get_all_statements(): + for v in i.defined(): + if v not in defs: + defs[v] = {b} + else: + defs[v].add(b) + return defs
    + +
    [docs] def iter_statements(self, f) -> None: + """Apply f to all instructions in all the blocks.""" + for b in self.get_blocks(): + b.iter_statements(f)
    + +
    [docs] def linearize_naive(self) -> Iterator[Statement]: + """ + Linearize the given control flow graph as a list of instructions. + Naive procedure that adds jumps everywhere. + """ + for label, block in self._blocks.items(): + yield label + for i in block._instructions: + yield i + match block.get_terminator(): + case BranchingTerminator() as j: + # In case of conditional jump, add the missing edge + yield ConditionalJump(j.cond, j.op1, j.op2, j.label_then) + yield AbsoluteJump(j.label_else) + case AbsoluteJump() as j: + yield AbsoluteJump(j.label) + case Return(): + yield AbsoluteJump(self.get_end())
    + +
    [docs] def print_code(self, output, linearize=(lambda cfg: list(cfg.linearize_naive())), + comment=None) -> None: + """Print the linearization of the CFG.""" + statements = linearize(self) + _print_code(statements, self.fdata, output, init_label=self._start, + fin_label=self._end, fin_div0=False, comment=comment)
    + +
    [docs] def print_dot(self, filename, DF=None, view=False) -> None: # pragma: no cover + """Print the CFG as a graph.""" + graph = Digraph() + # nodes + for name, blk in self._blocks.items(): + if DF is not None: + print(str(name), blk._label) + df_str = "{}" if blk not in DF or not len(DF[blk]) else str(DF[blk]) + df_lab = blk.to_dot() + "\n\nDominance frontier:\n" + df_str + else: + df_lab = blk.to_dot() + graph.node(str(blk._label), label=df_lab, shape='rectangle') + # edges + for name, blk in self._blocks.items(): + for child in blk.get_terminator().targets(): + graph.edge(str(blk._label), str(child)) + graph.render(filename, view=view)
    +
    + +
    +
    + +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/docs/_modules/Lib/Errors.html b/docs/_modules/Lib/Errors.html index 12c3e32..0d94674 100644 --- a/docs/_modules/Lib/Errors.html +++ b/docs/_modules/Lib/Errors.html @@ -44,6 +44,8 @@
  • Base library - Function data
  • Linear intermediate representation
  • Temporary allocation
  • +
  • Control Flow Graph - CFG and Basic blocks
  • +
  • Control Flow Graph - Terminators
  • diff --git a/docs/_modules/Lib/FunctionData.html b/docs/_modules/Lib/FunctionData.html index 580bce4..5a19688 100644 --- a/docs/_modules/Lib/FunctionData.html +++ b/docs/_modules/Lib/FunctionData.html @@ -44,6 +44,8 @@
  • Base library - Function data
  • Linear intermediate representation
  • Temporary allocation
  • +
  • Control Flow Graph - CFG and Basic blocks
  • +
  • Control Flow Graph - Terminators
  • diff --git a/docs/_modules/Lib/LinearCode.html b/docs/_modules/Lib/LinearCode.html index a385f23..cc350fe 100644 --- a/docs/_modules/Lib/LinearCode.html +++ b/docs/_modules/Lib/LinearCode.html @@ -44,6 +44,8 @@
  • Base library - Function data
  • Linear intermediate representation
  • Temporary allocation
  • +
  • Control Flow Graph - CFG and Basic blocks
  • +
  • Control Flow Graph - Terminators
  • diff --git a/docs/_modules/Lib/Operands.html b/docs/_modules/Lib/Operands.html index 4770337..1fcfa16 100644 --- a/docs/_modules/Lib/Operands.html +++ b/docs/_modules/Lib/Operands.html @@ -44,6 +44,8 @@
  • Base library - Function data
  • Linear intermediate representation
  • Temporary allocation
  • +
  • Control Flow Graph - CFG and Basic blocks
  • +
  • Control Flow Graph - Terminators
  • @@ -195,19 +197,33 @@ # Shortcuts for registers in RISCV # Only integer registers + +#: Zero register ZERO = Register(0) +#: RA = Register(1) +#: SP = Register(2) +#: GP = Register(3) # Register not used for this course +#: TP = Register(4) # Register not used for this course +#: A = tuple(Register(i + 10) for i in range(8)) +#: S = tuple(Register(i + 8) for i in range(2)) + tuple(Register(i + 18) for i in range(10)) +#: T = tuple(Register(i + 5) for i in range(3)) + tuple(Register(i + 28) for i in range(4)) + + +#: A0 = A[0] # function args/return Values: A0, A1 +#: A1 = A[1] +#: FP = S[0] # Frame Pointer = Saved register 0 -# General purpose registers, usable for the allocator +#: General purpose registers, usable for the allocator GP_REGS = S[4:] + T # s0, s1, s2 and s3 are special diff --git a/docs/_modules/Lib/RiscV.html b/docs/_modules/Lib/RiscV.html index a844dc3..6f37f75 100644 --- a/docs/_modules/Lib/RiscV.html +++ b/docs/_modules/Lib/RiscV.html @@ -44,6 +44,8 @@
  • Base library - Function data
  • Linear intermediate representation
  • Temporary allocation
  • +
  • Control Flow Graph - CFG and Basic blocks
  • +
  • Control Flow Graph - Terminators
  • diff --git a/docs/_modules/Lib/Statement.html b/docs/_modules/Lib/Statement.html index e23cd76..3160cdb 100644 --- a/docs/_modules/Lib/Statement.html +++ b/docs/_modules/Lib/Statement.html @@ -44,6 +44,8 @@
  • Base library - Function data
  • Linear intermediate representation
  • Temporary allocation
  • +
  • Control Flow Graph - CFG and Basic blocks
  • +
  • Control Flow Graph - Terminators
  • @@ -100,9 +102,11 @@ """A Statement, which is an instruction, a comment or a label."""
    [docs] def defined(self) -> List[Operand]: + """Operands defined (written) in this instruction""" return []
    [docs] def used(self) -> List[Operand]: + """Operands used (read) in this instruction""" return []
    [docs] def substitute(self: TStatement, subst: Dict[Operand, Operand]) -> TStatement: @@ -112,7 +116,7 @@
    [docs] def printIns(self, stream): """ - Print the statement on the output. + Print the statement on the given output. Should never be called on the base class. """ raise NotImplementedError
    @@ -163,6 +167,7 @@ raise NotImplementedError
    [docs] def args(self) -> List[Operand]: + """List of operands the instruction takes""" raise NotImplementedError
    [docs] def defined(self): @@ -194,7 +199,7 @@ return hash((self.ins, *self.args()))
    [docs] def printIns(self, stream): - """Print the instruction on the output.""" + """Print the instruction on the given output.""" print(' ', str(self), file=stream)
    diff --git a/docs/_modules/Lib/Terminator.html b/docs/_modules/Lib/Terminator.html new file mode 100644 index 0000000..8cd4e5f --- /dev/null +++ b/docs/_modules/Lib/Terminator.html @@ -0,0 +1,238 @@ + + + + + + Lib.Terminator — MiniC documentation + + + + + + + + + + + + + + + +
    + + +
    + +
    +
    +
    + +
    +
    +
    +
    + +

    Source code for Lib.Terminator

    +"""
    +MIF08, CAP, CFG library - Terminators.
    +
    +Each :py:class:`block <Lib.CFG.Block>` of a :py:class:`CFG <Lib.CFG.CFG>`
    +ends with a branching instruction called a terminator.
    +There are three kinds of terminators:
    +
    +- :py:class:`Lib.Statement.AbsoluteJump` is a non-conditional jump
    +  to another block of the CFG
    +- :py:class:`BranchingTerminator` is a conditional branching
    +  instruction with two successor blocks.
    +  Unlike the class :py:class:`ConditionalJump <Lib.Statement.ConditionalJump>`
    +  that was used in :py:class:`LinearCode <Lib.LinearCode.LinearCode>`,
    +  both successor labels have to be specified.
    +- :py:class:`Return` marks the end of the function
    +
    +During the construction of the CFG, :py:func:`jump2terminator` builds
    +a terminator for each extracted chunk of instructions.
    +"""
    +
    +from dataclasses import dataclass
    +from typing import List, Dict
    +from Lib.Errors import MiniCInternalError
    +from Lib.Operands import Operand, Renamer, Temporary, Condition
    +from Lib.Statement import AbsoluteJump, ConditionalJump, Instruction, Label, Statement
    +
    +
    +
    [docs]@dataclass(unsafe_hash=True) +class Return(Statement): + """A terminator that marks the end of the function.""" + + def __str__(self): + return ("return") + +
    [docs] def printIns(self, stream): + print("return", file=stream)
    + +
    [docs] def targets(self) -> List[Label]: + """Return the labels targetted by the Return terminator.""" + return []
    + +
    [docs] def args(self) -> List[Operand]: + return []
    + +
    [docs] def rename(self, renamer: Renamer): + pass
    + +
    [docs] def substitute(self, subst: Dict[Operand, Operand]): + if subst != {}: + raise Exception( + "substitute: No possible substitution on instruction {}" + .format(self)) + return self
    + + +
    [docs]@dataclass(init=False) +class BranchingTerminator(Instruction): + """A terminating statement with a condition.""" + + #: The condition of the branch + cond: Condition + #: The destination label if the condition is true + label_then: Label + #: The destination label if the condition is false + label_else: Label + #: The first operand of the condition + op1: Operand + #: The second operand of the condition + op2: Operand + _read_only = True + + def __init__(self, cond: Condition, op1: Operand, op2: Operand, + label_then: Label, label_else: Label): + self.cond = cond + self.label_then = label_then + self.label_else = label_else + self.op1 = op1 + self.op2 = op2 + self.ins = str(self.cond) + +
    [docs] def args(self) -> List[Operand]: + return [self.op1, self.op2, self.label_then, self.label_else]
    + +
    [docs] def targets(self) -> List[Label]: + """Return the labels targetted by the Branching terminator.""" + return [self.label_then, self.label_else]
    + +
    [docs] def rename(self, renamer: Renamer): + if isinstance(self.op1, Temporary): + self.op1 = renamer.replace(self.op1) + if isinstance(self.op2, Temporary): + self.op2 = renamer.replace(self.op2)
    + +
    [docs] def substitute(self, subst: Dict[Operand, Operand]): + for op in subst: + if op not in self.args(): + raise Exception( + "substitute: Operand {} is not present in instruction {}" + .format(op, self)) + op1 = subst.get(self.op1, self.op1) if isinstance(self.op1, Temporary) \ + else self.op1 + op2 = subst.get(self.op2, self.op2) if isinstance(self.op2, Temporary) \ + else self.op2 + return BranchingTerminator(self.cond, op1, op2, self.label_then, self.label_else)
    + + def __hash__(self): + return hash(super)
    + + +Terminator = Return | AbsoluteJump | BranchingTerminator + + +
    [docs]def jump2terminator(j: ConditionalJump | AbsoluteJump | None, + next_label: Label | None) -> Terminator: + """ + Construct the Terminator associated to the potential jump j + to the potential label next_label. + """ + match j: + case ConditionalJump(): + if (next_label is None): + raise MiniCInternalError( + "jump2terminator: Missing secondary label for instruction {}" + .format(j)) + label_else = next_label + return BranchingTerminator(j.cond, j.op1, j.op2, j.label, label_else) + case AbsoluteJump(): + return AbsoluteJump(label=j.label) + case None: + if next_label: + return AbsoluteJump(next_label) + else: + return Return()
    +
    + +
    +
    + +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/docs/_modules/index.html b/docs/_modules/index.html index 030026f..4dc1e00 100644 --- a/docs/_modules/index.html +++ b/docs/_modules/index.html @@ -44,6 +44,8 @@
  • Base library - Function data
  • Linear intermediate representation
  • Temporary allocation
  • +
  • Control Flow Graph - CFG and Basic blocks
  • +
  • Control Flow Graph - Terminators
  • @@ -71,12 +73,14 @@

    All modules for which code is available

    diff --git a/docs/_sources/api/Lib.CFG.rst.txt b/docs/_sources/api/Lib.CFG.rst.txt new file mode 100644 index 0000000..f66acb6 --- /dev/null +++ b/docs/_sources/api/Lib.CFG.rst.txt @@ -0,0 +1,7 @@ +Lib.CFG module +============== + +.. automodule:: Lib.CFG + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_sources/api/Lib.Terminator.rst.txt b/docs/_sources/api/Lib.Terminator.rst.txt new file mode 100644 index 0000000..47a406c --- /dev/null +++ b/docs/_sources/api/Lib.Terminator.rst.txt @@ -0,0 +1,7 @@ +Lib.Terminator module +===================== + +.. automodule:: Lib.Terminator + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_sources/api/Lib.rst.txt b/docs/_sources/api/Lib.rst.txt index 9de53f0..ed2c967 100644 --- a/docs/_sources/api/Lib.rst.txt +++ b/docs/_sources/api/Lib.rst.txt @@ -8,12 +8,14 @@ Submodules :maxdepth: 4 Lib.Allocator + Lib.CFG Lib.Errors Lib.FunctionData Lib.LinearCode Lib.Operands Lib.RiscV Lib.Statement + Lib.Terminator Module contents --------------- diff --git a/docs/_sources/index.rst.txt b/docs/_sources/index.rst.txt index 839de3a..5514932 100644 --- a/docs/_sources/index.rst.txt +++ b/docs/_sources/index.rst.txt @@ -17,6 +17,8 @@ Welcome to MiniC's documentation! Base library - Function data Linear intermediate representation Temporary allocation + Control Flow Graph - CFG and Basic blocks + Control Flow Graph - Terminators These pages document the various Python sources in the Lib/ folder of MiniC. You should not have to edit them *at all*. @@ -46,6 +48,12 @@ Temporary allocation Before implementing the all-in-memory allocator of lab 4a, you should understand the naive allocator in the :doc:`api/Lib.Allocator`. +Control Flow Graph Intermediate representation +---------------------------------------------- + +The classes for the CFG and its basic blocks are in the :doc:`api/Lib.CFG`. +Each block ends with a terminator, as documented in the :doc:`api/Lib.Terminator`. + Indices and tables ================== diff --git a/docs/api/Lib.Allocator.html b/docs/api/Lib.Allocator.html index 733254d..0691e4d 100644 --- a/docs/api/Lib.Allocator.html +++ b/docs/api/Lib.Allocator.html @@ -19,6 +19,7 @@ + @@ -46,6 +47,8 @@
  • Base library - Function data
  • Linear intermediate representation
  • Temporary allocation
  • +
  • Control Flow Graph - CFG and Basic blocks
  • +
  • Control Flow Graph - Terminators
  • @@ -121,6 +124,12 @@ registers or memory locations.

    Bases: Allocator

    Naive Allocator: try to assign a register to each temporary, fails if there are more temporaries than registers.

    +
    +
    +replace(old_instr: Instruction) List[Instruction][source]
    +

    Replace Temporary operands with the corresponding allocated Register.

    +
    +
    prepare() None[source]
    @@ -128,12 +137,6 @@ fails if there are more temporaries than registers.

    Fail if there are too many temporaries.

    -
    -
    -replace(old_instr: Instruction) List[Instruction][source]
    -

    Replace Temporary operands with the corresponding allocated Register.

    -
    - @@ -143,6 +146,7 @@ Fail if there are too many temporaries.