Commit 4aeb746c authored by Matthieu Moy's avatar Matthieu Moy
Browse files

Several minor fixes to the skeleton

parent 9d28d303
......@@ -28,10 +28,10 @@ antlr MiniCLexer.py MiniCParser.py: $(PACKAGE).g4
main-deps: MiniCLexer.py MiniCParser.py TP03/MiniCInterpretVisitor.py TP03/MiniCTypingVisitor.py
.PHONY: tests tests-interpret tests-codegen tests-regalloc clean clean-tests tar antlr
.PHONY: tests tests-interpret tests-codegen clean clean-tests tar antlr
tests: tests-interpret tests-codegen tests-regalloc
tests: tests-interpret tests-codegen
tests-pyright: antlr
pyright .
......@@ -56,6 +56,9 @@ tests-smart: tests-pyright antlr
tests-codegen: tests-pyright antlr
python3 -m pytest $(PYTEST_BASE_OPTS) $(PYTEST_OPTS) ./test_codegen.py
tests-optim: tests-pyright antlr
ENABLE_SSA=1 SSA_OPTIMS=1 python3 -m pytest $(PYTEST_BASE_OPTS) $(PYTEST_OPTS) ./test_codegen.py
tar: clean
dir=$$(basename "$$PWD") && cd .. && \
tar cvfz $(MYNAME).tgz --exclude="*.riscv" --exclude=".git" --exclude=".pytest_cache" \
......
......@@ -34,6 +34,10 @@ try: # Liveness for TP05b (CAP)
from TP05.LivenessSSA import LivenessSSA # type: ignore[import]
except ModuleNotFoundError:
pass
try: # Optim for TP05c (CAP)
from TP05c.OptimSSA import OptimSSA # type: ignore[import]
except ModuleNotFoundError:
pass
import argparse
......@@ -62,7 +66,7 @@ class CountErrorListener(ErrorListener):
def main(inputname, reg_alloc, enable_ssa=False,
typecheck=True, typecheck_only=False, stdout=False, output_name=None, debug=False,
debug_graphs=False, ssa_graphs=False):
debug_graphs=False, ssa_graphs=False, ssa_optims=False):
(basename, rest) = os.path.splitext(inputname)
if not typecheck_only:
if stdout:
......@@ -114,6 +118,12 @@ def main(inputname, reg_alloc, enable_ssa=False,
s = "{}.{}.ssa.dot".format(basename, cfg._name)
print("Output", s)
cfg.print_dot(s, DF, True)
if ssa_optims:
OptimSSA(cfg, debug=debug)
if ssa_graphs:
s = "{}.{}.optimssa.dot".format(basename, cfg._name)
print("Output", s)
cfg.print_dot(s, view=True)
allocator = None
if reg_alloc == "naive":
allocator = NaiveAllocator(cfg)
......@@ -172,6 +182,9 @@ if __name__ == '__main__':
parser.add_argument('--ssa', action='store_true',
default=False,
help='Enable SSA form')
parser.add_argument('--ssa-optim', action='store_true',
default=False,
help='Enable SSA optimizations')
parser.add_argument('--stdout', action='store_true',
help='Generate code to stdout')
parser.add_argument('--debug', action='store_true',
......@@ -186,7 +199,7 @@ if __name__ == '__main__':
parser.add_argument('--disable-typecheck', action='store_true',
default=False,
help="Don't run the typechecker before generating code")
parser.add_argument('--typecheck-only', action='store_true',
parser.add_argument('--disable-codegen', action='store_true',
default=False,
help="Run only the typechecker, don't try generating code.")
parser.add_argument('--output', type=str,
......@@ -194,15 +207,18 @@ if __name__ == '__main__':
args = parser.parse_args()
if args.reg_alloc is None and not args.typecheck_only:
if args.reg_alloc is None and not args.disable_codegen:
print("error: the following arguments is required: --reg-alloc")
exit(1)
if not args.ssa and args.ssa_optim:
print("error: SSA is needed for optimizations")
exit(1)
try:
main(args.filename, args.reg_alloc, args.ssa,
not args.disable_typecheck, args.typecheck_only,
not args.disable_typecheck, args.disable_codegen,
args.stdout, args.output, args.debug,
args.graphs, args.ssa_graphs)
args.graphs, args.ssa_graphs, args.ssa_optim)
except MiniCUnsupportedError as e:
print(e)
exit(5)
......
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from typing import List
from Errors import MiniCInternalError
from .Operands import (
Condition, Immediate, Offset, Temporary,
......@@ -8,7 +9,7 @@ from .Operands import (
A0,
ZERO)
from .Instruction3A import (
Instru3A, Jump, CondJump, Comment, Label
Instru3A, Instruction, Jump, CondJump, Comment, Label
)
"""
......@@ -64,7 +65,7 @@ class LinearCode:
self._listIns.insert(i, Comment("end " + str(old_i)))
i += 1
def get_instructions(self):
def get_instructions(self) -> List[Instruction]:
return self._listIns
def new_tmp(self) -> Temporary:
......
......@@ -107,10 +107,14 @@ class Instru3A(Instruction):
return [arg for arg in uses if isinstance(arg, Temporary)]
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
......
......@@ -99,11 +99,9 @@ class Offset(DataLocation):
self._offset = offset
self._basereg = basereg
def __str__(self):
def __repr__(self):
return("{}({})".format(self._offset, self._basereg))
__repr__ = __str__
def get_offset(self):
return self._offset
......@@ -116,16 +114,13 @@ class Register(DataLocation):
super().__init__()
self._number = number
def __str__(self):
def __repr__(self):
numreg = self._number
if numreg not in reg_map:
raise Exception("Register number %d should not be used", numreg)
else:
return ("{}".format(reg_map[numreg]))
def __repr__(self):
return self.__str__()
def __eq__(self, other):
return isinstance(other, Register) and self._number == other._number
......@@ -141,15 +136,12 @@ class RegisterAdd(DataLocation):
super().__init__()
self._number = number
def __str__(self):
def __repr__(self):
if self._number == 2:
return "sp"
else: # should not happen in RISCV
return ("blu{}".format(self._number))
def __repr__(self):
return self.__str__()
class Immediate(DataLocation):
"""Immediate operand (integer)."""
......@@ -235,11 +227,9 @@ class Temporary(DataLocation):
self._pool = pool
pool.add_tmp(self)
def __str__(self):
def __repr__(self):
return("temp_{}".format(str(self._number)))
__repr__ = __str__
def get_alloced_loc(self):
return self._pool.get_alloced_loc(self)
......
......@@ -79,7 +79,7 @@ class AllInMemAllocator(Allocator):
def replace_mem(old_i):
"""Replace Temporary operands with the corresponding allocated
memory location. FP points to the stack"""
memory location. FP points to the stack."""
before = []
after = []
ins, old_args = old_i.unfold()
......
from typing import Dict, Set, Tuple
from TP04.Operands import Operand
from TP04.Instruction3A import Instruction, regset_to_string
from TP05.CFG import Block
from TP05.CFG import Block, CFG
from TP05.SSA import PhiNode
class LivenessSSA:
def __init__(self, function, debug=False):
def __init__(self, function: CFG, debug=False):
self._function = function
self._debug = debug
self._seen: Dict[Block, Set[Operand]] = dict()
......@@ -58,7 +58,14 @@ class LivenessSSA:
uses: Dict[Operand, Set[Tuple[Block, int, Instruction]]] = dict()
for block in self._function.get_blocks():
for pos, instr in enumerate(block.get_instructions()):
args = instr.used().values() if isinstance(instr, PhiNode) else instr.used()
# Workaround for a weird behavior (aka "bug"...) of Pyright
# 1.1.191. If using instr everywhere, Pyright considers it as
# type PhiNode | Instruction, and then complains about PhiNode
# being incompatible with Instruction on the uses[var] = ...
# assignment.
instr_or_phi = instr
args = instr_or_phi.used().values() if isinstance(instr_or_phi, PhiNode) \
else instr.used()
for var in args:
if var is not None:
var_uses = uses.get(var, set())
......
......@@ -28,7 +28,9 @@ Unit test infrastructure for testing code generation:
DISABLE_TYPECHECK = False
TYPECHECK_ONLY = False
ENABLE_SSA = False
SSA_OPTIMS = False
env_bool_variable('ENABLE_SSA', globals())
env_bool_variable('SSA_OPTIMS', globals())
HERE = os.path.dirname(os.path.realpath(__file__))
if HERE == os.path.realpath('.'):
......@@ -77,9 +79,9 @@ class TestCodeGen(TestExpectPragmas):
if TYPECHECK_ONLY and expected.exitcode == 0:
# Compiler does not fail => no output expected
assert actual.output == "", \
"Compiler unexpectedly generated some output with --typecheck-only"
"Compiler unexpectedly generated some output with --disable-codegen"
assert actual.exitcode == 0, \
"Compiler unexpectedly failed with --typecheck-only"
"Compiler unexpectedly failed with --disable-codegen"
return
if DISABLE_TYPECHECK and expected.exitcode != 0:
# Test should fail at typecheck, and we don't do
......@@ -126,10 +128,12 @@ class TestCodeGen(TestExpectPragmas):
alloc_opt, out_opt]
if ENABLE_SSA:
cmd += ['--ssa']
if SSA_OPTIMS:
cmd += ['--ssa-optim']
if DISABLE_TYPECHECK:
cmd += ['--disable-typecheck']
if TYPECHECK_ONLY:
cmd += ['--typecheck-only']
cmd += ['--disable-codegen']
cmd += [file]
result = self.run_command(cmd)
print(' '.join(cmd))
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment