Adding TP4a

This commit is contained in:
BuildTools 2024-10-06 19:58:11 +02:00
parent a29c888d25
commit b9b122efe2
158 changed files with 14725 additions and 4 deletions

79
MiniC/Lib/Allocator.py Normal file
View File

@ -0,0 +1,79 @@
"""
This file defines the base class :py:class:`Allocator`
and the naïve implementation :py:class:`NaiveAllocator`.
"""
from Lib.Operands import Temporary, Operand, DataLocation, GP_REGS
from Lib.Statement import Instruction
from Lib.Errors import AllocationError
from Lib.FunctionData import FunctionData
from typing import Dict, List
class Allocator():
"""General base class for Naive, AllInMem and Smart Allocators.
Replace all temporaries in the code with actual data locations.
Allocation is done in two steps:
- First, :py:meth:`prepare` is responsible for calling
:py:meth:`Lib.Operands.TemporaryPool.set_temp_allocation`
with a mapping from temporaries to where they should actually be stored
(in registers or in memory).
- Then, :py:meth:`replace` is called for each instruction in order to
replace the temporary operands with the previously assigned locations
(and possibly add some instructions before or after).
Concretely, it returns a list of instructions that should replace the original
instruction. The actual iteration over all the instructions is handled transparently
by :py:meth:`Lib.LinearCode.LinearCode.iter_statements`.
"""
_fdata: FunctionData
def __init__(self, fdata: FunctionData):
self._fdata = fdata
def prepare(self) -> None: # pragma: no cover
pass
def replace(self, old_instr: Instruction) -> List[Instruction]:
"""Transform an instruction with temporaries into a list of instructions."""
return [old_instr]
def rewriteCode(self, listcode) -> None:
"""Modify the code to replace temporaries with
registers or memory locations.
"""
listcode.iter_statements(self.replace)
class NaiveAllocator(Allocator):
"""Naive Allocator: try to assign a register to each temporary,
fails if there are more temporaries than registers.
"""
def replace(self, old_instr: Instruction) -> List[Instruction]:
"""Replace Temporary operands with the corresponding allocated Register."""
new_args: List[Operand] = []
for arg in old_instr.args():
if isinstance(arg, Temporary):
new_args.append(arg.get_alloced_loc())
else:
new_args.append(arg)
new_instr = old_instr.with_args(new_args)
return [new_instr]
def prepare(self) -> None:
"""Allocate all temporaries to registers.
Fail if there are too many temporaries."""
regs = list(GP_REGS) # Get a writable copy
temp_allocation: Dict[Temporary, DataLocation] = dict()
for tmp in self._fdata._pool.get_all_temps():
try:
reg = regs.pop()
except IndexError:
raise AllocationError(
"Too many temporaries ({}) for the naive allocation, sorry."
.format(len(self._fdata._pool.get_all_temps())))
temp_allocation[tmp] = reg
self._fdata._pool.set_temp_allocation(temp_allocation)

295
MiniC/Lib/CFG.py Normal file
View File

@ -0,0 +1,295 @@
"""
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 <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
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_body_and_terminator(self) -> List[Statement]:
"""
Return all statements of the block, except phi-nodes
(and the label of the block).
"""
return (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 get_phis(self) -> List[Statement]:
"""Return the list of all φ instructions of the block."""
return self._phis
def add_phi(self, phi: Statement) -> None:
"""Add a φ instruction to the block."""
self._phis.append(phi)
def set_phis(self, phis: List[Statement]) -> None:
"""Replace the φ instructions in the block by the given list `phis`."""
self._phis = phis
def remove_all_phis(self) -> None:
"""Remove all φ instructions in the block."""
self._phis = []
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 <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)
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:
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)

128
MiniC/Lib/Dominators.py Normal file
View File

@ -0,0 +1,128 @@
"""
Utility functions to work with dominators in a :py:class:`CFG <Lib.CFG.CFG>`.
Do not hesitate to look at the source of the functions
to get a better understanding of the algorithms.
"""
from typing import Dict, Set
from graphviz import Digraph
from Lib.CFG import Block, CFG
def computeDom(cfg: CFG) -> Dict[Block, Set[Block]]:
"""
`computeDom(cfg)` computes the table associating blocks to their
dominators in `cfg`.
It works by solving the equation system.
This is an helper function called during SSA entry.
"""
all_blocks: Set[Block] = set(cfg.get_blocks())
dominators: Dict[Block, Set[Block]] = dict()
for b in all_blocks:
if b.get_in(): # If b has some predecessor
dominators[b] = all_blocks
else: # If b has no predecessors
dominators[b] = {b}
new_dominators: Dict[Block, Set[Block]] = dict()
while True:
for b in all_blocks:
if b.get_in():
dom_preds = [dominators[b2] for b2 in b.get_in()]
new_dominators[b] = {b}.union(set.intersection(*dom_preds))
else:
new_dominators[b] = {b}
if dominators == new_dominators:
break
else:
dominators = new_dominators
new_dominators = dict()
return dominators
def printDT(filename: str, graph: Dict[Block, Set[Block]]) -> None: # pragma: no cover
"""Display a graphical rendering of the given domination tree."""
dot = Digraph()
for k in graph:
dot.node(str(k.get_label()))
for k in graph:
for v in graph[k]:
dot.edge(str(k.get_label()), str(v.get_label()))
dot.render(filename, view=True)
def computeDT(cfg: CFG, dominators: Dict[Block, Set[Block]],
dom_graphs: bool, basename: str) -> Dict[Block, Set[Block]]:
"""
`computeDT(cfg, dominators)` computes the domination tree of `cfg`
using the previously computed `dominators`.
It returns `DT`, a dictionary which associates a block with its children
in the dominator tree.
This is an helper function called during SSA entry.
"""
# First, compute the immediate dominators
idominators: Dict[Block, Block] = {}
for b, doms in dominators.items():
# The immediate dominator of b is the unique vertex n ≠ b
# which dominates b and is dominated by all vertices in Dom(b) b.
strict_doms = doms - {b}
idoms = set()
for n in strict_doms:
if strict_doms.issubset(dominators[n]):
idoms.add(n)
if idoms:
assert (len(idoms) == 1)
idominators[b] = idoms.pop()
# Then, simply inverse the relation to obtain the domination tree
DT = {b: set() for b in cfg.get_blocks()}
for i, idominator in idominators.items():
DT[idominator].add(i)
# Print the domination tree if asked
if dom_graphs:
s = "{}.{}.ssa.DT.dot".format(basename, cfg.fdata.get_name())
print("SSA - domination tree graph:", s)
printDT(s, DT)
return DT
def _computeDF_at_block(
cfg: CFG,
dominators: Dict[Block, Set[Block]],
DT: Dict[Block, Set[Block]],
b: Block,
DF: Dict[Block, Set[Block]]) -> None:
"""
`_computeDF_at_block(...)` computes the dominance frontier at the given block,
by updating `DF`.
This is an helper function called during SSA entry.
"""
S: Set[Block] = {succ for succ in cfg.out_blocks(b) if succ not in DT[b]}
for b_succ in DT[b]:
_computeDF_at_block(cfg, dominators, DT, b_succ, DF)
for b_frontier in DF[b_succ]:
if b not in (dominators[b_frontier] - {b_frontier}):
S.add(b_frontier)
DF[b] = S
def computeDF(cfg: CFG, dominators: Dict[Block, Set[Block]],
DT: Dict[Block, Set[Block]], dom_graphs: bool, basename: str
) -> Dict[Block, Set[Block]]:
"""
`computeDF(...)` computes the dominance frontier of a CFG.
It returns `DF` which associates a block to its frontier.
This is an helper function called during SSA entry.
"""
DF: Dict[Block, Set[Block]] = dict()
for b_entry in cfg.get_entries():
_computeDF_at_block(cfg, dominators, DT, b_entry, DF)
# Print the domination frontier on the CFG if asked
if dom_graphs:
s = "{}.{}.ssa.DF.dot".format(basename, cfg.fdata.get_name())
print("SSA - dominance frontier graph:", s)
cfg.print_dot(s, DF, True)
return DF

181
MiniC/Lib/FunctionData.py Normal file
View File

@ -0,0 +1,181 @@
"""
This file defines the base class :py:class:`FunctionData`,
containing metadata on a RiscV function, as well as utility
functions common to the different intermediate representations.
"""
from typing import (List, Callable, TypeVar)
from Lib.Errors import AllocationError
from Lib.Operands import (
Offset, Temporary, TemporaryPool,
S, T, FP)
from Lib.Statement import (Statement, Instruction, Label, Comment)
class FunctionData:
"""
Stores some metadata on a RiscV function:
name of the function, label names, temporary variables
(using :py:class:`Lib.Operands.TemporaryPool`),
and div_by_zero label.
This class is usually used indirectly through the
different intermediate representations we work with,
such as :py:attr:`Lib.LinearCode.LinearCode.fdata`.
"""
_nblabel: int
_dec: int
_pool: TemporaryPool
_name: str
_label_div_by_zero: Label
def __init__(self, name: str):
self._nblabel = -1
self._dec = 0
self._pool = TemporaryPool()
self._name = name
self._label_div_by_zero = self.fresh_label("div_by_zero")
def get_name(self) -> str:
"""Return the name of the function."""
return self._name
def fresh_tmp(self) -> Temporary:
"""
Return a new fresh Temporary,
which is added to the pool.
"""
return self._pool.fresh_tmp()
def fresh_offset(self) -> Offset:
"""
Return a new offset in the memory stack.
Offsets are decreasing relative to FP.
"""
self._dec = self._dec + 1
# For ld or sd, an offset on 12 signed bits is expected
# Raise an error if the offset is too big
if -8 * self._dec < - 2 ** 11:
raise AllocationError(
"Offset given by the allocation too big to be manipulated ({}), sorry."
.format(self._dec))
return Offset(FP, -8 * self._dec)
def get_offset(self) -> int:
"""
Return the current offset in the memory stack.
"""
return self._dec
def _fresh_label_name(self, name) -> str:
"""
Return a new unique label name based on the given string.
"""
self._nblabel = self._nblabel + 1
return name + "_" + str(self._nblabel) + "_" + self._name
def fresh_label(self, name) -> Label:
"""
Return a new label, with a unique name based on the given string.
"""
return Label(self._fresh_label_name(name))
def get_label_div_by_zero(self) -> Label:
return self._label_div_by_zero
_T = TypeVar("_T", bound=Statement)
def _iter_statements(
listIns: List[_T], f: Callable[[_T], List[_T]]) -> List[_T | Comment]:
"""Iterate over instructions.
For each real instruction i (not label or comment), replace it
with the list of instructions given by f(i).
"""
newListIns: List[_T | Comment] = []
for old_i in listIns:
# Do nothing for label or comment
if not isinstance(old_i, Instruction):
newListIns.append(old_i)
continue
new_i_list = f(old_i)
# Otherwise, replace the instruction by the list
# returned by f, with comments giving the replacement
newListIns.append(Comment("Replaced " + str(old_i)))
newListIns.extend(new_i_list)
return newListIns
def _print_code(listIns: List, fdata: FunctionData, output,
init_label=None, fin_label=None, fin_div0=False, comment=None) -> None:
"""
Please use print_code from LinearCode or CFG, not directly this one.
Print the instructions from listIns, forming fdata, on output.
If init_label is given, add an initial jump to it before the generated code.
If fin_label is given, add it after the generated code.
If fin_div0 is given equal to true, add the code for returning an
error when dividing by 0, at the very end.
"""
# compute size for the local stack - do not forget to align by 16
fo = fdata.get_offset() # allocate enough memory for stack
# Room for S_i (except S_0 which is fp) and T_i backup
fo += len(S[1:]) + len(T)
cardoffset = 8 * (fo + (0 if fo % 2 == 0 else 1)) + 16
output.write(
"##Automatically generated RISCV code, MIF08 & CAP\n")
if comment is not None:
output.write("##{} version\n".format(comment))
output.write("\n\n##prelude\n")
# We put an li t0, cardoffset in case it is greater than 2**11
# We use t0 because it is caller-saved
output.write("""
.text
.globl {0}
{0}:
li t0, {1}
sub sp, sp, t0
sd ra, 0(sp)
sd fp, 8(sp)
add fp, sp, t0
""".format(fdata.get_name(), cardoffset))
# Stack in RiscV is managed with SP
if init_label is not None:
# Add a jump to init_label before the generated code.
output.write("""
j {0}
""".format(init_label))
output.write("\n\n##Generated Code\n")
# Generated code
for i in listIns:
i.printIns(output)
output.write("\n\n##postlude\n")
if fin_label is not None:
# Add fin_label after the generated code.
output.write("""
{0}:
""".format(fin_label))
# We put an li t0, cardoffset in case it is greater than 2**11
# We use t0 because it is caller-saved
output.write("""
ld ra, 0(sp)
ld fp, 8(sp)
li t0, {0}
add sp, sp, t0
ret
""".format(cardoffset))
if fin_div0:
# Add code for division by 0 at the end.
output.write("""
{0}:
la a0, {0}_msg
call println_string
li a0, 1
call exit
""".format(fdata._label_div_by_zero))
# Add the data for the message of the division by 0
output.write("""
{0}_msg: .string "Division by 0"
""".format(fdata._label_div_by_zero))

312
MiniC/Lib/Graphes.py Normal file
View File

@ -0,0 +1,312 @@
""" Python Classes for Oriented and Non Oriented Graphs
"""
from graphviz import Digraph # for dot output
from typing import List, Dict, Set, Tuple, Any
class GraphError(Exception):
"""Exception raised for self loops.
"""
message: str
def __init__(self, message: str):
self.message = message
class GeneralGraph(object):
"""
General class regrouping similarities
between directed and non oriented graphs.
The only differences between the two are:
- how to compute the set of edges
- how to add an edge
- how to print the graph
- how to delete a vertex
- how to delete an edge
- we only color undirected graphs
"""
graph_dict: Dict[Any, Set]
def __init__(self, graph_dict=None):
"""
Initializes a graph object.
If no dictionary or None is given,
an empty dictionary will be used.
"""
if graph_dict is None:
graph_dict = {}
self.graph_dict = graph_dict
def vertices(self) -> List[Any]:
"""Return the vertices of a graph."""
return list(self.graph_dict.keys())
def add_vertex(self, vertex: Any) -> None:
"""
If the vertex "vertex" is not in
self.graph_dict, a key "vertex" with an empty
list as a value is added to the dictionary.
Otherwise nothing has to be done.
"""
if vertex not in self.graph_dict:
self.graph_dict[vertex] = set()
def edges(self) -> List[Set]:
"""Return the edges of the graph."""
return []
def __str__(self):
res = "vertices: "
for k in self.graph_dict:
res += str(k) + " "
res += "\nedges: "
for edge in self.edges():
res += str(edge) + " "
return res
def dfs_traversal(self, root: Any) -> List[Any]:
"""
Compute a depth first search of the graph,
from the vertex root.
"""
seen: List[Any] = []
todo: List[Any] = [root]
while len(todo) > 0: # while todo ...
current = todo.pop()
seen.append(current)
for neighbour in self.graph_dict[current]:
if neighbour not in seen:
todo.append(neighbour)
return seen
def is_reachable_from(self, v1: Any, v2: Any) -> bool:
"""True if there is a path from v1 to v2."""
return v2 in self.dfs_traversal(v1)
def connected_components(self) -> List[List[Any]]:
"""
Compute the list of all connected components of the graph,
each component being a list of vetices.
"""
components: List[List[Any]] = []
done: List[Any] = []
for v in self.vertices():
if v not in done:
v_comp = self.dfs_traversal(v)
components.append(v_comp)
done.extend(v_comp)
return components
def bfs_traversal(self, root: Any) -> List[Any]:
"""
Compute a breadth first search of the graph,
from the vertex root.
"""
seen: List[Any] = []
todo: List[Any] = [root]
while len(todo) > 0: # while todo ...
current = todo.pop(0) # list.pop(0): for dequeuing (on the left...) !
seen.append(current)
for neighbour in self.graph_dict[current]:
if neighbour not in seen:
todo.append(neighbour)
return seen
class Graph(GeneralGraph):
"""Class for non oriented graphs."""
def edges(self) -> List[Set]:
"""
A static method generating the set of edges
(they appear twice in the dictionnary).
Return a list of sets.
"""
edges = []
for vertex in self.graph_dict:
for neighbour in self.graph_dict[vertex]:
if {neighbour, vertex} not in edges:
edges.append({vertex, neighbour})
return edges
def add_edge(self, edge: Tuple[Any, Any]) -> None:
"""
Add an edge in the graph.
edge should be a pair and not (c,c)
(we call g.add_edge((v1,v2)))
"""
(vertex1, vertex2) = edge
if vertex1 == vertex2:
raise GraphError("Cannot add a self loop on vertex {} in an unoriented graph.".format(
str(vertex1)))
if vertex1 in self.graph_dict:
self.graph_dict[vertex1].add(vertex2)
else:
self.graph_dict[vertex1] = {vertex2}
if vertex2 in self.graph_dict:
self.graph_dict[vertex2].add(vertex1)
else:
self.graph_dict[vertex2] = {vertex1}
def print_dot(self, name: str, colors={}) -> None:
"""Print the graph."""
color_names = ['red', 'blue', 'green', 'yellow', 'cyan', 'magenta'] + \
[f"grey{i}" for i in range(0, 100, 10)]
color_shapes = ['ellipse', 'box', 'diamond', 'trapezium', 'egg',
'parallelogram', 'house', 'triangle', 'pentagon', 'hexagon',
'septagon', 'octagon']
dot = Digraph(comment='Conflict Graph')
for k in self.graph_dict:
shape = None
if not colors:
color = "red" # Graph not colored: red for everyone
elif k not in colors:
color = "grey" # Node not colored: grey
else:
n = colors[k]
if n < len(color_names):
color = color_names[colors[k]]
else:
color = "black" # Too many colors anyway, it won't be readable.
shape = color_shapes[n % len(color_shapes)]
dot.node(str(k), color=color, shape=shape)
for (v1, v2) in self.edges():
dot.edge(str(v1), str(v2), dir="none")
# print(dot.source)
dot.render(name, view=True) # print in pdf
def delete_vertex(self, vertex: Any) -> None:
"""Delete a vertex and all the adjacent edges."""
gdict = self.graph_dict
for neighbour in gdict[vertex]:
gdict[neighbour].remove(vertex)
del gdict[vertex]
def delete_edge(self, edge: Tuple[Any, Any]):
"""Delete an edge."""
(v1, v2) = edge
self.graph_dict[v1].remove(v2)
self.graph_dict[v2].remove(v1)
def color(self) -> Dict[Any, int]:
"""
Color the graph with an unlimited number of colors.
Return a dict vertex -> color, where color is an integer (0, 1, ...).
"""
coloring, _, _ = self.color_with_k_colors()
return coloring
# see algo of the course
def color_with_k_colors(self, K=None, avoidingnodes=()) -> Tuple[Dict[Any, int], bool, List]:
"""
Color with <= K colors (if K is unspecified, use unlimited colors).
Return 3 values:
- a dict vertex -> color
- a Boolean, True if the coloring succeeded
- the set of nodes actually colored
Do not color vertices belonging to avoidingnodes.
Continue even if the algo fails.
"""
if K is None:
K = len(self.graph_dict)
todo_vertices = []
is_total = True
gcopy = Graph(self.graph_dict.copy())
# suppress nodes that are not to be considered.
for node in avoidingnodes:
gcopy.delete_vertex(node)
# append nodes in the list according to their degree and node number:
while gcopy.graph_dict:
todo = list(gcopy.graph_dict)
todo.sort(key=lambda v: (len(gcopy.graph_dict[v]), str(v)))
lower = todo[0]
todo_vertices.append(lower)
gcopy.delete_vertex(lower)
# Now reverse the list: first elements are those with higher degree
# print(todo_vertices)
todo_vertices.reverse() # in place reversal
# print(todo_vertices)
coloring = {}
colored_nodes = []
# gdict will be the coloring map to return
gdict = self.graph_dict
for v in todo_vertices:
seen_neighbours = [x for x in gdict[v] if x in coloring]
choose_among = [i for i in range(K) if not (
i in [coloring[v1] for v1 in seen_neighbours])]
if choose_among:
# if the node can be colored, I choose the minimal color.
color = min(choose_among)
coloring[v] = color
colored_nodes.append(v)
else:
# if I cannot color some node, the coloring is not Total
# but I continue
is_total = False
return (coloring, is_total, colored_nodes)
class DiGraph(GeneralGraph):
"""Class for directed graphs."""
def pred(self, v: Any) -> Set:
"""Return all predecessors of the vertex `v` in the graph."""
return {src for src, dests in self.graph_dict.items() if v in dests}
def neighbourhoods(self) -> List[Tuple[Any, Set]]:
"""Return all neighbourhoods in the graph."""
return list(self.graph_dict.items())
def edges(self) -> List[Set]:
""" A static method generating the set of edges"""
edges = []
for vertex in self.graph_dict:
for neighbour in self.graph_dict[vertex]:
edges.append((vertex, neighbour))
return edges
def add_edge(self, edge: Tuple[Any, Any]) -> None:
"""
Add an edge in the graph.
edge should be a pair and not (c,c)
(we call g.add_edge((v1,v2)))
"""
(vertex1, vertex2) = edge
if vertex1 in self.graph_dict:
self.graph_dict[vertex1].add(vertex2)
else:
self.graph_dict[vertex1] = {vertex2}
if vertex2 not in self.graph_dict:
self.graph_dict[vertex2] = set()
def print_dot(self, name: str) -> None:
"""Print the graph."""
dot = Digraph(comment='Conflict Graph')
for k in self.graph_dict:
shape = None
color = "grey"
dot.node(str(k), color=color, shape=shape)
for (v1, v2) in self.edges():
dot.edge(str(v1), str(v2), dir="none")
# print(dot.source)
dot.render(name, view=True) # print in pdf
def delete_vertex(self, vertex: Any) -> None:
"""Delete a vertex and all the adjacent edges."""
for node, neighbours in self.graph_dict.items():
if vertex in neighbours:
neighbours.remove(vertex)
del self.graph_dict[vertex]
def delete_edge(self, edge: Tuple[Any, Any]) -> None:
"""Delete an edge."""
(v1, v2) = edge
self.graph_dict[v1].remove(v2)

103
MiniC/Lib/LinearCode.py Normal file
View File

@ -0,0 +1,103 @@
"""
CAP, CodeGeneration, LinearCode API
Classes for a RiscV linear code.
"""
from typing import List
from Lib.Operands import (A0, Function, DataLocation)
from Lib.Statement import (
Instru3A, AbsoluteJump, ConditionalJump, Comment, Label
)
from Lib.RiscV import (mv, call)
from Lib.FunctionData import (FunctionData, _iter_statements, _print_code)
CodeStatement = Comment | Label | Instru3A | AbsoluteJump | ConditionalJump
class LinearCode:
"""
Representation of a RiscV program as a list of instructions.
:py:meth:`add_instruction` is repeatedly called in the codegen visitor
to build a complete list of RiscV instructions for the source program.
The :py:attr:`fdata` member variable contains some meta-information
on the program, for instance to allocate a new temporary.
See :py:class:`Lib.FunctionData.FunctionData`.
For debugging purposes, :py:meth:`print_code` allows to print
the RiscV program to a file.
"""
"""
The :py:attr:`fdata` member variable contains some meta-information
on the program, for instance to allocate a new temporary.
See :py:class:`Lib.FunctionData.FunctionData`.
"""
fdata: FunctionData
_listIns: List[CodeStatement]
def __init__(self, name: str):
self._listIns = []
self.fdata = FunctionData(name)
def add_instruction(self, i: CodeStatement) -> None:
"""
Utility function to add an instruction in the program.
See also :py:mod:`Lib.RiscV` to generate relevant instructions.
"""
self._listIns.append(i)
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).
"""
new_list_ins = _iter_statements(self._listIns, f)
# TODO: we shoudn't need to split this assignment with intermediate
# variable new_list_ins, but at least pyright pyright 1.1.293
# raises an error here if we don't.
self._listIns = new_list_ins
def get_instructions(self) -> List[CodeStatement]:
"""Return the list of instructions of the program."""
return self._listIns
# each instruction has its own "add in list" version
def add_label(self, s: Label) -> None:
"""Add a label in the program."""
return self.add_instruction(s)
def add_comment(self, s: str) -> None:
"""Add a comment in the program."""
self.add_instruction(Comment(s))
def add_instruction_PRINTLN_INT(self, reg: DataLocation) -> None:
"""Print integer value, with newline. (see Expand)"""
# A print instruction generates the temp it prints.
self.add_instruction(mv(A0, reg))
self.add_instruction(call(Function('println_int')))
def __str__(self):
return '\n'.join(map(str, self._listIns))
def print_code(self, output, comment=None) -> None:
"""Outputs the RiscV program as text to a file at the given path."""
_print_code(self._listIns, self.fdata, output, init_label=None,
fin_label=None, fin_div0=True, comment=comment)
def print_dot(self, filename: str, DF=None, view=False) -> None: # pragma: no cover
"""Outputs the RiscV program as graph to a file at the given path."""
# import graphviz here so that students who don't have it can still work on lab4
from graphviz import Digraph
graph = Digraph()
# nodes
content = ""
for i in self._listIns:
content += str(i) + "\\l"
graph.node("Code", label=content, shape='rectangle')
# no edges
graph.render(filename, view=view)

279
MiniC/Lib/Operands.py Normal file
View File

@ -0,0 +1,279 @@
"""
This file defines the base class :py:class:`Operand`
and its subclasses for different operands: :py:class:`Condition`,
:py:class:`DataLocation` and :py:class:`Function`.
The class :py:class:`DataLocation` itself has subclasses:
:py:class:`Register`, :py:class:`Offset` for address in memory,
:py:class:`Immediate` for constants and :py:class:`Temporary`
for location not yet allocated.
This file also define shortcuts for registers in RISCV.
"""
from typing import Dict, List
from MiniCParser import MiniCParser
from Lib.Errors import MiniCInternalError
class Operand():
pass
# signed version for riscv
all_ops = ['blt', 'bgt', 'beq', 'bne', 'ble', 'bge', 'beqz', 'bnez']
opdict = {MiniCParser.LT: 'blt', MiniCParser.GT: 'bgt',
MiniCParser.LTEQ: 'ble', MiniCParser.GTEQ: 'bge',
MiniCParser.NEQ: 'bne', MiniCParser.EQ: 'beq'}
opnot_dict = {'bgt': 'ble',
'bge': 'blt',
'blt': 'bge',
'ble': 'bgt',
'beq': 'bne',
'bne': 'beq',
'beqz': 'bnez',
'bnez': 'beqz'}
class Condition(Operand):
"""Condition, i.e. comparison operand for a CondJump.
Example usage :
- Condition('beq') = branch if equal.
- Condition(MiniCParser.LT) = branch if lower than.
- ...
The constructor's argument shall be a string in the list all_ops, or a
comparison operator in MiniCParser.LT, MiniCParser.GT, ... (one of the keys
in opdict).
A 'negate' method allows getting the negation of this condition.
"""
_op: str
def __init__(self, optype):
if optype in opdict:
self._op = opdict[optype]
elif str(optype) in all_ops:
self._op = str(optype)
else:
raise MiniCInternalError(f"Unsupported comparison operator {optype}")
def negate(self) -> 'Condition':
"""Return the opposite condition."""
return Condition(opnot_dict[self._op])
def __str__(self):
return self._op
class Function(Operand):
"""Operand for build-in function call."""
_name: str
def __init__(self, name: str):
self._name = name
def __str__(self):
return self._name
class DataLocation(Operand):
""" A Data Location is either a register, a temporary
or a place in memory (offset).
"""
pass
# map for register shortcuts
reg_map = dict([(0, 'zero'), (1, 'ra'), (2, 'sp')] + # no (3, 'gp') nor (4, 'tp')
[(i+5, 't'+str(i)) for i in range(3)] +
[(8, 'fp'), (9, 's1')] +
[(i+10, 'a'+str(i)) for i in range(8)] +
[(i+18, 's'+str(i+2)) for i in range(10)] +
[(i+28, 't'+str(i+3)) for i in range(4)])
class Register(DataLocation):
""" A (physical) register."""
_number: int
def __init__(self, number: int):
self._number = number
def __repr__(self):
if self._number not in reg_map:
raise MiniCInternalError(f"Register number {self._number} should not be used")
else:
return ("{}".format(reg_map[self._number]))
def __eq__(self, other):
return isinstance(other, Register) and self._number == other._number
def __hash__(self):
return self._number
# Shortcuts for registers in RISCV
# Only integer registers
#: Zero register
ZERO = Register(0)
#:
RA = Register(1)
#:
SP = Register(2)
#: Register not used for this course
GP = Register(3)
#: Register not used for this course
TP = Register(4)
#:
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]
#: Frame Pointer = Saved register 0
FP = S[0]
#: General purpose registers, usable for the allocator
GP_REGS = S[4:] + T # s0, s1, s2 and s3 are special
class Offset(DataLocation):
""" Offset = address in memory computed with base + offset."""
_basereg: Register
_offset: int
def __init__(self, basereg: Register, offset: int):
self._basereg = basereg
self._offset = offset
def __repr__(self):
return ("{}({})".format(self._offset, self._basereg))
def get_offset(self) -> int:
"""Return the value of the offset."""
return self._offset
class Immediate(DataLocation):
"""Immediate operand (integer)."""
_val: int
def __init__(self, val):
self._val = val
def __str__(self):
return str(self._val)
class Temporary(DataLocation):
"""Temporary, a location that has not been allocated yet.
It will later be mapped to a physical register (Register) or to a memory location (Offset).
"""
_number: int
_pool: 'TemporaryPool'
def __init__(self, number: int, pool: 'TemporaryPool'):
self._number = number
self._pool = pool
def __repr__(self):
return ("temp_{}".format(str(self._number)))
def get_alloced_loc(self) -> DataLocation:
"""Return the DataLocation allocated to this Temporary."""
return self._pool.get_alloced_loc(self)
class TemporaryPool:
"""Manage a pool of temporaries."""
_all_temps: List[Temporary]
_current_num: int
_allocation: Dict[Temporary, DataLocation]
def __init__(self):
self._all_temps = []
self._current_num = 0
self._allocation = dict()
def get_all_temps(self) -> List[Temporary]:
"""Return all the temporaries of the pool."""
return self._all_temps
def get_alloced_loc(self, t: Temporary) -> DataLocation:
"""Get the actual DataLocation allocated for the temporary t."""
return self._allocation[t]
def add_tmp(self, t: Temporary):
"""Add a temporary to the pool."""
self._all_temps.append(t)
self._allocation[t] = t # While no allocation, return the temporary itself
def set_temp_allocation(self, allocation: Dict[Temporary, DataLocation]) -> None:
"""Give a mapping from temporaries to actual registers.
The argument allocation must be a dict from Temporary to
DataLocation other than Temporary (typically Register or Offset).
Typing enforces that keys are Temporary and values are Datalocation.
We check the values are indeed not Temporary.
"""
for v in allocation.values():
assert not isinstance(v, Temporary), (
"Incorrect allocation scheme: value " +
str(v) + " is a Temporary.")
self._allocation = allocation
def fresh_tmp(self) -> Temporary:
"""Give a new fresh Temporary and add it to the pool."""
t = Temporary(self._current_num, self)
self._current_num += 1
self.add_tmp(t)
return t
class Renamer:
"""Manage a renaming of temporaries."""
_pool: TemporaryPool
_env: Dict[Temporary, Temporary]
def __init__(self, pool: TemporaryPool):
self._pool = pool
self._env = dict()
def fresh(self, t: Temporary) -> Temporary:
"""Give a fresh rename for a Temporary."""
new_t = self._pool.fresh_tmp()
self._env[t] = new_t
return new_t
def replace(self, t: Temporary) -> Temporary:
"""Give the rename for a Temporary (which is itself if it is not renamed)."""
return self._env.get(t, t)
def defined(self, t: Temporary) -> bool:
"""True if the Temporary is renamed."""
return t in self._env
def copy(self):
"""Give a copy of the Renamer."""
r = Renamer(self._pool)
r._env = self._env.copy()
return r

62
MiniC/Lib/PhiNode.py Normal file
View File

@ -0,0 +1,62 @@
"""
Classes for φ nodes in a RiscV CFG :py:class:`CFG <Lib.CFG.CFG>` under SSA Form:
:py:class:`PhiNode` for a statement of the form temp_x = φ(temp_0, ..., temp_n).
These particular kinds of statements are expected to be in the field
b._phis for a :py:class:`Block <Lib.CFG.Block>` b.
"""
from dataclasses import dataclass
from typing import List, Dict
from Lib.Operands import Operand, Temporary, DataLocation, Renamer
from Lib.Statement import Statement, Label
@dataclass
class PhiNode(Statement):
"""
A φ node is a renaming in the CFG, of the form temp_x = φ(temp_0, ..., temp_n).
The field var contains the variable temp_x.
The field srcs relies for each precedent block in the CFG, identified with its label,
the variable temp_i of the φ node.
"""
var: DataLocation
srcs: Dict[Label, Operand]
def defined(self) -> List[Operand]:
"""Return the variable defined by the φ node."""
return [self.var]
def get_srcs(self) -> Dict[Label, Operand]:
"""
Return the dictionnary associating for each previous block the corresponding variable.
"""
return self.srcs
def used(self) -> List[Operand]:
"""Return the variables used by the statement."""
return list(self.srcs.values())
def rename(self, renamer: Renamer) -> None:
"""Rename the variable defined by the φ node with a fresh name."""
if isinstance(self.var, Temporary):
self.var = renamer.fresh(self.var)
def rename_from(self, renamer: Renamer, label: Label) -> None:
"""Rename the variable associated to the block identified by `label`."""
if label in self.srcs:
t = self.srcs[label]
if isinstance(t, Temporary):
if renamer.defined(t):
self.srcs[label] = renamer.replace(t)
else:
del self.srcs[label]
def __str__(self):
return "{} = φ({})".format(self.var, self.srcs)
def __hash__(self):
return hash((self.var, *self.srcs.items()))
def printIns(self, stream):
print(' # ' + str(self), file=stream)

92
MiniC/Lib/RiscV.py Normal file
View File

@ -0,0 +1,92 @@
"""
MIF08, CAP, CodeGeneration, RiscV API
Functions to define instructions.
"""
from Lib.Errors import MiniCInternalError
from Lib.Operands import (Condition, Immediate, Operand, Function)
from Lib.Statement import (Instru3A, AbsoluteJump, ConditionalJump, Label)
def call(function: Function) -> Instru3A:
"""Function call."""
return Instru3A('call', function)
def jump(label: Label) -> AbsoluteJump:
"""Unconditional jump to label."""
return AbsoluteJump(label)
def conditional_jump(label: Label, op1: Operand, cond: Condition, op2: Operand):
"""Add a conditional jump to the code.
This is a wrapper around bge, bgt, beq, ... c is a Condition, like
Condition('bgt'), Condition(MiniCParser.EQ), ...
"""
return ConditionalJump(cond=cond, op1=op1, op2=op2, label=label)
def add(dr: Operand, sr1: Operand, sr2orimm7: Operand) -> Instru3A:
if isinstance(sr2orimm7, Immediate):
return Instru3A("addi", dr, sr1, sr2orimm7)
else:
return Instru3A("add", dr, sr1, sr2orimm7)
def mul(dr: Operand, sr1: Operand, sr2orimm7: Operand) -> Instru3A:
if isinstance(sr2orimm7, Immediate):
raise MiniCInternalError("Cant multiply by an immediate")
else:
return Instru3A("mul", dr, sr1, sr2orimm7)
def div(dr: Operand, sr1: Operand, sr2orimm7: Operand) -> Instru3A:
if isinstance(sr2orimm7, Immediate):
raise MiniCInternalError("Cant divide by an immediate")
else:
return Instru3A("div", dr, sr1, sr2orimm7)
def rem(dr: Operand, sr1: Operand, sr2orimm7: Operand) -> Instru3A:
if isinstance(sr2orimm7, Immediate):
raise MiniCInternalError("Cant divide by an immediate")
return Instru3A("rem", dr, sr1, sr2orimm7)
def sub(dr: Operand, sr1: Operand, sr2orimm7: Operand) -> Instru3A:
if isinstance(sr2orimm7, Immediate):
raise MiniCInternalError("Cant substract by an immediate")
return Instru3A("sub", dr, sr1, sr2orimm7)
def land(dr: Operand, sr1: Operand, sr2orimm7: Operand) -> Instru3A:
"""And instruction (cannot be called `and` due to Python and)."""
return Instru3A("and", dr, sr1, sr2orimm7)
def lor(dr: Operand, sr1: Operand, sr2orimm7: Operand) -> Instru3A:
"""Or instruction (cannot be called `or` due to Python or)."""
return Instru3A("or", dr, sr1, sr2orimm7)
def xor(dr: Operand, sr1: Operand, sr2orimm7: Operand) -> Instru3A: # pragma: no cover
if isinstance(sr2orimm7, Immediate):
return Instru3A("xori", dr, sr1, sr2orimm7)
else:
return Instru3A("xor", dr, sr1, sr2orimm7)
def li(dr: Operand, imm7: Immediate) -> Instru3A:
return Instru3A("li", dr, imm7)
def mv(dr: Operand, sr: Operand) -> Instru3A:
return Instru3A("mv", dr, sr)
def ld(dr: Operand, mem: Operand) -> Instru3A:
return Instru3A("ld", dr, mem)
def sd(sr: Operand, mem: Operand) -> Instru3A:
return Instru3A("sd", sr, mem)

278
MiniC/Lib/Statement.py Normal file
View File

@ -0,0 +1,278 @@
"""
The base class for RISCV ASM statements is :py:class:`Statement`.
It is inherited by :py:class:`Comment`, :py:class:`Label`
and :py:class:`Instruction`. In turn, :py:class:`Instruction`
is inherited by :py:class:`Instru3A`
(for regular non-branching 3-address instructions),
:py:class:`AbsoluteJump` and :py:class:`ConditionalJump`.
"""
from dataclasses import dataclass
from typing import (List, Dict, TypeVar)
from Lib.Operands import (Operand, Renamer, Temporary, Condition)
from Lib.Errors import MiniCInternalError
def regset_to_string(registerset) -> str:
"""Utility function: pretty-prints a set of locations."""
return "{" + ",".join(str(x) for x in registerset) + "}"
# Temporary until we can use Typing.Self in python 3.11
TStatement = TypeVar("TStatement", bound="Statement")
@dataclass(unsafe_hash=True)
class Statement:
"""A Statement, which is an instruction, a comment or a label."""
def defined(self) -> List[Operand]:
"""Operands defined (written) in this instruction"""
return []
def used(self) -> List[Operand]:
"""Operands used (read) in this instruction"""
return []
def substitute(self: TStatement, subst: Dict[Operand, Operand]) -> TStatement:
"""Return a new instruction, cloned from this one, replacing operands
that appear as key in subst by their value."""
raise Exception(
"substitute: Operands {} are not present in instruction {}"
.format(subst, self))
def with_args(self: TStatement, new_args: List[Operand]) -> TStatement:
"""Return a new instruction, cloned from this one, where operands have
been replaced by new_args."""
raise Exception(
"substitute: Operands {} are not present in instruction {}"
.format(new_args, self))
def printIns(self, stream):
"""
Print the statement on the given output.
Should never be called on the base class.
"""
raise NotImplementedError
@dataclass(unsafe_hash=True)
class Comment(Statement):
"""A comment."""
comment: str
def __str__(self): # use only for print_dot !
return "# {}".format(self.comment)
def printIns(self, stream):
print(' # ' + self.comment, file=stream)
@dataclass(unsafe_hash=True)
class Label(Statement, Operand):
"""A label is both a Statement and an Operand."""
name: str
def __str__(self):
return ("lbl_{}".format(self.name))
def __repr__(self):
return ("{}".format(self.name))
def printIns(self, stream):
print(str(self) + ':', file=stream)
@dataclass(init=False)
class Instruction(Statement):
ins: str
_read_only: bool
def is_read_only(self):
"""
True if the instruction only reads from its operands.
Otherwise, the first operand is considered as the destination
and others are source.
"""
return self._read_only
def rename(self, renamer: Renamer) -> None:
raise NotImplementedError
def args(self) -> List[Operand]:
"""List of operands the instruction takes"""
raise NotImplementedError
def defined(self):
if self.is_read_only():
defs = []
else:
defs = [self.args()[0]]
return defs
def used(self) -> List[Operand]:
if self.is_read_only():
uses = self.args()
else:
uses = self.args()[1:]
return uses
def __str__(self):
s = self.ins
first = True
for arg in self.args():
if first:
s += ' ' + str(arg)
first = False
else:
s += ', ' + str(arg)
return s
def __hash__(self):
return hash((self.ins, *self.args()))
def printIns(self, stream):
"""Print the instruction on the given output."""
print(' ', str(self), file=stream)
@dataclass(init=False)
class Instru3A(Instruction):
_args: List[Operand]
def __init__(self, ins, *args: Operand):
# convention is to use lower-case in RISCV
self.ins = ins.lower()
self._args = list(args)
self._read_only = (self.ins == "call"
or self.ins == "ld"
or self.ins == "lw"
or self.ins == "lb")
if (self.ins.startswith("b") or self.ins == "j"):
raise MiniCInternalError
def args(self):
return self._args
def rename(self, renamer: Renamer):
old_replaced = dict()
for i, arg in enumerate(self._args):
if isinstance(arg, Temporary):
if i == 0 and not self.is_read_only():
old_replaced[arg] = renamer.replace(arg)
new_t = renamer.fresh(arg)
elif arg in old_replaced.keys():
new_t = old_replaced[arg]
else:
new_t = renamer.replace(arg)
self._args[i] = new_t
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))
args = [subst.get(arg, arg)
if isinstance(arg, Temporary) else arg
for arg in self.args()]
return Instru3A(self.ins, *args)
def with_args(self, new_args: List[Operand]):
if len(new_args) != len(self._args):
raise Exception(
"substitute: Expected {} operands for {}, got {}."
.format(len(self._args), self, new_args))
return Instru3A(self.ins, *new_args)
def __hash__(self):
return hash(super)
@dataclass(init=False)
class AbsoluteJump(Instruction):
""" An Absolute Jump is a specific kind of instruction"""
ins = "j"
label: Label
_read_only = True
def __init__(self, label: Label):
self.label = label
def args(self) -> List[Operand]:
return [self.label]
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
def with_args(self, new_args: List[Operand]):
if new_args != self.args():
raise Exception(
"substitute: No possible substitution on instruction {}. Old args={}, new args={}"
.format(self, self.args(), new_args))
return self
def __hash__(self):
return hash(super)
def targets(self) -> List[Label]:
"""Return the labels targetted by the AbsoluteJump."""
return [self.label]
@dataclass(init=False)
class ConditionalJump(Instruction):
""" A Conditional Jump is a specific kind of instruction"""
cond: Condition
label: Label
op1: Operand
op2: Operand
_read_only = True
def __init__(self, cond: Condition, op1: Operand, op2: Operand, label: Label):
self.cond = cond
self.label = label
self.op1 = op1
self.op2 = op2
self.ins = str(self.cond)
def args(self):
return [self.op1, self.op2, self.label]
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 ConditionalJump(self.cond, op1, op2, self.label)
def with_args(self, new_args: List[Operand]):
if len(new_args) != 3:
raise Exception(
"substitute: Expected 3 operands for {}, got {}."
.format(self, new_args))
assert isinstance(new_args[2], Label)
label: Label = new_args[2]
return ConditionalJump(self.cond, new_args[0], new_args[1], label)
def __hash__(self):
return hash(super)

153
MiniC/Lib/Terminator.py Normal file
View File

@ -0,0 +1,153 @@
"""
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
@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
def with_args(self, new_args: List[Operand]):
if new_args != []:
raise Exception(
"substitute: No possible substitution on instruction {}"
.format(self))
return self
def is_read_only(self) -> bool:
return True
@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 with_args(self, new_args: List[Operand]):
if len(new_args) != 4:
raise Exception(
"substitute: Invalid number of arguments for instruction {}, expected 4 got {}"
.format(self, new_args))
op1 = new_args[0]
op2 = new_args[1]
return BranchingTerminator(self.cond, op1, op2, self.label_then, self.label_else)
def __hash__(self):
return hash(super)
Terminator = Return | AbsoluteJump | BranchingTerminator
"""Type alias for terminators"""
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 _:
if next_label:
return AbsoluteJump(next_label)
else:
return Return()

0
MiniC/Lib/__init__.py Normal file
View File

View File

@ -35,8 +35,8 @@ doc: antlr
sphinx-apidoc -e -f -o doc/api . TP* replace_* *Wrapper* MiniC* conf* test*
make -C doc html
test: test-interpret
test: test-interpret test-codegen
test-pyright: antlr
@ -67,8 +67,6 @@ test-naive: test-pyright antlr
test-mem: test-pyright antlr
$(LINEAR) python3 -m pytest $(PYTEST_BASE_OPTS) $(PYTEST_OPTS) ./test_codegen.py -k 'test_alloc_mem'
test-hybrid: test-pyright antlr
$(LINEAR) python3 -m pytest $(PYTEST_BASE_OPTS) $(PYTEST_OPTS) ./test_codegen.py -k 'test_alloc_hybrid'
# Test for all but the smart allocator, i.e. everything that lab4 should pass:
test-lab4: test-pyright antlr

21
MiniC/README-SSA.md Normal file
View File

@ -0,0 +1,21 @@
# MiniC Compiler
LAB5a (Control Flow Graph in SSA Form) & LAB5b (Smart Register Allocation), CAP 2022-23
# Authors
YOUR NAME HERE
# Contents
TODO:
- Explain any design choices you may have made.
- Do not forget to remove all debug traces from your code!
- Did you implement an extension?
# Test design
TODO: give the main objectives of your tests.
# Known bugs
TODO: bugs you could not fix (if any).

38
MiniC/README-alloc.md Normal file
View File

@ -0,0 +1,38 @@
# MiniC Compiler
LAB5 (smart code generation), MIF08 / CAP 2022-23
# Authors
YOUR NAME HERE
# Contents
TODO for STUDENTS : Say a bit about the code infrastructure ...
# Howto
To compile and run a program:
```
$ python3 ./MiniCC.py --reg-alloc=smart TP04/tests/provided/step1/test00.c
Code will be generated in file TP04/tests/provided/step1/test00.s
$ riscv64-unknown-elf-gcc TP04/tests/provided/step1/test00.s ../TP01/riscv/libprint.s -o /tmp/a.out
$ spike pk /tmp/a.out
```
To launch the testsuite:
```
make test-smart
```
# Test design
TODO: explain your tests
# Design choices
TODO: explain your choices
# Known bugs
TODO: Bugs and limitations.

57
MiniC/README-codegen.md Normal file
View File

@ -0,0 +1,57 @@
# MiniC Compiler
LAB4 (simple code generation), MIF08 / CAP 2022-23
# Authors
YOUR NAME HERE
# Contents
TODO for STUDENTS : Say a bit about the code infrastructure ...
# Test design
TODO: explain your tests
# Design choices
TODO: explain your choices. How did you implement boolean not? Did you implement an extension?
# Known bugs
TODO: Bugs and limitations.
# Checklists
A check ([X]) means that the feature is implemented
and *tested* with appropriate test cases.
## Code generation
- [ ] Number Atom
- [ ] Boolean Atom
- [ ] Id Atom
- [ ] Additive expression
- [ ] Multiplicative expression
- [ ] UnaryMinus expression
- [ ] Or expression
- [ ] And expression
- [ ] Equality expression
- [ ] Relational expression (! many cases -> many tests)
- [ ] Not expression
## Statements
- [ ] Prog, assignements
- [ ] While
- [ ] Cond Block
- [ ] If
- [ ] Nested ifs
- [ ] Nested whiles
## Allocation
- [ ] Naive allocation
- [ ] All in memory allocation
- [ ] Massive tests of memory allocation

60
MiniC/README-functions.md Normal file
View File

@ -0,0 +1,60 @@
# MiniC Compiler
LAB6 (code generation for functions), MIF08 / CAP 2022-23
# Authors
YOUR NAME HERE
# Contents
TODO: Say a bit about the code infrastructure ...
# Howto
As in the previous labs.
`make test-codegen SSA=1` to lauch pyright and the testsuite
with the three allocators (do not forget the options you can add).
# Test design
TODO: give the main objectives of your tests.
# Design choices
TODO: explain your choices
# Known bugs
TODO: bugs and limitations you could not fix (if any).
# Checklists
A check ([X]) means that the feature is implemented
and *tested* with appropriate test cases.
## Parser
- [ ] Function definition
- [ ] Function declaration
- [ ] Function call
## Typer
- [ ] Function declaration
- [ ] Function definition
- [ ] Function call
- [ ] Function return
## Code generation
- [ ] Function return
- [ ] Callee-saved registers
- [ ] Function call
- [ ] Getting the result of a function call
- [ ] Caller-saved registers
- [ ] Increase the size of the stack for callee/caller-saved registers
- [ ] Temporaries for giving arguments to a function call
- [ ] Temporaries for retriving arguments at the beginning of a function

View File

@ -0,0 +1,33 @@
from Lib import RiscV
from Lib.Operands import Temporary, Operand, S
from Lib.Statement import Instruction
from Lib.Allocator import Allocator
from typing import List
class AllInMemAllocator(Allocator):
def replace(self, old_instr: Instruction) -> List[Instruction]:
"""Replace Temporary operands with the corresponding allocated
memory location."""
numreg = 1
before: List[Instruction] = []
after: List[Instruction] = []
new_args: List[Operand] = []
# TODO: compute before,after,args.
# TODO: iterate over old_args, check which argument
# TODO: is a temporary (e.g. isinstance(..., Temporary)),
# TODO: and if so, generate ld/sd accordingly. Replace the
# TODO: temporary with S[1], S[2] or S[3] physical registers.
new_instr = old_instr.with_args(new_args)
return before + [new_instr] + after
def prepare(self) -> None:
"""Allocate all temporaries to memory.
Invariants:
- Expanded instructions can use s2 and s3
(to store the values of temporaries before the actual instruction).
"""
self._fdata._pool.set_temp_allocation(
{temp: self._fdata.fresh_offset()
for temp in self._fdata._pool.get_all_temps()})

111
MiniC/TP04/BuildCFG.py Normal file
View File

@ -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
# 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
# Extract the last instruction from inner_statements if it is a jump, or do nothing
raise NotImplementedError() # TODO
# 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

View File

@ -0,0 +1,40 @@
"""
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, CFG
def ordered_blocks_list(cfg: CFG) -> List[Block]:
"""
Compute a list of blocks with optimized ordering for linearization.
"""
# TODO
return cfg.get_blocks()
def linearize(cfg: CFG) -> List[Statement]:
"""
Linearize the given control flow graph as a list of instructions.
"""
# TODO
l: List[Statement] = [] # Linearized CFG
blocks: List[Block] = ordered_blocks_list(cfg) # All blocks of the CFG
for i, 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

View File

@ -0,0 +1,196 @@
from typing import List
from MiniCVisitor import MiniCVisitor
from MiniCParser import MiniCParser
from Lib.LinearCode import LinearCode
from Lib import RiscV
from Lib.RiscV import Condition
from Lib import Operands
from antlr4.tree.Trees import Trees
from Lib.Errors import MiniCInternalError, MiniCUnsupportedError
"""
CAP, MIF08, three-address code generation + simple alloc
This visitor constructs an object of type "LinearCode".
"""
class MiniCCodeGen3AVisitor(MiniCVisitor):
_current_function: LinearCode
def __init__(self, debug, parser):
super().__init__()
self._parser = parser
self._debug = debug
self._functions = []
self._lastlabel = ""
def get_functions(self) -> List[LinearCode]:
return self._functions
def printSymbolTable(self): # pragma: no cover
print("--variables to temporaries map--")
for keys, values in self._symbol_table.items():
print(keys + '-->' + str(values))
# handle variable decl
def visitVarDecl(self, ctx) -> None:
type_str = ctx.typee().getText()
vars_l = self.visit(ctx.id_l())
for name in vars_l:
if name in self._symbol_table:
raise MiniCInternalError(
"Variable {} has already been declared".format(name))
else:
tmp = self._current_function.fdata.fresh_tmp()
self._symbol_table[name] = tmp
if type_str not in ("int", "bool"):
raise MiniCUnsupportedError("Unsupported type " + type_str)
# Initialization to 0 or False, both represented with 0
self._current_function.add_instruction(
RiscV.li(tmp, Operands.Immediate(0)))
def visitIdList(self, ctx) -> List[str]:
t = self.visit(ctx.id_l())
t.append(ctx.ID().getText())
return t
def visitIdListBase(self, ctx) -> List[str]:
return [ctx.ID().getText()]
# expressions
def visitParExpr(self, ctx) -> Operands.Temporary:
return self.visit(ctx.expr())
def visitIntAtom(self, ctx) -> Operands.Temporary:
val = Operands.Immediate(int(ctx.getText()))
dest_temp = self._current_function.fdata.fresh_tmp()
self._current_function.add_instruction(RiscV.li(dest_temp, val))
return dest_temp
def visitFloatAtom(self, ctx) -> Operands.Temporary:
raise MiniCUnsupportedError("float literal")
def visitBooleanAtom(self, ctx) -> Operands.Temporary:
# true is 1 false is 0
raise NotImplementedError() # TODO
def visitIdAtom(self, ctx) -> Operands.Temporary:
try:
# get the temporary associated to id
return self._symbol_table[ctx.getText()]
except KeyError: # pragma: no cover
raise MiniCInternalError(
"Undefined variable {}, this should have failed to typecheck."
.format(ctx.getText())
)
def visitStringAtom(self, ctx) -> Operands.Temporary:
raise MiniCUnsupportedError("string atom")
# now visit expressions
def visitAtomExpr(self, ctx) -> Operands.Temporary:
return self.visit(ctx.atom())
def visitAdditiveExpr(self, ctx) -> Operands.Temporary:
assert ctx.myop is not None
tmpl: Operands.Temporary = self.visit(ctx.expr(0))
tmpr: Operands.Temporary = self.visit(ctx.expr(1))
raise NotImplementedError() # TODO
def visitOrExpr(self, ctx) -> Operands.Temporary:
raise NotImplementedError() # TODO
def visitAndExpr(self, ctx) -> Operands.Temporary:
raise NotImplementedError() # TODO
def visitEqualityExpr(self, ctx) -> Operands.Temporary:
return self.visitRelationalExpr(ctx)
def visitRelationalExpr(self, ctx) -> Operands.Temporary:
assert ctx.myop is not None
c = Condition(ctx.myop.type)
if self._debug:
print("relational expression:")
print(Trees.toStringTree(ctx, [], self._parser))
print("Condition:", c)
raise NotImplementedError() # TODO
def visitMultiplicativeExpr(self, ctx) -> Operands.Temporary:
assert ctx.myop is not None
div_by_zero_lbl = self._current_function.fdata.get_label_div_by_zero()
raise NotImplementedError() # TODO
def visitNotExpr(self, ctx) -> Operands.Temporary:
raise NotImplementedError() # TODO
def visitUnaryMinusExpr(self, ctx) -> Operands.Temporary:
raise NotImplementedError("unaryminusexpr") # TODO
def visitProgRule(self, ctx) -> None:
self.visitChildren(ctx)
def visitFuncDef(self, ctx) -> None:
funcname = ctx.ID().getText()
self._current_function = LinearCode(funcname)
self._symbol_table = dict()
self.visit(ctx.vardecl_l())
self.visit(ctx.block())
self._current_function.add_comment("Return at end of function:")
# This skeleton doesn't deal properly with functions, and
# hardcodes a "return 0;" at the end of function. Generate
# code for this "return 0;".
self._current_function.add_instruction(
RiscV.li(Operands.A0, Operands.Immediate(0)))
self._functions.append(self._current_function)
del self._current_function
def visitAssignStat(self, ctx) -> None:
if self._debug:
print("assign statement, rightexpression is:")
print(Trees.toStringTree(ctx.expr(), [], self._parser))
expr_temp = self.visit(ctx.expr())
name = ctx.ID().getText()
self._current_function.add_instruction(RiscV.mv(self._symbol_table[name], expr_temp))
def visitIfStat(self, ctx) -> None:
if self._debug:
print("if statement")
end_if_label = self._current_function.fdata.fresh_label("end_if")
raise NotImplementedError() # TODO
self._current_function.add_label(end_if_label)
def visitWhileStat(self, ctx) -> None:
if self._debug:
print("while statement, condition is:")
print(Trees.toStringTree(ctx.expr(), [], self._parser))
print("and block is:")
print(Trees.toStringTree(ctx.stat_block(), [], self._parser))
raise NotImplementedError() # TODO
# visit statements
def visitPrintlnintStat(self, ctx) -> None:
expr_loc = self.visit(ctx.expr())
if self._debug:
print("print_int statement, expression is:")
print(Trees.toStringTree(ctx.expr(), [], self._parser))
self._current_function.add_instruction_PRINTLN_INT(expr_loc)
def visitPrintlnboolStat(self, ctx) -> None:
expr_loc = self.visit(ctx.expr())
self._current_function.add_instruction_PRINTLN_INT(expr_loc)
def visitPrintlnfloatStat(self, ctx) -> None:
raise MiniCUnsupportedError("Unsupported type float")
def visitPrintlnstringStat(self, ctx) -> None:
raise MiniCUnsupportedError("Unsupported type string")
def visitStatList(self, ctx) -> None:
for stat in ctx.stat():
self._current_function.add_comment(Trees.toStringTree(stat, [], self._parser))
self.visit(stat)

View File

@ -0,0 +1,13 @@
#include "printlib.h"
int main() {
int n,u;
n=6;
println_int(n);
return 0;
}
// EXPECTED
// 6

View File

@ -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

View File

@ -0,0 +1,14 @@
#include "printlib.h"
int main() {
int n,v;
bool u;
n=6;
u=12>n;
println_bool(1<n && u);
return 0;
}
// EXPECTED
// 1

View File

@ -0,0 +1,18 @@
#include "printlib.h"
int main()
{
int n, u, v;
n = 6;
u = 0;
while (n > 1)
{
n = n - 1;
u = u + n;
}
println_int(u);
return 0;
}
// EXPECTED
// 15

View File

@ -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

View File

@ -0,0 +1,14 @@
#include "printlib.h"
int main()
{
int x;
x = 0;
while (x < 4)
{
x = x + 1;
}
return 0;
}
// EXPECTED

View File

@ -0,0 +1,9 @@
#include "printlib.h"
int main() {
println_int(42);
return 0;
}
// EXPECTED
// 42

View File

@ -0,0 +1,11 @@
#include "printlib.h"
int main() {
int x,y;
x=4;
y=12+x;
return 0;
}
// EXPECTED

View File

@ -0,0 +1,11 @@
#include "printlib.h"
int main() {
int a,n;
n=1;
a=n+12;
return 0;
}
// EXPECTED

View File

@ -0,0 +1,11 @@
#include "printlib.h"
int main() {
int n;
n=6;
return 0;
}
// EXPECTED

View File

@ -0,0 +1,11 @@
#include "printlib.h"
int main() {
println_int(43);
return 0;
}
// EXPECTED
// 43

View File

@ -0,0 +1,12 @@
#include "printlib.h"
int main() {
int x;
x = 42;
println_int(x);
return 0;
}
// EXPECTED
// 42

View File

@ -0,0 +1,16 @@
#include "printlib.h"
int main() {
int x;
x = 42;
println_int(x + x);
println_int(x + 1);
println_int(1 + x);
return 0;
}
// EXPECTED
// 84
// 43
// 43

View File

@ -0,0 +1,20 @@
#include "printlib.h"
int main() {
int x, y;
x = 42;
y = 66;
println_int(x + y);
x = 1;
println_int(x + y);
y = 2;
println_int(x + y);
return 0;
}
// EXPECTED
// 108
// 67
// 3

View File

@ -0,0 +1,16 @@
#include "printlib.h"
int main() {
int x,y;
x = 9;
if (x < 2)
y=7;
else
y=12;
x = y;
return 0;
}
// EXPECTED

View File

@ -0,0 +1,13 @@
#include "printlib.h"
int main() {
int n;
bool a,b;
n=1;
a=true;
b=(a==(n<6));
return 0;
}
// EXPECTED

View File

@ -0,0 +1,13 @@
#include "printlib.h"
int main() {
int x,y;
x=3;
if (x<5) {
y=x+1;
}
return 0;
}
// EXPECTED

View File

@ -0,0 +1,16 @@
#include "printlib.h"
int main() {
int x,y,z;
x=(2);
if (((x)<(3))) {
y=7;
} else {
y=8;
}
z=y+1;
return 0;
}
// EXPECTED

View File

@ -0,0 +1,20 @@
#include "printlib.h"
int main() {
int x,y,z,u;
x=3;
if (x < 4) {
z=4;
}
else if ( x < 5) {
z=5;
}
else {
z=6 ;
}
u=z+1;
return 0;
}
// EXPECTED

View File

@ -0,0 +1,19 @@
#include "printlib.h"
int main() {
bool b;
b = false;
println_bool(b);
b = true;
println_bool(b);
println_bool(true);
println_bool(false);
return 0;
}
// EXPECTED
// 0
// 1
// 1
// 0

View File

@ -0,0 +1,10 @@
#include "printlib.h"
int main() {
println_bool(3 >= 2);
return 0;
}
// EXPECTED
// 1

View File

@ -0,0 +1,19 @@
#include "printlib.h"
int main() {
if (10 == 10) {
println_int(12);
} else if (10 == 10) {
println_int(15);
} else {
println_int(13);
}
println_int(14);
return 0;
}
// EXPECTED
// 12
// 14

View File

@ -0,0 +1,25 @@
#include "printlib.h"
int main() {
int n;
n = 9;
while (n > 0) {
n = n-1 ;
println_int(n) ;
}
return 0;
}
// EXPECTED
// 8
// 7
// 6
// 5
// 4
// 3
// 2
// 1
// 0

View File

@ -0,0 +1,18 @@
#include "printlib.h"
int main() {
int a,n;
n = 1;
a = 7;
while (n < a) {
n = n+1;
}
println_int(n);
return 0;
}
// EXPECTED
// 7

View File

@ -0,0 +1,9 @@
int main() {
float f;
return 0;
}
// SKIP TEST EXPECTED
// EXITCODE 5
// EXPECTED
// Unsupported type float

View File

@ -0,0 +1,9 @@
int main() {
println_float(0.0);
return 0;
}
// SKIP TEST EXPECTED
// EXITCODE 5
// EXPECTED
// Unsupported type float

View File

@ -0,0 +1,9 @@
int main() {
println_string("Hello");
return 0;
}
// SKIP TEST EXPECTED
// EXITCODE 5
// EXPECTED
// Unsupported type string

View File

@ -0,0 +1,9 @@
int main() {
string b;
return 0;
}
// SKIP TEST EXPECTED
// EXITCODE 5
// EXPECTED
// Unsupported type string

70
MiniC/TP05/EnterSSA.py Normal file
View File

@ -0,0 +1,70 @@
"""
CAP, SSA Intro, Elimination and Optimisations
Functions to convert a CFG into SSA Form.
"""
from typing import List, Dict, Set
from Lib.CFG import Block, CFG
from Lib.Operands import Renamer
from Lib.Statement import Instruction
from Lib.PhiNode import PhiNode
from Lib.Dominators import computeDom, computeDT, computeDF
def insertPhis(cfg: CFG, DF: Dict[Block, Set[Block]]) -> None:
"""
`insertPhis(CFG, DF)` inserts phi nodes in `cfg` where needed.
At this point, phi nodes will look like `temp_x = φ(temp_x, ..., temp_x)`.
This is an helper function called during SSA entry.
"""
for var, defs in cfg.gather_defs().items():
has_phi: Set[Block] = set()
queue: List[Block] = list(defs)
while queue:
d = queue.pop(0)
for b in DF[d]:
if b not in has_phi:
# TODO add a phi node in block `b` (Lab 5a, Exercise 4)
raise NotImplementedError("insertPhis")
def rename_block(cfg: CFG, DT: Dict[Block, Set[Block]], renamer: Renamer, b: Block) -> None:
"""
Rename variables from block b.
This is an auxiliary function for `rename_variables`.
"""
renamer = renamer.copy()
for i in b.get_all_statements():
if isinstance(i, Instruction | PhiNode):
i.rename(renamer)
for succ in cfg.out_blocks(b):
for i in succ.get_phis():
assert (isinstance(i, PhiNode))
i.rename_from(renamer, b.get_label())
# TODO recursive call(s) of rename_block (Lab 5a, Exercise 5)
def rename_variables(cfg: CFG, DT: Dict[Block, Set[Block]]) -> None:
"""
Rename variables in the CFG, to transform `temp_x = φ(temp_x, ..., temp_x)`
into `temp_x = φ(temp_0, ... temp_n)`.
This is an helper function called during SSA entry.
"""
renamer = Renamer(cfg.fdata._pool)
# TODO initial call(s) to rename_block (Lab 5a, Exercise 5)
def enter_ssa(cfg: CFG, dom_graphs=False, basename="prog") -> None:
"""
Convert the CFG `cfg` into SSA Form:
compute the dominance frontier, then insert phi nodes and finally
rename variables accordingly.
`dom_graphs` indicates if we have to print the domination graphs.
`basename` is used for the names of the produced graphs.
"""
# TODO implement this function (Lab 5a, Exercise 2)
raise NotImplementedError("enter_ssa")

44
MiniC/TP05/ExitSSA.py Normal file
View File

@ -0,0 +1,44 @@
"""
CAP, SSA Intro, Elimination and Optimisations
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.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]:
"""
`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
`phis`.
This is an helper function called during SSA exit.
"""
moves: List[BlockInstr] = []
# TODO compute 'moves', a list of 'mv' instructions to insert under parent
# (Lab 5a, Exercise 6)
return moves
def exit_ssa(cfg: CFG, is_smart: bool) -> None:
"""
`exit_ssa(cfg)` replaces phi nodes with move instructions to exit SSA form.
`is_smart` is set to true when smart register allocation is enabled (Lab 5b).
"""
for b in cfg.get_blocks():
phis = cast(List[PhiNode], b.get_phis()) # Use cast for Pyright
b.remove_all_phis() # Remove all phi nodes in the block
parents: List[Block] = b.get_in().copy() # Copy as we modify it by adding blocks
for parent in parents:
moves = generate_moves_from_phis(phis, parent)
# TODO Add the block containing 'moves' to 'cfg'
# and update edges and jumps accordingly (Lab 5a, Exercise 6)
raise NotImplementedError("exit_ssa")

View File

@ -0,0 +1,99 @@
from typing import Dict, Set
from Lib.Operands import Operand, Temporary
from Lib.Statement import Statement, Instruction, regset_to_string
from Lib.CFG import CFG, Block
import copy
class LivenessDataFlow:
def __init__(self, function, debug=False):
self._function: CFG = function
self._debug = debug
# Live Operands at input and output of blocks
self._blockin: Dict[Block, Set[Operand]] = {}
self._blockout: Dict[Block, Set[Operand]] = {}
# Live Operands at outputs of instructions
self._liveout: Dict[tuple[Block, Statement], Set[Operand]] = {}
def run(self):
self.set_gen_kill()
if self._debug:
self.print_gen_kill()
self.run_dataflow_analysis()
if self._debug:
self.print_map_in_out()
self.fill_liveout()
def set_gen_kill(self):
"""Set the _gen and _kill field for each block in the function."""
for blk in self._function.get_blocks():
self.set_gen_kill_in_block(blk)
def set_gen_kill_in_block(self, block: Block) -> None:
gen = set()
kill = set()
for i in block.get_all_statements():
# Reminder: '|' is set union, '-' is subtraction.
raise NotImplementedError()
block._gen = gen
block._kill = kill
def run_dataflow_analysis(self):
"""Run the dataflow liveness analysis, i.e. compute self._blockin and
self._blockout based on the ._kill and ._gen fields of individual
instructions."""
if self._debug:
print("Dataflow Analysis")
# initialisation of all blockout,blockin sets, and def = kill
for blk in self._function.get_blocks():
self._blockin[blk] = set()
self._blockout[blk] = set()
stable = False
while not stable:
# Iterate until fixpoint :
# make calls to self._function.dataflow_one_step
stable = True # CHANGE
# TODO (lab5) ! (perform iterations until fixpoint).
def dataflow_one_step(self):
"""Run one iteration of the dataflow analysis. This function is meant
to be run iteratively until fixpoint."""
for blk in self._function.get_blocks():
self._blockout[blk] = set()
for child_label in blk.get_terminator().targets():
child = self._function.get_block(child_label)
self._blockout[blk] = self._blockout[blk] | self._blockin[child]
self._blockin[blk] = (self._blockout[blk] - blk._kill) | blk._gen
def fill_liveout(self):
"""Propagate the information from blockout/blockin inside the block
to get liveset instruction by instructions."""
for blk in self._function.get_blocks():
liveset = self._blockout[blk]
for instr in reversed(blk.get_all_statements()):
self._liveout[blk, instr] = liveset
liveset = (liveset - set(instr.defined())) | set(instr.used())
def print_gen_kill(self): # pragma: no cover
print("Dataflow Analysis, Initialisation")
for i, block in enumerate(self._function.get_blocks()):
print("block " + str(block._label), ":", i)
print("gen: " + regset_to_string(block._gen))
print("kill: " + regset_to_string(block._kill) + "\n")
def print_map_in_out(self): # pragma: no cover
"""Print in/out sets, useful for debug!"""
print("In: {" +
", ".join(str(x.get_label()) + ": "
+ regset_to_string(self._blockin[x])
for x in self._blockin.keys()) +
"}")
print("Out: {" +
", ".join(str(x.get_label()) + ": "
+ regset_to_string(self._blockout[x])
for x in self._blockout.keys()) +
"}")

81
MiniC/TP05/LivenessSSA.py Normal file
View File

@ -0,0 +1,81 @@
from typing import Dict, Set, Tuple
from Lib.Operands import Temporary
from Lib.Statement import Statement, regset_to_string
from Lib.CFG import Block, CFG
from Lib.PhiNode import PhiNode
class LivenessSSA:
"""Liveness Analysis on a CFG under SSA Form."""
def __init__(self, cfg: CFG, debug=False):
self._cfg: CFG = cfg
self._debug: bool = debug
# Temporary already propagated, by Block
self._seen: Dict[Block, Set[Temporary]] = dict()
# Live Temporary at outputs of Statement
self._liveout: Dict[tuple[Block, Statement], Set[Temporary]] = dict()
def run(self) -> None:
"""Compute the liveness: fill out self._seen and self._liveout."""
# Initialization
for block in self._cfg.get_blocks():
self._seen[block] = set()
for instr in block.get_all_statements():
self._liveout[block, instr] = set()
# Start the used-defined chains with backward propagation of liveness information
for var, uses in self.gather_uses().items():
for block, pos in uses:
self.livein_at_instruction(block, pos, var)
# Add conflicts on phis
self.conflict_on_phis()
# Final debugging print
if self._debug:
self.print_map_in_out()
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)
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)
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)
def gather_uses(self) -> Dict[Temporary, Set[Tuple[Block, int]]]:
"""
Return a dictionnary giving for each variable the set of statements using it,
with a statement identified by its block and its position inside the latter.
Phi instructions are at the beginning of their block, while a Terminator is at
the last position of its block.
"""
uses: Dict[Temporary, Set[Tuple[Block, int]]] = dict()
for block in self._cfg.get_blocks():
for pos, instr in enumerate(block.get_all_statements()):
# Variables used by a statement `s` are `s.used()`
for var in instr.used():
if isinstance(var, Temporary):
# Already computed uses of the var if any, otherwise the empty set
var_uses = uses.get(var, set())
# Add for a statement its block and its position inside to the uses of var
uses[var] = var_uses.union({(block, pos)})
return uses
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)
def print_map_in_out(self) -> None: # pragma: no cover
"""Print live out sets at each instruction, group by block, useful for debugging!"""
print("Liveout: [")
for block in self._cfg.get_blocks():
print("Block " + str(block.get_label()) + ": {\n "
+ ",\n ".join("\"{}\": {}"
.format(instr, regset_to_string(self._liveout[block, instr]))
for instr in block.get_all_statements()) +
"}")
print("]")

View File

@ -0,0 +1,60 @@
"""
CAP, SSA Intro, Elimination and Optimisations
Helper functions to convert a CFG out of SSA Form
for the Smart Allocator.
"""
from typing import List, Set, Tuple
from Lib import RiscV
from Lib.Graphes import DiGraph
from Lib.CFG import BlockInstr
from Lib.Operands import Register, Offset, DataLocation, S
def generate_smart_move(dest: DataLocation, src: DataLocation) -> List[BlockInstr]:
"""
Generate a list of move, store and load instructions, depending on
whether the operands are registers or memory locations.
This is an helper function for `sequentialize_moves`.
"""
instr: List[BlockInstr] = []
# TODO Compute the moves (Lab 5b, Exercise 4)
raise NotImplementedError("generate_smart_move")
return instr
def sequentialize_moves(parallel_moves: Set[Tuple[DataLocation, DataLocation]]
) -> List[BlockInstr]:
"""
Take a set of parallel moves represented as (destination, source) pairs,
and return a list of sequential moves which respect the cycles.
Use the register `tmp` S2 for the cycles.
Return a corresponding list of RiscV instructions.
This is an helper function called during SSA exit.
"""
tmp: Register = S[2] # S2 is not a general purpose register
# Build the graph of the moves
move_graph: DiGraph = DiGraph()
for dest, src in parallel_moves:
move_graph.add_edge((src, dest))
# 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
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")
# 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")
# Transform the moves to do in actual RiscV instructions
moves_instr: List[BlockInstr] = []
for dest, src in moves:
instrs = generate_smart_move(dest, src)
moves_instr.extend(instrs)
return moves_instr

View File

@ -0,0 +1,99 @@
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.Allocator import Allocator
from Lib.FunctionData import FunctionData
from Lib import RiscV
from Lib.Graphes import Graph # For Graph coloring utility functions
class SmartAllocator(Allocator):
_igraph: Graph # interference graph
def __init__(self, fdata: FunctionData, basename: str, liveness,
debug=False, debug_graphs=False):
self._liveness = liveness
self._basename: str = basename
self._debug: bool = debug
self._debug_graphs: bool = debug_graphs
super().__init__(fdata)
def replace(self, old_instr: Instruction) -> List[Instruction]:
"""
Replace Temporary operands with the corresponding allocated
physical register (Register) OR memory location (Offset).
"""
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
# And now return the new list!
instr = old_instr.with_args(new_args)
return before + [instr] + after
def prepare(self) -> None:
"""
Perform all preparatory steps related to smart register allocation:
- Dataflow analysis to compute the liveness range of each
temporary.
- Interference graph construction.
- Graph coloring.
- Associating temporaries with actual locations.
"""
# Liveness analysis
self._liveness.run()
# Interference graph
self.build_interference_graph()
if self._debug_graphs:
print("Printing the interference graph")
self._igraph.print_dot(self._basename + "interference.dot")
# Smart Allocation via graph coloring
self.smart_alloc()
def build_interference_graph(self) -> None:
"""
Build the interference graph (in self._igraph).
Vertices of the graph are temporaries,
and an edge exists between temporaries iff they are in conflict.
"""
self._igraph: Graph = Graph()
# Create a vertex for every temporary
# There may be temporaries the code does not use anymore,
# but it does not matter as they interfere with no one.
for v in self._fdata._pool.get_all_temps():
self._igraph.add_vertex(v)
# 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
def smart_alloc(self) -> None:
"""
Allocates all temporaries via graph coloring.
Prints the colored graph if self._debug_graphs is True.
Precondition: the interference graph _igraph must have been built.
"""
# Checking the interference graph has been built
if not self._igraph:
raise MiniCInternalError("Empty interference graph in the Smart Allocator")
# Coloring of the interference graph
coloringreg: Dict[Temporary, int] = self._igraph.color()
if self._debug_graphs:
print("coloring = " + str(coloringreg))
self._igraph.print_dot(self._basename + "_colored.dot", coloringreg)
# Temporary -> DataLocation (Register or Offset) dictionary,
# specifying where a given Temporary should be allocated:
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
if self._debug:
print("Allocation:")
print(alloc_dict)
self._fdata._pool.set_temp_allocation(alloc_dict)

View File

@ -0,0 +1,19 @@
#include "printlib.h"
int f(int x){
int y ;
y = 42;
return y;
}
int main(){
int x ;
x = f(41, 41);
println_int(x);
return 0;
}
// EXITCODE 2
// EXPECTED
// In function main: Line 11 col 6: wrong number of arguments in call to function f

View File

@ -0,0 +1,20 @@
#include "printlib.h"
int f(int x){
int y ;
y = 42;
return y;
}
int main(){
int x ;
bool b;
b = true;
x = f(b);
println_int(x);
return 0;
}
// EXITCODE 2
// EXPECTED
// In function main: Line 13 col 6: type mismatch for method argument in call to function f: boolean and integer

View File

@ -0,0 +1,19 @@
#include "printlib.h"
int f(int x){
int y ;
y = 42;
return y;
}
int main(){
bool b;
b = f(12);
return 0;
}
// EXITCODE 2
// EXPECTED
// In function main: Line 11 col 2: type mismatch for b: boolean and integer

View File

@ -0,0 +1,19 @@
#include "printlib.h"
int f(int x, bool b, int z);
int main(){
bool b;
b = f(12,1,2);
return 0;
}
int f(int x, bool b, int z){
int y ;
y = 42;
return y;
}
// EXITCODE 2
// EXPECTED
// In function main: Line 7 col 6: type mismatch for method argument in call to function f: integer and boolean

View File

@ -0,0 +1,19 @@
#include "printlib.h"
int f(int x, bool b, int z);
int main(){
int b;
b = f(12,true,2);
return 0;
}
int f(int x, bool b, int z){
int y ;
y = 42;
return true;
}
// EXITCODE 2
// EXPECTED
// In function f: Line 11 col 0: type mismatch for return type of function f: integer and boolean

View File

@ -0,0 +1,19 @@
#include "printlib.h"
int f(int x, bool x){
int y ;
y = 42;
return y;
}
int main(){
int x ;
x = f(41, 41);
println_int(x);
return 0;
}
// EXITCODE 2
// EXPECTED
// In function f: Line 3 col 13: Parameter x already defined

View File

@ -0,0 +1,19 @@
#include "printlib.h"
bool f(int x, bool b){
int x ;
x = 42;
return b;
}
int main(){
int x ;
x = f(41, 41);
println_int(x);
return 0;
}
// EXITCODE 2
// EXPECTED
// In function f: Line 4 col 2: Variable x already declared

View File

@ -0,0 +1,21 @@
#include "printlib.h"
int f(int x, bool y);
int f(int x, int y){
int y ;
y = 42;
return y;
}
int main(){
bool b;
b = f(12);
return 0;
}
// EXITCODE 2
// EXPECTED
// In function f: Line 5 col 0: function f already declared with a different signature

View File

@ -0,0 +1,23 @@
#include "printlib.h"
int f(int x, bool y);
int f(int x, bool y){
return 2;
}
int f(int x, bool y){
return 0;
}
int main(){
bool b;
b = f(12);
return 0;
}
// EXITCODE 2
// EXPECTED
// In function f: Line 9 col 0: function f already defined

View File

@ -0,0 +1,14 @@
#include "printlib.h"
bool bbb(bool b0, bool b1, bool b2, bool b3, bool b4, bool b5, bool b6, bool b7, bool b8, bool b9){
return b9;
}
bool main() {
bool dummy;
return dummy;
}
// EXITCODE 2
// EXPECTED
// In function bbb: Line 3 col 0: function bbb declared with 10 > 8 arguments

View File

@ -0,0 +1,17 @@
#include "printlib.h"
bool bbb(bool b0, bool b1, bool b2, bool b3, bool b4, bool b5, bool b6, bool b7, bool b8, bool b9, bool b10);
bool bbb(bool b0, bool b1, bool b2, bool b3, bool b4, bool b5, bool b6, bool b7, bool b8, bool b9, bool b10){
return b9;
}
bool main() {
bool dummy;
dummy = bbb(true, true, true, true, true, true, true, true, true, false);
return dummy;
}
// EXITCODE 2
// EXPECTED
// In function bbb: Line 3 col 0: function bbb declared with 11 > 8 arguments

View File

@ -0,0 +1,5 @@
#include <stdio.h>
int print_hello() {
printf("Hello, world!\n");
}

View File

@ -0,0 +1,7 @@
int main() {
x = f(1);
return 0;
}
// EXITCODE 2
// EXPECTED
// In function main: Line 2 col 6: Undefined function f

View File

@ -0,0 +1,13 @@
#include "printlib.h"
bool bbb(bool b){
return b;
}
int main() {
bool dummy;
dummy = bbb(false);
return 0;
}
// EXPECTED

View File

@ -0,0 +1,14 @@
int f() {return 42;}
int f();
int main(){
int dummy;
dummy = f();
return 0;
}
// EXPECTED
// EXITCODE 0

View File

@ -0,0 +1,13 @@
// Call to external functions
int print_hello();
int main() {
int dummy;
dummy = print_hello();
return 0;
}
// EXPECTED
// Hello, world!
// LINKARGS $dir/lib/_hello.c

View File

@ -0,0 +1,13 @@
// Call to external functions written in assembly
int print_42();
int main() {
int dummy;
dummy = print_42();
return 0;
}
// EXPECTED
// 42
// LINKARGS $dir/lib/_print42.s

View File

@ -0,0 +1,19 @@
#include "printlib.h"
// Call of function with no parameter
int f(int x){
int y ;
y = 42;
return y;
}
int main(){
int val;
val = f(123);
println_int(val);
return 0;
}
// EXPECTED
// 42

View File

@ -0,0 +1,19 @@
#include "printlib.h"
// Call of function with a single parameter
int f(int x){
int y ;
y = 42;
return y;
}
int main(){
int val;
val = f(12);
println_int(val);
return 0;
}
// EXPECTED
// 42

View File

@ -0,0 +1,17 @@
#include "printlib.h"
// Call of function with two parameters
int f(int x, int y){
return x + y;
}
int main(){
int val;
val = f(12, 30);
println_int(val);
return 0;
}
// EXPECTED
// 42

View File

@ -0,0 +1,17 @@
#include "printlib.h"
// Call of function with two parameters
int f(int x, int y){
return x + y;
}
int main(){
int val;
val = f(12, 31) - f(13,-12);
println_int(val);
return 0;
}
// EXPECTED
// 42

View File

@ -0,0 +1,11 @@
#include "printlib.h"
// Forward declaration of function with no parameter
int f();
int main(){
return 0;
}
// EXPECTED

View File

@ -0,0 +1,11 @@
#include "printlib.h"
// Forward declaration of function with a single parameter
int f(int x);
int main(){
return 0;
}
// EXPECTED

View File

@ -0,0 +1,11 @@
#include "printlib.h"
// Forward declaration of function with two parameters
int f(int x, bool y);
int main(){
return 0;
}
// EXPECTED

View File

@ -0,0 +1,15 @@
#include "printlib.h"
// Definition of function with a single parameter
int f(int x){
int y ;
y = 42;
return y;
}
int main(){
return 0;
}
// EXPECTED

View File

@ -0,0 +1,12 @@
#include "printlib.h"
// Declaration of a function with two parameters
int f(int x, bool y) {
return x;
}
int main(){
return 0;
}
// EXPECTED

View File

@ -0,0 +1,15 @@
#include "printlib.h"
int f(int x){
return x + 1;
}
int main() {
int dummy;
dummy = f(f(10) + f(100));
println_int(dummy);
return 0;
}
// EXPECTED
// 113

View File

@ -0,0 +1,20 @@
#include "printlib.h"
// Definition of function with a single parameter
// with forward declaration, i.e. declaration here and definition after main
int f(int x);
int main(){
int z;
z = f(0);
return 0;
}
int f(int x){
int y ;
y = 42;
return y;
}
// EXPECTED

View File

@ -0,0 +1,10 @@
#include "printlib.h"
// Return statememnt with expression
int main(){
return 1 + 2;
}
// EXPECTED
// EXECCODE 3

427
MiniC/TPoptim/OptimSSA.py Normal file
View File

@ -0,0 +1,427 @@
"""
CAP, SSA Intro, Elimination and Optimisations
Optimisations on SSA.
"""
from enum import Enum
from typing import List, Dict, Tuple, cast
from Lib.Errors import MiniCInternalError
from Lib.Operands import (Operand, Temporary, Immediate, A, ZERO)
from Lib.Statement import (Statement, Instruction, Label, AbsoluteJump)
from Lib.CFG import (BlockInstr, Terminator, Block, CFG)
from Lib.Terminator import (Return, BranchingTerminator)
from Lib.PhiNode import PhiNode
from Lib import RiscV
def div_rd_0(a: int, b: int) -> int:
"""Division rounded towards 0 (integer division in Python rounds down)."""
return -(-a // b) if (a < 0) ^ (b < 0) else a // b
def mod_rd_0(a: int, b: int) -> int:
"""Modulo rounded towards 0 (integer division in Python rounds down)."""
return -(-a % b) if (a < 0) ^ (b < 0) else a % b
class Lattice(Enum):
Bottom = 0
Top = 1
LATTICE_VALUE = int | Lattice # Type for our values: Bottom < int < Top
def join(v1: LATTICE_VALUE, v2: LATTICE_VALUE) -> LATTICE_VALUE:
"""Compute the join of the two lattice values."""
match v1, v2:
case Lattice.Top, _:
return Lattice.Top
case _, Lattice.Top:
return Lattice.Top
case Lattice.Bottom, _:
return v2
case _, Lattice.Bottom:
return v1
case _, _: # both int
if v1 == v2:
return v1
else:
return Lattice.Top
def joinl(values: List[LATTICE_VALUE]) -> LATTICE_VALUE:
"""Compute the join of the list of lattice values."""
res = Lattice.Bottom
for v in values:
res = join(res, v)
return res
class CondConstantPropagation:
"""
Class that optimises a CFG under SSA form
following the algorithm "Sparse Conditionnal Constant Propagation".
"""
cfg: CFG
# CFG under SSA form to optimise
valueness: Dict[Operand, LATTICE_VALUE]
# Values of each variable v:
# valueness[v] = Lattice.Bottom if no evidence that v is assigned
# valueness[v] = n if we found evidence that only n is assigned to v
# valueness[v] = Lattice.Top if we found evidence that v is assigned
# to at least two different values
executability: Dict[Tuple[Block | None, Block], bool]
# Exectuability of an edge (B, C):
# executability[B, C] = False if no evidence that the edge (B, C) can ever be executed
# executability[B, C] = True if (B, C) may be executed (over-approximation)
# There is an initial edge from None to the start block
modified_flag: bool
# Flag to check if we reach the fixpoint
debug: bool
# Print valueness and executability at each step if True
all_vars: List[Operand]
# All the variables of the CFG
all_blocks: List[Block]
# All the blocks of the CFG
def __init__(self, cfg: CFG, debug: bool):
self.cfg = cfg
self.valueness = dict()
self.executability = dict()
self.debug = debug
self.all_vars = list(cfg.gather_defs().keys())
self.all_blocks = cfg.get_blocks()
# Initialisation of valueness and executability
for var in self.all_vars:
self.valueness[var] = Lattice.Bottom
for block in self.all_blocks:
for succ in cfg.out_blocks(block):
self.executability[block, succ] = False
# Add an initial edge from None to the start block
start_blk = self.cfg.get_block(self.cfg.get_start())
self.executability[None, start_blk] = False
def dump(self) -> None: # pragma: no cover
"""
For debug purposes: print valueness and executability.
"""
print("Valueness:")
for x, v in self.valueness.items():
print("{0}: {1}".format(x, v))
print("Executability:")
for (B, C), v in self.executability.items():
print("{0} -> {1}: {2}".format(B.get_label() if B is not None else "",
C.get_label(), v))
def set_valueness(self, v: Operand, x: LATTICE_VALUE) -> None:
"""
Update the valueness of a variable `v` by performing a join with
its current value.
"""
old_x = self.valueness[v]
new_x = join(x, old_x)
if new_x != old_x:
self.modified_flag = True
self.valueness[v] = new_x
def set_executability(self, B: Block | None, C: Block) -> None:
"""
Mark the edge from `B` to `C` as executable.
"""
old_x = self.executability[B, C]
if not old_x:
self.modified_flag = True
self.executability[B, C] = True
def is_constant(self, op: Operand) -> bool:
"""True if the value of `op` is constant."""
return isinstance(self.valueness.get(op, None), int)
def is_executable(self, B: Block) -> bool:
"""True if the block `B` may be executed."""
return B in (C for ((_, C), b) in self.executability.items() if b)
def compute(self) -> None:
"""
Compute executability for all edges and valueness for all variables
using a fixpoint algorithm.
"""
# 1. For any v coming from outside the CFG (parameters, function calls),
# set valueness[v] = Top. These are exactly the registers of A.
for var in A:
self.valueness[var] = Lattice.Top
# 2. The start block is executable, with an initial edge coming from None.
start_blk = self.cfg.get_block(self.cfg.get_start())
self.set_executability(None, start_blk)
# Start the fixpoint.
self.modified_flag = True
while self.modified_flag:
# Whenever executability or valueness is modified,
# modified_flag is set to True (see set_executability and set_valueness)
# so that the fixpoint continues.
self.modified_flag = False
if self.debug:
self.dump()
# 3. For any executable block B with only one successor C,
# set executability[B, C] = True.
for B in self.all_blocks:
nexts = self.cfg.out_blocks(B)
if self.is_executable(B) and len(nexts) == 1:
C = nexts[0]
self.set_executability(B, C)
for B in self.all_blocks:
if self.is_executable(B):
for stat in B.get_all_statements():
self.propagate_in(B, stat)
def propagate_in(self, B: Block, stat: Statement) -> None:
"""
Propagate valueness and executability to the given statement `stat`
located in the given executable block `B`.
See the `compute` function for more context.
"""
# 4. For any executable assignment v <- op (x, y),
# set valueness[v] = eval (op, x, y)
# TODO (Exercise 4)
# 5. For any executable assignment v <- phi (x1, ..., xn),
# set valueness[v] = join(x1, .., xn)
# TODO (Exercise 6)
# 6. For any executable conditional branch to blocks B1 and B2,
# set executability[B1] = True and/or executability[B2] = True
# depending on the valueness of its condition
# TODO (Exercise 6)
def get_executable_srcs(self, B: Block, phi: PhiNode) -> List[Operand]:
"""
Given a phi node `phi` belonging to the block `B`,
return its operands coming from an executable edge.
"""
return [x for lbl, x in phi.get_srcs().items()
if self.executability[self.cfg.get_block(lbl), B]]
def get_operands(self, ins: Instruction) -> List[LATTICE_VALUE]:
"""
Returns the valueness of the operands of the given instruction `ins`.
Also takes into account immediate values and the zero register.
"""
args: List[LATTICE_VALUE] = []
for x in ins.used():
if isinstance(x, Temporary):
args.append(self.valueness[x])
elif isinstance(x, Immediate):
args.append(x._val)
elif (x == ZERO):
args.append(0)
elif isinstance(x, Label):
continue
else:
args.append(Lattice.Top)
return args
def eval_arith_instr(self, ins: Instruction) -> LATTICE_VALUE:
"""
Computes the result of an arithmetic instruction in the valueness lattice,
from the valueness of its operands.
"""
args = self.get_operands(ins)
name: str = ins.ins
if Lattice.Top in args:
return Lattice.Top
elif Lattice.Bottom in args:
return Lattice.Bottom
args = cast(List[int], args)
if name == "add" or name == "addi":
return args[0] + args[1]
elif name == "mul":
return args[0] * args[1]
elif name == "div":
return div_rd_0(args[0], args[1])
elif name == "rem":
return mod_rd_0(args[0], args[1])
elif name == "sub":
return args[0] - args[1]
elif name == "and":
return args[0] & args[1]
elif name == "or":
return args[0] | args[1]
elif name == "xor" or name == "xori":
return args[0] ^ args[1]
elif name == "li":
assert (isinstance(ins.used()[0], Immediate))
return args[0]
elif name == "mv":
return args[0]
raise MiniCInternalError("Instruction modifying a temporary not in\
['add', 'addi', 'mul', 'div', 'rem',\
'sub', 'and', 'or', 'xor', 'xori', 'li', 'mv']")
def eval_bool_instr(self, ins: BranchingTerminator) -> LATTICE_VALUE:
"""
Computes the result of the comparison of a branching instruction
in the valueness lattice, from the valueness of its operands.
"""
args = self.get_operands(ins)
name: str = ins.ins
if Lattice.Top in args:
return Lattice.Top
elif Lattice.Bottom in args:
return Lattice.Bottom
args = cast(List[int], args)
if name == "blt":
return args[0] < args[1]
elif name == "bgt":
return args[0] > args[1]
elif name == "beq":
return args[0] == args[1]
elif name == "bne":
return args[0] != args[1]
elif name == "ble":
return args[0] <= args[1]
elif name == "bge":
return args[0] >= args[1]
elif name == "beqz":
return args[0] == 0
elif name == "bnez":
return args[0] != 0
raise MiniCInternalError("Condition of a CondJump not in ['blt',\
'bgt', 'beq', 'bne', 'ble', 'bge',\
'beqz', 'bnez']")
def replacePhi(self, B: Block, ins: PhiNode) -> PhiNode:
"""
Replace a phi node that has constant operands
according to the valueness computation.
"""
to_remove: List[Label] = [] # List of block's labels with no executable edge to B
for Bi_label, xi in ins.get_srcs().items():
Bi = self.cfg.get_block(Bi_label)
if self.executability[Bi, B]:
if self.is_constant(xi):
# Add a LI instruction in the block from where xi comes,
# at the end of its body (i.e. just before its Terminator),
# and replace xi by this new temporary
new_xi = self.cfg.fdata.fresh_tmp()
ins.srcs[Bi_label] = new_xi
imm = Immediate(self.valueness[xi])
li_ins = RiscV.li(new_xi, imm)
Bi.add_instruction(li_ins)
else:
to_remove.append(Bi_label)
for Bi_label in to_remove:
del ins.srcs[Bi_label]
return ins
def replaceInstruction(self, ins: BlockInstr) -> List[BlockInstr]:
"""
Replace an instruction that has constant operands
according to the valueness computation.
"""
# Add some LI instructions before the instruction `ins`
li_instrs: List[BlockInstr] = []
# Replace the constant variables with the temporaries defined by the new LI instructions
subst: Dict[Operand, Operand] = {}
# Compute `li_instrs` and `subst`
# TODO (Exercise 5)
new_ins = ins.substitute(subst)
return li_instrs + [new_ins]
def replaceTerminator(self, ins: Terminator) -> Tuple[List[BlockInstr], Terminator]:
"""
Replace a terminator that has constant operands
according to the valueness computation.
Return the list of LI instructions to do before,
and the new terminator.
"""
# Add some LI instructions at the end of the body of the block
li_instrs: List[BlockInstr] = []
# Replace the constant variables with the temporaries defined by the new LI instructions
subst: Dict[Operand, Operand] = {}
# Compute `li_instrs` and `subst`
# TODO (Exercise 5)
new_ins = ins.substitute(subst)
return li_instrs, new_ins
def rewriteCFG(self) -> None:
"""Update the CFG."""
# a. Whenever executability[B, C] = False, delete this edge
for (B, C) in [(B, C) for ((B, C), b) in self.executability.items()
if not b and B is not None]:
# Remove the edge
self.cfg.remove_edge(B, C)
# Update the corresponding terminator
targets = B.get_terminator().targets()
targets.remove(C.get_label())
if len(targets) == 0:
B.set_terminator(Return())
elif len(targets) == 1:
B.set_terminator(AbsoluteJump(targets[0]))
else:
raise MiniCInternalError(
"rewriteCFG: A terminator has more than 2 targets: {}"
.format(targets + [C.get_label()]))
# b. Whenever valueness[x] = c, substitute c for x and delete assignment to x
for block in self.all_blocks:
if self.is_executable(block):
new_phis: List[PhiNode] = []
for ins in block.get_phis():
assert (isinstance(ins, PhiNode))
v = ins.defined()[0]
if self.is_constant(v):
# We do not keep instructions defining operands of constant values
continue
else:
new_phis.append(self.replacePhi(block, ins))
new_instrs: List[BlockInstr] = []
for ins in block.get_body():
defs = ins.defined()
if len(defs) == 1 and self.is_constant(defs[0]):
# We do not keep instructions defining operands of constant values
continue
elif isinstance(ins, Instruction):
# We replace others instructions
new_instrs.extend(self.replaceInstruction(ins))
else:
# We do nothing for comments
new_instrs.append(ins)
term_instrs, new_term = self.replaceTerminator(block.get_terminator())
block.set_phis(cast(List[Statement], new_phis))
block._instructions = new_instrs + term_instrs
block.set_terminator(new_term)
# c. Whenever a block B is not executable, delete B
# There are no edge implicating B, for such an edge would not be
# executable, whence would have been deleted beforehand
for block in self.all_blocks:
if not self.is_executable(block):
del self.cfg._blocks[block.get_label()]
def OptimSSA(cfg: CFG, debug: bool) -> None:
"""Optimise a CFG under SSA form."""
optim = CondConstantPropagation(cfg, debug)
optim.compute()
optim.rewriteCFG()

View File

@ -0,0 +1,23 @@
#include "printlib.h"
int main() {
int i, j, k;
i = 1;
j = 1;
k = 0;
while (k < 100) {
if (j < 20) {
j = i;
k = k+1;
}
else {
j = k;
k = k+2;
}
}
println_int(j);
return 0;
}
// EXPECTED
// 1

View File

@ -0,0 +1,12 @@
#include "printlib.h"
int main() {
int i, j;
i = 1;
j = i;
println_int(j);
return 0;
}
// EXPECTED
// 1

157
MiniC/test_codegen.py Executable file
View File

@ -0,0 +1,157 @@
#! /usr/bin/env python3
import os
import sys
import pytest
import glob
from test_expect_pragma import (
TestExpectPragmas, TestCompiler,
filter_pathnames, cat
)
"""
Usage:
python3 test_codegen.py
(or make test)
"""
"""
MIF08 and CAP, 2019
Unit test infrastructure for testing code generation:
1) compare the actual output to the expected one (in comments)
2) compare the actual output to the one obtained by simulation
3) for different allocation algorithms
"""
MINICC_OPTS = []
if "MINICC_OPTS" in os.environ and os.environ["MINICC_OPTS"]:
MINICC_OPTS = os.environ["MINICC_OPTS"].split()
else:
MINICC_OPTS = ["--mode=codegen-cfg"]
DISABLE_TYPECHECK = "--disable-typecheck" in MINICC_OPTS \
or "--mode=parse" in MINICC_OPTS or "parse" in MINICC_OPTS
DISABLE_CODEGEN = "--mode=parse" in MINICC_OPTS or "--mode=typecheck" in MINICC_OPTS \
or "parse" in MINICC_OPTS or "typecheck" in MINICC_OPTS
HERE = os.path.dirname(os.path.realpath(__file__))
if HERE == os.path.realpath('.'):
HERE = '.'
TEST_DIR = HERE
IMPLEM_DIR = HERE
SKIP_EXPECT = False
if 'SKIP_EXPECT' in os.environ:
SKIP_EXPECT = True
MINIC_COMPILE = os.path.join(IMPLEM_DIR, 'MiniCC.py')
ALL_FILES = []
# tests for typing AND evaluation
ALL_FILES += glob.glob(os.path.join(TEST_DIR, 'TP04/tests/**/[a-zA-Z]*.c'),
recursive=True)
ALLOC_FILES = glob.glob(os.path.join(HERE, 'TP05/tests/**/*.c'), recursive=True)
SKIP_NOT_IMPLEMENTED = False
if 'SKIP_NOT_IMPLEMENTED' in os.environ:
SKIP_NOT_IMPLEMENTED = True
if 'TEST_FILES' in os.environ:
ALL_FILES = glob.glob(os.environ['TEST_FILES'], recursive=True)
MINIC_EVAL = os.path.join(
HERE, '..', '..', 'TP03', 'MiniC-type-interpret', 'Main.py')
# if 'COMPIL_MINIC_EVAL' in os.environ:
# MINIC_EVAL = os.environ['COMPIL_MINIC_EVAL']
# else:
# MINIC_EVAL = os.path.join(
# HERE, '..', '..', 'TP03', 'MiniC-type-interpret', 'Main.py')
# Avoid duplicates
ALL_IN_MEM_FILES = list(set(ALL_FILES) | set(ALLOC_FILES))
ALL_IN_MEM_FILES.sort()
ALL_FILES = list(set(ALL_FILES))
ALL_FILES.sort()
if 'TEST_FILES' in os.environ:
ALLOC_FILES = ALL_FILES
ALL_IN_MEM_FILES = ALL_FILES
if 'FILTER' in os.environ:
ALL_FILES = filter_pathnames(ALL_FILES, os.environ['FILTER'])
ALLOC_FILES = filter_pathnames(ALLOC_FILES, os.environ['FILTER'])
ALL_IN_MEM_FILES = filter_pathnames(ALL_IN_MEM_FILES, os.environ['FILTER'])
class TestCodeGen(TestExpectPragmas, TestCompiler):
DISABLE_CODEGEN = DISABLE_CODEGEN
SKIP_NOT_IMPLEMENTED = SKIP_NOT_IMPLEMENTED
MINIC_COMPILE = MINIC_COMPILE
MINICC_OPTS = MINICC_OPTS
# Not in test_expect_pragma to get assertion rewritting
def assert_equal(self, actual, expected, compiler):
if DISABLE_CODEGEN and expected.exitcode in (0, 5):
# Compiler does not fail => no output expected
assert actual.output == "", \
"Compiler unexpectedly generated some output with codegen disabled"
assert actual.exitcode == 0, \
"Compiler unexpectedly failed with codegen disabled"
return
if DISABLE_TYPECHECK and expected.exitcode != 0:
# Test should fail at typecheck, and we don't do
# typechecking => nothing to check.
pytest.skip("Test that doesn't typecheck with --disable-typecheck")
assert actual.exitcode == expected.exitcode, \
f"Exit code of the compiler ({compiler}) is incorrect"
if expected.output is not None and actual.output is not None:
assert actual.output == expected.output, \
f"Output of the program is incorrect (using {compiler})."
assert actual.execcode == expected.execcode, \
f"Exit code of the execution is incorrect (after compiling with {compiler})"
@pytest.mark.parametrize('filename', ALL_FILES)
def test_expect(self, filename):
"""Test the EXPECTED annotations in test files by launching the
program with GCC."""
if SKIP_EXPECT:
pytest.skip("Skipping all test_expect because $SKIP_EXPECT is set.")
expect = self.get_expect(filename)
if expect.skip_test_expected:
pytest.skip("Skipping test_expect with GCC because "
"the test contains SKIP TEST EXPECTED")
if expect.exitcode != 0:
# GCC is more permissive than us, so trying to compile an
# incorrect program would bring us no information (it may
# compile, or fail with a different message...)
pytest.skip("Not testing the expected value for tests expecting exitcode!=0")
gcc_result = self.run_with_gcc(filename, expect)
self.assert_equal(gcc_result, expect, "GCC")
@pytest.mark.parametrize('filename', ALL_FILES)
def test_naive_alloc(self, filename):
cat(filename) # For diagnosis
expect = self.get_expect(filename)
naive = self.compile_and_simulate(filename, expect, 'naive')
self.assert_equal(naive, expect, "MiniCC with naive alloc")
@pytest.mark.parametrize('filename', ALL_IN_MEM_FILES)
def test_alloc_mem(self, filename):
cat(filename) # For diagnosis
expect = self.get_expect(filename)
actual = self.compile_and_simulate(filename, expect, 'all-in-mem')
self.assert_equal(actual, expect, "MiniCC with all-in-mem")
@pytest.mark.parametrize('filename', ALL_IN_MEM_FILES)
def test_smart_alloc(self, filename):
"""Generate code with smart allocation."""
cat(filename) # For diagnosis
expect = self.get_expect(filename)
actual = self.compile_and_simulate(filename, expect, 'smart')
self.assert_equal(actual, expect, "MiniCC with smart alloc")
if __name__ == '__main__':
pytest.main(sys.argv)

View File

@ -43,7 +43,7 @@ _Academic first semester 2024-2025_
# Week 4:
- hammer: Lab 3: Monday 30/09/2024, 13h30-15h30. Room E001 (Samuel Humeau & Emma Nardino)
- :hammer: Lab 3: Monday 30/09/2024, 13h30-15h30. Room E001 (Samuel Humeau & Emma Nardino)
* Interpreter & Typer [TP03](TP03/tp3.pdf).
* Code in [TP03/](TP03/) and [MiniC/TP03/](MiniC/TP03/).
@ -51,3 +51,12 @@ _Academic first semester 2024-2025_
- :book: Course: Thursday 3/10/2024, 10h15-12h15. Amphi B (Gabriel Radanne)
* CFG [slides in english](course/capmif_cours06_irs.pdf).
# Week 5:
- :hammer: Lab 4a: Monday 07/10/2024, 13h30-15h30. Room E001 (Samuel Humeau & Emma Nardino)
* Syntax directed code generation [TP04](TP04/tp4a.pdf).
* Code in [MiniC/TP04/](MiniC/TP04/).
* Documentation [here](docs/html/index.html).

BIN
TP04/tp4a.pdf Normal file

Binary file not shown.

0
docs/.nojekyll Normal file
View File

4
docs/html/.buildinfo Normal file
View File

@ -0,0 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 486d1ff73ffb3f41d31651516deff8a8
tags: 645f666f9bcd5a90fca523b33c5a78b7

View File

@ -0,0 +1,185 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lib.Allocator &mdash; MiniC documentation</title>
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="../../_static/js/html5shiv.min.js"></script>
<![endif]-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
<script src="../../_static/doctools.js"></script>
<script src="../../_static/sphinx_highlight.js"></script>
<script src="../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../genindex.html" />
<link rel="search" title="Search" href="../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../index.html" class="icon icon-home">
MiniC
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Errors.html">Base library - Errors</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Statement.html">Base library - Statement</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.RiscV.html">Base library - RISC-V instructions</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Operands.html">Base library - Operands</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.FunctionData.html">Base library - Function data</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.LinearCode.html">Linear intermediate representation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Allocator.html">Temporary allocation</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../index.html">MiniC</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../index.html">Module code</a></li>
<li class="breadcrumb-item active">Lib.Allocator</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for Lib.Allocator</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">This file defines the base class :py:class:`Allocator`</span>
<span class="sd">and the naïve implementation :py:class:`NaiveAllocator`.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">Lib.Operands</span> <span class="kn">import</span> <span class="n">Temporary</span><span class="p">,</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">DataLocation</span><span class="p">,</span> <span class="n">GP_REGS</span>
<span class="kn">from</span> <span class="nn">Lib.Statement</span> <span class="kn">import</span> <span class="n">Instruction</span>
<span class="kn">from</span> <span class="nn">Lib.Errors</span> <span class="kn">import</span> <span class="n">AllocationError</span>
<span class="kn">from</span> <span class="nn">Lib.FunctionData</span> <span class="kn">import</span> <span class="n">FunctionData</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">List</span>
<div class="viewcode-block" id="Allocator"><a class="viewcode-back" href="../../api/Lib.Allocator.html#Lib.Allocator.Allocator">[docs]</a><span class="k">class</span> <span class="nc">Allocator</span><span class="p">():</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;General base class for Naive, AllInMem and Smart Allocators.</span>
<span class="sd"> Replace all temporaries in the code with actual data locations.</span>
<span class="sd"> Allocation is done in two steps:</span>
<span class="sd"> - First, :py:meth:`prepare` is responsible for calling</span>
<span class="sd"> :py:meth:`Lib.Operands.TemporaryPool.set_temp_allocation`</span>
<span class="sd"> with a mapping from temporaries to where they should actually be stored</span>
<span class="sd"> (in registers or in memory).</span>
<span class="sd"> - Then, :py:meth:`replace` is called for each instruction in order to</span>
<span class="sd"> replace the temporary operands with the previously assigned locations</span>
<span class="sd"> (and possibly add some instructions before or after).</span>
<span class="sd"> Concretely, it returns a list of instructions that should replace the original</span>
<span class="sd"> instruction. The actual iteration over all the instructions is handled transparently</span>
<span class="sd"> by :py:meth:`Lib.LinearCode.LinearCode.iter_statements`.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_fdata</span><span class="p">:</span> <span class="n">FunctionData</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fdata</span><span class="p">:</span> <span class="n">FunctionData</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_fdata</span> <span class="o">=</span> <span class="n">fdata</span>
<div class="viewcode-block" id="Allocator.prepare"><a class="viewcode-back" href="../../api/Lib.Allocator.html#Lib.Allocator.Allocator.prepare">[docs]</a> <span class="k">def</span> <span class="nf">prepare</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="c1"># pragma: no cover</span>
<span class="k">pass</span></div>
<div class="viewcode-block" id="Allocator.replace"><a class="viewcode-back" href="../../api/Lib.Allocator.html#Lib.Allocator.Allocator.replace">[docs]</a> <span class="k">def</span> <span class="nf">replace</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">old_instr</span><span class="p">:</span> <span class="n">Instruction</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Instruction</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Transform an instruction with temporaries into a list of instructions.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="p">[</span><span class="n">old_instr</span><span class="p">]</span></div>
<div class="viewcode-block" id="Allocator.rewriteCode"><a class="viewcode-back" href="../../api/Lib.Allocator.html#Lib.Allocator.Allocator.rewriteCode">[docs]</a> <span class="k">def</span> <span class="nf">rewriteCode</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">listcode</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Modify the code to replace temporaries with</span>
<span class="sd"> registers or memory locations.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">listcode</span><span class="o">.</span><span class="n">iter_statements</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">replace</span><span class="p">)</span></div></div>
<div class="viewcode-block" id="NaiveAllocator"><a class="viewcode-back" href="../../api/Lib.Allocator.html#Lib.Allocator.NaiveAllocator">[docs]</a><span class="k">class</span> <span class="nc">NaiveAllocator</span><span class="p">(</span><span class="n">Allocator</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Naive Allocator: try to assign a register to each temporary,</span>
<span class="sd"> fails if there are more temporaries than registers.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="NaiveAllocator.replace"><a class="viewcode-back" href="../../api/Lib.Allocator.html#Lib.Allocator.NaiveAllocator.replace">[docs]</a> <span class="k">def</span> <span class="nf">replace</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">old_instr</span><span class="p">:</span> <span class="n">Instruction</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Instruction</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Replace Temporary operands with the corresponding allocated Register.&quot;&quot;&quot;</span>
<span class="n">new_args</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Operand</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">old_instr</span><span class="o">.</span><span class="n">args</span><span class="p">():</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="n">Temporary</span><span class="p">):</span>
<span class="n">new_args</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">arg</span><span class="o">.</span><span class="n">get_alloced_loc</span><span class="p">())</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">new_args</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
<span class="n">new_instr</span> <span class="o">=</span> <span class="n">old_instr</span><span class="o">.</span><span class="n">with_args</span><span class="p">(</span><span class="n">new_args</span><span class="p">)</span>
<span class="k">return</span> <span class="p">[</span><span class="n">new_instr</span><span class="p">]</span></div>
<div class="viewcode-block" id="NaiveAllocator.prepare"><a class="viewcode-back" href="../../api/Lib.Allocator.html#Lib.Allocator.NaiveAllocator.prepare">[docs]</a> <span class="k">def</span> <span class="nf">prepare</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Allocate all temporaries to registers.</span>
<span class="sd"> Fail if there are too many temporaries.&quot;&quot;&quot;</span>
<span class="n">regs</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">GP_REGS</span><span class="p">)</span> <span class="c1"># Get a writable copy</span>
<span class="n">temp_allocation</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="n">Temporary</span><span class="p">,</span> <span class="n">DataLocation</span><span class="p">]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
<span class="k">for</span> <span class="n">tmp</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_fdata</span><span class="o">.</span><span class="n">_pool</span><span class="o">.</span><span class="n">get_all_temps</span><span class="p">():</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">reg</span> <span class="o">=</span> <span class="n">regs</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
<span class="k">except</span> <span class="ne">IndexError</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">AllocationError</span><span class="p">(</span>
<span class="s2">&quot;Too many temporaries (</span><span class="si">{}</span><span class="s2">) for the naive allocation, sorry.&quot;</span>
<span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_fdata</span><span class="o">.</span><span class="n">_pool</span><span class="o">.</span><span class="n">get_all_temps</span><span class="p">())))</span>
<span class="n">temp_allocation</span><span class="p">[</span><span class="n">tmp</span><span class="p">]</span> <span class="o">=</span> <span class="n">reg</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_fdata</span><span class="o">.</span><span class="n">_pool</span><span class="o">.</span><span class="n">set_temp_allocation</span><span class="p">(</span><span class="n">temp_allocation</span><span class="p">)</span></div></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2023, compil-lyon.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

View File

@ -0,0 +1,124 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lib.Errors &mdash; MiniC documentation</title>
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="../../_static/js/html5shiv.min.js"></script>
<![endif]-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
<script src="../../_static/doctools.js"></script>
<script src="../../_static/sphinx_highlight.js"></script>
<script src="../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../genindex.html" />
<link rel="search" title="Search" href="../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../index.html" class="icon icon-home">
MiniC
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Errors.html">Base library - Errors</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Statement.html">Base library - Statement</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.RiscV.html">Base library - RISC-V instructions</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Operands.html">Base library - Operands</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.FunctionData.html">Base library - Function data</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.LinearCode.html">Linear intermediate representation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Allocator.html">Temporary allocation</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../index.html">MiniC</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../index.html">Module code</a></li>
<li class="breadcrumb-item active">Lib.Errors</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for Lib.Errors</h1><div class="highlight"><pre>
<div class="viewcode-block" id="MiniCRuntimeError"><a class="viewcode-back" href="../../api/Lib.Errors.html#Lib.Errors.MiniCRuntimeError">[docs]</a><span></span><span class="k">class</span> <span class="nc">MiniCRuntimeError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="k">pass</span></div>
<div class="viewcode-block" id="MiniCInternalError"><a class="viewcode-back" href="../../api/Lib.Errors.html#Lib.Errors.MiniCInternalError">[docs]</a><span class="k">class</span> <span class="nc">MiniCInternalError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="k">pass</span></div>
<div class="viewcode-block" id="MiniCUnsupportedError"><a class="viewcode-back" href="../../api/Lib.Errors.html#Lib.Errors.MiniCUnsupportedError">[docs]</a><span class="k">class</span> <span class="nc">MiniCUnsupportedError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="k">pass</span></div>
<div class="viewcode-block" id="MiniCTypeError"><a class="viewcode-back" href="../../api/Lib.Errors.html#Lib.Errors.MiniCTypeError">[docs]</a><span class="k">class</span> <span class="nc">MiniCTypeError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="k">pass</span></div>
<div class="viewcode-block" id="AllocationError"><a class="viewcode-back" href="../../api/Lib.Errors.html#Lib.Errors.AllocationError">[docs]</a><span class="k">class</span> <span class="nc">AllocationError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="k">pass</span></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2023, compil-lyon.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

View File

@ -0,0 +1,287 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lib.FunctionData &mdash; MiniC documentation</title>
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="../../_static/js/html5shiv.min.js"></script>
<![endif]-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
<script src="../../_static/doctools.js"></script>
<script src="../../_static/sphinx_highlight.js"></script>
<script src="../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../genindex.html" />
<link rel="search" title="Search" href="../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../index.html" class="icon icon-home">
MiniC
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Errors.html">Base library - Errors</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Statement.html">Base library - Statement</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.RiscV.html">Base library - RISC-V instructions</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Operands.html">Base library - Operands</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.FunctionData.html">Base library - Function data</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.LinearCode.html">Linear intermediate representation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Allocator.html">Temporary allocation</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../index.html">MiniC</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../index.html">Module code</a></li>
<li class="breadcrumb-item active">Lib.FunctionData</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for Lib.FunctionData</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">This file defines the base class :py:class:`FunctionData`,</span>
<span class="sd">containing metadata on a RiscV function, as well as utility</span>
<span class="sd">functions common to the different intermediate representations.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="p">(</span><span class="n">List</span><span class="p">,</span> <span class="n">Callable</span><span class="p">,</span> <span class="n">TypeVar</span><span class="p">)</span>
<span class="kn">from</span> <span class="nn">Lib.Errors</span> <span class="kn">import</span> <span class="n">AllocationError</span>
<span class="kn">from</span> <span class="nn">Lib.Operands</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">Offset</span><span class="p">,</span> <span class="n">Temporary</span><span class="p">,</span> <span class="n">TemporaryPool</span><span class="p">,</span>
<span class="n">S</span><span class="p">,</span> <span class="n">T</span><span class="p">,</span> <span class="n">FP</span><span class="p">)</span>
<span class="kn">from</span> <span class="nn">Lib.Statement</span> <span class="kn">import</span> <span class="p">(</span><span class="n">Statement</span><span class="p">,</span> <span class="n">Instruction</span><span class="p">,</span> <span class="n">Label</span><span class="p">,</span> <span class="n">Comment</span><span class="p">)</span>
<div class="viewcode-block" id="FunctionData"><a class="viewcode-back" href="../../api/Lib.FunctionData.html#Lib.FunctionData.FunctionData">[docs]</a><span class="k">class</span> <span class="nc">FunctionData</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Stores some metadata on a RiscV function:</span>
<span class="sd"> name of the function, label names, temporary variables</span>
<span class="sd"> (using :py:class:`Lib.Operands.TemporaryPool`),</span>
<span class="sd"> and div_by_zero label.</span>
<span class="sd"> This class is usually used indirectly through the</span>
<span class="sd"> different intermediate representations we work with,</span>
<span class="sd"> such as :py:attr:`Lib.LinearCode.LinearCode.fdata`.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_nblabel</span><span class="p">:</span> <span class="nb">int</span>
<span class="n">_dec</span><span class="p">:</span> <span class="nb">int</span>
<span class="n">_pool</span><span class="p">:</span> <span class="n">TemporaryPool</span>
<span class="n">_name</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">_label_div_by_zero</span><span class="p">:</span> <span class="n">Label</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_nblabel</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_dec</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_pool</span> <span class="o">=</span> <span class="n">TemporaryPool</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_name</span> <span class="o">=</span> <span class="n">name</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_label_div_by_zero</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fresh_label</span><span class="p">(</span><span class="s2">&quot;div_by_zero&quot;</span><span class="p">)</span>
<div class="viewcode-block" id="FunctionData.get_name"><a class="viewcode-back" href="../../api/Lib.FunctionData.html#Lib.FunctionData.FunctionData.get_name">[docs]</a> <span class="k">def</span> <span class="nf">get_name</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return the name of the function.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_name</span></div>
<div class="viewcode-block" id="FunctionData.fresh_tmp"><a class="viewcode-back" href="../../api/Lib.FunctionData.html#Lib.FunctionData.FunctionData.fresh_tmp">[docs]</a> <span class="k">def</span> <span class="nf">fresh_tmp</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Temporary</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Return a new fresh Temporary,</span>
<span class="sd"> which is added to the pool.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_pool</span><span class="o">.</span><span class="n">fresh_tmp</span><span class="p">()</span></div>
<div class="viewcode-block" id="FunctionData.fresh_offset"><a class="viewcode-back" href="../../api/Lib.FunctionData.html#Lib.FunctionData.FunctionData.fresh_offset">[docs]</a> <span class="k">def</span> <span class="nf">fresh_offset</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Offset</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Return a new offset in the memory stack.</span>
<span class="sd"> Offsets are decreasing relative to FP.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_dec</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dec</span> <span class="o">+</span> <span class="mi">1</span>
<span class="c1"># For ld or sd, an offset on 12 signed bits is expected</span>
<span class="c1"># Raise an error if the offset is too big</span>
<span class="k">if</span> <span class="o">-</span><span class="mi">8</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dec</span> <span class="o">&lt;</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">**</span> <span class="mi">11</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">AllocationError</span><span class="p">(</span>
<span class="s2">&quot;Offset given by the allocation too big to be manipulated (</span><span class="si">{}</span><span class="s2">), sorry.&quot;</span>
<span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dec</span><span class="p">))</span>
<span class="k">return</span> <span class="n">Offset</span><span class="p">(</span><span class="n">FP</span><span class="p">,</span> <span class="o">-</span><span class="mi">8</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dec</span><span class="p">)</span></div>
<div class="viewcode-block" id="FunctionData.get_offset"><a class="viewcode-back" href="../../api/Lib.FunctionData.html#Lib.FunctionData.FunctionData.get_offset">[docs]</a> <span class="k">def</span> <span class="nf">get_offset</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Return the current offset in the memory stack.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dec</span></div>
<span class="k">def</span> <span class="nf">_fresh_label_name</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Return a new unique label name based on the given string.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_nblabel</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_nblabel</span> <span class="o">+</span> <span class="mi">1</span>
<span class="k">return</span> <span class="n">name</span> <span class="o">+</span> <span class="s2">&quot;_&quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_nblabel</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;_&quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">_name</span>
<div class="viewcode-block" id="FunctionData.fresh_label"><a class="viewcode-back" href="../../api/Lib.FunctionData.html#Lib.FunctionData.FunctionData.fresh_label">[docs]</a> <span class="k">def</span> <span class="nf">fresh_label</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Label</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Return a new label, with a unique name based on the given string.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">Label</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_fresh_label_name</span><span class="p">(</span><span class="n">name</span><span class="p">))</span></div>
<div class="viewcode-block" id="FunctionData.get_label_div_by_zero"><a class="viewcode-back" href="../../api/Lib.FunctionData.html#Lib.FunctionData.FunctionData.get_label_div_by_zero">[docs]</a> <span class="k">def</span> <span class="nf">get_label_div_by_zero</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Label</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_label_div_by_zero</span></div></div>
<span class="n">_T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;_T&quot;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="n">Statement</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_iter_statements</span><span class="p">(</span>
<span class="n">listIns</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">_T</span><span class="p">],</span> <span class="n">f</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">_T</span><span class="p">],</span> <span class="n">List</span><span class="p">[</span><span class="n">_T</span><span class="p">]])</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">_T</span> <span class="o">|</span> <span class="n">Comment</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Iterate over instructions.</span>
<span class="sd"> For each real instruction i (not label or comment), replace it</span>
<span class="sd"> with the list of instructions given by f(i).</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">newListIns</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">_T</span> <span class="o">|</span> <span class="n">Comment</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">old_i</span> <span class="ow">in</span> <span class="n">listIns</span><span class="p">:</span>
<span class="c1"># Do nothing for label or comment</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">old_i</span><span class="p">,</span> <span class="n">Instruction</span><span class="p">):</span>
<span class="n">newListIns</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">old_i</span><span class="p">)</span>
<span class="k">continue</span>
<span class="n">new_i_list</span> <span class="o">=</span> <span class="n">f</span><span class="p">(</span><span class="n">old_i</span><span class="p">)</span>
<span class="c1"># Otherwise, replace the instruction by the list</span>
<span class="c1"># returned by f, with comments giving the replacement</span>
<span class="n">newListIns</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">Comment</span><span class="p">(</span><span class="s2">&quot;Replaced &quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">old_i</span><span class="p">)))</span>
<span class="n">newListIns</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">new_i_list</span><span class="p">)</span>
<span class="k">return</span> <span class="n">newListIns</span>
<span class="k">def</span> <span class="nf">_print_code</span><span class="p">(</span><span class="n">listIns</span><span class="p">:</span> <span class="n">List</span><span class="p">,</span> <span class="n">fdata</span><span class="p">:</span> <span class="n">FunctionData</span><span class="p">,</span> <span class="n">output</span><span class="p">,</span>
<span class="n">init_label</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">fin_label</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">fin_div0</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">comment</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Please use print_code from LinearCode or CFG, not directly this one.</span>
<span class="sd"> Print the instructions from listIns, forming fdata, on output.</span>
<span class="sd"> If init_label is given, add an initial jump to it before the generated code.</span>
<span class="sd"> If fin_label is given, add it after the generated code.</span>
<span class="sd"> If fin_div0 is given equal to true, add the code for returning an</span>
<span class="sd"> error when dividing by 0, at the very end.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># compute size for the local stack - do not forget to align by 16</span>
<span class="n">fo</span> <span class="o">=</span> <span class="n">fdata</span><span class="o">.</span><span class="n">get_offset</span><span class="p">()</span> <span class="c1"># allocate enough memory for stack</span>
<span class="c1"># Room for S_i (except S_0 which is fp) and T_i backup</span>
<span class="n">fo</span> <span class="o">+=</span> <span class="nb">len</span><span class="p">(</span><span class="n">S</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">T</span><span class="p">)</span>
<span class="n">cardoffset</span> <span class="o">=</span> <span class="mi">8</span> <span class="o">*</span> <span class="p">(</span><span class="n">fo</span> <span class="o">+</span> <span class="p">(</span><span class="mi">0</span> <span class="k">if</span> <span class="n">fo</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">else</span> <span class="mi">1</span><span class="p">))</span> <span class="o">+</span> <span class="mi">16</span>
<span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span>
<span class="s2">&quot;##Automatically generated RISCV code, MIF08 &amp; CAP</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">comment</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;##</span><span class="si">{}</span><span class="s2"> version</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">comment</span><span class="p">))</span>
<span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2">##prelude</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># We put an li t0, cardoffset in case it is greater than 2**11</span>
<span class="c1"># We use t0 because it is caller-saved</span>
<span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;&quot;&quot;</span>
<span class="s2"> .text</span>
<span class="s2"> .globl </span><span class="si">{0}</span>
<span class="si">{0}</span><span class="s2">:</span>
<span class="s2"> li t0, </span><span class="si">{1}</span>
<span class="s2"> sub sp, sp, t0</span>
<span class="s2"> sd ra, 0(sp)</span>
<span class="s2"> sd fp, 8(sp)</span>
<span class="s2"> add fp, sp, t0</span>
<span class="s2">&quot;&quot;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">fdata</span><span class="o">.</span><span class="n">get_name</span><span class="p">(),</span> <span class="n">cardoffset</span><span class="p">))</span>
<span class="c1"># Stack in RiscV is managed with SP</span>
<span class="k">if</span> <span class="n">init_label</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># Add a jump to init_label before the generated code.</span>
<span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;&quot;&quot;</span>
<span class="s2"> j </span><span class="si">{0}</span>
<span class="s2">&quot;&quot;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">init_label</span><span class="p">))</span>
<span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2">##Generated Code</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Generated code</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">listIns</span><span class="p">:</span>
<span class="n">i</span><span class="o">.</span><span class="n">printIns</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
<span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2">##postlude</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">fin_label</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># Add fin_label after the generated code.</span>
<span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;&quot;&quot;</span>
<span class="si">{0}</span><span class="s2">:</span>
<span class="s2">&quot;&quot;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">fin_label</span><span class="p">))</span>
<span class="c1"># We put an li t0, cardoffset in case it is greater than 2**11</span>
<span class="c1"># We use t0 because it is caller-saved</span>
<span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;&quot;&quot;</span>
<span class="s2"> ld ra, 0(sp)</span>
<span class="s2"> ld fp, 8(sp)</span>
<span class="s2"> li t0, </span><span class="si">{0}</span>
<span class="s2"> add sp, sp, t0</span>
<span class="s2"> ret</span>
<span class="s2">&quot;&quot;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">cardoffset</span><span class="p">))</span>
<span class="k">if</span> <span class="n">fin_div0</span><span class="p">:</span>
<span class="c1"># Add code for division by 0 at the end.</span>
<span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;&quot;&quot;</span>
<span class="si">{0}</span><span class="s2">:</span>
<span class="s2"> la a0, </span><span class="si">{0}</span><span class="s2">_msg</span>
<span class="s2"> call println_string</span>
<span class="s2"> li a0, 1</span>
<span class="s2"> call exit</span>
<span class="s2">&quot;&quot;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">fdata</span><span class="o">.</span><span class="n">_label_div_by_zero</span><span class="p">))</span>
<span class="c1"># Add the data for the message of the division by 0</span>
<span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;&quot;&quot;</span>
<span class="si">{0}</span><span class="s2">_msg: .string &quot;Division by 0&quot;</span>
<span class="s2">&quot;&quot;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">fdata</span><span class="o">.</span><span class="n">_label_div_by_zero</span><span class="p">))</span>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2023, compil-lyon.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

View File

@ -0,0 +1,209 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lib.LinearCode &mdash; MiniC documentation</title>
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="../../_static/js/html5shiv.min.js"></script>
<![endif]-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
<script src="../../_static/doctools.js"></script>
<script src="../../_static/sphinx_highlight.js"></script>
<script src="../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../genindex.html" />
<link rel="search" title="Search" href="../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../index.html" class="icon icon-home">
MiniC
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Errors.html">Base library - Errors</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Statement.html">Base library - Statement</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.RiscV.html">Base library - RISC-V instructions</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Operands.html">Base library - Operands</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.FunctionData.html">Base library - Function data</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.LinearCode.html">Linear intermediate representation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Allocator.html">Temporary allocation</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../index.html">MiniC</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../index.html">Module code</a></li>
<li class="breadcrumb-item active">Lib.LinearCode</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for Lib.LinearCode</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">CAP, CodeGeneration, LinearCode API</span>
<span class="sd">Classes for a RiscV linear code.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span>
<span class="kn">from</span> <span class="nn">Lib.Operands</span> <span class="kn">import</span> <span class="p">(</span><span class="n">A0</span><span class="p">,</span> <span class="n">Function</span><span class="p">,</span> <span class="n">DataLocation</span><span class="p">)</span>
<span class="kn">from</span> <span class="nn">Lib.Statement</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">Instru3A</span><span class="p">,</span> <span class="n">AbsoluteJump</span><span class="p">,</span> <span class="n">ConditionalJump</span><span class="p">,</span> <span class="n">Comment</span><span class="p">,</span> <span class="n">Label</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">Lib.RiscV</span> <span class="kn">import</span> <span class="p">(</span><span class="n">mv</span><span class="p">,</span> <span class="n">call</span><span class="p">)</span>
<span class="kn">from</span> <span class="nn">Lib.FunctionData</span> <span class="kn">import</span> <span class="p">(</span><span class="n">FunctionData</span><span class="p">,</span> <span class="n">_iter_statements</span><span class="p">,</span> <span class="n">_print_code</span><span class="p">)</span>
<span class="n">CodeStatement</span> <span class="o">=</span> <span class="n">Comment</span> <span class="o">|</span> <span class="n">Label</span> <span class="o">|</span> <span class="n">Instru3A</span> <span class="o">|</span> <span class="n">AbsoluteJump</span> <span class="o">|</span> <span class="n">ConditionalJump</span>
<div class="viewcode-block" id="LinearCode"><a class="viewcode-back" href="../../api/Lib.LinearCode.html#Lib.LinearCode.LinearCode">[docs]</a><span class="k">class</span> <span class="nc">LinearCode</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Representation of a RiscV program as a list of instructions.</span>
<span class="sd"> :py:meth:`add_instruction` is repeatedly called in the codegen visitor</span>
<span class="sd"> to build a complete list of RiscV instructions for the source program.</span>
<span class="sd"> The :py:attr:`fdata` member variable contains some meta-information</span>
<span class="sd"> on the program, for instance to allocate a new temporary.</span>
<span class="sd"> See :py:class:`Lib.FunctionData.FunctionData`.</span>
<span class="sd"> For debugging purposes, :py:meth:`print_code` allows to print</span>
<span class="sd"> the RiscV program to a file.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The :py:attr:`fdata` member variable contains some meta-information</span>
<span class="sd"> on the program, for instance to allocate a new temporary.</span>
<span class="sd"> See :py:class:`Lib.FunctionData.FunctionData`.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">fdata</span><span class="p">:</span> <span class="n">FunctionData</span>
<span class="n">_listIns</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">CodeStatement</span><span class="p">]</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_listIns</span> <span class="o">=</span> <span class="p">[]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">fdata</span> <span class="o">=</span> <span class="n">FunctionData</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
<div class="viewcode-block" id="LinearCode.add_instruction"><a class="viewcode-back" href="../../api/Lib.LinearCode.html#Lib.LinearCode.LinearCode.add_instruction">[docs]</a> <span class="k">def</span> <span class="nf">add_instruction</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">i</span><span class="p">:</span> <span class="n">CodeStatement</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Utility function to add an instruction in the program.</span>
<span class="sd"> See also :py:mod:`Lib.RiscV` to generate relevant instructions.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_listIns</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span></div>
<div class="viewcode-block" id="LinearCode.iter_statements"><a class="viewcode-back" href="../../api/Lib.LinearCode.html#Lib.LinearCode.LinearCode.iter_statements">[docs]</a> <span class="k">def</span> <span class="nf">iter_statements</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Iterate over instructions.</span>
<span class="sd"> For each real instruction i (not label or comment), replace it</span>
<span class="sd"> with the list of instructions given by f(i).</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">new_list_ins</span> <span class="o">=</span> <span class="n">_iter_statements</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_listIns</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span>
<span class="c1"># TODO: we shoudn&#39;t need to split this assignment with intermediate</span>
<span class="c1"># variable new_list_ins, but at least pyright pyright 1.1.293</span>
<span class="c1"># raises an error here if we don&#39;t.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_listIns</span> <span class="o">=</span> <span class="n">new_list_ins</span></div>
<div class="viewcode-block" id="LinearCode.get_instructions"><a class="viewcode-back" href="../../api/Lib.LinearCode.html#Lib.LinearCode.LinearCode.get_instructions">[docs]</a> <span class="k">def</span> <span class="nf">get_instructions</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">CodeStatement</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return the list of instructions of the program.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_listIns</span></div>
<span class="c1"># each instruction has its own &quot;add in list&quot; version</span>
<div class="viewcode-block" id="LinearCode.add_label"><a class="viewcode-back" href="../../api/Lib.LinearCode.html#Lib.LinearCode.LinearCode.add_label">[docs]</a> <span class="k">def</span> <span class="nf">add_label</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">s</span><span class="p">:</span> <span class="n">Label</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Add a label in the program.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">add_instruction</span><span class="p">(</span><span class="n">s</span><span class="p">)</span></div>
<div class="viewcode-block" id="LinearCode.add_comment"><a class="viewcode-back" href="../../api/Lib.LinearCode.html#Lib.LinearCode.LinearCode.add_comment">[docs]</a> <span class="k">def</span> <span class="nf">add_comment</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">s</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Add a comment in the program.&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_instruction</span><span class="p">(</span><span class="n">Comment</span><span class="p">(</span><span class="n">s</span><span class="p">))</span></div>
<div class="viewcode-block" id="LinearCode.add_instruction_PRINTLN_INT"><a class="viewcode-back" href="../../api/Lib.LinearCode.html#Lib.LinearCode.LinearCode.add_instruction_PRINTLN_INT">[docs]</a> <span class="k">def</span> <span class="nf">add_instruction_PRINTLN_INT</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">reg</span><span class="p">:</span> <span class="n">DataLocation</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Print integer value, with newline. (see Expand)&quot;&quot;&quot;</span>
<span class="c1"># A print instruction generates the temp it prints.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_instruction</span><span class="p">(</span><span class="n">mv</span><span class="p">(</span><span class="n">A0</span><span class="p">,</span> <span class="n">reg</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_instruction</span><span class="p">(</span><span class="n">call</span><span class="p">(</span><span class="n">Function</span><span class="p">(</span><span class="s1">&#39;println_int&#39;</span><span class="p">)))</span></div>
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_listIns</span><span class="p">))</span>
<div class="viewcode-block" id="LinearCode.print_code"><a class="viewcode-back" href="../../api/Lib.LinearCode.html#Lib.LinearCode.LinearCode.print_code">[docs]</a> <span class="k">def</span> <span class="nf">print_code</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">output</span><span class="p">,</span> <span class="n">comment</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Outputs the RiscV program as text to a file at the given path.&quot;&quot;&quot;</span>
<span class="n">_print_code</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_listIns</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">fdata</span><span class="p">,</span> <span class="n">output</span><span class="p">,</span> <span class="n">init_label</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="n">fin_label</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">fin_div0</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">comment</span><span class="o">=</span><span class="n">comment</span><span class="p">)</span></div>
<div class="viewcode-block" id="LinearCode.print_dot"><a class="viewcode-back" href="../../api/Lib.LinearCode.html#Lib.LinearCode.LinearCode.print_dot">[docs]</a> <span class="k">def</span> <span class="nf">print_dot</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">DF</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">view</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="c1"># pragma: no cover</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Outputs the RiscV program as graph to a file at the given path.&quot;&quot;&quot;</span>
<span class="c1"># import graphviz here so that students who don&#39;t have it can still work on lab4</span>
<span class="kn">from</span> <span class="nn">graphviz</span> <span class="kn">import</span> <span class="n">Digraph</span>
<span class="n">graph</span> <span class="o">=</span> <span class="n">Digraph</span><span class="p">()</span>
<span class="c1"># nodes</span>
<span class="n">content</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_listIns</span><span class="p">:</span>
<span class="n">content</span> <span class="o">+=</span> <span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;</span><span class="se">\\</span><span class="s2">l&quot;</span>
<span class="n">graph</span><span class="o">.</span><span class="n">node</span><span class="p">(</span><span class="s2">&quot;Code&quot;</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="n">content</span><span class="p">,</span> <span class="n">shape</span><span class="o">=</span><span class="s1">&#39;rectangle&#39;</span><span class="p">)</span>
<span class="c1"># no edges</span>
<span class="n">graph</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">view</span><span class="o">=</span><span class="n">view</span><span class="p">)</span></div></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2023, compil-lyon.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

View File

@ -0,0 +1,385 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lib.Operands &mdash; MiniC documentation</title>
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="../../_static/js/html5shiv.min.js"></script>
<![endif]-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
<script src="../../_static/doctools.js"></script>
<script src="../../_static/sphinx_highlight.js"></script>
<script src="../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../genindex.html" />
<link rel="search" title="Search" href="../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../index.html" class="icon icon-home">
MiniC
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Errors.html">Base library - Errors</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Statement.html">Base library - Statement</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.RiscV.html">Base library - RISC-V instructions</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Operands.html">Base library - Operands</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.FunctionData.html">Base library - Function data</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.LinearCode.html">Linear intermediate representation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Allocator.html">Temporary allocation</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../index.html">MiniC</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../index.html">Module code</a></li>
<li class="breadcrumb-item active">Lib.Operands</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for Lib.Operands</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">This file defines the base class :py:class:`Operand`</span>
<span class="sd">and its subclasses for different operands: :py:class:`Condition`,</span>
<span class="sd">:py:class:`DataLocation` and :py:class:`Function`.</span>
<span class="sd">The class :py:class:`DataLocation` itself has subclasses:</span>
<span class="sd">:py:class:`Register`, :py:class:`Offset` for address in memory,</span>
<span class="sd">:py:class:`Immediate` for constants and :py:class:`Temporary`</span>
<span class="sd">for location not yet allocated.</span>
<span class="sd">This file also define shortcuts for registers in RISCV.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">List</span>
<span class="kn">from</span> <span class="nn">MiniCParser</span> <span class="kn">import</span> <span class="n">MiniCParser</span>
<span class="kn">from</span> <span class="nn">Lib.Errors</span> <span class="kn">import</span> <span class="n">MiniCInternalError</span>
<div class="viewcode-block" id="Operand"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Operand">[docs]</a><span class="k">class</span> <span class="nc">Operand</span><span class="p">():</span>
<span class="k">pass</span></div>
<span class="c1"># signed version for riscv</span>
<span class="n">all_ops</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;blt&#39;</span><span class="p">,</span> <span class="s1">&#39;bgt&#39;</span><span class="p">,</span> <span class="s1">&#39;beq&#39;</span><span class="p">,</span> <span class="s1">&#39;bne&#39;</span><span class="p">,</span> <span class="s1">&#39;ble&#39;</span><span class="p">,</span> <span class="s1">&#39;bge&#39;</span><span class="p">,</span> <span class="s1">&#39;beqz&#39;</span><span class="p">,</span> <span class="s1">&#39;bnez&#39;</span><span class="p">]</span>
<span class="n">opdict</span> <span class="o">=</span> <span class="p">{</span><span class="n">MiniCParser</span><span class="o">.</span><span class="n">LT</span><span class="p">:</span> <span class="s1">&#39;blt&#39;</span><span class="p">,</span> <span class="n">MiniCParser</span><span class="o">.</span><span class="n">GT</span><span class="p">:</span> <span class="s1">&#39;bgt&#39;</span><span class="p">,</span>
<span class="n">MiniCParser</span><span class="o">.</span><span class="n">LTEQ</span><span class="p">:</span> <span class="s1">&#39;ble&#39;</span><span class="p">,</span> <span class="n">MiniCParser</span><span class="o">.</span><span class="n">GTEQ</span><span class="p">:</span> <span class="s1">&#39;bge&#39;</span><span class="p">,</span>
<span class="n">MiniCParser</span><span class="o">.</span><span class="n">NEQ</span><span class="p">:</span> <span class="s1">&#39;bne&#39;</span><span class="p">,</span> <span class="n">MiniCParser</span><span class="o">.</span><span class="n">EQ</span><span class="p">:</span> <span class="s1">&#39;beq&#39;</span><span class="p">}</span>
<span class="n">opnot_dict</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;bgt&#39;</span><span class="p">:</span> <span class="s1">&#39;ble&#39;</span><span class="p">,</span>
<span class="s1">&#39;bge&#39;</span><span class="p">:</span> <span class="s1">&#39;blt&#39;</span><span class="p">,</span>
<span class="s1">&#39;blt&#39;</span><span class="p">:</span> <span class="s1">&#39;bge&#39;</span><span class="p">,</span>
<span class="s1">&#39;ble&#39;</span><span class="p">:</span> <span class="s1">&#39;bgt&#39;</span><span class="p">,</span>
<span class="s1">&#39;beq&#39;</span><span class="p">:</span> <span class="s1">&#39;bne&#39;</span><span class="p">,</span>
<span class="s1">&#39;bne&#39;</span><span class="p">:</span> <span class="s1">&#39;beq&#39;</span><span class="p">,</span>
<span class="s1">&#39;beqz&#39;</span><span class="p">:</span> <span class="s1">&#39;bnez&#39;</span><span class="p">,</span>
<span class="s1">&#39;bnez&#39;</span><span class="p">:</span> <span class="s1">&#39;beqz&#39;</span><span class="p">}</span>
<div class="viewcode-block" id="Condition"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Condition">[docs]</a><span class="k">class</span> <span class="nc">Condition</span><span class="p">(</span><span class="n">Operand</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Condition, i.e. comparison operand for a CondJump.</span>
<span class="sd"> Example usage :</span>
<span class="sd"> - Condition(&#39;beq&#39;) = branch if equal.</span>
<span class="sd"> - Condition(MiniCParser.LT) = branch if lower than.</span>
<span class="sd"> - ...</span>
<span class="sd"> The constructor&#39;s argument shall be a string in the list all_ops, or a</span>
<span class="sd"> comparison operator in MiniCParser.LT, MiniCParser.GT, ... (one of the keys</span>
<span class="sd"> in opdict).</span>
<span class="sd"> A &#39;negate&#39; method allows getting the negation of this condition.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_op</span><span class="p">:</span> <span class="nb">str</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">optype</span><span class="p">):</span>
<span class="k">if</span> <span class="n">optype</span> <span class="ow">in</span> <span class="n">opdict</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_op</span> <span class="o">=</span> <span class="n">opdict</span><span class="p">[</span><span class="n">optype</span><span class="p">]</span>
<span class="k">elif</span> <span class="nb">str</span><span class="p">(</span><span class="n">optype</span><span class="p">)</span> <span class="ow">in</span> <span class="n">all_ops</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_op</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">optype</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">MiniCInternalError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unsupported comparison operator </span><span class="si">{</span><span class="n">optype</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<div class="viewcode-block" id="Condition.negate"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Condition.negate">[docs]</a> <span class="k">def</span> <span class="nf">negate</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s1">&#39;Condition&#39;</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return the opposite condition.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">Condition</span><span class="p">(</span><span class="n">opnot_dict</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_op</span><span class="p">])</span></div>
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_op</span></div>
<div class="viewcode-block" id="Function"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Function">[docs]</a><span class="k">class</span> <span class="nc">Function</span><span class="p">(</span><span class="n">Operand</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Operand for build-in function call.&quot;&quot;&quot;</span>
<span class="n">_name</span><span class="p">:</span> <span class="nb">str</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_name</span> <span class="o">=</span> <span class="n">name</span>
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_name</span></div>
<div class="viewcode-block" id="DataLocation"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.DataLocation">[docs]</a><span class="k">class</span> <span class="nc">DataLocation</span><span class="p">(</span><span class="n">Operand</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot; A Data Location is either a register, a temporary</span>
<span class="sd"> or a place in memory (offset).</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">pass</span></div>
<span class="c1"># map for register shortcuts</span>
<span class="n">reg_map</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">([(</span><span class="mi">0</span><span class="p">,</span> <span class="s1">&#39;zero&#39;</span><span class="p">),</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;ra&#39;</span><span class="p">),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s1">&#39;sp&#39;</span><span class="p">)]</span> <span class="o">+</span> <span class="c1"># no (3, &#39;gp&#39;) nor (4, &#39;tp&#39;)</span>
<span class="p">[(</span><span class="n">i</span><span class="o">+</span><span class="mi">5</span><span class="p">,</span> <span class="s1">&#39;t&#39;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="p">))</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">)]</span> <span class="o">+</span>
<span class="p">[(</span><span class="mi">8</span><span class="p">,</span> <span class="s1">&#39;fp&#39;</span><span class="p">),</span> <span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="s1">&#39;s1&#39;</span><span class="p">)]</span> <span class="o">+</span>
<span class="p">[(</span><span class="n">i</span><span class="o">+</span><span class="mi">10</span><span class="p">,</span> <span class="s1">&#39;a&#39;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="p">))</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">)]</span> <span class="o">+</span>
<span class="p">[(</span><span class="n">i</span><span class="o">+</span><span class="mi">18</span><span class="p">,</span> <span class="s1">&#39;s&#39;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">2</span><span class="p">))</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">)]</span> <span class="o">+</span>
<span class="p">[(</span><span class="n">i</span><span class="o">+</span><span class="mi">28</span><span class="p">,</span> <span class="s1">&#39;t&#39;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">3</span><span class="p">))</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">4</span><span class="p">)])</span>
<div class="viewcode-block" id="Register"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Register">[docs]</a><span class="k">class</span> <span class="nc">Register</span><span class="p">(</span><span class="n">DataLocation</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot; A (physical) register.&quot;&quot;&quot;</span>
<span class="n">_number</span><span class="p">:</span> <span class="nb">int</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">number</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_number</span> <span class="o">=</span> <span class="n">number</span>
<span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_number</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">reg_map</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">MiniCInternalError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Register number </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_number</span><span class="si">}</span><span class="s2"> should not be used&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="p">(</span><span class="s2">&quot;</span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">reg_map</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_number</span><span class="p">]))</span>
<span class="k">def</span> <span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">Register</span><span class="p">)</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_number</span> <span class="o">==</span> <span class="n">other</span><span class="o">.</span><span class="n">_number</span>
<span class="k">def</span> <span class="fm">__hash__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_number</span></div>
<span class="c1"># Shortcuts for registers in RISCV</span>
<span class="c1"># Only integer registers</span>
<span class="c1">#: Zero register</span>
<span class="n">ZERO</span> <span class="o">=</span> <span class="n">Register</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="c1">#:</span>
<span class="n">RA</span> <span class="o">=</span> <span class="n">Register</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="c1">#:</span>
<span class="n">SP</span> <span class="o">=</span> <span class="n">Register</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="c1">#: Register not used for this course</span>
<span class="n">GP</span> <span class="o">=</span> <span class="n">Register</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="c1">#: Register not used for this course</span>
<span class="n">TP</span> <span class="o">=</span> <span class="n">Register</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="c1">#:</span>
<span class="n">A</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">Register</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">10</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">))</span>
<span class="c1">#:</span>
<span class="n">S</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">Register</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">8</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="p">))</span> <span class="o">+</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">Register</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">18</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
<span class="c1">#:</span>
<span class="n">T</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">Register</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">5</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">))</span> <span class="o">+</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">Register</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">28</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">4</span><span class="p">))</span>
<span class="c1">#:</span>
<span class="n">A0</span> <span class="o">=</span> <span class="n">A</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># function args/return Values: A0, A1</span>
<span class="c1">#:</span>
<span class="n">A1</span> <span class="o">=</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="c1">#: Frame Pointer = Saved register 0</span>
<span class="n">FP</span> <span class="o">=</span> <span class="n">S</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="c1">#: General purpose registers, usable for the allocator</span>
<span class="n">GP_REGS</span> <span class="o">=</span> <span class="n">S</span><span class="p">[</span><span class="mi">4</span><span class="p">:]</span> <span class="o">+</span> <span class="n">T</span> <span class="c1"># s0, s1, s2 and s3 are special</span>
<div class="viewcode-block" id="Offset"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Offset">[docs]</a><span class="k">class</span> <span class="nc">Offset</span><span class="p">(</span><span class="n">DataLocation</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot; Offset = address in memory computed with base + offset.&quot;&quot;&quot;</span>
<span class="n">_basereg</span><span class="p">:</span> <span class="n">Register</span>
<span class="n">_offset</span><span class="p">:</span> <span class="nb">int</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">basereg</span><span class="p">:</span> <span class="n">Register</span><span class="p">,</span> <span class="n">offset</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_basereg</span> <span class="o">=</span> <span class="n">basereg</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_offset</span> <span class="o">=</span> <span class="n">offset</span>
<span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="p">(</span><span class="s2">&quot;</span><span class="si">{}</span><span class="s2">(</span><span class="si">{}</span><span class="s2">)&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_offset</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_basereg</span><span class="p">))</span>
<div class="viewcode-block" id="Offset.get_offset"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Offset.get_offset">[docs]</a> <span class="k">def</span> <span class="nf">get_offset</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return the value of the offset.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_offset</span></div></div>
<div class="viewcode-block" id="Immediate"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Immediate">[docs]</a><span class="k">class</span> <span class="nc">Immediate</span><span class="p">(</span><span class="n">DataLocation</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Immediate operand (integer).&quot;&quot;&quot;</span>
<span class="n">_val</span><span class="p">:</span> <span class="nb">int</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">val</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_val</span> <span class="o">=</span> <span class="n">val</span>
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_val</span><span class="p">)</span></div>
<div class="viewcode-block" id="Temporary"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Temporary">[docs]</a><span class="k">class</span> <span class="nc">Temporary</span><span class="p">(</span><span class="n">DataLocation</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Temporary, a location that has not been allocated yet.</span>
<span class="sd"> It will later be mapped to a physical register (Register) or to a memory location (Offset).</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_number</span><span class="p">:</span> <span class="nb">int</span>
<span class="n">_pool</span><span class="p">:</span> <span class="s1">&#39;TemporaryPool&#39;</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">number</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">pool</span><span class="p">:</span> <span class="s1">&#39;TemporaryPool&#39;</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_number</span> <span class="o">=</span> <span class="n">number</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_pool</span> <span class="o">=</span> <span class="n">pool</span>
<span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="p">(</span><span class="s2">&quot;temp_</span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_number</span><span class="p">)))</span>
<div class="viewcode-block" id="Temporary.get_alloced_loc"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Temporary.get_alloced_loc">[docs]</a> <span class="k">def</span> <span class="nf">get_alloced_loc</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataLocation</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return the DataLocation allocated to this Temporary.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_pool</span><span class="o">.</span><span class="n">get_alloced_loc</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span></div></div>
<div class="viewcode-block" id="TemporaryPool"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.TemporaryPool">[docs]</a><span class="k">class</span> <span class="nc">TemporaryPool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Manage a pool of temporaries.&quot;&quot;&quot;</span>
<span class="n">_all_temps</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Temporary</span><span class="p">]</span>
<span class="n">_current_num</span><span class="p">:</span> <span class="nb">int</span>
<span class="n">_allocation</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="n">Temporary</span><span class="p">,</span> <span class="n">DataLocation</span><span class="p">]</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_all_temps</span> <span class="o">=</span> <span class="p">[]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_current_num</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_allocation</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
<div class="viewcode-block" id="TemporaryPool.get_all_temps"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.TemporaryPool.get_all_temps">[docs]</a> <span class="k">def</span> <span class="nf">get_all_temps</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Temporary</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return all the temporaries of the pool.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_all_temps</span></div>
<div class="viewcode-block" id="TemporaryPool.get_alloced_loc"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.TemporaryPool.get_alloced_loc">[docs]</a> <span class="k">def</span> <span class="nf">get_alloced_loc</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">t</span><span class="p">:</span> <span class="n">Temporary</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">DataLocation</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get the actual DataLocation allocated for the temporary t.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_allocation</span><span class="p">[</span><span class="n">t</span><span class="p">]</span></div>
<div class="viewcode-block" id="TemporaryPool.add_tmp"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.TemporaryPool.add_tmp">[docs]</a> <span class="k">def</span> <span class="nf">add_tmp</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">t</span><span class="p">:</span> <span class="n">Temporary</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Add a temporary to the pool.&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_all_temps</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_allocation</span><span class="p">[</span><span class="n">t</span><span class="p">]</span> <span class="o">=</span> <span class="n">t</span> <span class="c1"># While no allocation, return the temporary itself</span></div>
<div class="viewcode-block" id="TemporaryPool.set_temp_allocation"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.TemporaryPool.set_temp_allocation">[docs]</a> <span class="k">def</span> <span class="nf">set_temp_allocation</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">allocation</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="n">Temporary</span><span class="p">,</span> <span class="n">DataLocation</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Give a mapping from temporaries to actual registers.</span>
<span class="sd"> The argument allocation must be a dict from Temporary to</span>
<span class="sd"> DataLocation other than Temporary (typically Register or Offset).</span>
<span class="sd"> Typing enforces that keys are Temporary and values are Datalocation.</span>
<span class="sd"> We check the values are indeed not Temporary.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">allocation</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
<span class="k">assert</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">Temporary</span><span class="p">),</span> <span class="p">(</span>
<span class="s2">&quot;Incorrect allocation scheme: value &quot;</span> <span class="o">+</span>
<span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot; is a Temporary.&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_allocation</span> <span class="o">=</span> <span class="n">allocation</span></div>
<div class="viewcode-block" id="TemporaryPool.fresh_tmp"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.TemporaryPool.fresh_tmp">[docs]</a> <span class="k">def</span> <span class="nf">fresh_tmp</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Temporary</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Give a new fresh Temporary and add it to the pool.&quot;&quot;&quot;</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">Temporary</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_current_num</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_current_num</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_tmp</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
<span class="k">return</span> <span class="n">t</span></div></div>
<div class="viewcode-block" id="Renamer"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Renamer">[docs]</a><span class="k">class</span> <span class="nc">Renamer</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Manage a renaming of temporaries.&quot;&quot;&quot;</span>
<span class="n">_pool</span><span class="p">:</span> <span class="n">TemporaryPool</span>
<span class="n">_env</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="n">Temporary</span><span class="p">,</span> <span class="n">Temporary</span><span class="p">]</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pool</span><span class="p">:</span> <span class="n">TemporaryPool</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_pool</span> <span class="o">=</span> <span class="n">pool</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_env</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
<div class="viewcode-block" id="Renamer.fresh"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Renamer.fresh">[docs]</a> <span class="k">def</span> <span class="nf">fresh</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">t</span><span class="p">:</span> <span class="n">Temporary</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Temporary</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Give a fresh rename for a Temporary.&quot;&quot;&quot;</span>
<span class="n">new_t</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_pool</span><span class="o">.</span><span class="n">fresh_tmp</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_env</span><span class="p">[</span><span class="n">t</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_t</span>
<span class="k">return</span> <span class="n">new_t</span></div>
<div class="viewcode-block" id="Renamer.replace"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Renamer.replace">[docs]</a> <span class="k">def</span> <span class="nf">replace</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">t</span><span class="p">:</span> <span class="n">Temporary</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Temporary</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Give the rename for a Temporary (which is itself if it is not renamed).&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_env</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">t</span><span class="p">)</span></div>
<div class="viewcode-block" id="Renamer.defined"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Renamer.defined">[docs]</a> <span class="k">def</span> <span class="nf">defined</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">t</span><span class="p">:</span> <span class="n">Temporary</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;True if the Temporary is renamed.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">t</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_env</span></div>
<div class="viewcode-block" id="Renamer.copy"><a class="viewcode-back" href="../../api/Lib.Operands.html#Lib.Operands.Renamer.copy">[docs]</a> <span class="k">def</span> <span class="nf">copy</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Give a copy of the Renamer.&quot;&quot;&quot;</span>
<span class="n">r</span> <span class="o">=</span> <span class="n">Renamer</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_pool</span><span class="p">)</span>
<span class="n">r</span><span class="o">.</span><span class="n">_env</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_env</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
<span class="k">return</span> <span class="n">r</span></div></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2023, compil-lyon.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

View File

@ -0,0 +1,198 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lib.RiscV &mdash; MiniC documentation</title>
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="../../_static/js/html5shiv.min.js"></script>
<![endif]-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
<script src="../../_static/doctools.js"></script>
<script src="../../_static/sphinx_highlight.js"></script>
<script src="../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../genindex.html" />
<link rel="search" title="Search" href="../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../index.html" class="icon icon-home">
MiniC
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Errors.html">Base library - Errors</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Statement.html">Base library - Statement</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.RiscV.html">Base library - RISC-V instructions</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Operands.html">Base library - Operands</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.FunctionData.html">Base library - Function data</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.LinearCode.html">Linear intermediate representation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Allocator.html">Temporary allocation</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../index.html">MiniC</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../index.html">Module code</a></li>
<li class="breadcrumb-item active">Lib.RiscV</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for Lib.RiscV</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">MIF08, CAP, CodeGeneration, RiscV API</span>
<span class="sd">Functions to define instructions.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">Lib.Errors</span> <span class="kn">import</span> <span class="n">MiniCInternalError</span>
<span class="kn">from</span> <span class="nn">Lib.Operands</span> <span class="kn">import</span> <span class="p">(</span><span class="n">Condition</span><span class="p">,</span> <span class="n">Immediate</span><span class="p">,</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">Function</span><span class="p">)</span>
<span class="kn">from</span> <span class="nn">Lib.Statement</span> <span class="kn">import</span> <span class="p">(</span><span class="n">Instru3A</span><span class="p">,</span> <span class="n">AbsoluteJump</span><span class="p">,</span> <span class="n">ConditionalJump</span><span class="p">,</span> <span class="n">Label</span><span class="p">)</span>
<div class="viewcode-block" id="call"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.call">[docs]</a><span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="n">function</span><span class="p">:</span> <span class="n">Function</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Instru3A</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Function call.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s1">&#39;call&#39;</span><span class="p">,</span> <span class="n">function</span><span class="p">)</span></div>
<div class="viewcode-block" id="jump"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.jump">[docs]</a><span class="k">def</span> <span class="nf">jump</span><span class="p">(</span><span class="n">label</span><span class="p">:</span> <span class="n">Label</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">AbsoluteJump</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Unconditional jump to label.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">AbsoluteJump</span><span class="p">(</span><span class="n">label</span><span class="p">)</span></div>
<div class="viewcode-block" id="conditional_jump"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.conditional_jump">[docs]</a><span class="k">def</span> <span class="nf">conditional_jump</span><span class="p">(</span><span class="n">label</span><span class="p">:</span> <span class="n">Label</span><span class="p">,</span> <span class="n">op1</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">cond</span><span class="p">:</span> <span class="n">Condition</span><span class="p">,</span> <span class="n">op2</span><span class="p">:</span> <span class="n">Operand</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Add a conditional jump to the code.</span>
<span class="sd"> This is a wrapper around bge, bgt, beq, ... c is a Condition, like</span>
<span class="sd"> Condition(&#39;bgt&#39;), Condition(MiniCParser.EQ), ...</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">ConditionalJump</span><span class="p">(</span><span class="n">cond</span><span class="o">=</span><span class="n">cond</span><span class="p">,</span> <span class="n">op1</span><span class="o">=</span><span class="n">op1</span><span class="p">,</span> <span class="n">op2</span><span class="o">=</span><span class="n">op2</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="n">label</span><span class="p">)</span></div>
<div class="viewcode-block" id="add"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.add">[docs]</a><span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">dr</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr1</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">:</span> <span class="n">Operand</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Instru3A</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">sr2orimm7</span><span class="p">,</span> <span class="n">Immediate</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s2">&quot;addi&quot;</span><span class="p">,</span> <span class="n">dr</span><span class="p">,</span> <span class="n">sr1</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s2">&quot;add&quot;</span><span class="p">,</span> <span class="n">dr</span><span class="p">,</span> <span class="n">sr1</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">)</span></div>
<div class="viewcode-block" id="mul"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.mul">[docs]</a><span class="k">def</span> <span class="nf">mul</span><span class="p">(</span><span class="n">dr</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr1</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">:</span> <span class="n">Operand</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Instru3A</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">sr2orimm7</span><span class="p">,</span> <span class="n">Immediate</span><span class="p">):</span>
<span class="k">raise</span> <span class="n">MiniCInternalError</span><span class="p">(</span><span class="s2">&quot;Cant multiply by an immediate&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s2">&quot;mul&quot;</span><span class="p">,</span> <span class="n">dr</span><span class="p">,</span> <span class="n">sr1</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">)</span></div>
<div class="viewcode-block" id="div"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.div">[docs]</a><span class="k">def</span> <span class="nf">div</span><span class="p">(</span><span class="n">dr</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr1</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">:</span> <span class="n">Operand</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Instru3A</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">sr2orimm7</span><span class="p">,</span> <span class="n">Immediate</span><span class="p">):</span>
<span class="k">raise</span> <span class="n">MiniCInternalError</span><span class="p">(</span><span class="s2">&quot;Cant divide by an immediate&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s2">&quot;div&quot;</span><span class="p">,</span> <span class="n">dr</span><span class="p">,</span> <span class="n">sr1</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">)</span></div>
<div class="viewcode-block" id="rem"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.rem">[docs]</a><span class="k">def</span> <span class="nf">rem</span><span class="p">(</span><span class="n">dr</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr1</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">:</span> <span class="n">Operand</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Instru3A</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">sr2orimm7</span><span class="p">,</span> <span class="n">Immediate</span><span class="p">):</span>
<span class="k">raise</span> <span class="n">MiniCInternalError</span><span class="p">(</span><span class="s2">&quot;Cant divide by an immediate&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s2">&quot;rem&quot;</span><span class="p">,</span> <span class="n">dr</span><span class="p">,</span> <span class="n">sr1</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">)</span></div>
<div class="viewcode-block" id="sub"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.sub">[docs]</a><span class="k">def</span> <span class="nf">sub</span><span class="p">(</span><span class="n">dr</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr1</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">:</span> <span class="n">Operand</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Instru3A</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">sr2orimm7</span><span class="p">,</span> <span class="n">Immediate</span><span class="p">):</span>
<span class="k">raise</span> <span class="n">MiniCInternalError</span><span class="p">(</span><span class="s2">&quot;Cant substract by an immediate&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s2">&quot;sub&quot;</span><span class="p">,</span> <span class="n">dr</span><span class="p">,</span> <span class="n">sr1</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">)</span></div>
<div class="viewcode-block" id="land"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.land">[docs]</a><span class="k">def</span> <span class="nf">land</span><span class="p">(</span><span class="n">dr</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr1</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">:</span> <span class="n">Operand</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Instru3A</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;And instruction (cannot be called `and` due to Python and).&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s2">&quot;and&quot;</span><span class="p">,</span> <span class="n">dr</span><span class="p">,</span> <span class="n">sr1</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">)</span></div>
<div class="viewcode-block" id="lor"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.lor">[docs]</a><span class="k">def</span> <span class="nf">lor</span><span class="p">(</span><span class="n">dr</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr1</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">:</span> <span class="n">Operand</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Instru3A</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Or instruction (cannot be called `or` due to Python or).&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s2">&quot;or&quot;</span><span class="p">,</span> <span class="n">dr</span><span class="p">,</span> <span class="n">sr1</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">)</span></div>
<div class="viewcode-block" id="xor"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.xor">[docs]</a><span class="k">def</span> <span class="nf">xor</span><span class="p">(</span><span class="n">dr</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr1</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">:</span> <span class="n">Operand</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Instru3A</span><span class="p">:</span> <span class="c1"># pragma: no cover</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">sr2orimm7</span><span class="p">,</span> <span class="n">Immediate</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s2">&quot;xori&quot;</span><span class="p">,</span> <span class="n">dr</span><span class="p">,</span> <span class="n">sr1</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s2">&quot;xor&quot;</span><span class="p">,</span> <span class="n">dr</span><span class="p">,</span> <span class="n">sr1</span><span class="p">,</span> <span class="n">sr2orimm7</span><span class="p">)</span></div>
<div class="viewcode-block" id="li"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.li">[docs]</a><span class="k">def</span> <span class="nf">li</span><span class="p">(</span><span class="n">dr</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">imm7</span><span class="p">:</span> <span class="n">Immediate</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Instru3A</span><span class="p">:</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s2">&quot;li&quot;</span><span class="p">,</span> <span class="n">dr</span><span class="p">,</span> <span class="n">imm7</span><span class="p">)</span></div>
<div class="viewcode-block" id="mv"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.mv">[docs]</a><span class="k">def</span> <span class="nf">mv</span><span class="p">(</span><span class="n">dr</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">sr</span><span class="p">:</span> <span class="n">Operand</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Instru3A</span><span class="p">:</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s2">&quot;mv&quot;</span><span class="p">,</span> <span class="n">dr</span><span class="p">,</span> <span class="n">sr</span><span class="p">)</span></div>
<div class="viewcode-block" id="ld"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.ld">[docs]</a><span class="k">def</span> <span class="nf">ld</span><span class="p">(</span><span class="n">dr</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">mem</span><span class="p">:</span> <span class="n">Operand</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Instru3A</span><span class="p">:</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s2">&quot;ld&quot;</span><span class="p">,</span> <span class="n">dr</span><span class="p">,</span> <span class="n">mem</span><span class="p">)</span></div>
<div class="viewcode-block" id="sd"><a class="viewcode-back" href="../../api/Lib.RiscV.html#Lib.RiscV.sd">[docs]</a><span class="k">def</span> <span class="nf">sd</span><span class="p">(</span><span class="n">sr</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">mem</span><span class="p">:</span> <span class="n">Operand</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Instru3A</span><span class="p">:</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="s2">&quot;sd&quot;</span><span class="p">,</span> <span class="n">sr</span><span class="p">,</span> <span class="n">mem</span><span class="p">)</span></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2023, compil-lyon.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

View File

@ -0,0 +1,384 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lib.Statement &mdash; MiniC documentation</title>
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="../../_static/js/html5shiv.min.js"></script>
<![endif]-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
<script src="../../_static/doctools.js"></script>
<script src="../../_static/sphinx_highlight.js"></script>
<script src="../../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../../genindex.html" />
<link rel="search" title="Search" href="../../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../../index.html" class="icon icon-home">
MiniC
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Errors.html">Base library - Errors</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Statement.html">Base library - Statement</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.RiscV.html">Base library - RISC-V instructions</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Operands.html">Base library - Operands</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.FunctionData.html">Base library - Function data</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.LinearCode.html">Linear intermediate representation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/Lib.Allocator.html">Temporary allocation</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../../index.html">MiniC</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item"><a href="../index.html">Module code</a></li>
<li class="breadcrumb-item active">Lib.Statement</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>Source code for Lib.Statement</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">The base class for RISCV ASM statements is :py:class:`Statement`.</span>
<span class="sd">It is inherited by :py:class:`Comment`, :py:class:`Label`</span>
<span class="sd">and :py:class:`Instruction`. In turn, :py:class:`Instruction`</span>
<span class="sd">is inherited by :py:class:`Instru3A`</span>
<span class="sd">(for regular non-branching 3-address instructions),</span>
<span class="sd">:py:class:`AbsoluteJump` and :py:class:`ConditionalJump`.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="p">(</span><span class="n">List</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">TypeVar</span><span class="p">)</span>
<span class="kn">from</span> <span class="nn">Lib.Operands</span> <span class="kn">import</span> <span class="p">(</span><span class="n">Operand</span><span class="p">,</span> <span class="n">Renamer</span><span class="p">,</span> <span class="n">Temporary</span><span class="p">,</span> <span class="n">Condition</span><span class="p">)</span>
<span class="kn">from</span> <span class="nn">Lib.Errors</span> <span class="kn">import</span> <span class="n">MiniCInternalError</span>
<div class="viewcode-block" id="regset_to_string"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.regset_to_string">[docs]</a><span class="k">def</span> <span class="nf">regset_to_string</span><span class="p">(</span><span class="n">registerset</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Utility function: pretty-prints a set of locations.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="s2">&quot;{&quot;</span> <span class="o">+</span> <span class="s2">&quot;,&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">registerset</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;}&quot;</span></div>
<span class="c1"># Temporary until we can use Typing.Self in python 3.11</span>
<span class="n">TStatement</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;TStatement&quot;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">&quot;Statement&quot;</span><span class="p">)</span>
<div class="viewcode-block" id="Statement"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Statement">[docs]</a><span class="nd">@dataclass</span><span class="p">(</span><span class="n">unsafe_hash</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Statement</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;A Statement, which is an instruction, a comment or a label.&quot;&quot;&quot;</span>
<div class="viewcode-block" id="Statement.defined"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Statement.defined">[docs]</a> <span class="k">def</span> <span class="nf">defined</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Operand</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Operands defined (written) in this instruction&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="p">[]</span></div>
<div class="viewcode-block" id="Statement.used"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Statement.used">[docs]</a> <span class="k">def</span> <span class="nf">used</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Operand</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Operands used (read) in this instruction&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="p">[]</span></div>
<div class="viewcode-block" id="Statement.substitute"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Statement.substitute">[docs]</a> <span class="k">def</span> <span class="nf">substitute</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">TStatement</span><span class="p">,</span> <span class="n">subst</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="n">Operand</span><span class="p">,</span> <span class="n">Operand</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">TStatement</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return a new instruction, cloned from this one, replacing operands</span>
<span class="sd"> that appear as key in subst by their value.&quot;&quot;&quot;</span>
<span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span>
<span class="s2">&quot;substitute: Operands </span><span class="si">{}</span><span class="s2"> are not present in instruction </span><span class="si">{}</span><span class="s2">&quot;</span>
<span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">subst</span><span class="p">,</span> <span class="bp">self</span><span class="p">))</span></div>
<div class="viewcode-block" id="Statement.with_args"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Statement.with_args">[docs]</a> <span class="k">def</span> <span class="nf">with_args</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">TStatement</span><span class="p">,</span> <span class="n">new_args</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Operand</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">TStatement</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return a new instruction, cloned from this one, where operands have</span>
<span class="sd"> been replaced by new_args.&quot;&quot;&quot;</span>
<span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span>
<span class="s2">&quot;substitute: Operands </span><span class="si">{}</span><span class="s2"> are not present in instruction </span><span class="si">{}</span><span class="s2">&quot;</span>
<span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">new_args</span><span class="p">,</span> <span class="bp">self</span><span class="p">))</span></div>
<div class="viewcode-block" id="Statement.printIns"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Statement.printIns">[docs]</a> <span class="k">def</span> <span class="nf">printIns</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stream</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Print the statement on the given output.</span>
<span class="sd"> Should never be called on the base class.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span></div></div>
<div class="viewcode-block" id="Comment"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Comment">[docs]</a><span class="nd">@dataclass</span><span class="p">(</span><span class="n">unsafe_hash</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Comment</span><span class="p">(</span><span class="n">Statement</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;A comment.&quot;&quot;&quot;</span>
<span class="n">comment</span><span class="p">:</span> <span class="nb">str</span>
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="c1"># use only for print_dot !</span>
<span class="k">return</span> <span class="s2">&quot;# </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">comment</span><span class="p">)</span>
<div class="viewcode-block" id="Comment.printIns"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Comment.printIns">[docs]</a> <span class="k">def</span> <span class="nf">printIns</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stream</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39; # &#39;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">comment</span><span class="p">,</span> <span class="n">file</span><span class="o">=</span><span class="n">stream</span><span class="p">)</span></div></div>
<div class="viewcode-block" id="Label"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Label">[docs]</a><span class="nd">@dataclass</span><span class="p">(</span><span class="n">unsafe_hash</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Label</span><span class="p">(</span><span class="n">Statement</span><span class="p">,</span> <span class="n">Operand</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;A label is both a Statement and an Operand.&quot;&quot;&quot;</span>
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="p">(</span><span class="s2">&quot;lbl_</span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">))</span>
<span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="p">(</span><span class="s2">&quot;</span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">))</span>
<div class="viewcode-block" id="Label.printIns"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Label.printIns">[docs]</a> <span class="k">def</span> <span class="nf">printIns</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stream</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;:&#39;</span><span class="p">,</span> <span class="n">file</span><span class="o">=</span><span class="n">stream</span><span class="p">)</span></div></div>
<div class="viewcode-block" id="Instruction"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Instruction">[docs]</a><span class="nd">@dataclass</span><span class="p">(</span><span class="n">init</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Instruction</span><span class="p">(</span><span class="n">Statement</span><span class="p">):</span>
<span class="n">ins</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">_read_only</span><span class="p">:</span> <span class="nb">bool</span>
<div class="viewcode-block" id="Instruction.is_read_only"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Instruction.is_read_only">[docs]</a> <span class="k">def</span> <span class="nf">is_read_only</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> True if the instruction only reads from its operands.</span>
<span class="sd"> Otherwise, the first operand is considered as the destination</span>
<span class="sd"> and others are source.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_read_only</span></div>
<div class="viewcode-block" id="Instruction.rename"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Instruction.rename">[docs]</a> <span class="k">def</span> <span class="nf">rename</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">renamer</span><span class="p">:</span> <span class="n">Renamer</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span></div>
<div class="viewcode-block" id="Instruction.args"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Instruction.args">[docs]</a> <span class="k">def</span> <span class="nf">args</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Operand</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;List of operands the instruction takes&quot;&quot;&quot;</span>
<span class="k">raise</span> <span class="ne">NotImplementedError</span></div>
<div class="viewcode-block" id="Instruction.defined"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Instruction.defined">[docs]</a> <span class="k">def</span> <span class="nf">defined</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_read_only</span><span class="p">():</span>
<span class="n">defs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">defs</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span>
<span class="k">return</span> <span class="n">defs</span></div>
<div class="viewcode-block" id="Instruction.used"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Instruction.used">[docs]</a> <span class="k">def</span> <span class="nf">used</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Operand</span><span class="p">]:</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_read_only</span><span class="p">():</span>
<span class="n">uses</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">uses</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">()[</span><span class="mi">1</span><span class="p">:]</span>
<span class="k">return</span> <span class="n">uses</span></div>
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">s</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">ins</span>
<span class="n">first</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">():</span>
<span class="k">if</span> <span class="n">first</span><span class="p">:</span>
<span class="n">s</span> <span class="o">+=</span> <span class="s1">&#39; &#39;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
<span class="n">first</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">s</span> <span class="o">+=</span> <span class="s1">&#39;, &#39;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
<span class="k">return</span> <span class="n">s</span>
<span class="k">def</span> <span class="fm">__hash__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">hash</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">ins</span><span class="p">,</span> <span class="o">*</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">()))</span>
<div class="viewcode-block" id="Instruction.printIns"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Instruction.printIns">[docs]</a> <span class="k">def</span> <span class="nf">printIns</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stream</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Print the instruction on the given output.&quot;&quot;&quot;</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39; &#39;</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">),</span> <span class="n">file</span><span class="o">=</span><span class="n">stream</span><span class="p">)</span></div></div>
<div class="viewcode-block" id="Instru3A"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Instru3A">[docs]</a><span class="nd">@dataclass</span><span class="p">(</span><span class="n">init</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Instru3A</span><span class="p">(</span><span class="n">Instruction</span><span class="p">):</span>
<span class="n">_args</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Operand</span><span class="p">]</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ins</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">:</span> <span class="n">Operand</span><span class="p">):</span>
<span class="c1"># convention is to use lower-case in RISCV</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ins</span> <span class="o">=</span> <span class="n">ins</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_args</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_read_only</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">ins</span> <span class="o">==</span> <span class="s2">&quot;call&quot;</span>
<span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">ins</span> <span class="o">==</span> <span class="s2">&quot;ld&quot;</span>
<span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">ins</span> <span class="o">==</span> <span class="s2">&quot;lw&quot;</span>
<span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">ins</span> <span class="o">==</span> <span class="s2">&quot;lb&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">ins</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;b&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">ins</span> <span class="o">==</span> <span class="s2">&quot;j&quot;</span><span class="p">):</span>
<span class="k">raise</span> <span class="n">MiniCInternalError</span>
<div class="viewcode-block" id="Instru3A.args"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Instru3A.args">[docs]</a> <span class="k">def</span> <span class="nf">args</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_args</span></div>
<div class="viewcode-block" id="Instru3A.rename"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Instru3A.rename">[docs]</a> <span class="k">def</span> <span class="nf">rename</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">renamer</span><span class="p">:</span> <span class="n">Renamer</span><span class="p">):</span>
<span class="n">old_replaced</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">arg</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_args</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="n">Temporary</span><span class="p">):</span>
<span class="k">if</span> <span class="n">i</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_read_only</span><span class="p">():</span>
<span class="n">old_replaced</span><span class="p">[</span><span class="n">arg</span><span class="p">]</span> <span class="o">=</span> <span class="n">renamer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
<span class="n">new_t</span> <span class="o">=</span> <span class="n">renamer</span><span class="o">.</span><span class="n">fresh</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">old_replaced</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
<span class="n">new_t</span> <span class="o">=</span> <span class="n">old_replaced</span><span class="p">[</span><span class="n">arg</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">new_t</span> <span class="o">=</span> <span class="n">renamer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_args</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_t</span></div>
<div class="viewcode-block" id="Instru3A.substitute"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Instru3A.substitute">[docs]</a> <span class="k">def</span> <span class="nf">substitute</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">subst</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="n">Operand</span><span class="p">,</span> <span class="n">Operand</span><span class="p">]):</span>
<span class="k">for</span> <span class="n">op</span> <span class="ow">in</span> <span class="n">subst</span><span class="p">:</span>
<span class="k">if</span> <span class="n">op</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">():</span>
<span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span>
<span class="s2">&quot;substitute: Operand </span><span class="si">{}</span><span class="s2"> is not present in instruction </span><span class="si">{}</span><span class="s2">&quot;</span>
<span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">op</span><span class="p">,</span> <span class="bp">self</span><span class="p">))</span>
<span class="n">args</span> <span class="o">=</span> <span class="p">[</span><span class="n">subst</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="n">arg</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="n">Temporary</span><span class="p">)</span> <span class="k">else</span> <span class="n">arg</span>
<span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">()]</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">ins</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span></div>
<div class="viewcode-block" id="Instru3A.with_args"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.Instru3A.with_args">[docs]</a> <span class="k">def</span> <span class="nf">with_args</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">new_args</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Operand</span><span class="p">]):</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">new_args</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_args</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span>
<span class="s2">&quot;substitute: Expected </span><span class="si">{}</span><span class="s2"> operands for </span><span class="si">{}</span><span class="s2">, got </span><span class="si">{}</span><span class="s2">.&quot;</span>
<span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_args</span><span class="p">),</span> <span class="bp">self</span><span class="p">,</span> <span class="n">new_args</span><span class="p">))</span>
<span class="k">return</span> <span class="n">Instru3A</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">ins</span><span class="p">,</span> <span class="o">*</span><span class="n">new_args</span><span class="p">)</span></div>
<span class="k">def</span> <span class="fm">__hash__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">hash</span><span class="p">(</span><span class="nb">super</span><span class="p">)</span></div>
<div class="viewcode-block" id="AbsoluteJump"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.AbsoluteJump">[docs]</a><span class="nd">@dataclass</span><span class="p">(</span><span class="n">init</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">AbsoluteJump</span><span class="p">(</span><span class="n">Instruction</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot; An Absolute Jump is a specific kind of instruction&quot;&quot;&quot;</span>
<span class="n">ins</span> <span class="o">=</span> <span class="s2">&quot;j&quot;</span>
<span class="n">label</span><span class="p">:</span> <span class="n">Label</span>
<span class="n">_read_only</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">label</span><span class="p">:</span> <span class="n">Label</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">label</span> <span class="o">=</span> <span class="n">label</span>
<div class="viewcode-block" id="AbsoluteJump.args"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.AbsoluteJump.args">[docs]</a> <span class="k">def</span> <span class="nf">args</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Operand</span><span class="p">]:</span>
<span class="k">return</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">label</span><span class="p">]</span></div>
<div class="viewcode-block" id="AbsoluteJump.rename"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.AbsoluteJump.rename">[docs]</a> <span class="k">def</span> <span class="nf">rename</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">renamer</span><span class="p">:</span> <span class="n">Renamer</span><span class="p">):</span>
<span class="k">pass</span></div>
<div class="viewcode-block" id="AbsoluteJump.substitute"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.AbsoluteJump.substitute">[docs]</a> <span class="k">def</span> <span class="nf">substitute</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">subst</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="n">Operand</span><span class="p">,</span> <span class="n">Operand</span><span class="p">]):</span>
<span class="k">if</span> <span class="n">subst</span> <span class="o">!=</span> <span class="p">{}:</span>
<span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span>
<span class="s2">&quot;substitute: No possible substitution on instruction </span><span class="si">{}</span><span class="s2">&quot;</span>
<span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="p">))</span>
<span class="k">return</span> <span class="bp">self</span></div>
<div class="viewcode-block" id="AbsoluteJump.with_args"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.AbsoluteJump.with_args">[docs]</a> <span class="k">def</span> <span class="nf">with_args</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">new_args</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Operand</span><span class="p">]):</span>
<span class="k">if</span> <span class="n">new_args</span> <span class="o">!=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">():</span>
<span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span>
<span class="s2">&quot;substitute: No possible substitution on instruction </span><span class="si">{}</span><span class="s2">. Old args=</span><span class="si">{}</span><span class="s2">, new args=</span><span class="si">{}</span><span class="s2">&quot;</span>
<span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">(),</span> <span class="n">new_args</span><span class="p">))</span>
<span class="k">return</span> <span class="bp">self</span></div>
<span class="k">def</span> <span class="fm">__hash__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">hash</span><span class="p">(</span><span class="nb">super</span><span class="p">)</span>
<div class="viewcode-block" id="AbsoluteJump.targets"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.AbsoluteJump.targets">[docs]</a> <span class="k">def</span> <span class="nf">targets</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Label</span><span class="p">]:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return the labels targetted by the AbsoluteJump.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">label</span><span class="p">]</span></div></div>
<div class="viewcode-block" id="ConditionalJump"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.ConditionalJump">[docs]</a><span class="nd">@dataclass</span><span class="p">(</span><span class="n">init</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">ConditionalJump</span><span class="p">(</span><span class="n">Instruction</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot; A Conditional Jump is a specific kind of instruction&quot;&quot;&quot;</span>
<span class="n">cond</span><span class="p">:</span> <span class="n">Condition</span>
<span class="n">label</span><span class="p">:</span> <span class="n">Label</span>
<span class="n">op1</span><span class="p">:</span> <span class="n">Operand</span>
<span class="n">op2</span><span class="p">:</span> <span class="n">Operand</span>
<span class="n">_read_only</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cond</span><span class="p">:</span> <span class="n">Condition</span><span class="p">,</span> <span class="n">op1</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">op2</span><span class="p">:</span> <span class="n">Operand</span><span class="p">,</span> <span class="n">label</span><span class="p">:</span> <span class="n">Label</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cond</span> <span class="o">=</span> <span class="n">cond</span>
<span class="bp">self</span><span class="o">.</span><span class="n">label</span> <span class="o">=</span> <span class="n">label</span>
<span class="bp">self</span><span class="o">.</span><span class="n">op1</span> <span class="o">=</span> <span class="n">op1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">op2</span> <span class="o">=</span> <span class="n">op2</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ins</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">cond</span><span class="p">)</span>
<div class="viewcode-block" id="ConditionalJump.args"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.ConditionalJump.args">[docs]</a> <span class="k">def</span> <span class="nf">args</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">op1</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">op2</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">label</span><span class="p">]</span></div>
<div class="viewcode-block" id="ConditionalJump.rename"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.ConditionalJump.rename">[docs]</a> <span class="k">def</span> <span class="nf">rename</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">renamer</span><span class="p">:</span> <span class="n">Renamer</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">op1</span><span class="p">,</span> <span class="n">Temporary</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">op1</span> <span class="o">=</span> <span class="n">renamer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">op1</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">op2</span><span class="p">,</span> <span class="n">Temporary</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">op2</span> <span class="o">=</span> <span class="n">renamer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">op2</span><span class="p">)</span></div>
<div class="viewcode-block" id="ConditionalJump.substitute"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.ConditionalJump.substitute">[docs]</a> <span class="k">def</span> <span class="nf">substitute</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">subst</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="n">Operand</span><span class="p">,</span> <span class="n">Operand</span><span class="p">]):</span>
<span class="k">for</span> <span class="n">op</span> <span class="ow">in</span> <span class="n">subst</span><span class="p">:</span>
<span class="k">if</span> <span class="n">op</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">():</span>
<span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span>
<span class="s2">&quot;substitute: Operand </span><span class="si">{}</span><span class="s2"> is not present in instruction </span><span class="si">{}</span><span class="s2">&quot;</span>
<span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">op</span><span class="p">,</span> <span class="bp">self</span><span class="p">))</span>
<span class="n">op1</span> <span class="o">=</span> <span class="n">subst</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">op1</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">op1</span><span class="p">)</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">op1</span><span class="p">,</span> <span class="n">Temporary</span><span class="p">)</span> \
<span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">op1</span>
<span class="n">op2</span> <span class="o">=</span> <span class="n">subst</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">op2</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">op2</span><span class="p">)</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">op2</span><span class="p">,</span> <span class="n">Temporary</span><span class="p">)</span> \
<span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">op2</span>
<span class="k">return</span> <span class="n">ConditionalJump</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">cond</span><span class="p">,</span> <span class="n">op1</span><span class="p">,</span> <span class="n">op2</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">label</span><span class="p">)</span></div>
<div class="viewcode-block" id="ConditionalJump.with_args"><a class="viewcode-back" href="../../api/Lib.Statement.html#Lib.Statement.ConditionalJump.with_args">[docs]</a> <span class="k">def</span> <span class="nf">with_args</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">new_args</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Operand</span><span class="p">]):</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">new_args</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">3</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span>
<span class="s2">&quot;substitute: Expected 3 operands for </span><span class="si">{}</span><span class="s2">, got </span><span class="si">{}</span><span class="s2">.&quot;</span>
<span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">new_args</span><span class="p">))</span>
<span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">new_args</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">Label</span><span class="p">)</span>
<span class="n">label</span><span class="p">:</span> <span class="n">Label</span> <span class="o">=</span> <span class="n">new_args</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
<span class="k">return</span> <span class="n">ConditionalJump</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">cond</span><span class="p">,</span> <span class="n">new_args</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">new_args</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">label</span><span class="p">)</span></div>
<span class="k">def</span> <span class="fm">__hash__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">hash</span><span class="p">(</span><span class="nb">super</span><span class="p">)</span></div>
</pre></div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2023, compil-lyon.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

View File

@ -0,0 +1,112 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Overview: module code &mdash; MiniC documentation</title>
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="../_static/js/html5shiv.min.js"></script>
<![endif]-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/sphinx_highlight.js"></script>
<script src="../_static/js/theme.js"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="../index.html" class="icon icon-home">
MiniC
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../api/Lib.Errors.html">Base library - Errors</a></li>
<li class="toctree-l1"><a class="reference internal" href="../api/Lib.Statement.html">Base library - Statement</a></li>
<li class="toctree-l1"><a class="reference internal" href="../api/Lib.RiscV.html">Base library - RISC-V instructions</a></li>
<li class="toctree-l1"><a class="reference internal" href="../api/Lib.Operands.html">Base library - Operands</a></li>
<li class="toctree-l1"><a class="reference internal" href="../api/Lib.FunctionData.html">Base library - Function data</a></li>
<li class="toctree-l1"><a class="reference internal" href="../api/Lib.LinearCode.html">Linear intermediate representation</a></li>
<li class="toctree-l1"><a class="reference internal" href="../api/Lib.Allocator.html">Temporary allocation</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../index.html">MiniC</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="../index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item active">Overview: module code</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1>All modules for which code is available</h1>
<ul><li><a href="Lib/Allocator.html">Lib.Allocator</a></li>
<li><a href="Lib/Errors.html">Lib.Errors</a></li>
<li><a href="Lib/FunctionData.html">Lib.FunctionData</a></li>
<li><a href="Lib/LinearCode.html">Lib.LinearCode</a></li>
<li><a href="Lib/Operands.html">Lib.Operands</a></li>
<li><a href="Lib/RiscV.html">Lib.RiscV</a></li>
<li><a href="Lib/Statement.html">Lib.Statement</a></li>
</ul>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2023, compil-lyon.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More