Commit TP4b
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
"""
|
||||
CAP, CodeGeneration, CFG construction from linear code
|
||||
"""
|
||||
|
||||
from typing import List
|
||||
from Lib.Errors import MiniCInternalError
|
||||
from Lib.FunctionData import FunctionData
|
||||
from Lib.LinearCode import LinearCode, CodeStatement
|
||||
from Lib.Statement import (
|
||||
Instru3A, Comment, Label, AbsoluteJump, ConditionalJump
|
||||
)
|
||||
from Lib.Terminator import jump2terminator
|
||||
from Lib.CFG import Block, BlockInstr, CFG
|
||||
|
||||
|
||||
def find_leaders(instructions: List[CodeStatement]) -> List[int]:
|
||||
"""
|
||||
Find the leaders in the given list of instructions as linear code.
|
||||
Returns a list of indices in the instruction list whose first is 0 and
|
||||
last is len(instructions)
|
||||
"""
|
||||
leaders: List[int] = [0]
|
||||
# TODO fill leaders (Lab4b, Exercise 3)
|
||||
# The final "ret" is also a form of jump
|
||||
leaders.append(len(instructions))
|
||||
return leaders
|
||||
|
||||
|
||||
def separate_with_leaders(instructions: List[CodeStatement],
|
||||
leaders: List[int]) -> List[List[CodeStatement]]:
|
||||
"""
|
||||
Partition the lists instructions into a list containing for
|
||||
elements the lists of statements between indices
|
||||
leaders[i] (included) and leaders[i+1] (excluded).
|
||||
|
||||
If leaders[i] = leaders[i+1], do not add the empty list.
|
||||
"""
|
||||
chunks: List[List[CodeStatement]] = []
|
||||
for i in range(0, len(leaders)-1):
|
||||
start = leaders[i]
|
||||
end = leaders[i+1]
|
||||
if start != end:
|
||||
# Avoid corner-cases when a label immediately follows a jump
|
||||
chunks.append(instructions[start:end])
|
||||
return chunks
|
||||
|
||||
|
||||
def prepare_chunk(pre_chunk: List[CodeStatement], fdata: FunctionData) -> tuple[
|
||||
Label, ConditionalJump | AbsoluteJump | None, List[BlockInstr]]:
|
||||
"""
|
||||
Extract the potential label (respectively jump)
|
||||
at the start (respectively end) of the list instrs_chunk,
|
||||
and return the tuple with this label, this jump and the
|
||||
rest of instrs_chunk.
|
||||
|
||||
If there is no label at the start then return a fresh label instead,
|
||||
thanks to fdata (use `fdata.fresh_label(fdata._name)` for instance).
|
||||
If there is no jump at the end, return None instead.
|
||||
|
||||
Raise an error if there is a label not in first position in pre_chunk,
|
||||
or a jump not in last position.
|
||||
"""
|
||||
label = None
|
||||
jump = None
|
||||
inner_statements: List[CodeStatement] = pre_chunk
|
||||
# Extract the first instruction from inner_statements if it is a label, or create a fresh one
|
||||
raise NotImplementedError() # TODO (Lab4b, Exercise 3)
|
||||
# Extract the last instruction from inner_statements if it is a jump, or do nothing
|
||||
raise NotImplementedError() # TODO (Lab4b, Exercise 3)
|
||||
# Check that there is no other label or jump left in inner_statements
|
||||
l: List[BlockInstr] = []
|
||||
for i in inner_statements:
|
||||
match i:
|
||||
case AbsoluteJump() | ConditionalJump():
|
||||
raise MiniCInternalError(
|
||||
"prepare_chunk: Jump {} not in last position of a chunk"
|
||||
.format(i))
|
||||
case Label():
|
||||
raise MiniCInternalError(
|
||||
"prepare_chunk: Label {} not in first position of a chunk"
|
||||
.format(i))
|
||||
case Instru3A() | Comment():
|
||||
l.append(i)
|
||||
return (label, jump, l)
|
||||
|
||||
|
||||
def build_cfg(linCode: LinearCode) -> CFG:
|
||||
"""Extract the blocks from the linear code and add them to the CFG."""
|
||||
fdata = linCode.fdata
|
||||
cfg = CFG(fdata)
|
||||
instructions = linCode.get_instructions()
|
||||
# 1. Identify Leaders
|
||||
leaders = find_leaders(instructions)
|
||||
# 2. Extract Chunks of Instructions
|
||||
pre_chunks: List[List[CodeStatement]] = separate_with_leaders(instructions, leaders)
|
||||
chunks: List[tuple[Label, ConditionalJump | AbsoluteJump | None, List[BlockInstr]]] = [
|
||||
prepare_chunk(pre_chunk, fdata) for pre_chunk in pre_chunks]
|
||||
# 3. Build the Blocks
|
||||
next_label = None
|
||||
for (label, jump, block_instrs) in reversed(chunks):
|
||||
term = jump2terminator(jump, next_label)
|
||||
block = Block(label, block_instrs, term)
|
||||
cfg.add_block(block)
|
||||
next_label = label
|
||||
# 4. Fill the edges
|
||||
for block in cfg.get_blocks():
|
||||
for dest in cfg.out_blocks(block):
|
||||
cfg.add_edge(block, dest)
|
||||
# 5. Identify the entry label of the CFG
|
||||
cfg.set_start(chunks[0][0])
|
||||
return cfg
|
||||
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
CAP, CodeGeneration, CFG linearization to a list of statements
|
||||
"""
|
||||
|
||||
from typing import List, Set
|
||||
|
||||
from Lib.Statement import (
|
||||
Statement, AbsoluteJump, ConditionalJump
|
||||
)
|
||||
from Lib.Terminator import (Return, BranchingTerminator)
|
||||
from Lib.CFG import Block
|
||||
|
||||
|
||||
def ordered_blocks_list(cfg) -> List[Block]:
|
||||
"""
|
||||
Compute a list of blocks with optimized ordering for linearization.
|
||||
"""
|
||||
# TODO (Lab4b, Extension)
|
||||
return cfg.get_blocks()
|
||||
|
||||
|
||||
def linearize(cfg) -> List[Statement]:
|
||||
"""
|
||||
Linearize the given control flow graph as a list of instructions.
|
||||
"""
|
||||
# TODO (Lab 4b, Exercise 5)
|
||||
l: List[Statement] = [] # Linearized CFG
|
||||
blocks: List[Block] = ordered_blocks_list(cfg)
|
||||
for j, block in enumerate(blocks):
|
||||
# 1. Add the label of the block to the linearization
|
||||
l.append(block.get_label())
|
||||
# 2. Add the body of the block to the linearization
|
||||
l.extend(block.get_body())
|
||||
# 3. Add the terminator of the block to the linearization
|
||||
match block.get_terminator():
|
||||
case BranchingTerminator() as j:
|
||||
l.append(ConditionalJump(j.cond, j.op1, j.op2, j.label_then))
|
||||
l.append(AbsoluteJump(j.label_else))
|
||||
case AbsoluteJump() as j:
|
||||
l.append(AbsoluteJump(j.label))
|
||||
case Return():
|
||||
l.append(AbsoluteJump(cfg.get_end()))
|
||||
return l
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main() {
|
||||
|
||||
int n,u;
|
||||
n=6;
|
||||
println_int(n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
// 6
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "printlib.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
int x;
|
||||
x = 0;
|
||||
while (x < 4)
|
||||
{
|
||||
x = x + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXPECTED
|
||||
Binary file not shown.
Reference in New Issue
Block a user