summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile28
-rw-r--r--dune-project2
-rw-r--r--dune-workspace0
-rw-r--r--mod_student.opam0
-rw-r--r--source/mod_student/.merlin7
-rw-r--r--source/mod_student/dune21
-rw-r--r--source/mod_student/lexer.mll79
-rw-r--r--source/mod_student/parser.mly70
-rw-r--r--source/mod_student/plugin.ml61
-rw-r--r--source/xi/.merlin15
-rw-r--r--source/xi/dune15
-rw-r--r--source/xi/invariants.ml146
-rw-r--r--source/xi/parser_wrapper.ml42
-rw-r--r--source/xi/pipeline.ml137
-rw-r--r--source/xi/plugin_manager.ml245
-rw-r--r--source/xi/xi.ml82
-rw-r--r--source/xi_lib/.merlin5
-rw-r--r--source/xi_lib/analysis.ml77
-rw-r--r--source/xi_lib/analysis_domain.ml135
-rw-r--r--source/xi_lib/analysis_visualizer.ml295
-rw-r--r--source/xi_lib/ast.ml288
-rw-r--r--source/xi_lib/ast_printer.ml271
-rw-r--r--source/xi_lib/ast_rawprinter.ml313
-rw-r--r--source/xi_lib/dune9
-rw-r--r--source/xi_lib/hardcoded.ml122
-rw-r--r--source/xi_lib/hashset.ml30
-rw-r--r--source/xi_lib/iface.ml199
-rw-r--r--source/xi_lib/ir.ml288
-rw-r--r--source/xi_lib/ir_arch.ml107
-rw-r--r--source/xi_lib/ir_utils.ml668
-rw-r--r--source/xi_lib/logger.ml170
-rw-r--r--source/xi_lib/measure.ml8
-rw-r--r--source/xi_lib/mips32.ml217
-rw-r--r--source/xi_lib/mygraph.ml155
-rw-r--r--source/xi_lib/parser_utils.ml7
-rw-r--r--source/xi_lib/plugin.ml85
-rw-r--r--source/xi_lib/plugin_register.ml16
-rw-r--r--source/xi_lib/typechecker_errors.ml257
-rw-r--r--source/xi_lib/types.ml31
-rw-r--r--tests/pracownia1/parse_error.xi75
-rw-r--r--tests/pracownia1/parse_ok.xi163
-rw-r--r--tests/pracownia1/parse_operators.xi14
-rwxr-xr-xtools/tester.py404
-rw-r--r--xi.opam0
-rw-r--r--xi_lib.opam0
-rw-r--r--xisdk/mod_uwr.cmabin0 -> 1183174 bytes
46 files changed, 5359 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c6077e0
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,28 @@
+.PHONY: all compile clean test
+BUILD_PATH_XI=./_build/install/default/bin/xi
+BUILD_PATH_MOD_UWR=./_build/install/default/lib/mod_uwr/mod_uwr.cma
+BUILD_PATH_MOD_STUDENT=./_build/install/default/lib/mod_student/mod_student.cma
+all: compile
+
+compile:
+ dune build
+
+install: all
+ rm -f ./xi
+ rm -rf mods
+ mkdir mods
+ if [ -e ${BUILD_PATH_MOD_STUDENT} ]; then (cd mods; ln -s ../${BUILD_PATH_MOD_STUDENT} .); fi
+ if [ -e ${BUILD_PATH_MOD_UWR} ]; then (cd xisdk; rm -f mod_uwr.cma; ln -s ../${BUILD_PATH_MOD_UWR} .); fi
+ if [ -e ${BUILD_PATH_MOD_STUDENT} ]; then (cd mods; rm -f mod_student.cma; ln -s ../${BUILD_PATH_MOD_STUDENT} .); fi
+ ln -s ${BUILD_PATH_XI} ./xi
+
+test: all
+ python3 ./tools/tester.py --plugin mods/mod_student.cma
+
+test_without_plugin: all
+ python3 ./tools/tester.py
+
+clean:
+ rm -f ./xi
+ dune clean
+
diff --git a/dune-project b/dune-project
new file mode 100644
index 0000000..977e7d7
--- /dev/null
+++ b/dune-project
@@ -0,0 +1,2 @@
+(lang dune 1.1)
+(using menhir 1.0)
diff --git a/dune-workspace b/dune-workspace
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dune-workspace
diff --git a/mod_student.opam b/mod_student.opam
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mod_student.opam
diff --git a/source/mod_student/.merlin b/source/mod_student/.merlin
new file mode 100644
index 0000000..e07c2b1
--- /dev/null
+++ b/source/mod_student/.merlin
@@ -0,0 +1,7 @@
+B /home/wieczyk/.opam/4.07.0/lib/ocamlgraph
+B ../../_build/default/source/mod_student/.mod_student.objs
+B ../../_build/default/source/xi_lib/.xi_lib.objs
+S /home/wieczyk/.opam/4.07.0/lib/ocamlgraph
+S .
+S ../xi_lib
+FLG -open Mod_student -w @a-4-29-40-41-42-44-45-48-58-59-60-40 -strict-sequence -strict-formats -short-paths -keep-locs -g -w -39-33-26-27-32
diff --git a/source/mod_student/dune b/source/mod_student/dune
new file mode 100644
index 0000000..c590740
--- /dev/null
+++ b/source/mod_student/dune
@@ -0,0 +1,21 @@
+(library
+ (name mod_student)
+ (public_name mod_student)
+ (libraries ocamlgraph xi_lib)
+ (modes byte)
+)
+(menhir
+ (flags (--explain --dump))
+ (modules parser)
+)
+(ocamllex
+ lexer
+)
+(env
+ (dev
+ (flags (:standard -g -w -39-33-26-27-32))
+ )
+ (release
+ (flags (:standard -w -39-33-26-27))
+ )
+)
diff --git a/source/mod_student/lexer.mll b/source/mod_student/lexer.mll
new file mode 100644
index 0000000..4cd656c
--- /dev/null
+++ b/source/mod_student/lexer.mll
@@ -0,0 +1,79 @@
+{
+ open Xi_lib
+ open Parser
+ open Parser_utils
+
+ (* Lexing z biblioteki standardowej ocamla *)
+ open Lexing
+
+ (* Standardowo w YACC-podobnych narzędziach to lekser jest uzależniony od parsera. To znaczy, że typ
+ * danych z tokenami definiuje moduł wygenerowany na bazie grammar.mly. Definiujemy alias na typ
+ * tokenu na potrzeby interfejsów Xi_lib.Iface *)
+ type token = Parser.token
+
+ (* Obsługa błędu *)
+ let handleError pos token =
+ let exc = InvalidToken (mkLocation pos, token) in
+ raise exc
+
+ (* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+ * Miejsce na twój kod w Ocamlu
+ *)
+
+
+ (* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ----------------------------------------------------------------------------- *)
+
+ }
+
+ (* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+ * Miejsce na nazwane wyrażenia regularne
+ *)
+
+ let identifier = ['a'-'z' '_' 'A' - 'Z']['_' 'A' - 'Z' 'a'-'z' '0'-'9']*
+
+ (* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ----------------------------------------------------------------------------- *)
+
+
+ rule token = parse
+ (* Trzeba pamiętać aby uaktualnić pozycje w lexbuf, gdy widzimy znak końca wiersza.
+ * To się samo nie robi. Moduł Lexing z standardowej biblioteki daje do tego wygodną
+ * funkcję new_line.
+ *)
+ | ['\n']
+ { new_line lexbuf; token lexbuf }
+
+ (* widzimy początek komentarza i przechodzimy do pomocniczego stanu *)
+ | "//"
+ { line_comment lexbuf }
+
+ | eof
+ { EOF }
+
+ (* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+ * Miejsce na twoje reguły
+ *)
+
+ | identifier as id
+ { failwith id }
+
+ (* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ----------------------------------------------------------------------------- *)
+
+ | _
+ { handleError (Lexing.lexeme_start_p lexbuf) (Lexing.lexeme lexbuf) }
+
+ (* Pomocniczy stan aby wygodnie i prawidłowo obsłużyć komentarze *)
+ and line_comment = parse
+ | '\n'
+ { new_line lexbuf; token lexbuf }
+
+ (* Niektóre edytory nie wstawiają znaku końca wiersza w ostatniej linijce, jesteśmy
+ * przygotowani na obsługę takiego komentarza.
+ *)
+ | eof
+ { EOF }
+
+ | _
+ { line_comment lexbuf }
diff --git a/source/mod_student/parser.mly b/source/mod_student/parser.mly
new file mode 100644
index 0000000..3eacf51
--- /dev/null
+++ b/source/mod_student/parser.mly
@@ -0,0 +1,70 @@
+(*
+ * Menhir wygeneruje funkcję o nazwie file
+ *)
+%start <Xi_lib.Ast.module_definition> file
+
+%{
+open Xi_lib
+open Ast
+open Parser_utils
+
+(* Generator znaczników *)
+let mkTag =
+ let i = ref 0 in
+ fun () ->
+ let tag = !i in
+ incr i;
+ NodeTag tag
+
+(* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+ * Miejsce na twój kod w Ocamlu
+ *)
+
+(* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ----------------------------------------------------------------------------- *)
+
+%}
+
+(* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+ * Miejsce na dyrektywy
+ *)
+
+%token EOF
+%token <string>IDENTIFIER
+
+(* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ----------------------------------------------------------------------------- *)
+
+%%
+
+(* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+ * Miejsce na gramatykę
+ *)
+
+
+(* Obecnie potrafimy sparsować tylko pusty plik (wymagamy od razu tokena EOF) *)
+file:
+ | EOF
+ { ModuleDefinition {global_declarations=[] } }
+
+
+identifier:
+ | IDENTIFIER
+ { Identifier $1 }
+
+(*
+ ** przykład użycia mkLocation
+
+ use_declaration:
+ | USE suffix(identifier, opt(SEMICOLON))
+ { GDECL_Use {loc=mkLocation $startpos; id=$2} }
+
+ ** przykład użycia mkTag
+
+ atomic_expression:
+ | identifier
+ { EXPR_Id {loc=mkLocation $startpos; id=$1; tag=mkTag ()} }
+*)
+
+(* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ----------------------------------------------------------------------------- *)
diff --git a/source/mod_student/plugin.ml b/source/mod_student/plugin.ml
new file mode 100644
index 0000000..26d15d0
--- /dev/null
+++ b/source/mod_student/plugin.ml
@@ -0,0 +1,61 @@
+open Xi_lib.Iface
+open Xi_lib.Plugin
+open Xi_lib.Plugin_register
+
+
+module LexerAndParser = struct
+
+ type token = Parser.token
+
+ module Lexer = Lexer
+
+ module Parser = Parser
+
+end
+
+module Plugin : PLUGIN = struct
+
+ let version = "na"
+
+ let make_live_variables_analysis = None
+
+ let make_dominators_analysis = None
+
+ let make_scheduler = None
+
+ let make_natural_loops_analysis = None
+
+ let make_spill_costs_analysis = None
+
+ let lexer_and_parser = Some (module LexerAndParser : LEXER_AND_PARSER)
+
+ let make_typechecker = None
+
+ let make_translator = None
+
+ let make_jump_threading = None
+
+ let make_constant_folding = None
+
+ let make_hilower = None
+
+ let make_callconv = None
+
+ let make_mipslower = None
+
+ let make_register_allocator = None
+
+ let make_constant_folding_analysis = None
+
+ let make_codegen = None
+
+ let make_dead_code_elimination = None
+
+ let make_interference_graph_analysis = None
+
+ let make_spilling = None
+
+ let make_reachability_analysis = None
+end
+
+module RegisterMyPlugin = RegisterPlugin(Plugin) \ No newline at end of file
diff --git a/source/xi/.merlin b/source/xi/.merlin
new file mode 100644
index 0000000..dc01a8e
--- /dev/null
+++ b/source/xi/.merlin
@@ -0,0 +1,15 @@
+B /home/wieczyk/.opam/4.07.0/lib/bytes
+B /home/wieczyk/.opam/4.07.0/lib/cmdliner
+B /home/wieczyk/.opam/4.07.0/lib/ocaml
+B /home/wieczyk/.opam/4.07.0/lib/ocamlgraph
+B /home/wieczyk/.opam/4.07.0/lib/result
+B ../../_build/default/source/xi/.xi.eobjs
+B ../../_build/default/source/xi_lib/.xi_lib.objs
+S /home/wieczyk/.opam/4.07.0/lib/bytes
+S /home/wieczyk/.opam/4.07.0/lib/cmdliner
+S /home/wieczyk/.opam/4.07.0/lib/ocaml
+S /home/wieczyk/.opam/4.07.0/lib/ocamlgraph
+S /home/wieczyk/.opam/4.07.0/lib/result
+S .
+S ../xi_lib
+FLG -w @a-4-29-40-41-42-44-45-48-58-59-60-40 -strict-sequence -strict-formats -short-paths -keep-locs -g -w -39-33-26-27
diff --git a/source/xi/dune b/source/xi/dune
new file mode 100644
index 0000000..1c209ac
--- /dev/null
+++ b/source/xi/dune
@@ -0,0 +1,15 @@
+(executable
+ (name xi)
+ (public_name xi)
+ (modes byte)
+ (libraries cmdliner ocamlgraph unix xi_lib dynlink)
+ (package xi)
+)
+(env
+ (dev
+ (flags (:standard -g -w -39-33-26-27))
+ )
+ (release
+ (flags (:standard -w -39-33-26-27))
+ )
+)
diff --git a/source/xi/invariants.ml b/source/xi/invariants.ml
new file mode 100644
index 0000000..09c8b86
--- /dev/null
+++ b/source/xi/invariants.ml
@@ -0,0 +1,146 @@
+open Xi_lib
+open Ast
+open Types
+
+
+module AllExpressionsAreTypecheck = struct
+
+ exception MissingTypeInformation of location
+
+ module Implementation(M:sig val node2type: (node_tag, normal_type) Hashtbl.t end) = struct
+
+ open M
+
+ let check_tag loc tag =
+ match Hashtbl.find_opt node2type tag with
+ | Some _ -> ()
+ | None -> raise (MissingTypeInformation loc)
+
+ let expr_subexpressions = function
+ | EXPR_Id _ -> []
+ | EXPR_Int _ -> []
+ | EXPR_Char _ -> []
+ | EXPR_String _ -> []
+ | EXPR_Bool _ -> []
+
+ | EXPR_Relation {lhs; rhs; _} ->
+ [lhs; rhs]
+
+ | EXPR_Binop {lhs; rhs; _} ->
+ [lhs; rhs]
+
+ | EXPR_Length {arg; _} ->
+ [arg]
+
+ | EXPR_Unop {sub; _} ->
+ [sub]
+
+ | EXPR_Call (Call {arguments; _}) ->
+ arguments
+
+ | EXPR_Index {expr; index; _} ->
+ [expr; index]
+
+ | EXPR_Struct {elements; _} ->
+ elements
+
+ let some2list = function
+ | Some x -> [x]
+ | None -> []
+
+ let block_substatements = function
+ | STMTBlock {body; _} -> body
+
+ let block_substatements_opt = function
+ | Some (STMTBlock {body; _}) -> body
+ | None -> []
+
+ let stmt_subexpressions = function
+ | STMT_Call (Call {arguments; _}) ->
+ arguments
+
+ | STMT_Assign {rhs; _} ->
+ [rhs]
+
+ | STMT_VarDecl {init=Some init; _} ->
+ [init]
+
+ | STMT_VarDecl {init=None; _} ->
+ []
+
+ | STMT_If {cond; _} ->
+ [cond]
+
+ | STMT_While {cond; _} ->
+ [cond]
+
+ | STMT_Return {values; _} ->
+ values
+
+ | STMT_MultiVarDecl {init=Call{arguments; _}; _} ->
+ arguments
+
+ | STMT_Block _ ->
+ []
+
+ let stmt_substatements = function
+ | STMT_Call _ ->
+ []
+
+ | STMT_Assign _ ->
+ []
+
+ | STMT_VarDecl _ ->
+ []
+
+ | STMT_If {then_branch; else_branch; _} ->
+ [then_branch] @ some2list else_branch
+
+ | STMT_While {body; _} ->
+ [body]
+
+ | STMT_Return _ ->
+ []
+
+ | STMT_MultiVarDecl _ ->
+ []
+
+ | STMT_Block block ->
+ block_substatements block
+
+
+ let rec verify_expression e =
+ check_tag (location_of_expression e) (tag_of_expression e);
+ let sube = expr_subexpressions e in
+ List.iter verify_expression sube
+
+ let rec verify_statement s =
+ let exprs = stmt_subexpressions s in
+ let stmts = stmt_substatements s in
+ List.iter verify_expression exprs;
+ List.iter verify_statement stmts
+
+ let verify_block_opt s =
+ let stmts = block_substatements_opt s in
+ List.iter verify_statement stmts
+
+
+ let verify_global_declaration = function
+ | GDECL_Function {body; _} ->
+ verify_block_opt body
+
+ let verify_module_definition (ModuleDefinition {global_declarations}) =
+ List.iter verify_global_declaration global_declarations
+
+ end
+
+ let verify_module_definition node2tag mdef =
+ try
+ let module Instance = Implementation(struct let node2type = node2tag end) in
+ Instance.verify_module_definition mdef;
+ true
+ with MissingTypeInformation e ->
+ Format.eprintf "Missing type information for expression %s\n%!" (string_of_location e);
+ false
+
+end \ No newline at end of file
diff --git a/source/xi/parser_wrapper.ml b/source/xi/parser_wrapper.ml
new file mode 100644
index 0000000..4b371c5
--- /dev/null
+++ b/source/xi/parser_wrapper.ml
@@ -0,0 +1,42 @@
+open Xi_lib
+open Iface
+
+module Make(LP:LEXER_AND_PARSER) = struct
+
+ module L = LP.Lexer
+
+ module P = LP.Parser
+
+ let open_file_lexbuf file =
+ let channel = open_in file in
+ let lexbuf = Lexing.from_channel channel in
+ (* Wpisujemy nazwe pliku (katalog ze ścieżki ucina Filename.basename)
+ * do lexbuf. Dzięki temu Parser_utils.makeLocation będzie mógł lokacje
+ * uzupełniać o prawidłową nazwę pliku.
+ *)
+ lexbuf.Lexing.lex_curr_p <- {
+ lexbuf.Lexing.lex_curr_p with
+ Lexing.pos_fname = Filename.basename file
+ };
+ lexbuf
+
+ let parse_lexbuf f lexbuf =
+ try
+ Ok (P.file L.token lexbuf);
+ with
+ | P.Error ->
+ let loc = Parser_utils.mkLocation lexbuf.Lexing.lex_curr_p in
+ let token = Lexing.lexeme lexbuf in
+ let s = if String.length token > 0
+ then Printf.sprintf "syntax error: unexpected token: %s" token
+ else Printf.sprintf "syntax error: unexpected end"
+ in
+ Error (loc, s)
+
+ | Parser_utils.InvalidToken (loc, str) ->
+ let s = Printf.sprintf "syntax error: invalid token: %s" str in
+ Error (loc, s)
+
+ let parse_file f = parse_lexbuf f (open_file_lexbuf f)
+end
+
diff --git a/source/xi/pipeline.ml b/source/xi/pipeline.ml
new file mode 100644
index 0000000..34a06f9
--- /dev/null
+++ b/source/xi/pipeline.ml
@@ -0,0 +1,137 @@
+open Xi_lib
+open Iface
+
+module type PARAMS = sig
+ val stop_point : string
+ val output: string
+end
+
+module Make(Steps:COMPILER_STEPS)(Params:PARAMS) = struct
+
+ module Hack = Xi_lib.Analysis
+
+ open Params
+ module Toolbox = Steps.Toolbox
+
+ module Parser_wrapper = Parser_wrapper.Make(Steps.LexerAndParser)
+
+ let check_stop_point name cont x =
+ if name = stop_point then Ok ()
+ else cont x
+
+
+ let describe_register_mapping mapping =
+ let describe_map k v xs =
+ let entry = Format.sprintf "%s -> %s" (Ir.string_of_reg k) (Ir.string_of_reg v) in
+ entry :: xs
+ in
+ String.concat "\n" @@ Hashtbl.fold describe_map mapping []
+
+ let dump_register_mapping proc_ir mapping =
+ Logger.dump_string "regmapping" @@ describe_register_mapping mapping
+
+ let dump_schedule proc_ir schedule =
+ let title = Format.sprintf "%s.schedule" (Ir_utils.string_of_procid @@ Ir.procid_of_procedure proc_ir) in
+ let output = Ir_utils.string_of_labellist schedule in
+ Logger.dump_string title output
+
+ module IrPhases = struct
+
+ let regalloc proc =
+ let register_mapping = Steps.RegisterAllocator.regalloc proc in
+ dump_register_mapping proc register_mapping;
+ Ir_utils.remap_registers_proc register_mapping proc
+
+ let scale_to_program f name ir =
+ let handle_proc proc =
+ Logger.new_phase_proc @@ Ir.procid_of_procedure proc;
+ Measure.measure name (fun () -> f proc);
+ Logger.dump_ir_proc "final.irproc" proc
+ in
+ Measure.measure ("whole " ^ name) (fun () ->
+ List.iter handle_proc @@ Ir.procedures_of_program ir;
+ Logger.close_phase_proc ()
+ );
+ Logger.dump_ir_program "final.ir" ir
+
+ let ir_phases =
+ [ "jump_threading", scale_to_program Steps.JumpThreading.jump_threading
+ ; "hi_lower", scale_to_program Steps.HiLower.lower
+ ; "constant_folding", scale_to_program Steps.ConstantFolding.fold_constants
+ ; "dead_code_elimination", scale_to_program Steps.DeadCodeElimination.eliminate_dead_code
+ ; "callconv", scale_to_program Steps.CallConv.callconv
+ ; "mips_lower", scale_to_program Steps.MipsLower.lower
+ ; "regalloc", scale_to_program regalloc
+ ; "dead_code_elimination", scale_to_program Steps.DeadCodeElimination.eliminate_dead_code
+ ]
+
+
+ let rec execute_ir_phases ir = function
+ | [] ->
+ ()
+ | (name, f)::rest ->
+ Logger.new_phase name;
+ f name ir;
+ execute_ir_phases ir rest
+
+ let transform_ir ir =
+ execute_ir_phases ir ir_phases
+
+ end
+
+ let finish result =
+ Format.printf "done\n";
+ let out = open_out output in
+ output_string out result;
+ output_string out "\n";
+ close_out out;
+ Ok ()
+
+ let codegen ir =
+ Logger.new_phase "codegen";
+ let schedule = Toolbox.Scheduler.schedule ir in
+ Hashtbl.iter dump_schedule schedule;
+ let assembler = Steps.Codegen.codegen schedule ir in
+ let result = Hardcoded.preamble ^ Mips32.string_of_program assembler in
+ Logger.dump_string "final" result;
+ finish result
+
+ let translate (ast, node2type) =
+ Logger.new_phase "translate";
+ let ir = Steps.Translator.translate_module ast node2type in
+ Logger.dump_ir_program "translated.ir" ir;
+ IrPhases.transform_ir ir;
+ codegen ir
+
+ let type_check ast =
+ Logger.new_phase "typechecking";
+ match Steps.Typechecker.check_module ast with
+ | Error xs ->
+ let xs = List.map Typechecker_errors.string_of_type_checking_error xs in
+ List.iter prerr_endline xs;
+ Error "typechecker"
+ | Ok (node2type) ->
+ if Invariants.AllExpressionsAreTypecheck.verify_module_definition node2type ast then
+ check_stop_point "typechecker" translate (ast, node2type)
+ else
+ Error "typechecker"
+
+
+ let parse_step source =
+ Logger.new_phase "parsing";
+ match Parser_wrapper.parse_file source with
+ | Error (loc, descr) ->
+ Format.printf "%s: %s\n%!" (Ast.string_of_location loc) descr;
+ Error "parser"
+
+ | Ok ok ->
+ let ast_str = Ast_printer.show_module_definition ok in
+ Logger.dump_string "ast" ast_str;
+ let ast_str = Ast_rawprinter.show_module_definition ok in
+ Logger.dump_string "raw.ast" ast_str;
+ check_stop_point "parser" type_check ok
+
+
+ let compile =
+ parse_step
+end
diff --git a/source/xi/plugin_manager.ml b/source/xi/plugin_manager.ml
new file mode 100644
index 0000000..3c6cdf0
--- /dev/null
+++ b/source/xi/plugin_manager.ml
@@ -0,0 +1,245 @@
+open Xi_lib
+open Plugin_register
+
+type plugin = string * (module Plugin.PLUGIN)
+
+module Getters = struct
+
+ let make_live_variables_analysis (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_live_variables_analysis with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_dominators_analysis (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_dominators_analysis with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_reachability_analysis (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_reachability_analysis with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_scheduler (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_scheduler with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_natural_loops_analysis (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_natural_loops_analysis with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_spill_costs_analysis (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_spill_costs_analysis with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let lexer_and_parser (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.lexer_and_parser with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_typechecker (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_typechecker with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_translator (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_translator with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_jump_threading (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_jump_threading with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_constant_folding (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_constant_folding with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_hilower (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_hilower with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_callconv (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_callconv with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_mipslower (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_mipslower with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_register_allocator (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_register_allocator with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_dead_code_elimination (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_dead_code_elimination with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_codegen (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_codegen with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_constant_folding_analysis (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_constant_folding_analysis with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_interference_graph_analysis (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_interference_graph_analysis with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+
+ let make_spilling (name, plugin) =
+ let module Plugin = (val plugin : Plugin.PLUGIN) in
+ match Plugin.make_spilling with
+ | Some x -> Some (name, Plugin.version, x)
+ | None -> None
+end
+
+module Resolver = struct
+
+ let rec find_module name getter = function
+ | [] ->
+ failwith @@ Format.sprintf "Cannot find %s" name
+ | x::xs ->
+ match getter x with
+ | Some (modname, version, impl) ->
+ Format.eprintf "module %s=%s:%s\n%!" name modname version;
+ impl
+ | None ->
+ find_module name getter xs
+
+ let make_live_variables_analysis = find_module "MakeLiveVariablesAnalysis" Getters.make_live_variables_analysis
+
+ let make_dominators_analysis = find_module "MakeDominanceAnalysis" Getters.make_dominators_analysis
+
+ let make_reachability_analysis = find_module "MakeReachabilityAnalysis" Getters.make_reachability_analysis
+
+ let make_scheduler = find_module "MakeScheduler" Getters.make_scheduler
+
+ let make_natural_loops_analysis = find_module "MakeNaturalLoopsAnalysis" Getters.make_natural_loops_analysis
+
+ let make_spill_costs_analysis = find_module "MakeSpillCostsAnalysis" Getters.make_spill_costs_analysis
+
+ let lexer_and_parser = find_module "LexerAndParser" Getters.lexer_and_parser
+
+ let make_typechecker = find_module "MakeTypechecker" Getters.make_typechecker
+
+ let make_translator = find_module "MakeTranslator" Getters.make_translator
+
+ let make_jump_threading = find_module "MakeJumpThreading" Getters.make_jump_threading
+
+ let make_constant_folding = find_module "MakeConstantFolding" Getters.make_constant_folding
+
+ let make_hilower = find_module "MakeHiLower" Getters.make_hilower
+
+ let make_callconv = find_module "MakeCallConv" Getters.make_callconv
+
+ let make_mipslower = find_module "MakeMipsLower" Getters.make_mipslower
+
+ let make_register_allocator = find_module "MakeRegisterAllocator" Getters.make_register_allocator
+
+ let make_dead_code_elimination = find_module "MakeDeadCodeElimination" Getters.make_dead_code_elimination
+
+ let make_codegen = find_module "MakeCodegen" Getters.make_codegen
+
+ let make_constant_folding_analysis = find_module "MakeConstantFoldingAnalysis" Getters.make_constant_folding_analysis
+
+ let make_interference_graph_analysis = find_module "MakeInterferenceGraphAnalysis" Getters.make_interference_graph_analysis
+
+ let make_spilling = find_module "MakeSpilling" Getters.make_spilling
+
+end
+
+let resolve_compiler_toolbox regdescr =
+ let module MakeLiveVariablesAnalysis = (val Resolver.make_live_variables_analysis !register) in
+ let module MakeDominatorsAnalysis = (val Resolver.make_dominators_analysis !register) in
+ let module MakeNaturalLoopsAnalysis = (val Resolver.make_natural_loops_analysis !register) in
+ let module MakeSpillCostsAnalysis = (val Resolver.make_spill_costs_analysis !register) in
+ let module MakeScheduler = (val Resolver.make_scheduler !register) in
+ let module MakeConstantFoldingAnalysis = (val Resolver.make_constant_folding_analysis !register) in
+ let module MakeInterferenceGraphAnalysis = (val Resolver.make_interference_graph_analysis !register) in
+ let module MakeSpilling = (val Resolver.make_spilling !register) in
+ let module MakeReachabilityAnalysis = (val Resolver.make_reachability_analysis !register) in
+ let module M = struct
+ module LiveVariablesAnalysis = MakeLiveVariablesAnalysis()
+ module DominatorsAnalysis = MakeDominatorsAnalysis()
+ module Scheduler = MakeScheduler()
+ module NaturalLoopsAnalysis = MakeNaturalLoopsAnalysis()
+ module SpillCostsAnalysis = MakeSpillCostsAnalysis()
+ module RegistersDescription = (val regdescr : Ir_arch.REGISTERS_DESCRIPTION)
+ module ConstantFoldingAnalysis = MakeConstantFoldingAnalysis()
+ module InterferenceGraphAnalysis = MakeInterferenceGraphAnalysis()
+ module Spilling = MakeSpilling()
+ module ReachabilityAnalysis = MakeReachabilityAnalysis()
+ end in
+ (module M : Iface.COMPILER_TOOLBOX)
+
+let resolve_compiler_steps regdescr =
+ let module CompilerToolbox = (val resolve_compiler_toolbox regdescr : Iface.COMPILER_TOOLBOX) in
+ let module LexerAndParser = (val Resolver.lexer_and_parser !register) in
+ let module MakeTypechecker = (val Resolver.make_typechecker !register) in
+ let module MakeTranslator = (val Resolver.make_translator !register) in
+ let module MakeJumpThreading = (val Resolver.make_jump_threading !register) in
+ let module MakeConstantFolding = (val Resolver.make_constant_folding !register) in
+ let module MakeHiLower = (val Resolver.make_hilower !register) in
+ let module MakeCallConv = (val Resolver.make_callconv !register) in
+ let module MakeMipsLower = (val Resolver.make_mipslower !register) in
+ let module MakeRegisterAllocator = (val Resolver.make_register_allocator !register) in
+ let module MakeDeadCodeElimination = (val Resolver.make_dead_code_elimination !register) in
+ let module MakeCodegen = (val Resolver.make_codegen !register) in
+
+ let module Steps = struct
+ module Toolbox = CompilerToolbox
+ module LexerAndParser = LexerAndParser
+ module Typechecker = MakeTypechecker()
+ module Translator = MakeTranslator()
+ module JumpThreading = MakeJumpThreading()
+ module HiLower = MakeHiLower(CompilerToolbox)
+ module CallConv = MakeCallConv(CompilerToolbox)
+ module MipsLower = MakeMipsLower(CompilerToolbox)
+ module RegisterAllocator = MakeRegisterAllocator(CompilerToolbox)
+ module ConstantFolding = MakeConstantFolding(CompilerToolbox)
+ module DeadCodeElimination = MakeDeadCodeElimination(CompilerToolbox)
+ module Codegen = MakeCodegen(CompilerToolbox)
+ end in
+
+ (module Steps : Iface.COMPILER_STEPS)
+
+let load_plugin path =
+ try
+ Plugin_register.current_file := Filename.basename path;
+ Dynlink.loadfile path;
+ Plugin_register.current_file := "";
+ with Dynlink.Error e ->
+ failwith @@ Format.sprintf "Cannot load plugin '%s': %s" path (Dynlink.error_message e) \ No newline at end of file
diff --git a/source/xi/xi.ml b/source/xi/xi.ml
new file mode 100644
index 0000000..86a23f1
--- /dev/null
+++ b/source/xi/xi.ml
@@ -0,0 +1,82 @@
+open Xi_lib
+
+
+module CommandLine = struct
+ open Cmdliner
+
+ let compile xi_log extra_debug mod_uwr plugin reg_descr stop_after output source =
+ Logger.init xi_log;
+ Logger.set_extra_debug extra_debug;
+ Plugin_manager.load_plugin mod_uwr;
+ let reg_descr = match List.assoc_opt reg_descr Ir_arch.descriptions with
+ | Some reg_descr -> reg_descr
+ | None -> failwith "Unknown registers description"
+ in
+ begin match plugin with
+ | Some path ->
+ Plugin_manager.load_plugin path
+ | None ->
+ ()
+ end;
+ let module Steps = (val Plugin_manager.resolve_compiler_steps reg_descr) in
+ let module Params = struct
+ let output = output
+ let stop_point = match stop_after with
+ | Some s -> s
+ | None -> ""
+ end in
+ let module Pipeline = Pipeline.Make(Steps)(Params) in
+ match Pipeline.compile source with
+ | Ok () ->
+ 0
+ | Error xs ->
+ Format.eprintf "Failed: %s\n%!" xs;
+ 1
+
+ let stop_after =
+ let doc = "Stops compiler after given phase" in
+ Arg.(value & opt (some string) None & info ["stop-after"] ~doc)
+
+ let mod_uwr =
+ let doc = "Base module" in
+ Arg.(value & opt string "xisdk/mod_uwr.cma" & info ["mod-uwr"] ~doc)
+
+ let reg_descr =
+ let doc = "EXPERIMENTAL: Registers description (see Ir_arch.descriptions)" in
+ Arg.(value & opt string "normal" & info ["registers-description"] ~doc)
+
+ let plugin =
+ let doc = "Plugin module" in
+ Arg.(value & opt (some string) None & info ["plugin"] ~doc)
+
+ let output =
+ let doc = "Output file" in
+ Arg.(value & opt string "main.s" & info ["o"; "output"] ~doc)
+
+ let xi_log =
+ let doc = "Log directory" in
+ Arg.(value & opt string "xilog" & info ["xi-log"] ~doc)
+
+ let runtime =
+ let doc = "Runtime" in
+ Arg.(value & opt file "xisdk/runtime.s" & info ["runtime"] ~doc)
+
+ let extra_debug =
+ let doc = "Enables extra debug" in
+ Arg.(value & flag & info ["extra-debug"] ~doc)
+
+ let source_file =
+ let doc = "Xi Source File" in
+ Arg.(required & pos 0 (some file) None & info [] ~doc)
+
+
+ let cmd =
+ let doc = "Compile Xi Program" in
+ let version = "pracownia1.1-0-gc10b4f2" in
+ Term.(const compile $ xi_log $ extra_debug $ mod_uwr $ plugin $ reg_descr $ stop_after $ output $ source_file),
+ Term.info "xi" ~doc ~version
+
+
+ let () = Term.(exit_status @@ eval cmd)
+
+end
diff --git a/source/xi_lib/.merlin b/source/xi_lib/.merlin
new file mode 100644
index 0000000..e44069f
--- /dev/null
+++ b/source/xi_lib/.merlin
@@ -0,0 +1,5 @@
+B /home/wieczyk/.opam/4.07.0/lib/ocamlgraph
+B ../../_build/default/source/xi_lib/.xi_lib.objs
+S /home/wieczyk/.opam/4.07.0/lib/ocamlgraph
+S .
+FLG -open Xi_lib -w @a-4-29-40-41-42-44-45-48-58-59-60-40 -strict-sequence -strict-formats -short-paths -keep-locs
diff --git a/source/xi_lib/analysis.ml b/source/xi_lib/analysis.ml
new file mode 100644
index 0000000..ac15cb5
--- /dev/null
+++ b/source/xi_lib/analysis.ml
@@ -0,0 +1,77 @@
+module Knowledge = struct
+
+ type 'a t =
+ { pre: 'a
+ ; post: 'a
+ }
+
+ let pre t = t.pre
+
+ let post t = t.post
+
+ let alter ?pre ?post t =
+ let t = match pre with
+ | Some pre -> {t with pre = pre}
+ | None -> t
+ in
+ let t = match post with
+ | Some post -> {t with post = post}
+ | None -> t
+ in
+ t
+
+ let make pre post : 'a t = {pre; post}
+
+ type 'a table = (Ir.label, 'a t) Hashtbl.t
+
+end
+
+module BlockKnowledge = struct
+
+ type 'a t =
+ | Simple of 'a Knowledge.t
+ | Complex of
+ { block: 'a Knowledge.t
+ ; body: ('a Knowledge.t * Ir.instr) list
+ ; terminator: 'a Knowledge.t * Ir.terminator
+ }
+
+ let block = function
+ | Simple t -> t
+ | Complex {block; _} -> block
+
+ let pre t = Knowledge.pre @@ block t
+ let post t = Knowledge.post @@ block t
+
+ let terminator = function
+ | Simple _ -> failwith "BlockKnowledge.terminator"
+ | Complex t-> t.terminator
+
+ let body = function
+ | Simple _ -> failwith "BlockKnowledge.body"
+ | Complex t -> t.body
+
+ let terminator_instr t = snd @@ terminator t
+
+ let terminator_kw t = fst @@ terminator t
+
+ let make_complex ~block ~body ~terminator =
+ Complex { block; body; terminator }
+
+ let make_simple t = Simple t
+
+ type 'a table = (Ir.label, 'a t) Hashtbl.t
+
+ let alter_prepost ?pre ?post = function
+ | Simple t ->
+ Simple (Knowledge.alter ?pre ?post t)
+
+ | Complex {block; body; terminator} ->
+ let block = Knowledge.alter ?pre ?post block in
+ Complex {block; body; terminator}
+
+ let is_complex = function
+ | Complex _ -> true
+ | Simple _ -> false
+
+end
diff --git a/source/xi_lib/analysis_domain.ml b/source/xi_lib/analysis_domain.ml
new file mode 100644
index 0000000..9f49a3e
--- /dev/null
+++ b/source/xi_lib/analysis_domain.ml
@@ -0,0 +1,135 @@
+
+module MapWithTop(M:Map.S) = struct
+
+ type 'v t =
+ | Top
+ | Map of 'v M.t
+
+ let equal a b = match a,b with
+ | Top, Top ->
+ true
+ | Top, _
+ | _, Top ->
+ false
+ | Map a, Map b ->
+ M.equal (=) a b
+
+ let less_or_equal a b = match a,b with
+ | _, Top ->
+ true
+
+ | Top, _ ->
+ false
+
+ | Map a, Map b ->
+ let check (k, v) =
+ match M.find_opt k b with
+ | Some v' -> v = v'
+ | None -> false
+ in
+ let a_items = M.to_seq a in
+ let checks = Seq.map check a_items in
+ Seq.fold_left (&&) true checks
+
+ let greater_or_equal a b = less_or_equal b a
+
+ let unhask dfl = function
+ | Top -> dfl
+ | Map m -> m
+
+end
+
+module SetWithTop(M:Set.S) = struct
+
+ type t =
+ | Top
+ | Set of M.t
+
+ let equal a b = match a,b with
+ | Top, Top ->
+ true
+ | Top, _
+ | _, Top ->
+ false
+ | Set a, Set b ->
+ M.equal a b
+
+ let less_or_equal a b = match a,b with
+ | _, Top ->
+ true
+
+ | Top, _ ->
+ false
+
+ | Set a, Set b ->
+ M.subset a b
+
+ let greater_or_equal a b = less_or_equal b a
+
+ let unhask dfl = function
+ | Top -> dfl
+ | Set m -> m
+
+end
+
+
+module LiveVariables = struct
+
+ type domain = Ir.RegSet.t
+
+ type table = domain Analysis.BlockKnowledge.table
+
+ type block_knowledge = domain Analysis.BlockKnowledge.t
+
+ let string_of_domain x = Ir_utils.string_of_reglist @@ List.of_seq @@ Ir.RegSet.to_seq x
+end
+
+module InterferenceGraph = struct
+
+ type graph = Ir.RegGraph.t
+
+end
+
+module ConstantFolding = struct
+
+ type domain = Ir.expr option Ir.RegMap.t
+
+ type table = domain Analysis.BlockKnowledge.table
+
+ type block_knowledge = domain Analysis.BlockKnowledge.t
+
+ let string_of_el = function
+ | None -> "T"
+ | Some a -> Ir_utils.string_of_expr a
+
+ let string_of_domain dom =
+ let f (k,v) = Format.sprintf "%s=%s" (Ir.string_of_reg k) (string_of_el v) in
+ let seq = Ir.RegMap.to_seq dom in
+ let seq = Seq.map f seq in
+ String.concat " " @@ List.of_seq seq
+
+end
+
+module DominatorsAnalysis = struct
+
+ module D = SetWithTop(Ir.LabelSet)
+
+ type t = D.t
+
+ type table = t Analysis.BlockKnowledge.table
+
+ let unhask = D.unhask Ir.LabelSet.empty
+
+end
+
+module NaturalLoops = struct
+
+ type table = (Ir.label, Ir.LabelSet.t) Hashtbl.t
+
+end
+
+module ReachabilityAnalysis = struct
+
+ type table = Ir.LabelSet.t Analysis.BlockKnowledge.table
+
+end \ No newline at end of file
diff --git a/source/xi_lib/analysis_visualizer.ml b/source/xi_lib/analysis_visualizer.ml
new file mode 100644
index 0000000..6c8ccf3
--- /dev/null
+++ b/source/xi_lib/analysis_visualizer.ml
@@ -0,0 +1,295 @@
+open Ir
+open Ir_utils
+open Analysis
+
+module type DOMAIN = sig
+
+ type domain
+
+ val string_of_domain: domain -> string
+
+end
+
+module type DOMAIN_AND_BLOCK_ANALYSIS = sig
+
+ include DOMAIN
+
+
+ val analyse_block: ControlFlowGraph.t -> domain Knowledge.table -> label -> domain BlockKnowledge.t
+
+end
+
+(*
+module TableVisualizer = struct
+
+ let stringize_table (to_string: 'a -> string) result =
+ let new_result = Hashtbl.create 513 in
+ let f k v =
+ let kw = Knowledge.make (to_string @@ Knowledge.pre v) (to_string @@ Knowledge.post v) in
+ Hashtbl.replace new_result k kw
+ in
+ Hashtbl.iter f result;
+ new_result
+
+ let stringize_full_table (to_string: 'a -> string) result =
+ let visualize_kw v = Knowledge.make (to_string @@ Knowledge.pre v) (to_string @@ Knowledge.post v) in
+ let visualize_instr (kw, instr) = (visualize_kw kw, instr) in
+ let visualize_body = List.map visualize_instr in
+ let visualize_terminator (kw, terminator) = (visualize_kw kw, terminator) in
+ let new_result = Hashtbl.create 513 in
+ let f k v =
+ let pre = to_string @@ BlockKnowledge.pre v in
+ let post = to_string @@ BlockKnowledge.post v in
+ let body = visualize_body @@ BlockKnowledge.body v in
+ let terminator = visualize_terminator @@ BlockKnowledge.terminator v in
+ Hashtbl.replace new_result k @@ BlockKnowledge.make ~pre ~post ~body ~terminator
+ in
+ Hashtbl.iter f result;
+ new_result
+
+
+end
+*)
+
+module NgMakeGraphvizVisualizer(D:DOMAIN) = struct
+
+ let visualise_instr (pre, post, instr) =
+ let instr = string_of_instr instr in
+ String.concat "\n"
+ [
+ Format.sprintf "<tr><td>%s</td><td align='left'><b>%s</b></td><td>%s</td></tr>" pre instr post
+ ]
+
+ let visualise_terminator (pre, post, t) =
+ let t = string_of_terminator t in
+ String.concat "\n"
+ [
+ Format.sprintf "<tr><td>%s</td><td bgcolor='green' ><b>%s</b></td><td>%s</td></tr>" pre t post
+ ]
+
+ let block_template_pre pre name =
+ [ Format.sprintf "<table cellspacing='0' cellborder='1' align='left' border='0'>"
+ ; Format.sprintf "<tr><td colspan='3' port='e' bgcolor='yellow'><b>%s</b></td></tr>" name
+ ; Format.sprintf "<tr><td colspan='3'>%s</td></tr>" @@ pre
+ ]
+
+ let block_template_post post =
+ [ Format.sprintf "<tr><td colspan='3' port='x'>%s</td></tr>" post
+ ; Format.sprintf "</table>"
+ ]
+
+ let block_template name pre post body =
+ String.concat "" @@ List.flatten
+ [ block_template_pre pre name
+ ; body
+ ; block_template_post post
+ ]
+
+ let stringize_body body =
+ let f (kw, instr) =
+ let pre = D.string_of_domain @@ Knowledge.pre kw in
+ let post = D.string_of_domain @@ Knowledge.post kw in
+ (pre, post, instr)
+ in
+ List.map f body
+
+ let artificial_body body =
+ let f instr =
+ ("", "", instr)
+ in
+ List.map f body
+
+
+ let stringize_terminator (kw, terminator) =
+ let pre = D.string_of_domain @@ Knowledge.pre kw in
+ let post = D.string_of_domain @@ Knowledge.post kw in
+ (pre, post, terminator)
+
+ let artificial_terminator terminator =
+ ("", "", terminator)
+
+ let prepare_block bb_kw body terminator =
+ if BlockKnowledge.is_complex bb_kw then
+ let sbody = stringize_body @@ BlockKnowledge.body bb_kw in
+ let sterm = stringize_terminator @@ BlockKnowledge.terminator bb_kw in
+ sbody, sterm
+ else
+ let sbody = artificial_body body in
+ let sterm = artificial_terminator terminator in
+ sbody, sterm
+
+ let compute_block_label cfg table v =
+ let v_str = string_of_label v in
+ let kw = Hashtbl.find table v in
+ let pre = D.string_of_domain @@ BlockKnowledge.pre kw in
+ let post = D.string_of_domain @@ BlockKnowledge.post kw in
+ if v = ControlFlowGraph.entry_label cfg then
+ block_template (Format.sprintf "ENTRY %s" v_str) pre post []
+ else if v = ControlFlowGraph.exit_label cfg then
+ block_template (Format.sprintf "EXIT %s" v_str) pre post []
+ else
+ let body = ControlFlowGraph.block cfg v in
+ let terminator = ControlFlowGraph.terminator cfg v in
+ let sbody, sterm = prepare_block kw body terminator in
+ let body = List.flatten
+ [ List.map visualise_instr sbody
+ ; [visualise_terminator sterm]
+ ] in
+ block_template (Format.sprintf "BLOCK %s" v_str) pre post body
+
+
+ let describe_vertex cfg table v =
+ Format.sprintf "N%s[shape=none, margin=0, label=<%s>];"
+ (string_of_label v)
+ (compute_block_label cfg table v)
+
+ let describe_outedges cfg v =
+ let describe_edge w =
+ Format.sprintf "N%s:x -> N%s:e;" (string_of_label v) (string_of_label w)
+ in
+ String.concat "\n" @@ List.map describe_edge @@ ControlFlowGraph.successors cfg v
+
+ let visualize cfg table =
+ let labels = ControlFlowGraph.labels cfg in
+ let vertices = String.concat "\n" @@ List.map (describe_vertex cfg table) labels in
+ let edges = String.concat "\n" @@ List.map (describe_outedges cfg) labels in
+ String.concat "\n"
+ [ "digraph CFG {"
+ ; "node [shape=none; fontname=\"Courier\" fontsize=\"9\"];"
+ ; "ordering=out;"
+ ; vertices
+ ; edges
+ ; "}"
+ ]
+
+end
+
+module MakeGraphvizVisualizer(D:DOMAIN_AND_BLOCK_ANALYSIS) = struct
+
+ let visualise_instr (kw, instr) =
+ let pre = D.string_of_domain @@ Knowledge.pre kw in
+ let post = D.string_of_domain @@ Knowledge.post kw in
+ let instr = string_of_instr instr in
+ String.concat "\n"
+ [
+ Format.sprintf "<tr><td>%s</td><td align='left'><b>%s</b></td><td>%s</td></tr>" pre instr post
+ ]
+
+ let visualise_terminator (kw, t) =
+ let pre = D.string_of_domain @@ Knowledge.pre kw in
+ let post = D.string_of_domain @@ Knowledge.post kw in
+ let t = string_of_terminator t in
+ String.concat "\n"
+ [
+ Format.sprintf "<tr><td>%s</td><td bgcolor='green' ><b>%s</b></td><td>%s</td></tr>" pre t post
+ ]
+
+ let block_template_pre pre name =
+ [ Format.sprintf "<table cellspacing='0' cellborder='1' align='left' border='0'>"
+ ; Format.sprintf "<tr><td colspan='3' port='e' bgcolor='yellow'><b>%s</b></td></tr>" name
+ ; Format.sprintf "<tr><td colspan='3'>%s</td></tr>" @@ pre
+ ]
+
+ let block_template_post post =
+ [ Format.sprintf "<tr><td colspan='3' port='x'>%s</td></tr>" post
+ ; Format.sprintf "</table>"
+ ]
+
+ let block_template name pre post body =
+ String.concat "" @@ List.flatten
+ [ block_template_pre pre name
+ ; body
+ ; block_template_post post
+ ]
+
+ let compute_block_label cfg table v =
+ let v_str = string_of_label v in
+ let kw = Hashtbl.find table v in
+ let pre = D.string_of_domain @@ Knowledge.pre kw in
+ let post = D.string_of_domain @@ Knowledge.post kw in
+ if v = ControlFlowGraph.entry_label cfg then
+ block_template (Format.sprintf "ENTRY %s" v_str) pre post []
+ else if v = ControlFlowGraph.exit_label cfg then
+ block_template (Format.sprintf "EXIT %s" v_str) pre post []
+ else
+ let bb_kw = D.analyse_block cfg table v in
+ let body = List.flatten
+ [ List.map visualise_instr (BlockKnowledge.body bb_kw)
+ ; [visualise_terminator (BlockKnowledge.terminator bb_kw)]
+ ] in
+ block_template (Format.sprintf "BLOCK %s" v_str) pre post body
+
+
+ let describe_vertex cfg table v =
+ Format.sprintf "N%s[shape=none, margin=0, label=<%s>];"
+ (string_of_label v)
+ (compute_block_label cfg table v)
+
+ let describe_outedges cfg v =
+ let describe_edge w =
+ Format.sprintf "N%s:x -> N%s:e;" (string_of_label v) (string_of_label w)
+ in
+ String.concat "\n" @@ List.map describe_edge @@ ControlFlowGraph.successors cfg v
+
+ let visualize cfg table =
+ let labels = ControlFlowGraph.labels cfg in
+ let vertices = String.concat "\n" @@ List.map (describe_vertex cfg table) labels in
+ let edges = String.concat "\n" @@ List.map (describe_outedges cfg) labels in
+ String.concat "\n"
+ [ "digraph CFG {"
+ ; "node [shape=none; fontname=\"Courier\" fontsize=\"9\"];"
+ ; "ordering=out;"
+ ; vertices
+ ; edges
+ ; "}"
+ ]
+
+end
+
+module VisualiseRegGraph = struct
+
+ let reg_to_name = function
+ | REG_Hard i -> Format.sprintf "H%u" i
+ | REG_Tmp i -> Format.sprintf "T%u" i
+ | REG_Spec i -> Format.sprintf "S%u" i
+
+ let describe_vertex v =
+ Format.sprintf "%s[label=\"%s\"];" (reg_to_name v) (string_of_reg v)
+
+ let describe_edge a b =
+ Format.sprintf "%s -- %s;" (reg_to_name a) (reg_to_name b)
+
+ let describe_vertices graph =
+ String.concat "\n" @@ RegGraph.fold_vertex (fun r xs -> describe_vertex r :: xs) graph []
+
+ let describe_edges graph =
+ String.concat "\n" @@ RegGraph.fold_edges (fun a b xs -> describe_edge a b :: xs) graph []
+
+ let visualise_graph reggraph =
+ String.concat "\n"
+ [ "graph INF {"
+ ; "layout=circo;"
+ ; describe_vertices reggraph
+ ; describe_edges reggraph
+ ; "}"
+ ]
+
+end
+
+module Lva_Graphviz = NgMakeGraphvizVisualizer(struct
+ type domain = Analysis_domain.LiveVariables.domain
+ let string_of_domain = Analysis_domain.LiveVariables.string_of_domain
+end)
+
+module Cfa_Graphviz = NgMakeGraphvizVisualizer(struct
+ type domain = Analysis_domain.ConstantFolding.domain
+ let string_of_domain = Analysis_domain.ConstantFolding.string_of_domain
+end)
+
+let visualize_live_variables = Lva_Graphviz.visualize
+
+
+let visualize_interference_graph = VisualiseRegGraph.visualise_graph
+
+
+let visualize_constant_folding = Cfa_Graphviz.visualize
diff --git a/source/xi_lib/ast.ml b/source/xi_lib/ast.ml
new file mode 100644
index 0000000..3123af7
--- /dev/null
+++ b/source/xi_lib/ast.ml
@@ -0,0 +1,288 @@
+
+type location = Location of { line: int; column: int; file: string }
+
+let string_of_location (Location {line;column;file}) =
+ Format.sprintf "%s:%u:%u" file line column
+
+type identifier
+ = Identifier of string
+
+let string_of_identifier (Identifier i) = i
+
+type node_tag =
+ NodeTag of int
+
+let string_of_node_tag (NodeTag i) =
+ Format.sprintf "%%node%i" i
+
+type binop =
+ | BINOP_And
+ | BINOP_Or
+ | BINOP_Add
+ | BINOP_Sub
+ | BINOP_Mult
+ | BINOP_Div
+ | BINOP_Rem
+
+let string_of_binop = function
+ | BINOP_And -> "&"
+ | BINOP_Or -> "|"
+ | BINOP_Add -> "+"
+ | BINOP_Sub -> "-"
+ | BINOP_Mult -> "*"
+ | BINOP_Div -> "/"
+ | BINOP_Rem -> "%"
+
+type relop =
+ | RELOP_Eq
+ | RELOP_Ne
+ | RELOP_Lt
+ | RELOP_Gt
+ | RELOP_Le
+ | RELOP_Ge
+
+let string_of_relop = function
+ | RELOP_Eq -> "=="
+ | RELOP_Ne -> "!="
+ | RELOP_Lt -> "<"
+ | RELOP_Gt -> ">"
+ | RELOP_Ge -> ">="
+ | RELOP_Le -> "<="
+
+type unop =
+ | UNOP_Not
+ | UNOP_Neg
+
+type type_expression =
+ | TEXPR_Int of
+ { loc:location
+ }
+
+ | TEXPR_Bool of
+ { loc:location
+ }
+
+ | TEXPR_Array of
+ { loc:location
+ ; sub:type_expression
+ ; dim:expression option
+ }
+
+and expression =
+ | EXPR_Id of
+ { tag:node_tag
+ ; loc:location
+ ; id:identifier
+ }
+
+ | EXPR_Int of
+ { tag:node_tag
+ ; loc:location
+ ; value:Int32.t
+ }
+
+ | EXPR_Char of
+ { tag:node_tag
+ ; loc:location
+ ; value:Char.t
+ }
+
+ | EXPR_String of
+ { tag:node_tag
+ ; loc:location
+ ; value:string
+ }
+
+ | EXPR_Bool of
+ { tag:node_tag
+ ; loc:location
+ ; value:bool
+ }
+
+ | EXPR_Relation of
+ { tag:node_tag
+ ; loc:location
+ ; op:relop
+ ; lhs:expression
+ ; rhs:expression
+ }
+
+ | EXPR_Binop of
+ { tag:node_tag
+ ; loc:location
+ ; op:binop
+ ; lhs:expression
+ ; rhs:expression
+ }
+
+ | EXPR_Length of
+ { tag:node_tag
+ ; loc:location
+ ; arg:expression
+ }
+
+ | EXPR_Unop of
+ { tag:node_tag
+ ; loc:location
+ ; op:unop
+ ; sub:expression
+ }
+
+ | EXPR_Call of
+ call
+
+ | EXPR_Index of
+ { tag:node_tag
+ ; loc:location
+ ; expr:expression
+ ; index:expression
+ }
+
+ | EXPR_Struct of
+ { tag:node_tag
+ ; loc:location
+ ; elements: expression list
+ }
+
+and call =
+ | Call of
+ { tag:node_tag
+ ; loc:location
+ ; callee:identifier
+ ; arguments:expression list
+ }
+
+
+let location_of_expression = function
+ | EXPR_Id {loc; _} -> loc
+ | EXPR_Struct {loc; _} -> loc
+ | EXPR_Index {loc; _} -> loc
+ | EXPR_Call (Call {loc; _}) -> loc
+ | EXPR_Unop {loc; _} -> loc
+ | EXPR_Binop {loc; _} -> loc
+ | EXPR_Relation {loc; _} -> loc
+ | EXPR_Length {loc; _} -> loc
+ | EXPR_Int {loc; _} -> loc
+ | EXPR_Char {loc; _} -> loc
+ | EXPR_Bool {loc; _} -> loc
+ | EXPR_String {loc; _} -> loc
+
+let tag_of_expression = function
+ | EXPR_Id {tag; _} -> tag
+ | EXPR_Struct {tag; _} -> tag
+ | EXPR_Index {tag; _} -> tag
+ | EXPR_Call (Call {tag; _}) -> tag
+ | EXPR_Unop {tag; _} -> tag
+ | EXPR_Binop {tag; _} -> tag
+ | EXPR_Relation {tag; _} -> tag
+ | EXPR_Length {tag; _} -> tag
+ | EXPR_Int {tag; _} -> tag
+ | EXPR_Char {tag; _} -> tag
+ | EXPR_Bool {tag; _} -> tag
+ | EXPR_String {tag; _} -> tag
+
+let location_of_call (Call {loc; _}) = loc
+
+let identifier_of_call (Call {callee; _}) = callee
+
+type var_declaration =
+ | VarDecl of
+ { loc:location
+ ; id:identifier
+ ; tp:type_expression
+ }
+
+let location_of_var_declaration (VarDecl {loc; _}) = loc
+let identifier_of_var_declaration (VarDecl {id; _}) = id
+let type_expression_of_var_declaration (VarDecl {tp; _}) = tp
+
+module IdMap = Map.Make(struct
+ type t = identifier
+
+ let compare = compare
+ end)
+
+type lvalue =
+ | LVALUE_Id of
+ { loc:location
+ ; id:identifier
+ }
+
+ | LVALUE_Index of
+ { loc:location
+ ; sub:expression
+ ; index:expression
+ }
+
+type statement =
+ | STMT_Call of
+ call
+
+ | STMT_Assign of
+ { loc:location
+ ; lhs:lvalue
+ ; rhs:expression
+ }
+
+ | STMT_VarDecl of
+ { var:var_declaration
+ ; init:expression option
+ }
+
+ | STMT_If of
+ { loc:location
+ ; cond:expression
+ ; then_branch: statement
+ ; else_branch: statement option
+ }
+
+ | STMT_While of
+ { loc:location
+ ; cond:expression
+ ; body: statement
+ }
+
+ | STMT_Return of
+ { loc:location
+ ; values:expression list
+ }
+
+ | STMT_MultiVarDecl of
+ { loc:location
+ ; vars:var_declaration option list
+ ; init:call
+ }
+
+ | STMT_Block of
+ statement_block
+
+and statement_block =
+ | STMTBlock of
+ { loc:location
+ ; body: statement list
+ }
+
+let location_of_block (STMTBlock {loc; _}) = loc
+
+let location_of_statement = function
+ | STMT_Assign {loc; _} -> loc
+ | STMT_While {loc; _} -> loc
+ | STMT_Call call -> location_of_call call
+ | STMT_Block block -> location_of_block block
+ | STMT_Return {loc; _} -> loc
+ | STMT_VarDecl {var; _} -> location_of_var_declaration var
+ | STMT_MultiVarDecl {loc; _} -> loc
+ | STMT_If {loc; _} -> loc
+
+type global_declaration =
+ | GDECL_Function of
+ { loc:location
+ ; id:identifier
+ ; formal_parameters:var_declaration list
+ ; return_types:type_expression list
+ ; body:statement_block option
+ }
+
+type module_definition = ModuleDefinition of
+ { global_declarations: global_declaration list
+ }
diff --git a/source/xi_lib/ast_printer.ml b/source/xi_lib/ast_printer.ml
new file mode 100644
index 0000000..67b4dd5
--- /dev/null
+++ b/source/xi_lib/ast_printer.ml
@@ -0,0 +1,271 @@
+open Ast
+
+
+let string_of_binop = function
+ | BINOP_And -> "&"
+ | BINOP_Or -> "|"
+ | BINOP_Add -> "+"
+ | BINOP_Sub -> "-"
+ | BINOP_Mult -> "*"
+ | BINOP_Div -> "/"
+ | BINOP_Rem -> "%"
+
+let string_of_relop = function
+ | RELOP_Eq -> "=="
+ | RELOP_Ne -> "!="
+ | RELOP_Lt -> "<"
+ | RELOP_Gt -> ">"
+ | RELOP_Le -> "<="
+ | RELOP_Ge -> ">="
+
+let string_of_unop = function
+ | UNOP_Not -> "!"
+ | UNOP_Neg -> "-"
+
+let indent x = " " ^ x
+
+let indentxs = List.map indent
+
+let rec show_expression = function
+ | EXPR_Id {id; _} ->
+ string_of_identifier id
+
+
+ | EXPR_Int {value; _} ->
+ Int32.to_string value
+
+ | EXPR_Char {value; _} ->
+ Format.sprintf "%c" value
+
+ | EXPR_String {value; _} ->
+ value
+
+ | EXPR_Bool {value; _} ->
+ string_of_bool value
+
+ | EXPR_Binop {op; lhs; rhs; _} ->
+ String.concat ""
+ [ "("
+ ; show_expression lhs
+ ; " "
+ ; string_of_binop op
+ ; " "
+ ; show_expression rhs
+ ; ")"
+ ]
+
+ | EXPR_Relation {op; lhs; rhs; _} ->
+ String.concat ""
+ [ "("
+ ; show_expression lhs
+ ; " "
+ ; string_of_relop op
+ ; " "
+ ; show_expression rhs
+ ; ")"
+ ]
+
+ | EXPR_Length {arg; _} ->
+ String.concat ""
+ [ "length("
+ ; show_expression arg
+ ; ")"
+ ]
+
+ | EXPR_Unop {op; sub; _} ->
+ String.concat ""
+ [ string_of_unop op
+ ; show_expression sub
+ ]
+
+ | EXPR_Call call ->
+ show_call call
+
+ | EXPR_Index {expr; index; _} ->
+ String.concat ""
+ [ show_expression expr
+ ; "["
+ ; show_expression index
+ ; "]"
+ ]
+
+ | EXPR_Struct {elements; _} ->
+ String.concat ""
+ [ "{"
+ ; String.concat ", " (List.map show_expression elements)
+ ; "}"
+ ]
+
+and show_call (Call {callee; arguments; _}) =
+ String.concat ""
+ [ string_of_identifier callee
+ ; "("
+ ; String.concat ", " (List.map show_expression arguments)
+ ; ")"
+ ]
+
+let rec show_type_expression = function
+ | TEXPR_Int _ ->
+ "int"
+
+ | TEXPR_Bool _ ->
+ "bool"
+
+ | TEXPR_Array {sub;dim;_} ->
+ String.concat ""
+ [ show_type_expression sub
+ ; "["
+ ; (match dim with | None -> "" | Some e -> show_expression e)
+ ; "]"
+ ]
+
+let show_var_declaration (VarDecl {id; tp; _}) =
+ String.concat ""
+ [ string_of_identifier id
+ ; ":"
+ ; show_type_expression tp
+ ]
+
+let show_var_declaration_opt = function
+ | Some v -> show_var_declaration v
+ | None -> "_"
+
+let show_lvalue = function
+ | LVALUE_Id {id; _} ->
+ string_of_identifier id
+ | LVALUE_Index {sub; index; _} ->
+ String.concat ""
+ [ show_expression sub
+ ; "["
+ ; show_expression index
+ ; "]"
+ ]
+
+
+let rec showxs_statement = function
+ | STMT_Call call ->
+ [ show_call call
+ ]
+
+ | STMT_VarDecl {var; init=None} ->
+ [ show_var_declaration var
+ ]
+
+ | STMT_VarDecl {var; init=Some v} ->
+ [ String.concat " "
+ [ show_var_declaration var
+ ; "="
+ ; show_expression v
+ ]
+ ]
+
+ | STMT_Return {values; _} ->
+ [ String.concat " "
+ [ "return"
+ ; String.concat ", " (List.map show_expression values)
+ ]
+ ]
+
+ | STMT_Block blok ->
+ showxs_block blok
+
+ | STMT_While {cond; body; _} ->
+ List.concat
+ [ [ String.concat " "
+ [ "while"
+ ; "("
+ ; show_expression cond
+ ; ")"
+ ] ]
+ ; showxs_statement_as_block body
+ ]
+
+ | STMT_If {cond; then_branch; else_branch=None; _} ->
+ List.concat
+ [ [ String.concat " "
+ [ "if"
+ ; "("
+ ; show_expression cond
+ ; ")"
+ ] ]
+ ; showxs_statement_as_block then_branch
+ ]
+
+ | STMT_If {cond; then_branch; else_branch=Some else_branch; _} ->
+ List.concat
+ [ [ String.concat " "
+ [ "if"
+ ; "("
+ ; show_expression cond
+ ; ")"
+ ] ]
+ ; showxs_statement_as_block then_branch
+ ; [ "else" ]
+ ; showxs_statement_as_block else_branch
+ ]
+ | STMT_Assign {lhs; rhs; _} ->
+ [ String.concat " "
+ [ show_lvalue lhs
+ ; "="
+ ; show_expression rhs
+ ]
+ ]
+ | STMT_MultiVarDecl {vars; init; _} ->
+ [ String.concat " "
+ [ String.concat ", " (List.map show_var_declaration_opt vars)
+ ; "="
+ ; show_call init
+ ]
+ ]
+
+and showxs_block = function
+ | STMTBlock {body; _} ->
+ List.concat
+ [ ["{"]
+ ; indentxs @@ List.concat @@ List.map showxs_statement body
+ ; ["}"]
+ ]
+
+and showxs_statement_as_block = function
+ | STMT_Block blok ->
+ showxs_block blok
+ | s ->
+ List.concat
+ [ ["{"]
+ ; indentxs @@ showxs_statement s
+ ; ["}"]
+ ]
+
+let show_formal_parameters params =
+ String.concat ", " @@ List.map show_var_declaration params
+
+
+let show_return_types = function
+ | [] ->
+ ""
+ | return_types ->
+ ": " ^ String.concat ", " (List.map show_type_expression return_types)
+
+let showxs_global_declaration = function
+ | GDECL_Function {id; body; formal_parameters; return_types; _} ->
+ List.concat
+ [ [ String.concat ""
+ [ string_of_identifier id
+ ; "("
+ ; show_formal_parameters formal_parameters
+ ; ")"
+ ; show_return_types return_types
+ ] ]
+ ; match body with
+ | Some body -> showxs_block body
+ | None -> []
+ ]
+
+let showxs_module_definition (ModuleDefinition {global_declarations; _}) =
+ let f x =
+ showxs_global_declaration x @ [""]
+ in
+ List.flatten (List.map f global_declarations)
+
+let show_module_definition m =
+ String.concat "\n" @@ showxs_module_definition m \ No newline at end of file
diff --git a/source/xi_lib/ast_rawprinter.ml b/source/xi_lib/ast_rawprinter.ml
new file mode 100644
index 0000000..0c6494e
--- /dev/null
+++ b/source/xi_lib/ast_rawprinter.ml
@@ -0,0 +1,313 @@
+open Ast
+
+
+let string_of_binop = function
+ | BINOP_And -> "BINOP_And"
+ | BINOP_Or -> "BINOP_Or"
+ | BINOP_Add -> "BINOP_Add"
+ | BINOP_Sub -> "BINOP_Sub"
+ | BINOP_Mult -> "BINOP_Mult"
+ | BINOP_Div -> "BINOP_Div"
+ | BINOP_Rem -> "BINOP_Rem"
+
+let string_of_relop = function
+ | RELOP_Eq -> "RELOP_Eq"
+ | RELOP_Ne -> "RELOP_Ne"
+ | RELOP_Lt -> "RELOP_Lt"
+ | RELOP_Gt -> "RELOP_Gt"
+ | RELOP_Le -> "RELOP_Le"
+ | RELOP_Ge -> "RELOP_Ge"
+
+let string_of_unop = function
+ | UNOP_Not -> "UNOP_Not"
+ | UNOP_Neg -> "UNOP_Neg"
+
+let indent x = " " ^ x
+let indentfmt fmt =
+ let cont = Format.sprintf " %s" in
+ Format.ksprintf cont fmt
+
+let indentxs = List.map indent
+
+type p =
+ | P_String of string
+ | P_Sequence of p list
+ | P_List of p list
+ | P_Dict of string * (string * p) list
+
+type r =
+ | R_String of string
+ | R_Indent of r
+ | R_Break
+ | R_Tab
+ | R_Group of r list
+
+let render_r = function
+ | R_String s -> s
+ | R_Tab -> " "
+ | R_Break -> "\n"
+ | R_Group _ -> failwith "R_Group should be eliminated"
+ | R_Indent _ -> failwith "R_Indent should be eliminated"
+
+let rec insert_tabs tabs = function
+ | R_Indent r ->
+ insert_tabs (R_Tab::tabs) r
+ | R_Break ->
+ R_Group [R_Break; R_Group tabs]
+ | R_Group rs ->
+ R_Group (List.map (insert_tabs tabs) rs)
+ | r ->
+ r
+
+let rec flatten = function
+ | R_Indent _ -> failwith "R_Indent should be eliminated"
+ | R_Group xs -> List.concat @@ List.map flatten xs
+ | r -> [r]
+
+let render_r r =
+ String.concat "" @@ List.map render_r @@ flatten @@ insert_tabs [] r
+
+let rec render_p = function
+ | P_String s ->
+ R_String s
+ | P_List xs ->
+ let rec f acc = function
+ | [] ->
+ R_Group (List.rev acc)
+
+ | x::xs ->
+ let entry = R_Group [render_p x; R_String ";"; R_Break] in
+ f (entry::acc) xs
+ in
+ R_Group
+ [ R_String "["
+ ; R_Indent (R_Group [R_Break; f [] xs])
+ ; R_String "]"
+ ]
+
+ | P_Dict (kind, items) ->
+ let rec f acc = function
+ | [] ->
+ R_Group (List.rev acc)
+ | (k,v)::xs ->
+ let entry = R_Group [R_String k; R_String " = "; R_Indent (render_p v); R_String ";"; R_Break] in
+ f (entry::acc) xs
+ in
+ R_Group
+ [ R_String kind
+ ; R_String " "
+ ; R_String "{"
+ ; R_Indent (R_Group [R_Break; f [] items])
+ ; R_String "}"
+ ]
+
+ | P_Sequence xs ->
+ R_Group (List.map render_p xs)
+
+let p_dict k items = P_Dict (k,items)
+
+let p_identifier id = P_String (Format.sprintf "\"%s\"" @@ string_of_identifier id)
+let p_string id = P_String (Format.sprintf "\"%s\"" id)
+let p_location loc = P_String (string_of_location loc)
+let p_node_tag tag = P_String (string_of_node_tag tag)
+let p_i32 i = P_String (Int32.to_string i)
+let p_char c = P_String (Format.sprintf "'%c'" c)
+let p_bool b = P_String (string_of_bool b)
+
+let p_opt f = function
+ | None -> P_String "None"
+ | Some x -> P_Sequence [P_String "Some "; f x]
+
+
+let rec p_expression = function
+ | EXPR_Id {loc; tag; id} -> p_dict "EXPR_Id"
+ [ "loc", p_location loc
+ ; "tag", p_node_tag tag
+ ; "id", p_identifier id
+ ]
+
+ | EXPR_Int {tag; loc; value} -> p_dict "EXPR_Int"
+ [ "loc", p_location loc
+ ; "tag", p_node_tag tag
+ ; "value", p_i32 value
+ ]
+
+ | EXPR_Char {tag; loc; value} -> p_dict "EXPR_Char"
+ [ "loc", p_location loc
+ ; "tag", p_node_tag tag
+ ; "value", p_char value
+ ]
+
+ | EXPR_String {tag; loc; value} -> p_dict "EXPR_String"
+ [ "loc", p_location loc
+ ; "tag", p_node_tag tag
+ ; "value", p_string value
+ ]
+
+ | EXPR_Bool {tag; loc; value} -> p_dict "EXPR_Bool"
+ [ "loc", p_location loc
+ ; "tag", p_node_tag tag
+ ; "value", p_bool value
+ ]
+
+ | EXPR_Relation {tag; loc; op; lhs; rhs} -> p_dict "EXPR_Relation"
+ [ "loc", p_location loc
+ ; "tag", p_node_tag tag
+ ; "op", P_String (string_of_relop op)
+ ; "lhs", p_expression lhs
+ ; "rhs", p_expression rhs
+ ]
+
+ | EXPR_Binop {tag; loc; op; lhs; rhs} -> p_dict "EXPR_Binop"
+ [ "loc", p_location loc
+ ; "tag", p_node_tag tag
+ ; "op", P_String (string_of_binop op)
+ ; "lhs", p_expression lhs
+ ; "rhs", p_expression rhs
+ ]
+
+ | EXPR_Unop {tag; loc; op; sub} -> p_dict "EXPR_Unop"
+ [ "loc", p_location loc
+ ; "tag", p_node_tag tag
+ ; "op", P_String (string_of_unop op)
+ ; "sub", p_expression sub
+ ]
+
+ | EXPR_Length {tag; loc; arg} -> p_dict "EXPR_Length"
+ [ "loc", p_location loc
+ ; "tag", p_node_tag tag
+ ; "arg", p_expression arg
+ ]
+
+ | EXPR_Index {tag; loc; expr; index} -> p_dict "EXPR_Length"
+ [ "loc", p_location loc
+ ; "tag", p_node_tag tag
+ ; "expr", p_expression expr
+ ; "index", p_expression index
+ ]
+
+ | EXPR_Struct {tag; loc; elements} -> p_dict "EXPR_Struct"
+ [ "loc", p_location loc
+ ; "tag", p_node_tag tag
+ ; "elements", P_List (List.map p_expression elements)
+ ]
+
+ | EXPR_Call call -> P_Sequence
+ [ P_String "EXPR_Call "
+ ; p_call call
+ ]
+
+and p_call = function
+ | Call {tag; loc; callee; arguments} -> p_dict "Call"
+ [ "loc", p_location loc
+ ; "tag", p_node_tag tag
+ ; "callee", p_identifier callee
+ ; "arguments", P_List (List.map p_expression arguments)
+ ]
+
+let rec p_type_expression = function
+ | TEXPR_Int {loc} -> p_dict "TEXPR_Int"
+ [ "loc", p_location loc
+ ]
+
+ | TEXPR_Bool {loc} -> p_dict "TEXPR_Bool"
+ [ "loc", p_location loc
+ ]
+
+ | TEXPR_Array {loc;sub;dim} -> p_dict "TPEXPR_Array"
+ [ "loc", p_location loc
+ ; "sub", p_type_expression sub
+ ; "dim", p_opt p_expression dim
+ ]
+
+let p_lvalue = function
+ | LVALUE_Id {loc; id} -> p_dict "LVALUE_Id"
+ [ "loc", p_location loc
+ ; "id", p_identifier id
+ ]
+ | LVALUE_Index {loc; sub; index} -> p_dict "LVALUE_Index"
+ [ "loc", p_location loc
+ ; "sub", p_expression sub
+ ; "index", p_expression index
+ ]
+
+let p_var_declaration = function
+ | VarDecl {loc;id;tp} -> p_dict "VarDecl"
+ [ "loc", p_location loc
+ ; "id", p_identifier id
+ ; "tp", p_type_expression tp
+ ]
+
+let rec p_statement = function
+ | STMT_Call call -> P_Sequence
+ [ P_String "STMT_Call "
+ ; p_call call
+ ]
+
+ | STMT_Assign {loc; lhs; rhs} -> p_dict "STMT_Assign"
+ [ "loc", p_location loc
+ ; "lhs", p_lvalue lhs
+ ; "rhs", p_expression rhs
+ ]
+
+ | STMT_VarDecl {var; init} -> p_dict "STMT_VarDecl"
+ [ "var", p_var_declaration var
+ ; "init", p_opt p_expression init
+ ]
+
+ | STMT_If {loc; cond; then_branch; else_branch} -> p_dict "STMT_If"
+ [ "loc", p_location loc
+ ; "cond", p_expression cond
+ ; "then_branch", p_statement then_branch
+ ; "else_branch", p_opt p_statement else_branch
+ ]
+
+ | STMT_While {loc; cond; body} -> p_dict "STMT_While"
+ [ "loc", p_location loc
+ ; "cond", p_expression cond
+ ; "body", p_statement body
+ ]
+
+ | STMT_Block block -> P_Sequence
+ [ P_String "STMT_Block "
+ ; p_statement_block block
+ ]
+
+ | STMT_MultiVarDecl {loc; vars; init} -> p_dict "STMT_MultiVarDecl"
+ [ "loc", p_location loc
+ ; "vars", P_List (List.map (p_opt p_var_declaration) vars)
+ ; "init", p_call init
+ ]
+
+ | STMT_Return {loc; values} -> p_dict "STMT_Return"
+ [ "loc", p_location loc
+ ; "values", P_List (List.map p_expression values)
+ ]
+
+and p_statement_block = function
+ | STMTBlock {loc; body} -> p_dict "STMTBlock"
+ [ "loc", p_location loc
+ ; "body", P_List (List.map p_statement body)
+ ]
+
+
+
+let p_global_declaration = function
+ | GDECL_Function {loc;id;formal_parameters; return_types; body} ->
+ p_dict "GDECL_Function"
+ [ "loc", p_location loc
+ ; "id", p_identifier id
+ ; "formal_parameters", P_List (List.map p_var_declaration formal_parameters)
+ ; "return_types", P_List (List.map p_type_expression return_types)
+ ; "body", p_opt p_statement_block body
+ ]
+
+let p_module_definition = function
+ | ModuleDefinition {global_declarations} -> P_Sequence
+ [ P_String "ModuleDefinition "
+ ; P_List (List.map p_global_declaration global_declarations)
+ ]
+
+let show_module_definition mdef =
+ let p = p_module_definition mdef in
+ render_r @@ render_p p
diff --git a/source/xi_lib/dune b/source/xi_lib/dune
new file mode 100644
index 0000000..d4fbe33
--- /dev/null
+++ b/source/xi_lib/dune
@@ -0,0 +1,9 @@
+(library
+ (name xi_lib)
+ (public_name xi_lib)
+ (libraries ocamlgraph )
+ (modes byte)
+ ; Flaga -linkall potrzebna aby program `xi` był skonsolidowany ze wszystkimi
+ ; plikami znajdującymi się w xi_lib.cma, to jest w tej bibliotece.
+ (library_flags (-linkall))
+) \ No newline at end of file
diff --git a/source/xi_lib/hardcoded.ml b/source/xi_lib/hardcoded.ml
new file mode 100644
index 0000000..314fa1f
--- /dev/null
+++ b/source/xi_lib/hardcoded.ml
@@ -0,0 +1,122 @@
+open Ir
+
+let word_size = Int32.of_int 4
+let i32_0 = Int32.of_int 0
+let i32_1 = Int32.of_int 1
+let expr_0 = E_Int i32_0
+
+let preamble = String.concat "\n"
+ [ ".data"
+ ; "endline: .asciiz \"\\n\""
+ ; "endmessage: .asciiz \"Exit code: \""
+ ; ""
+ ; ".text"
+ ; ".set noat"
+ ; ""
+ ; "main:"
+ ; " add $sp, $sp, -4"
+ ; " sw $ra, 4($sp)"
+ ; " jal _I_main__i"
+ ; " move $a1, $v0"
+
+ ; " la $a0, endmessage"
+ ; " li $v0, 4"
+ ; " syscall"
+
+ ; " li $v0, 1"
+ ; " move $a0, $a1"
+ ; " syscall"
+
+ ; " la $a0, endline"
+ ; " li $v0, 4"
+ ; " syscall"
+
+ ; " lw $ra, 4($sp)"
+ ; " add $sp, $sp, 4"
+ ; " jr $ra"
+ ; ""
+ ; "_xi_length:"
+ ; " lw $v0, -4($a0)"
+ ; " jr $ra"
+ ; ""
+ ; "_xi_concat:"
+ ; " # t0 = lhs"
+ ; " # t1 = rhs"
+ ; " move $t0, $a0"
+ ; " move $t1, $a1"
+ ; " # t2 = len(lhs)"
+ ; " # t3 = len(rhs)"
+ ; " lw $t2, -4($t0)"
+ ; " lw $t3, -4($t1)"
+ ; " # t4 = len(lhs) + len(rhs)"
+ ; " addu $t4, $t2, $t3"
+ ; " # v0 = malloc(4*t4+4) "
+ ; " li $t5, 4"
+ ; " mul $a0, $t4, $t5"
+ ; " addiu $a0, $a0, 4"
+ ; " li $v0, 9"
+ ; " syscall"
+ ; " addiu $v0, $v0, 4"
+ ; " sw $t4, -4($v0)"
+ ; " move $v1, $v0"
+ ; " XL0:"
+ ; " beq $zero, $t2, XL1"
+ ; " lw $t4, 0($t0)"
+ ; " sw $t4, 0($v1)"
+ ; " addiu $t2, $t2, -1"
+ ; " addiu $t0, $t0, 4"
+ ; " addiu $v1, $v1, 4"
+ ; " j XL0"
+ ; " XL1:"
+ ; " beq $zero, $t3, XL2"
+ ; " lw $t4, 0($t1)"
+ ; " sw $t4, 0($v1)"
+ ; " addiu $t3, $t3, -1"
+ ; " addiu $t1, $t1, 4"
+ ; " addiu $v1, $v1, 4"
+ ; " j XL1"
+ ; " XL2:"
+ ; " jr $ra"
+ ; ""
+ ; "_xi_alloc:"
+ ; " li $v0, 9"
+ ; " syscall"
+ ; " jr $ra"
+ ; ""
+ ; "_I_printString_ai_:"
+ ; " # t0 = len a0"
+ ; " move $t1, $a0"
+ ; " lw $t0, -4($t1)"
+ ; " mul $a0, $t0, 4"
+ ; " addiu $a0, $a0, 2"
+ ; " li $v0, 9"
+ ; " syscall"
+ ; " move $a0, $v0"
+ ; " move $v1, $v0"
+ ; " XL10:"
+ ; " beq $zero, $t0, XL11"
+ ; " lw $t2, 0($t1)"
+ ; " sb $t2, 0($v1)"
+ ; " addiu $t0, $t0, -1"
+ ; " addu $t1, $t1, 4"
+ ; " addu $v1, $v1, 1"
+ ; " j XL10"
+ ; " XL11:"
+ ; " li $t0, 10"
+ ; " sb $t0, 0($v1)"
+ ; " sb $zero, 1($v1)"
+ ; " li $v0, 4"
+ ; " syscall"
+ ; " jr $ra"
+ ; ""
+ ; ""
+ ; "_I_printInt_i_:"
+ ; " li $v0, 1"
+ ; " syscall"
+ ; " li $v0, 4"
+ ; " la $a0, endline"
+ ; " syscall"
+ ; " jr $ra"
+ ; ""
+ ; ""
+ ] \ No newline at end of file
diff --git a/source/xi_lib/hashset.ml b/source/xi_lib/hashset.ml
new file mode 100644
index 0000000..455ba81
--- /dev/null
+++ b/source/xi_lib/hashset.ml
@@ -0,0 +1,30 @@
+
+type 'a t = ('a, unit) Hashtbl.t
+
+let create () : 'a t = Hashtbl.create 101
+
+let clear = Hashtbl.clear
+
+let add t x = Hashtbl.replace t x ()
+
+let mem = Hashtbl.mem
+
+let to_seq t = Hashtbl.to_seq_keys t
+
+let length t = Hashtbl.length t
+
+let remove t v = Hashtbl.remove t v
+
+let iter f t =
+ let g k _ = f k in
+ Hashtbl.iter g t
+
+
+let fold f t acc =
+ let g k () = f k in
+ Hashtbl.fold g t acc
+
+let of_seq seq : 'a t =
+ let result = create () in
+ Seq.iter (add result) seq;
+ result \ No newline at end of file
diff --git a/source/xi_lib/iface.ml b/source/xi_lib/iface.ml
new file mode 100644
index 0000000..b67a787
--- /dev/null
+++ b/source/xi_lib/iface.ml
@@ -0,0 +1,199 @@
+
+type node2type = (Ast.node_tag, Types.normal_type) Hashtbl.t
+
+type schedule = (Ir.procedure, Ir.label list) Hashtbl.t
+
+type register_mapping = (Ir.reg, Ir.reg) Hashtbl.t
+
+
+module type LEXER = sig
+
+ type token
+
+ val token: Lexing.lexbuf -> token
+
+end
+
+module type PARSER = sig
+
+ type token
+
+ exception Error
+
+ val file: (Lexing.lexbuf -> token) -> Lexing.lexbuf -> Ast.module_definition
+
+end
+
+module type LEXER_AND_PARSER = sig
+
+ type token
+
+ module Lexer: LEXER with type token = token
+
+ module Parser: PARSER with type token = token
+
+end
+
+module type TYPECHECKER = sig
+
+ val check_module: Ast.module_definition -> (node2type, Typechecker_errors.type_checking_error list) result
+
+end
+
+module type TRANSLATOR = sig
+
+ val translate_module: Ast.module_definition -> node2type -> Ir.program
+
+end
+
+module type HI_LOWER = sig
+
+ val lower: Ir.procedure -> unit
+
+end
+
+module type MIPS_LOWER = sig
+
+ val lower: Ir.procedure -> unit
+
+end
+
+module type CALLCONV = sig
+
+ val callconv: Ir.procedure -> unit
+
+end
+
+module type REGISTER_ALLOCATOR = sig
+
+ val regalloc: Ir.procedure -> register_mapping
+
+end
+
+module type CODEGEN = sig
+
+ val codegen: schedule -> Ir.program -> Mips32.program
+
+end
+
+module type LIVE_VARIABLES_ANALYSIS = sig
+
+ val analyse: Ir.ControlFlowGraph.t -> Analysis_domain.LiveVariables.table
+end
+
+module type REACHABILITY_ANALYSIS = sig
+
+ val analyse: Ir.ControlFlowGraph.t -> Analysis_domain.ReachabilityAnalysis.table
+
+end
+
+module type CONSTANT_FOLDING_ANALYSIS = sig
+
+ val analyse: Ir.procedure -> Analysis_domain.ConstantFolding.table
+
+end
+
+module type JUMP_THREADING = sig
+
+ val jump_threading: Ir.procedure -> unit
+
+end
+
+module type CONSTANT_FOLDING = sig
+
+ val fold_constants: Ir.procedure -> unit
+
+end
+
+module type DEAD_CODE_ELIMINATION = sig
+
+ val eliminate_dead_code: Ir.procedure -> unit
+
+end
+
+module type DOMINATORS_ANALYSIS = sig
+
+ val analyse: Ir.ControlFlowGraph.t -> Analysis_domain.DominatorsAnalysis.table
+
+end
+
+module type NATURAL_LOOPS_ANALYSIS = sig
+
+ val analyse: Ir.ControlFlowGraph.t -> Analysis_domain.DominatorsAnalysis.table -> Analysis_domain.NaturalLoops.table
+
+end
+
+module type SCHEDULER = sig
+
+ val schedule: Ir.program -> schedule
+
+end
+
+module type SPILL_COSTS_ANALYSIS = sig
+
+ val analyse: Ir.ControlFlowGraph.t -> Analysis_domain.NaturalLoops.table -> (Ir.reg, int) Hashtbl.t
+
+end
+
+module type INTERFERENCE_GRAPH_ANALYSIS = sig
+
+ val analyse: Ir.ControlFlowGraph.t -> Analysis_domain.LiveVariables.table -> Ir.RegGraph.t
+
+end
+
+module type SPILLING = sig
+
+ val spill: Ir.procedure -> Ir.reg list -> unit
+
+end
+
+module type COMPILER_TOOLBOX = sig
+
+ module LiveVariablesAnalysis : LIVE_VARIABLES_ANALYSIS
+
+ module DominatorsAnalysis : DOMINATORS_ANALYSIS
+
+ module NaturalLoopsAnalysis : NATURAL_LOOPS_ANALYSIS
+
+ module SpillCostsAnalysis : SPILL_COSTS_ANALYSIS
+
+ module Scheduler: SCHEDULER
+
+ module RegistersDescription : Ir_arch.REGISTERS_DESCRIPTION
+
+ module ConstantFoldingAnalysis : CONSTANT_FOLDING_ANALYSIS
+
+ module InterferenceGraphAnalysis : INTERFERENCE_GRAPH_ANALYSIS
+
+ module Spilling : SPILLING
+
+ module ReachabilityAnalysis : REACHABILITY_ANALYSIS
+end
+
+
+module type COMPILER_STEPS = sig
+
+ module Toolbox: COMPILER_TOOLBOX
+
+ module LexerAndParser: LEXER_AND_PARSER
+
+ module Typechecker: TYPECHECKER
+
+ module Translator: TRANSLATOR
+
+ module JumpThreading: JUMP_THREADING
+
+ module ConstantFolding: CONSTANT_FOLDING
+
+ module HiLower: HI_LOWER
+
+ module CallConv: CALLCONV
+
+ module MipsLower: MIPS_LOWER
+
+ module RegisterAllocator: REGISTER_ALLOCATOR
+
+ module Codegen: CODEGEN
+
+ module DeadCodeElimination: DEAD_CODE_ELIMINATION
+end
diff --git a/source/xi_lib/ir.ml b/source/xi_lib/ir.ml
new file mode 100644
index 0000000..b611916
--- /dev/null
+++ b/source/xi_lib/ir.ml
@@ -0,0 +1,288 @@
+type reg
+ = REG_Tmp of int
+ | REG_Hard of int
+ | REG_Spec of int
+
+let string_of_reg = function
+ | REG_Tmp i -> Format.sprintf "%%tmp%u" i
+ | REG_Hard i -> Format.sprintf "%%hard%u" i
+ | REG_Spec i -> Format.sprintf "%%spec%u" i
+
+let is_spec_reg = function
+ | REG_Spec _ -> true
+ | _ -> false
+
+let is_tmp_reg = function
+ | REG_Tmp _ -> true
+ | _ -> false
+
+module RegSet = Set.Make(struct
+ type t = reg
+
+ let compare = compare
+ end)
+
+module RegMap = Map.Make(struct
+ type t = reg
+
+ let compare = compare
+ end)
+
+
+module RegGraph = Graph.Imperative.Graph.Concrete(struct
+(* module RegGraph = Mygraph.MakeUndirected(struct *)
+ type t = reg
+
+ let hash = Hashtbl.hash
+
+ let equal a b = compare a b = 0
+
+ let compare a b = compare a b
+ end)
+
+type expr
+ = E_Reg of reg
+ | E_Int of Int32.t
+
+
+let reglist_of_expr = function
+ | E_Reg r -> [r]
+ | E_Int _ -> []
+
+type label
+ = Label of int
+
+module LabelSet = Set.Make(struct
+ type t = label
+ let compare = compare
+ end)
+
+type procid
+ = Procid of string
+
+
+type cond
+ = COND_Eq
+ | COND_Ne
+ | COND_Lt
+ | COND_Gt
+ | COND_Le
+ | COND_Ge
+
+let string_of_cond = function
+ | COND_Eq -> "eq"
+ | COND_Ne -> "ne"
+ | COND_Lt -> "lt"
+ | COND_Gt -> "gt"
+ | COND_Le -> "le"
+ | COND_Ge -> "ge"
+
+
+type instr
+ = I_Add of reg * expr * expr
+ | I_Sub of reg * expr * expr
+ | I_Div of reg * expr * expr
+ | I_Rem of reg * expr * expr
+ | I_Mul of reg * expr * expr
+ | I_And of reg * expr * expr
+ | I_Or of reg * expr * expr
+ | I_Xor of reg * expr * expr
+ | I_LoadArray of reg * expr * expr
+ | I_StoreArray of expr * expr * expr
+ | I_LoadMem of reg * expr * expr
+ | I_StoreMem of expr * expr * expr
+ | I_Concat of reg * expr * expr
+ | I_Neg of reg * expr
+ | I_Not of reg * expr
+ | I_Move of reg * expr
+ | I_Length of reg * expr
+ | I_NewArray of reg * expr
+ | I_Call of reg list * procid * expr list * reg list
+ | I_Set of reg * cond * expr * expr
+ | I_LoadVar of reg * int
+ | I_StoreVar of int * expr
+ | I_LoadStack of reg * int
+ | I_StoreStack of int * expr
+ | I_StackAlloc of Int32.t
+ | I_StackFree of Int32.t
+ | I_Use of reg list
+ | I_Def of reg list
+
+
+type terminator =
+ | T_Return of expr list
+ | T_Branch of cond * expr * expr * label * label
+ | T_Jump of label
+
+let labels_of_terminator = function
+ | T_Branch (_, _, _, lt, lf) -> [lt; lf]
+ | T_Jump l -> [l]
+ | _ -> []
+
+type block = instr list
+
+module LabelGraph = Graph.Imperative.Digraph.ConcreteBidirectional(struct
+(*module LabelGraph = Mygraph.MakeBidirectional(struct *)
+ type t = label
+ let compare = compare
+ let hash = Hashtbl.hash
+ let equal a b = a = b
+ end)
+
+module ControlFlowGraph = struct
+
+ type graph = LabelGraph.t
+
+ type t = Cfg of
+ { graph: graph
+ ; blockmap: (label, block) Hashtbl.t
+ ; terminatormap: (label, terminator) Hashtbl.t
+ ; entry: label
+ ; exit: label
+ }
+
+ let graph (Cfg {graph; _}) = graph
+
+ let _allocate_block graph =
+ let i = LabelGraph.nb_vertex graph in
+ let l = Label i in
+ LabelGraph.add_vertex graph l;
+ l
+
+ let remove (Cfg {graph; terminatormap; blockmap; _}) v =
+ LabelGraph.remove_vertex graph v;
+ Hashtbl.remove terminatormap v;
+ Hashtbl.remove blockmap v
+
+ let allocate_block (Cfg {graph; blockmap; terminatormap; _}) =
+ let i = LabelGraph.nb_vertex graph in
+ let l = Label i in
+ LabelGraph.add_vertex graph l;
+ Hashtbl.replace blockmap l [];
+ Hashtbl.replace terminatormap l (T_Return []);
+ l
+
+ let create () =
+ let graph = LabelGraph.create () in
+ let blockmap = Hashtbl.create 513 in
+ let terminatormap = Hashtbl.create 513 in
+ let entry = _allocate_block graph in
+ let exit = _allocate_block graph in
+ let _ = LabelGraph.add_vertex graph entry in
+ let _ = LabelGraph.add_vertex graph exit in
+ Cfg {graph; blockmap; terminatormap; entry; exit}
+
+ let successors (Cfg {graph; _}) v =
+ LabelGraph.succ graph v
+
+ let predecessors (Cfg {graph; _}) v =
+ LabelGraph.pred graph v
+
+ let entry_label (Cfg {entry; _}) = entry
+
+ let exit_label (Cfg {exit; _}) = exit
+
+ let blockmap (Cfg {blockmap;_}) = blockmap
+
+ let blocklist cfg =
+ let blockmap = blockmap cfg in
+ let f xs (k,v) = (k,v) :: xs in
+ let blocks = Seq.fold_left f [] (Hashtbl.to_seq blockmap) in
+ let blocks = List.sort compare blocks in
+ blocks
+
+ let terminator (Cfg {terminatormap; entry; exit; _}) v =
+ assert (entry <> v);
+ assert (exit <> v);
+ Hashtbl.find terminatormap v
+
+ let blocklist2 cfg =
+ let blockmap = blockmap cfg in
+ let f xs (k,v) = (k,v,terminator cfg k) :: xs in
+ let blocks = Seq.fold_left f [] (Hashtbl.to_seq blockmap) in
+ let blocks = List.sort compare blocks in
+ blocks
+
+ let blocklabels cfg =
+ let blockmap = blockmap cfg in
+ let f xs k = k :: xs in
+ let blocks = Seq.fold_left f [] (Hashtbl.to_seq_keys blockmap) in
+ let blocks = List.sort compare blocks in
+ blocks
+
+
+ let block (Cfg {blockmap; entry; exit; _}) v =
+ assert (entry <> v);
+ assert (exit <> v);
+ Hashtbl.find blockmap v
+
+ let block_safe (Cfg {blockmap; entry; exit; _}) v =
+ assert (entry <> v);
+ assert (exit <> v);
+ Hashtbl.find_opt blockmap v
+
+
+ let terminator_safe (Cfg {terminatormap; entry; exit; _}) v =
+ assert (entry <> v);
+ assert (exit <> v);
+ Hashtbl.find_opt terminatormap v
+
+ let set_block (Cfg {blockmap; entry; exit; _}) v body =
+ assert (entry <> v);
+ assert (exit <> v);
+ Hashtbl.replace blockmap v body
+
+ let set_block2 (Cfg {blockmap; terminatormap; entry; exit; _}) v body terminator =
+ assert (entry <> v);
+ assert (exit <> v);
+ Hashtbl.replace blockmap v body;
+ Hashtbl.replace terminatormap v terminator
+
+ let set_terminator (Cfg {terminatormap; entry; exit; _}) v body =
+ assert (entry <> v);
+ assert (exit <> v);
+ Hashtbl.replace terminatormap v body
+
+ let connect (Cfg {graph; exit; entry; _}) a b =
+ assert (entry <> b);
+ assert (exit <> a);
+ LabelGraph.add_edge graph a b
+
+ let labels (Cfg {graph; _}) =
+ LabelGraph.fold_vertex (fun x xs -> x::xs) graph []
+
+end
+
+type procedure = Procedure of
+ { procid: procid
+ ; cfg: ControlFlowGraph.t
+ ; mutable frame_size: int
+ ; formal_parameters: int
+ ; allocate_register: unit -> reg
+ }
+
+let cfg_of_procedure (Procedure {cfg; _}) = cfg
+
+let formal_parameters_of_procedure (Procedure {formal_parameters; _}) = formal_parameters
+
+let allocate_register_of_procedure (Procedure {allocate_register; _}) = allocate_register
+
+let allocate_frame_slot (Procedure procid) =
+ let slot = procid.frame_size in
+ procid.frame_size <- procid.frame_size + 1;
+ slot
+
+
+let procid_of_procedure (Procedure {procid; _}) = procid
+
+let frame_size_of_procedure (Procedure {frame_size; _}) = frame_size
+
+
+type program = Program of
+ { procedures: procedure list
+ ; externals: procid list
+ }
+
+let procedures_of_program (Program{procedures; _}) = procedures
+
+let externals_of_program (Program{externals; _}) = externals
diff --git a/source/xi_lib/ir_arch.ml b/source/xi_lib/ir_arch.ml
new file mode 100644
index 0000000..e7ffc60
--- /dev/null
+++ b/source/xi_lib/ir_arch.ml
@@ -0,0 +1,107 @@
+open Ir
+
+let reg_fp = REG_Spec 30
+
+let reg_sp = REG_Spec 29
+
+let reg_ra = REG_Spec 31
+
+let reg_zero = REG_Spec 0
+
+let expr_reg_zero = E_Reg reg_zero
+
+let reg_v0 = REG_Hard 2
+
+let reg_v1 = REG_Hard 3
+
+module type REGISTERS_DESCRIPTION = sig
+
+ val callee_saves_registers : reg list
+
+ val caller_saves_registers : reg list
+
+ val available_registers : reg list
+
+ val arguments_registers : reg list
+
+end
+
+
+module NormalRegistersDescription : REGISTERS_DESCRIPTION = struct
+
+ let callee_saves_registers =
+ [ REG_Hard 16
+ ; REG_Hard 17
+ ; REG_Hard 18
+ ; REG_Hard 19
+ ; REG_Hard 20
+ ; REG_Hard 21
+ ; REG_Hard 22
+ ; REG_Hard 23
+ ]
+
+ let caller_saves_registers =
+ [ REG_Hard 1
+ ; REG_Hard 2
+ ; REG_Hard 3
+ ; REG_Hard 4
+ ; REG_Hard 5
+ ; REG_Hard 6
+ ; REG_Hard 7
+ ; REG_Hard 8
+ ; REG_Hard 9
+ ; REG_Hard 10
+ ; REG_Hard 11
+ ; REG_Hard 12
+ ; REG_Hard 13
+ ; REG_Hard 14
+ ; REG_Hard 15
+ ; REG_Hard 24
+ ; REG_Hard 25
+ ]
+
+ let available_registers = List.flatten
+ [ caller_saves_registers
+ ; callee_saves_registers
+ ]
+
+ let arguments_registers =
+ [ REG_Hard 4
+ ; REG_Hard 5
+ ; REG_Hard 6
+ ; REG_Hard 7
+ ]
+
+end
+
+module SimpleCallerRegistersDescription : REGISTERS_DESCRIPTION = struct
+
+ let callee_saves_registers =
+ [
+ ]
+
+ let caller_saves_registers =
+ [ REG_Hard 2
+ ; REG_Hard 3
+ ; REG_Hard 4
+ ; REG_Hard 5
+ ; REG_Hard 6
+ ; REG_Hard 7
+ ]
+
+ let available_registers = List.flatten
+ [ callee_saves_registers
+ ; caller_saves_registers
+ ]
+
+ let arguments_registers =
+ [ REG_Hard 4
+ ; REG_Hard 5
+ ]
+
+end
+
+let descriptions =
+ [ "normal", (module NormalRegistersDescription : REGISTERS_DESCRIPTION )
+ ; "simple_caller", (module SimpleCallerRegistersDescription : REGISTERS_DESCRIPTION )
+ ] \ No newline at end of file
diff --git a/source/xi_lib/ir_utils.ml b/source/xi_lib/ir_utils.ml
new file mode 100644
index 0000000..48b59a1
--- /dev/null
+++ b/source/xi_lib/ir_utils.ml
@@ -0,0 +1,668 @@
+open Ir
+
+let remap_register_reg sb r =
+ try
+ Hashtbl.find sb r
+ with Not_found ->
+ r
+
+let remap_register_expr sb = function
+ | E_Reg r -> E_Reg (remap_register_reg sb r)
+ | e -> e
+
+let remap_register_instr sb = function
+ | I_Add (r0, r1, r2) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ let r2 = remap_register_expr sb r2 in
+ I_Add (r0, r1, r2)
+
+ | I_Sub (r0, r1, r2) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ let r2 = remap_register_expr sb r2 in
+ I_Sub (r0, r1, r2)
+
+ | I_Div (r0, r1, r2) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ let r2 = remap_register_expr sb r2 in
+ I_Div (r0, r1, r2)
+
+ | I_Rem (r0, r1, r2) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ let r2 = remap_register_expr sb r2 in
+ I_Rem (r0, r1, r2)
+
+ | I_Mul(r0, r1, r2) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ let r2 = remap_register_expr sb r2 in
+ I_Mul (r0, r1, r2)
+
+ | I_And(r0, r1, r2) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ let r2 = remap_register_expr sb r2 in
+ I_And(r0, r1, r2)
+
+ | I_Or(r0, r1, r2) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ let r2 = remap_register_expr sb r2 in
+ I_Or(r0, r1, r2)
+
+ | I_Xor(r0, r1, r2) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ let r2 = remap_register_expr sb r2 in
+ I_Xor(r0, r1, r2)
+
+ | I_LoadArray(r0, r1, r2) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ let r2 = remap_register_expr sb r2 in
+ I_LoadArray(r0, r1, r2)
+
+ | I_StoreArray(r0, r1, r2) ->
+ let r0 = remap_register_expr sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ let r2 = remap_register_expr sb r2 in
+ I_StoreArray(r0, r1, r2)
+
+ | I_LoadMem(r0, r1, r2) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ let r2 = remap_register_expr sb r2 in
+ I_LoadMem(r0, r1, r2)
+
+ | I_StoreMem(r0, r1, r2) ->
+ let r0 = remap_register_expr sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ let r2 = remap_register_expr sb r2 in
+ I_StoreMem(r0, r1, r2)
+
+ | I_Concat(r0, r1, r2) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ let r2 = remap_register_expr sb r2 in
+ I_Concat(r0, r1, r2)
+
+ | I_Neg(r0, r1) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ I_Neg(r0, r1)
+
+ | I_Not(r0, r1) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ I_Not(r0, r1)
+
+ | I_Move(r0, r1) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ I_Move(r0, r1)
+
+ | I_Length(r0, r1) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ I_Length(r0, r1)
+
+ | I_NewArray(r0, r1) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ I_NewArray(r0, r1)
+
+ | I_Set(r0, cond, r1, r2) ->
+ let r0 = remap_register_reg sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ let r2 = remap_register_expr sb r2 in
+ I_Set(r0, cond, r1, r2)
+
+ | I_LoadVar(r0, i) ->
+ let r0 = remap_register_reg sb r0 in
+ I_LoadVar(r0, i)
+
+ | I_StoreVar(i, r0) ->
+ let r0 = remap_register_expr sb r0 in
+ I_StoreVar(i, r0)
+
+ | I_LoadStack(r0, i) ->
+ let r0 = remap_register_reg sb r0 in
+ I_LoadStack(r0, i)
+
+ | I_StoreStack(i, r0) ->
+ let r0 = remap_register_expr sb r0 in
+ I_StoreStack(i, r0)
+
+ | I_StackAlloc i ->
+ I_StackAlloc i
+
+ | I_StackFree i ->
+ I_StackFree i
+
+ | I_Use rs ->
+ I_Use (List.map (remap_register_reg sb) rs)
+
+ | I_Def rs ->
+ I_Def (List.map (remap_register_reg sb) rs)
+
+ | I_Call (rs, procid, args, kills) ->
+ let rs = List.map (remap_register_reg sb) rs in
+ let args = List.map (remap_register_expr sb) args in
+ let kills = List.map (remap_register_reg sb) kills in
+ I_Call (rs, procid, args, kills)
+
+let subst_expr rmap = function
+ | (E_Reg r) as e ->
+ begin match RegMap.find_opt r rmap with
+ | None -> e
+ | Some e -> e
+ end
+ | e -> e
+
+let subst_expr_instr sb = function
+ | I_Add (r0, r1, r2) ->
+ let r1 = subst_expr sb r1 in
+ let r2 = subst_expr sb r2 in
+ I_Add (r0, r1, r2)
+
+ | I_Sub (r0, r1, r2) ->
+ let r1 = subst_expr sb r1 in
+ let r2 = subst_expr sb r2 in
+ I_Sub (r0, r1, r2)
+
+ | I_Div (r0, r1, r2) ->
+ let r1 = subst_expr sb r1 in
+ let r2 = subst_expr sb r2 in
+ I_Div (r0, r1, r2)
+
+ | I_Rem (r0, r1, r2) ->
+ let r1 = subst_expr sb r1 in
+ let r2 = subst_expr sb r2 in
+ I_Rem (r0, r1, r2)
+
+ | I_Mul(r0, r1, r2) ->
+ let r1 = subst_expr sb r1 in
+ let r2 = subst_expr sb r2 in
+ I_Mul (r0, r1, r2)
+
+ | I_And(r0, r1, r2) ->
+ let r1 = subst_expr sb r1 in
+ let r2 = subst_expr sb r2 in
+ I_And(r0, r1, r2)
+
+ | I_Or(r0, r1, r2) ->
+ let r1 = subst_expr sb r1 in
+ let r2 = subst_expr sb r2 in
+ I_Or(r0, r1, r2)
+
+ | I_Xor(r0, r1, r2) ->
+ let r1 = subst_expr sb r1 in
+ let r2 = subst_expr sb r2 in
+ I_Xor(r0, r1, r2)
+
+ | I_LoadArray(r0, r1, r2) ->
+ let r1 = subst_expr sb r1 in
+ let r2 = subst_expr sb r2 in
+ I_LoadArray(r0, r1, r2)
+
+ | I_StoreArray(r0, r1, r2) ->
+ let r0 = subst_expr sb r0 in
+ let r1 = subst_expr sb r1 in
+ let r2 = subst_expr sb r2 in
+ I_StoreArray(r0, r1, r2)
+
+ | I_LoadMem(r0, r1, r2) ->
+ let r1 = subst_expr sb r1 in
+ let r2 = subst_expr sb r2 in
+ I_LoadMem(r0, r1, r2)
+
+ | I_StoreMem(r0, r1, r2) ->
+ let r0 = subst_expr sb r0 in
+ let r1 = subst_expr sb r1 in
+ let r2 = subst_expr sb r2 in
+ I_StoreMem(r0, r1, r2)
+
+ | I_Concat(r0, r1, r2) ->
+ let r1 = subst_expr sb r1 in
+ let r2 = subst_expr sb r2 in
+ I_Concat(r0, r1, r2)
+
+ | I_Neg(r0, r1) ->
+ let r1 = subst_expr sb r1 in
+ I_Neg(r0, r1)
+
+ | I_Not(r0, r1) ->
+ let r1 = subst_expr sb r1 in
+ I_Not(r0, r1)
+
+ | I_Move(r0, r1) ->
+ let r1 = subst_expr sb r1 in
+ I_Move(r0, r1)
+
+ | I_Length(r0, r1) ->
+ let r1 = subst_expr sb r1 in
+ I_Length(r0, r1)
+
+ | I_NewArray(r0, r1) ->
+ let r1 = subst_expr sb r1 in
+ I_NewArray(r0, r1)
+
+ | I_Set(r0, cond, r1, r2) ->
+ let r1 = subst_expr sb r1 in
+ let r2 = subst_expr sb r2 in
+ I_Set(r0, cond, r1, r2)
+
+ | I_LoadVar(r0, i) ->
+ I_LoadVar(r0, i)
+
+ | I_StoreVar(i, r0) ->
+ let r0 = subst_expr sb r0 in
+ I_StoreVar(i, r0)
+
+ | I_LoadStack(r0, i) ->
+ I_LoadStack(r0, i)
+
+ | I_StoreStack(i, r0) ->
+ let r0 = subst_expr sb r0 in
+ I_StoreStack(i, r0)
+
+ | I_StackAlloc i ->
+ I_StackAlloc i
+
+ | I_StackFree i ->
+ I_StackFree i
+
+ | I_Use rs ->
+ I_Use rs
+
+ | I_Def rs ->
+ I_Def rs
+
+ | I_Call (rs, procid, args, kills) ->
+ let args = List.map (subst_expr sb) args in
+ I_Call (rs, procid, args, kills)
+
+let remap_label_label sb l =
+ try
+ Hashtbl.find sb l
+ with Not_found ->
+ l
+
+let remap_label_terminator sb = function
+ | T_Jump l ->
+ T_Jump (remap_label_label sb l)
+
+ | T_Branch (cond, r0, r1, lt, lf) ->
+ T_Branch (cond, r0, r1, remap_label_label sb lt, remap_label_label sb lf)
+
+ | t ->
+ t
+
+let remap_register_terminator sb = function
+ | T_Return xs ->
+ let xs = List.map (remap_register_expr sb) xs in
+ T_Return xs
+
+ | T_Branch (cond, r0, r1, l1, l2) ->
+ let r0 = remap_register_expr sb r0 in
+ let r1 = remap_register_expr sb r1 in
+ T_Branch (cond, r0, r1, l1, l2)
+
+ | T_Jump l ->
+ T_Jump l
+
+let subst_expr_terminator sb = function
+ | T_Return xs ->
+ let xs = List.map (subst_expr sb) xs in
+ T_Return xs
+
+ | T_Branch (cond, r0, r1, l1, l2) ->
+ let r0 = subst_expr sb r0 in
+ let r1 = subst_expr sb r1 in
+ T_Branch (cond, r0, r1, l1, l2)
+
+ | T_Jump l ->
+ T_Jump l
+
+let defined_registers_instr = function
+ | I_Add (r0, _, _)
+ | I_Sub (r0, _, _)
+ | I_Div (r0, _, _)
+ | I_Mul (r0, _, _)
+ | I_And (r0, _, _)
+ | I_Or (r0, _, _)
+ | I_Xor (r0, _, _)
+ | I_LoadArray (r0, _, _)
+ | I_LoadMem (r0, _, _)
+ | I_Concat (r0, _, _)
+ | I_Not (r0, _)
+ | I_Move (r0, _)
+ | I_Length (r0, _)
+ | I_NewArray (r0, _)
+ | I_Neg (r0, _)
+ | I_Set (r0, _, _, _)
+ | I_Rem (r0, _, _)
+ | I_LoadStack (r0, _)
+ | I_LoadVar (r0, _) ->
+ [r0]
+
+
+ | I_Call (outs, _, _, kills) ->
+ outs @ kills
+
+ | I_Use _
+ | I_StoreVar _
+ | I_StoreStack _
+ | I_StackAlloc _
+ | I_StackFree _
+ | I_StoreMem _
+ | I_StoreArray _ ->
+ []
+
+ | I_Def rs ->
+ rs
+
+let defined_registers_terminator _ = []
+
+let used_registers_instr = function
+ | I_Add (_, r0, r1)
+ | I_Sub (_, r0, r1)
+ | I_Div (_, r0, r1)
+ | I_Mul (_, r0, r1)
+ | I_And (_, r0, r1)
+ | I_Or (_, r0, r1)
+ | I_Xor (_, r0, r1)
+ | I_LoadArray (_, r0, r1)
+ | I_LoadMem (_, r0, r1)
+ | I_Concat (_, r0, r1)
+ | I_Set (_, _, r0, r1)
+ | I_Rem (_, r0, r1) ->
+ List.flatten @@ List.map reglist_of_expr [r0;r1]
+
+ | I_Not (_, r0)
+ | I_Move (_, r0)
+ | I_Length (_, r0)
+ | I_NewArray (_, r0)
+ | I_StoreVar (_, r0)
+ | I_StoreStack (_, r0)
+ | I_Neg (_, r0) ->
+ reglist_of_expr r0
+
+ | I_Call (_, _, args, _) ->
+ List.flatten @@ List.map reglist_of_expr args
+
+ | I_Def _
+ | I_StackAlloc _
+ | I_StackFree _
+ | I_LoadStack _
+ | I_LoadVar _ ->
+ []
+
+ | I_StoreArray (r0, r1, r2)
+ | I_StoreMem (r0, r1, r2) ->
+ List.flatten @@ List.map reglist_of_expr [r0; r1; r2]
+
+ | I_Use rs ->
+ rs
+
+let used_registers_terminator = function
+ | T_Branch (_, r0, r1, _, _) ->
+ List.flatten @@ List.map reglist_of_expr [r0;r1]
+
+
+ | T_Return args ->
+ List.flatten @@ List.map reglist_of_expr args
+
+ | T_Jump _ ->
+ []
+
+let remap_registers_proc sb proc =
+ let cfg = (cfg_of_procedure proc) in
+ let remap_block (l, body, terminator) =
+ let body = List.map (remap_register_instr sb) body in
+ let terminator = remap_register_terminator sb terminator in
+ (l, body, terminator)
+ in
+ let update_blocks (l, body, terminator) =
+ ControlFlowGraph.set_block2 cfg l body terminator
+ in
+
+ let blocks = ControlFlowGraph.blocklist2 cfg in
+ let blocks = List.map remap_block blocks in
+ List.iter update_blocks blocks
+
+let string_of_expr = function
+ | E_Reg r -> string_of_reg r
+ | E_Int i -> Int32.to_string i
+
+let string_of_label = function
+ | Label i -> Format.sprintf "L%u" i
+
+let string_of_procid = function
+ | Procid l -> Format.sprintf "%s" l
+
+let string_of_reglist xs =
+ Format.sprintf "[%s]" (String.concat ", " @@ List.map string_of_reg xs)
+
+let string_of_labellist xs =
+ Format.sprintf "[%s]" (String.concat ", " @@ List.map string_of_label xs)
+
+let string_of_exprlist xs =
+ Format.sprintf "[%s]" (String.concat ", " @@ List.map string_of_expr xs)
+
+let string_of_expr_regmap k =
+ let f (k, v) = Format.sprintf "%s=%s" (string_of_reg k) (string_of_expr v) in
+ String.concat "; " @@ List.of_seq @@ Seq.map f @@ RegMap.to_seq k
+let string_of_instr = function
+ | I_Add (r0, e0, e1) ->
+ Format.sprintf "add %s, %s, %s"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ | I_Sub (r0, e0, e1) ->
+ Format.sprintf "sub %s, %s, %s"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ | I_Div (r0, e0, e1) ->
+ Format.sprintf "div %s, %s, %s"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ | I_Rem (r0, e0, e1) ->
+ Format.sprintf "rem %s, %s, %s"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ | I_Mul (r0, e0, e1) ->
+ Format.sprintf "mul %s, %s, %s"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ | I_And (r0, e0, e1) ->
+ Format.sprintf "and %s, %s, %s"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ | I_Or (r0, e0, e1) ->
+ Format.sprintf "or %s, %s, %s"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ | I_Xor (r0, e0, e1) ->
+ Format.sprintf "xor %s, %s, %s"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ | I_LoadArray (r0, e0, e1) ->
+ Format.sprintf "loadarray %s, %s, %s // %s = %s[%s]"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ (string_of_reg r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ | I_LoadMem (r0, e0, e1) ->
+ Format.sprintf "loadmem %s, %s, %s // %s = mem[%s + %s]"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ (string_of_reg r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ | I_StoreArray (r0, e0, e1) ->
+ Format.sprintf "storearray %s, %s, %s // %s[%s] = %s"
+ (string_of_expr r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ (string_of_expr r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ | I_StoreMem (r0, e0, e1) ->
+ Format.sprintf "storemem %s, %s, %s // mem[%s + %s] = %s"
+ (string_of_expr r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ (string_of_expr r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ | I_Concat (r0, e0, e1) ->
+ Format.sprintf "concat %s, %s, %s"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ (string_of_expr e1)
+ | I_Neg (r0, e0) ->
+ Format.sprintf "neg %s, %s"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ | I_Not (r0, e0) ->
+ Format.sprintf "not %s, %s"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ | I_Length (r0, e0) ->
+ Format.sprintf "length %s, %s"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ | I_Move (r0, e0) ->
+ Format.sprintf "move %s, %s"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ | I_NewArray (r0, e0) ->
+ Format.sprintf "newarray %s, %s"
+ (string_of_reg r0)
+ (string_of_expr e0)
+ | I_Call (rs, p, xs, kill) ->
+ Format.sprintf "call %s, %s, %s, kill %s"
+ (string_of_reglist rs)
+ (string_of_procid p)
+ (string_of_exprlist xs)
+ (string_of_reglist kill)
+ | I_Set (rr, cond, r0, r1) ->
+ Format.sprintf "set %s, %s, %s, %s"
+ (string_of_reg rr)
+ (string_of_cond cond)
+ (string_of_expr r0)
+ (string_of_expr r1)
+ | I_StoreVar (i0, e0) ->
+ Format.sprintf "storevar %s, %s"
+ (string_of_int i0)
+ (string_of_expr e0)
+ | I_LoadVar (r0, i0) ->
+ Format.sprintf "loadvar %s, %s"
+ (string_of_reg r0)
+ (string_of_int i0)
+ | I_StoreStack (i0, e0) ->
+ Format.sprintf "storestack %s, %s"
+ (string_of_int i0)
+ (string_of_expr e0)
+ | I_LoadStack (r0, i0) ->
+ Format.sprintf "loadstack %s, %s"
+ (string_of_reg r0)
+ (string_of_int i0)
+ | I_StackAlloc (i0) ->
+ Format.sprintf "stackalloc %s"
+ (Int32.to_string i0)
+ | I_StackFree (i0) ->
+ Format.sprintf "stackfree %s"
+ (Int32.to_string i0)
+ | I_Use rs ->
+ Format.sprintf "use %s" (string_of_reglist rs)
+ | I_Def rs ->
+ Format.sprintf "def %s" (string_of_reglist rs)
+
+let string_of_terminator = function
+ | T_Branch (cond, r0, r1, l1, l2) ->
+ Format.sprintf "branch %s, %s, %s, %s, %s"
+ (string_of_cond cond)
+ (string_of_expr r0)
+ (string_of_expr r1)
+ (string_of_label l1)
+ (string_of_label l2)
+ | T_Jump (l) ->
+ Format.sprintf "jump %s"
+ (string_of_label l)
+ | T_Return xs ->
+ Format.sprintf "return %s"
+ (string_of_exprlist xs)
+
+let indented_string_of_instr i = " " ^ (string_of_instr i)
+let indented_string_of_terminator i = " " ^ (string_of_terminator i)
+
+let string_of_block_body cfg label body =
+ String.concat "\n"
+ [ Format.sprintf "%s:" (string_of_label label)
+ ; Format.sprintf " cfg successors: %s"
+ (string_of_labellist @@ ControlFlowGraph.successors cfg label)
+ ; Format.sprintf " cfg predecessors: %s"
+ (string_of_labellist @@ ControlFlowGraph.predecessors cfg label)
+ ; String.concat "\n" (List.map indented_string_of_instr body)
+ ]
+
+let string_of_block cfg k v =
+ let terminator = match ControlFlowGraph.terminator_safe cfg k with
+ | None -> "<<no terminator>>"
+ | Some t -> indented_string_of_terminator t
+ in
+ String.concat "\n"
+ [ string_of_block_body cfg k v
+ ; terminator
+ ]
+
+let string_of_blockmap cfg =
+ let f xs (k, v) = string_of_block cfg k v :: xs in
+ let items = Seq.fold_left (fun xs x -> x::xs) [] (Hashtbl.to_seq @@ ControlFlowGraph.blockmap cfg) in
+ let items = List.sort compare items in
+ String.concat "\n" @@ List.rev @@ List.fold_left f [] items
+
+let string_of_cfg cfg =
+ String.concat "\n"
+ [ Format.sprintf " cfg entry point: %s" (string_of_label @@ ControlFlowGraph.entry_label cfg)
+
+ ; Format.sprintf " cfg entry point successors: %s"
+ (string_of_labellist @@ ControlFlowGraph.successors cfg @@ ControlFlowGraph.entry_label cfg)
+
+ ; Format.sprintf " cfg exit point: %s" (string_of_label @@ ControlFlowGraph.exit_label cfg)
+
+ ; Format.sprintf " cfg exit point predecessors : %s"
+ (string_of_labellist @@ ControlFlowGraph.predecessors cfg @@ ControlFlowGraph.exit_label cfg)
+
+ ; string_of_blockmap cfg
+ ]
+
+let string_of_procedure (Procedure {procid; cfg; frame_size; formal_parameters; _}) =
+ String.concat "\n"
+ [ "////////////////////////////////////// "
+ ; Format.sprintf "procedure %s" (string_of_procid procid)
+ ; Format.sprintf " frame size: %u" frame_size
+ ; Format.sprintf " formal parameters: %u" formal_parameters
+ ; string_of_cfg cfg
+ ]
+
+let string_of_module_definition xs =
+ String.concat "\n" @@ List.map string_of_procedure xs
+
+let string_of_program (Program {procedures; _}) =
+ String.concat "\n" @@ List.map string_of_procedure procedures \ No newline at end of file
diff --git a/source/xi_lib/logger.ml b/source/xi_lib/logger.ml
new file mode 100644
index 0000000..746bbb8
--- /dev/null
+++ b/source/xi_lib/logger.ml
@@ -0,0 +1,170 @@
+module FS = struct
+
+ let removedir =
+ let rec rm path item =
+ let p = (Filename.concat path item) in
+ if Sys.is_directory p then
+ let items = Sys.readdir p in
+ Array.iter (rm p) items;
+ Unix.rmdir p;
+ else
+ Sys.remove p
+ in
+ fun item ->
+ if Sys.file_exists item then
+ rm "" item
+
+
+ let xilog_dir = ref "xilog"
+
+ let init xilog =
+ xilog_dir := xilog;
+ removedir xilog;
+ Unix.mkdir xilog 0o777
+end
+
+
+module State = struct
+
+ let extra_debug = ref false
+
+ let counter = ref 0
+
+ let phase_name = ref ""
+
+ let proc_name = ref ""
+
+ let log_file_name = ref ""
+
+ let log_file_handle : out_channel option ref = ref None
+
+ let get_lof_file_handle () =
+ match !log_file_handle with
+ | Some handle ->
+ handle
+ | None ->
+ assert (!log_file_name <> "");
+ let handle = open_out !log_file_name in
+ log_file_handle := Some handle;
+ handle
+
+ let close_log_file () =
+ match !log_file_handle with
+ | None ->
+ ()
+ | Some handle ->
+ close_out handle;
+ log_file_name := "";
+ log_file_handle := None
+
+ let make_entry_name = function
+ | () when !phase_name <> "" && !proc_name <> "" ->
+ Format.sprintf "%03u.%s.%s" !counter !phase_name !proc_name
+ | () when !phase_name <> "" ->
+ Format.sprintf "%03u.%s" !counter !phase_name
+ | _ ->
+ Format.sprintf "%03u.unknown-phase" !counter
+
+ let allocate_file_name title =
+ let r = Format.sprintf "%s/%s.%s" !FS.xilog_dir (make_entry_name ()) title in
+ incr counter;
+ r
+
+ let set_new_phase name =
+ phase_name := name;
+ proc_name := "";
+ close_log_file ();
+ log_file_name := allocate_file_name "log"
+
+
+ let set_proc_phase procid =
+ proc_name := Ir_utils.string_of_procid procid;
+ close_log_file ();
+ log_file_name := allocate_file_name "log"
+
+
+ let close_phase_proc () =
+ proc_name := "";
+ close_log_file ();
+ log_file_name := allocate_file_name "log"
+
+ let set_extra_debug v =
+ extra_debug := v
+end
+
+
+let extra_debug f =
+ if !State.extra_debug then
+ f ()
+
+let set_extra_debug = State.set_extra_debug
+
+let new_phase name =
+ State.set_new_phase name
+
+let new_phase_proc procid =
+ State.set_proc_phase procid
+
+let close_phase_proc () =
+ State.close_phase_proc ()
+
+let make_logf mname fmt =
+ let cont s =
+ let h = State.get_lof_file_handle () in
+ let entry = Format.sprintf "%s: %s\n" mname s in
+ output_string h entry;
+ flush h
+ in
+ Format.ksprintf cont fmt
+
+let dump_string title buffer =
+ let name = State.allocate_file_name title in
+ make_logf __MODULE__ "Dumping %s" (Filename.basename name);
+ let h = open_out name in
+ output_string h buffer;
+ output_string h "\n";
+ close_out h
+
+let dump_ir_program title ir =
+ let buffer = Ir_utils.string_of_program ir in
+ dump_string title buffer
+
+let dump_ir_proc title irproc =
+ let buffer = Ir_utils.string_of_procedure irproc in
+ dump_string title buffer
+
+let dump_spill_costs spill_costs =
+ let f (k,v) = Format.sprintf "%s -> %u" (Ir.string_of_reg k) v in
+ let seq = Hashtbl.to_seq spill_costs in
+ let seq = Seq.map f seq in
+ let seq = List.of_seq seq in
+ let buf = String.concat "\n" @@ List.sort compare seq in
+ dump_string "spill_costs" buf
+
+let dump_spill_costs_f spill_costs =
+ let f (k,v) = Format.sprintf "%s -> %f" (Ir.string_of_reg k) v in
+ let seq = Hashtbl.to_seq spill_costs in
+ let seq = Seq.map f seq in
+ let seq = List.of_seq seq in
+ let buf = String.concat "\n" @@ List.sort compare seq in
+ dump_string "spill_costs" buf
+
+
+let log_ir_proc mname irproc =
+ let buffer = Ir_utils.string_of_procedure irproc in
+ make_logf mname "%s" buffer
+
+let dump_interference_graph title x =
+ let buffer = Analysis_visualizer.visualize_interference_graph x in
+ dump_string (title ^ ".infg.xdot") buffer
+
+let dump_live_variables title cfg table =
+ let buffer = Analysis_visualizer.visualize_live_variables cfg table in
+ dump_string (title ^ ".lva.xdot") buffer
+
+let dump_constant_folding title cfg table =
+ let buffer = Analysis_visualizer.visualize_constant_folding cfg table in
+ dump_string (title ^ ".cfa.xdot") buffer
+
+let init xilog =
+ FS.init xilog \ No newline at end of file
diff --git a/source/xi_lib/measure.ml b/source/xi_lib/measure.ml
new file mode 100644
index 0000000..1aec0b9
--- /dev/null
+++ b/source/xi_lib/measure.ml
@@ -0,0 +1,8 @@
+let logf fmt = Logger.make_logf __MODULE__ fmt
+
+let measure name f =
+ let t_start = Unix.gettimeofday () in
+ let r = f () in
+ let t_end = Unix.gettimeofday () in
+ logf "%s: execution time %f" name (t_end -. t_start);
+ r \ No newline at end of file
diff --git a/source/xi_lib/mips32.ml b/source/xi_lib/mips32.ml
new file mode 100644
index 0000000..99735b3
--- /dev/null
+++ b/source/xi_lib/mips32.ml
@@ -0,0 +1,217 @@
+
+type reg =
+ | Reg of int
+
+let string_of_reg_raw (Reg i) = Format.sprintf "$%u" i
+
+let string_of_reg = function
+ | Reg 0 -> "$zero"
+ | Reg 1 -> "$at"
+ | Reg 2 -> "$v0"
+ | Reg 3 -> "$v1"
+ | Reg 4 -> "$a0"
+ | Reg 5 -> "$a1"
+ | Reg 6 -> "$a2"
+ | Reg 7 -> "$a3"
+ | Reg 8 -> "$t0"
+ | Reg 9 -> "$t1"
+ | Reg 10 -> "$t2"
+ | Reg 11 -> "$t3"
+ | Reg 12 -> "$t4"
+ | Reg 13 -> "$t5"
+ | Reg 14 -> "$t6"
+ | Reg 15 -> "$t7"
+ | Reg 16 -> "$s0"
+ | Reg 17 -> "$s1"
+ | Reg 18 -> "$s2"
+ | Reg 19 -> "$s3"
+ | Reg 20 -> "$s4"
+ | Reg 21 -> "$s5"
+ | Reg 22-> "$s6"
+ | Reg 23 -> "$s7"
+ | Reg 24 -> "$t8"
+ | Reg 25 -> "$t9"
+ | Reg 26 -> "$k0"
+ | Reg 27 -> "$k1"
+ | Reg 28 -> "$gp"
+ | Reg 29 -> "$sp"
+ | Reg 30 -> "$fp"
+ | Reg 31 -> "$ra"
+ | r -> string_of_reg_raw r
+
+let reg_zero = Reg 0
+let reg_sp = Reg 29
+let reg_fp = Reg 30
+let reg_ra = Reg 31
+
+let reg_s = function
+ | i when i < 8 ->
+ Reg (16 + i)
+ | i -> failwith @@ Format.sprintf "There is no $sp%u" i
+
+type label =
+ | Label of string
+
+let string_of_label (Label s) = s
+
+type instr =
+ | I_Label of label
+ | I_Add of reg * reg * reg
+ | I_Addu of reg * reg * reg
+ | I_Addi of reg * reg * Int32.t
+ | I_Addiu of reg * reg * Int32.t
+ | I_Sub of reg * reg * reg
+ | I_Subu of reg * reg * reg
+ | I_Div of reg * reg
+ | I_Mult of reg * reg
+ | I_Multu of reg * reg
+ | I_And of reg * reg * reg
+ | I_Andi of reg * reg * Int32.t
+ | I_Nor of reg * reg * reg
+ | I_Or of reg * reg * reg
+ | I_Ori of reg * reg * Int32.t
+ | I_Xor of reg * reg * reg
+ | I_Xori of reg * reg * Int32.t
+ | I_Sll of reg * reg * reg
+ | I_Sllv of reg * reg * reg
+ | I_Sra of reg * reg * reg
+ | I_Srav of reg * reg * reg
+ | I_Srl of reg * reg * reg
+ | I_Rol of reg * reg * reg
+ | I_Ror of reg * reg * reg
+ | I_Srlv of reg * reg * reg
+ | I_Mfhi of reg
+ | I_Mflo of reg
+ | I_Lui of reg * Int32.t
+ | I_Lb of reg * Int32.t * reg
+ | I_Sb of reg * Int32.t * reg
+ | I_Lw of reg * Int32.t * reg
+ | I_Sw of reg * Int32.t * reg
+ | I_Slt of reg * reg * reg
+ | I_Slti of reg * reg * Int32.t
+ | I_Sltu of reg * reg * reg
+ | I_Beq of reg * reg * label
+ | I_Bgez of reg * label
+ | I_Bgezal of reg * label
+ | I_Bgtz of reg * label
+ | I_Blez of reg * label
+ | I_Bltz of reg * label
+ | I_Bltzal of reg * label
+ | I_Bne of reg * reg * label
+ | I_J of label
+ | I_Jal of label
+ | I_Jr of reg
+ | I_Jalr of reg
+ | I_Nop
+
+let string_of_instr = function
+ | I_Label l -> Format.sprintf "%s:"
+ (string_of_label l)
+ |I_Add (r0, r1, r2) -> Format.sprintf "add %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Addu (r0, r1, r2) -> Format.sprintf "addu %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Addiu (r0, r1, i) -> Format.sprintf "addiu %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (Int32.to_string i)
+ |I_Addi (r0, r1, i) -> Format.sprintf "addi %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (Int32.to_string i)
+ |I_Sub (r0, r1, r2) -> Format.sprintf "sub %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Subu (r0, r1, r2) -> Format.sprintf "subu %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Div (r0, r1) -> Format.sprintf "div %s, %s"
+ (string_of_reg r0) (string_of_reg r1)
+ |I_Mult (r0, r1) -> Format.sprintf "mult %s, %s"
+ (string_of_reg r0) (string_of_reg r1)
+ |I_Multu (r0, r1) -> Format.sprintf "multu %s, %s"
+ (string_of_reg r0) (string_of_reg r1)
+ |I_And (r0, r1, r2) -> Format.sprintf "and %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Andi (r0, r1, i) -> Format.sprintf "andi %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (Int32.to_string i)
+ |I_Nor (r0, r1, r2) -> Format.sprintf "nor %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Or (r0, r1, r2) -> Format.sprintf "or %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Ori (r0, r1, i) -> Format.sprintf "ori %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (Int32.to_string i)
+ |I_Xor (r0, r1, r2) -> Format.sprintf "xor %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Xori (r0, r1, i) -> Format.sprintf "xori %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (Int32.to_string i)
+ |I_Sll (r0, r1, r2) -> Format.sprintf "sll %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Sllv (r0, r1, r2) -> Format.sprintf "sllv %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Srl (r0, r1, r2) -> Format.sprintf "srl %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Srlv (r0, r1, r2) -> Format.sprintf "srlv %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Mfhi (r0) -> Format.sprintf "mfhi %s"
+ (string_of_reg r0)
+ |I_Mflo (r0) -> Format.sprintf "mflo %s"
+ (string_of_reg r0)
+ |I_Lui (r0, i) -> Format.sprintf "lui %s, %s"
+ (string_of_reg r0) (Int32.to_string i)
+ |I_Lb (r0, i0, r1) -> Format.sprintf "lb %s, %s(%s)"
+ (string_of_reg r0) (Int32.to_string i0) (string_of_reg r1)
+ |I_Sb (r0, i0, r1) -> Format.sprintf "sb %s, %s(%s)"
+ (string_of_reg r0) (Int32.to_string i0) (string_of_reg r1)
+ |I_Lw (r0, i0, r1) -> Format.sprintf "lw %s, %s(%s)"
+ (string_of_reg r0) (Int32.to_string i0) (string_of_reg r1)
+ |I_Sw (r0, i0, r1) -> Format.sprintf "sw %s, %s(%s)"
+ (string_of_reg r0) (Int32.to_string i0) (string_of_reg r1)
+ |I_Slt (r0, r1, r2) -> Format.sprintf "slt %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Sra (r0, r1, r2) -> Format.sprintf "sra %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Srav (r0, r1, r2) -> Format.sprintf "srav %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Rol (r0, r1, r2) -> Format.sprintf "srav %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Ror (r0, r1, r2) -> Format.sprintf "srav %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Slti (r0, r1, i) -> Format.sprintf "slti %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (Int32.to_string i)
+ |I_Sltu (r0, r1, r2) -> Format.sprintf "sltu %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_reg r2)
+ |I_Beq (r0, r1, l) -> Format.sprintf "beq %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_label l)
+ |I_Bgez (r0, l) -> Format.sprintf "bgez %s, %s"
+ (string_of_reg r0) (string_of_label l)
+ |I_Bgezal (r0, l) -> Format.sprintf "bgezal %s, %s"
+ (string_of_reg r0) (string_of_label l)
+ |I_Bgtz (r0, l) -> Format.sprintf "bgtz %s, %s"
+ (string_of_reg r0) (string_of_label l)
+ |I_Blez (r0, l) -> Format.sprintf "blez %s, %s"
+ (string_of_reg r0) (string_of_label l)
+ |I_Bltz (r0, l) -> Format.sprintf "bltz %s, %s"
+ (string_of_reg r0) (string_of_label l)
+ |I_Bltzal (r0, l) -> Format.sprintf "bltzal %s, %s"
+ (string_of_reg r0) (string_of_label l)
+ |I_Bne (r0, r1, l) -> Format.sprintf "bne %s, %s, %s"
+ (string_of_reg r0) (string_of_reg r1) (string_of_label l)
+ |I_J (l) -> Format.sprintf "j %s"
+ (string_of_label l)
+ |I_Jal (l) -> Format.sprintf "jal %s"
+ (string_of_label l)
+ |I_Jr (r0) -> Format.sprintf "jr %s"
+ (string_of_reg r0)
+ |I_Jalr (r0) -> Format.sprintf "jalr %s"
+ (string_of_reg r0)
+ | I_Nop -> Format.sprintf "add $zero, $zero, $zero"
+
+type program = (label * instr list) list
+
+
+let indent x = " " ^ x
+
+let string_of_program (l, b) =
+ String.concat "\n"
+ [ Format.sprintf "%s:" (string_of_label l)
+ ; String.concat "\n" (List.map indent @@ List.map string_of_instr b)
+ ]
+
+let string_of_program xs =
+ String.concat "\n"
+ (List.map string_of_program xs)
diff --git a/source/xi_lib/mygraph.ml b/source/xi_lib/mygraph.ml
new file mode 100644
index 0000000..5836414
--- /dev/null
+++ b/source/xi_lib/mygraph.ml
@@ -0,0 +1,155 @@
+
+(* Just to keep compatibility with Ocamlgraph *)
+module type SElem = sig
+
+ type t
+
+ val compare: t -> t -> int
+
+ val hash: t -> int
+
+ val equal: t -> t -> bool
+
+end
+
+module MakeBidirectional(V:SElem) = struct
+
+ type t =
+ { g_successors: (V.t, V.t Hashset.t) Hashtbl.t
+ ; g_predecessors: (V.t, V.t Hashset.t) Hashtbl.t
+ ; g_vertices : V.t Hashset.t
+ }
+
+ let create () =
+ { g_successors = Hashtbl.create 101
+ ; g_predecessors = Hashtbl.create 101
+ ; g_vertices = Hashset.create ()
+ }
+
+ let nb_vertex g =
+ Hashset.length g.g_vertices
+
+ let _assert_mem g v =
+ assert (Hashset.mem g.g_vertices v)
+
+ let add_vertex g v =
+ if not @@ Hashset.mem g.g_vertices v then begin
+ Hashset.add g.g_vertices v;
+ Hashtbl.replace g.g_successors v @@ Hashset.create ();
+ Hashtbl.replace g.g_predecessors v @@ Hashset.create ()
+ end
+
+ let _succ g v =
+ Hashtbl.find g.g_successors v
+
+ let _pred g v =
+ Hashtbl.find g.g_predecessors v
+
+ let remove_vertex g v =
+ _assert_mem g v;
+ Hashset.remove g.g_vertices v;
+ let remove_pred w =
+ let pred = _pred g w in
+ Hashset.remove pred v
+ in
+ let succ = _succ g v in
+ Hashset.iter remove_pred succ
+
+ let add_edge g v w =
+ add_vertex g v;
+ add_vertex g w;
+ let v_succ = _succ g v in
+ let w_pred = _pred g w in
+ Hashset.add v_succ w;
+ Hashset.add w_pred v
+
+ let fold_vertex f g acc =
+ Hashset.fold f g.g_vertices acc
+
+ let succ g v =
+ _assert_mem g v;
+ List.of_seq @@ Hashset.to_seq @@ _succ g v
+
+ let pred g v =
+ _assert_mem g v;
+ List.of_seq @@ Hashset.to_seq @@ _pred g v
+
+ let remove_edge g v w =
+ _assert_mem g v;
+ _assert_mem g w;
+ let v_succ = _succ g v in
+ let w_pred = _pred g w in
+ Hashset.remove v_succ w;
+ Hashset.remove w_pred v
+
+end
+
+module MakeUndirected(V:SElem) = struct
+
+ type t =
+ { g_neighbours: (V.t, V.t Hashset.t) Hashtbl.t
+ }
+
+ let create () =
+ { g_neighbours = Hashtbl.create 101
+ }
+
+ let nb_vertex g =
+ Hashtbl.length g.g_neighbours
+
+ let _assert_mem g v =
+ assert (Hashtbl.mem g.g_neighbours v)
+
+ let add_vertex g v =
+ if not @@ Hashtbl.mem g.g_neighbours v then begin
+ Hashtbl.replace g.g_neighbours v @@ Hashset.create ();
+ end
+
+ let _nb g v =
+ Hashtbl.find g.g_neighbours v
+
+ let remove_vertex g v =
+ _assert_mem g v;
+ let remove_pred w =
+ let pred = _nb g w in
+ Hashset.remove pred v
+ in
+ let succ = _nb g v in
+ Hashset.iter remove_pred succ;
+ Hashtbl.remove g.g_neighbours v
+
+ let add_edge g v w =
+ add_vertex g v;
+ add_vertex g w;
+ let v_nb = _nb g v in
+ let w_nb = _nb g w in
+ Hashset.add v_nb w;
+ Hashset.add w_nb v
+
+ let fold_vertex f g acc =
+ let h k _ = f k in
+ Hashtbl.fold h g.g_neighbours acc
+
+ let succ g v =
+ _assert_mem g v;
+ List.of_seq @@ Hashset.to_seq @@ _nb g v
+
+ let fold_edges f g acc =
+ let h v nb acc =
+ let f' w acc = f w v acc in
+ Hashset.fold f' nb acc
+ in
+ Hashtbl.fold h g.g_neighbours acc
+
+ let iter_edges f g =
+ let h v nb =
+ let f' w = f w v in
+ Hashset.iter f' nb
+ in
+ Hashtbl.iter h g.g_neighbours
+
+ let out_degree g v =
+ _assert_mem g v;
+ Hashset.length @@ _nb g v
+
+end \ No newline at end of file
diff --git a/source/xi_lib/parser_utils.ml b/source/xi_lib/parser_utils.ml
new file mode 100644
index 0000000..0600d8b
--- /dev/null
+++ b/source/xi_lib/parser_utils.ml
@@ -0,0 +1,7 @@
+exception InvalidToken of Ast.location * string
+
+let mkLocation pos =
+ let line = pos.Lexing.pos_lnum in
+ let column = pos.Lexing.pos_cnum - pos.Lexing.pos_bol + 1 in
+ let file = pos.Lexing.pos_fname in
+ Ast.Location {line; column; file} \ No newline at end of file
diff --git a/source/xi_lib/plugin.ml b/source/xi_lib/plugin.ml
new file mode 100644
index 0000000..33e6e4e
--- /dev/null
+++ b/source/xi_lib/plugin.ml
@@ -0,0 +1,85 @@
+open Iface
+
+
+module type MAKE_NATURAL_LOOPS_ANALYSIS = functor () -> NATURAL_LOOPS_ANALYSIS
+
+module type MAKE_SPILL_COSTS_ANALYSIS = functor () -> SPILL_COSTS_ANALYSIS
+
+module type MAKE_LIVE_VARIABLES_ANALYSIS = functor () -> LIVE_VARIABLES_ANALYSIS
+
+module type MAKE_DOMINANCE_ANALYSIS = functor () -> DOMINATORS_ANALYSIS
+
+module type MAKE_REACHABILITY_ANALYSIS = functor () -> REACHABILITY_ANALYSIS
+
+module type MAKE_CONSTANT_FOLDING_ANALYSIS = functor () -> CONSTANT_FOLDING_ANALYSIS
+
+module type MAKE_SCHEDULER = functor () -> SCHEDULER
+
+module type MAKE_INTERFERENCE_GRAPH_ANALYSIS = functor () -> INTERFERENCE_GRAPH_ANALYSIS
+
+module type MAKE_REGISTER_ALLOCATOR = functor (T:COMPILER_TOOLBOX) -> REGISTER_ALLOCATOR
+
+module type MAKE_CALLCONV = functor (T:COMPILER_TOOLBOX) -> CALLCONV
+
+module type MAKE_CONSTANT_FOLDING = functor (T:COMPILER_TOOLBOX) -> CONSTANT_FOLDING
+
+module type MAKE_DEAD_CODE_ELIMINATION = functor (T:COMPILER_TOOLBOX) -> DEAD_CODE_ELIMINATION
+
+module type MAKE_TYPECHECKER = functor () -> TYPECHECKER
+
+module type MAKE_TRANSLATOR = functor () -> TRANSLATOR
+
+module type MAKE_JUMP_THREADING = functor () -> JUMP_THREADING
+
+module type MAKE_CODEGEN = functor (T:COMPILER_TOOLBOX) -> CODEGEN
+
+module type MAKE_HI_LOWER = functor (T:COMPILER_TOOLBOX) -> HI_LOWER
+
+module type MAKE_MIPS_LOWER = functor (T:COMPILER_TOOLBOX) -> MIPS_LOWER
+
+module type MAKE_SPILLING = functor () -> SPILLING
+
+module type PLUGIN = sig
+
+ val version: string
+
+ val make_live_variables_analysis : (module MAKE_LIVE_VARIABLES_ANALYSIS) option
+
+ val make_dominators_analysis : (module MAKE_DOMINANCE_ANALYSIS) option
+
+ val make_natural_loops_analysis : (module MAKE_NATURAL_LOOPS_ANALYSIS) option
+
+ val make_spill_costs_analysis : (module MAKE_SPILL_COSTS_ANALYSIS) option
+
+ val make_scheduler : (module MAKE_SCHEDULER) option
+
+ val lexer_and_parser : (module LEXER_AND_PARSER) option
+
+ val make_typechecker : (module MAKE_TYPECHECKER) option
+
+ val make_translator : (module MAKE_TRANSLATOR) option
+
+ val make_jump_threading : (module MAKE_JUMP_THREADING) option
+
+ val make_constant_folding : (module MAKE_CONSTANT_FOLDING) option
+
+ val make_hilower : (module MAKE_HI_LOWER) option
+
+ val make_callconv : (module MAKE_CALLCONV) option
+
+ val make_mipslower : (module MAKE_MIPS_LOWER) option
+
+ val make_constant_folding_analysis : (module MAKE_CONSTANT_FOLDING_ANALYSIS) option
+
+ val make_register_allocator : (module MAKE_REGISTER_ALLOCATOR) option
+
+ val make_codegen : (module MAKE_CODEGEN) option
+
+ val make_dead_code_elimination : (module MAKE_DEAD_CODE_ELIMINATION) option
+
+ val make_interference_graph_analysis : (module MAKE_INTERFERENCE_GRAPH_ANALYSIS) option
+
+ val make_spilling: (module MAKE_SPILLING) option
+
+ val make_reachability_analysis: (module MAKE_REACHABILITY_ANALYSIS) option
+end \ No newline at end of file
diff --git a/source/xi_lib/plugin_register.ml b/source/xi_lib/plugin_register.ml
new file mode 100644
index 0000000..da7e8a6
--- /dev/null
+++ b/source/xi_lib/plugin_register.ml
@@ -0,0 +1,16 @@
+open Plugin
+
+let register = ref []
+
+let current_file = ref ""
+
+let register_plugin plugin =
+ register := (!current_file, plugin) :: !register
+
+module RegisterPlugin(P:PLUGIN) = struct
+
+ let handle = (module P : PLUGIN)
+
+ let () = register_plugin handle
+
+end \ No newline at end of file
diff --git a/source/xi_lib/typechecker_errors.ml b/source/xi_lib/typechecker_errors.ml
new file mode 100644
index 0000000..f3ee529
--- /dev/null
+++ b/source/xi_lib/typechecker_errors.ml
@@ -0,0 +1,257 @@
+open Ast
+open Types
+
+type type_checking_error =
+ | TCERR_TypeMismatch of
+ { loc: location
+ ; expected: normal_type
+ ; actual: normal_type
+ }
+
+ | TCERR_BindingTypeMismatch of
+ { loc: location
+ ; expected: normal_type
+ ; actual: normal_type
+ ; id: identifier
+ }
+
+ | TCERR_BadNumberOfActualArguments of
+ { loc: location
+ ; expected: int
+ ; actual: int
+ }
+
+ | TCERR_BadNumberOfReturnValues of
+ { loc: location
+ ; expected: int
+ ; actual: int
+ }
+
+ | TCERR_UnknownIdentifier of
+ { loc: location
+ ; id: identifier
+ }
+
+ | TCERR_IdentifierIsNotVariable of
+ { loc: location
+ ; id: identifier
+ }
+
+ | TCERR_OtherError of
+ { loc: location
+ ; descr: string
+ }
+
+ | TCERR_IdentifierIsNotCallable of
+ { loc: location
+ ; id: identifier
+ }
+
+ | TCERR_NotAllControlPathsReturnValue of
+ { loc: location
+ ; id: identifier
+ }
+
+ | TCERR_ExpectedFunctionReturningOneValue of
+ { loc: location
+ ; id: identifier
+ }
+
+ | TCERR_ExpectedFunctionReturningManyValues of
+ { loc: location
+ ; expected: int
+ ; actual: int
+ ; id: identifier
+ }
+
+ | TCERR_ProcedureCannotReturnValue of
+ { loc: location
+ }
+
+ | TCERR_FunctionMustReturnValue of
+ { loc: location
+ }
+
+ | TCERR_ExpectedArray of
+ { loc: location
+ ; actual: normal_type
+ }
+
+ | TCERR_InvalidRedeclaration of
+ { loc: location
+ ; id: identifier
+ ; previous: env_type
+ }
+
+ | TCERR_ShadowsPreviousDefinition of
+ { loc: location
+ ; id: identifier
+ }
+
+ | TCERR_ArrayInitializationForbidden of
+ { loc: location }
+
+ | TCERR_CannotInferType of
+ { loc: location }
+
+let string_of_type_checking_error = function
+ | TCERR_TypeMismatch {loc; actual; expected} ->
+ Format.sprintf "%s: error: type mismatch: expected %s; got %s"
+ (string_of_location loc)
+ (string_of_normal_type expected)
+ (string_of_normal_type actual)
+
+ | TCERR_BindingTypeMismatch {loc; actual; expected; id} ->
+ Format.sprintf "%s: error: type mismatch: expected %s; got %s; binding %s"
+ (string_of_location loc)
+ (string_of_normal_type expected)
+ (string_of_normal_type actual)
+ (string_of_identifier id)
+
+ | TCERR_BadNumberOfActualArguments {loc; actual; expected} ->
+ Format.sprintf "%s: error: bad number of actual arguments: expected %u; got %u"
+ (string_of_location loc)
+ (expected)
+ (actual)
+
+ | TCERR_BadNumberOfReturnValues {loc; actual; expected} ->
+ Format.sprintf "%s: error: bad number of return values: expected %u; got %u"
+ (string_of_location loc)
+ (expected)
+ (actual)
+
+ | TCERR_UnknownIdentifier {loc; id} ->
+ Format.sprintf "%s: unknown identifier: %s"
+ (string_of_location loc)
+ (string_of_identifier id)
+
+ | TCERR_IdentifierIsNotVariable {loc; id} ->
+ Format.sprintf "%s: identifier is not a variable: %s"
+ (string_of_location loc)
+ (string_of_identifier id)
+
+ | TCERR_IdentifierIsNotCallable {loc; id} ->
+ Format.sprintf "%s: identifier is not callable: %s"
+ (string_of_location loc)
+ (string_of_identifier id)
+
+ | TCERR_OtherError {loc; descr} ->
+ Format.sprintf "%s: error: %s"
+ (string_of_location loc)
+ descr
+
+ | TCERR_NotAllControlPathsReturnValue {loc; id} ->
+ Format.sprintf "%s: not all control paths return value: %s"
+ (string_of_location loc)
+ (string_of_identifier id)
+
+ | TCERR_ExpectedFunctionReturningOneValue {loc; id} ->
+ Format.sprintf "%s: expected function returning exactly one value: %s"
+ (string_of_location loc)
+ (string_of_identifier id)
+
+ | TCERR_ExpectedFunctionReturningManyValues {loc; id; expected; actual} ->
+ Format.sprintf "%s: expected function returning %u values, not %u: %s"
+ (string_of_location loc)
+ expected actual
+ (string_of_identifier id)
+
+ | TCERR_ExpectedArray {loc; actual} ->
+ Format.sprintf "%s: expected array, not: %s"
+ (string_of_location loc)
+ (string_of_normal_type actual)
+
+ | TCERR_FunctionMustReturnValue {loc} ->
+ Format.sprintf "%s: function must return something"
+ (string_of_location loc)
+
+ | TCERR_ProcedureCannotReturnValue {loc} ->
+ Format.sprintf "%s: procedure cannot return value"
+ (string_of_location loc)
+
+ | TCERR_InvalidRedeclaration {loc; id; previous} ->
+ Format.sprintf "%s: invalid redeclaration: %s: previous type: %s"
+ (string_of_location loc)
+ (string_of_identifier id)
+ (string_of_env_type previous)
+
+ | TCERR_ShadowsPreviousDefinition {loc; id} ->
+ Format.sprintf "%s: shadows previous definition: %s"
+ (string_of_location loc)
+ (string_of_identifier id)
+
+ | TCERR_ArrayInitializationForbidden {loc} ->
+ Format.sprintf "%s: array initialization is forbidden here"
+ (string_of_location loc)
+
+ | TCERR_CannotInferType {loc} ->
+ Format.sprintf "%s: cannot infer type"
+ (string_of_location loc)
+
+ module MakeErrorReporter () = struct
+
+ let r = ref []
+
+ let add e = r := e :: !r
+
+ let report_type_mismatch ~loc ~expected ~actual =
+ add @@ TCERR_TypeMismatch {loc;expected;actual}
+
+ let report_binding_type_mismatch ~loc ~expected ~actual ~id =
+ add @@ TCERR_BindingTypeMismatch {loc;expected;actual; id}
+
+ let report_error ~loc ~descr =
+ add @@ TCERR_OtherError {loc; descr}
+
+ let report_identifier_is_not_variable ~loc ~id =
+ add @@ TCERR_IdentifierIsNotVariable {loc; id}
+
+ let report_unknown_identifier ~loc ~id =
+ add @@ TCERR_UnknownIdentifier {loc; id}
+
+ let report_identifier_is_not_callable ~loc ~id =
+ add @@ TCERR_IdentifierIsNotCallable {loc; id}
+
+ let report_bad_number_of_arguments ~loc ~expected ~actual =
+ add @@ TCERR_BadNumberOfActualArguments {loc; expected; actual}
+
+ let report_bad_number_of_return_values ~loc ~expected ~actual =
+ add @@ TCERR_BadNumberOfReturnValues {loc; expected; actual}
+
+ let report_expected_function_returning_one_value ~loc ~id =
+ add @@ TCERR_ExpectedFunctionReturningOneValue {loc;id}
+
+ let report_expected_function_returning_many_values ~loc ~id ~expected ~actual =
+ add @@ TCERR_ExpectedFunctionReturningManyValues {loc;id; expected;actual}
+
+ let report_function_must_return_something ~loc =
+ add @@ TCERR_FunctionMustReturnValue {loc}
+
+ let report_procedure_cannot_return_value ~loc =
+ add @@ TCERR_ProcedureCannotReturnValue {loc}
+
+ let report_expected_array ~loc ~actual =
+ add @@ TCERR_ExpectedArray {loc; actual}
+
+ let report_not_all_control_paths_return_value ~loc ~id =
+ add @@ TCERR_NotAllControlPathsReturnValue {loc; id}
+
+ let report_shadows_previous_definition ~loc ~id =
+ add @@ TCERR_ShadowsPreviousDefinition {loc; id}
+
+ let report_invalid_redeclaration ~loc ~id ~previous =
+ add @@ TCERR_InvalidRedeclaration {loc; id; previous}
+
+ let report_array_initialization_forbidden ~loc =
+ add @@ TCERR_ArrayInitializationForbidden {loc}
+
+ let report_cannot_infer ~loc =
+ add @@ TCERR_CannotInferType {loc}
+
+ let flush () =
+ let result = List.rev !r in
+ r := [];
+ result
+
+
+ end \ No newline at end of file
diff --git a/source/xi_lib/types.ml b/source/xi_lib/types.ml
new file mode 100644
index 0000000..14809cc
--- /dev/null
+++ b/source/xi_lib/types.ml
@@ -0,0 +1,31 @@
+
+type normal_type
+ = TP_Int
+ | TP_Bool
+ | TP_Array of normal_type
+
+let rec string_of_normal_type = function
+ | TP_Int -> "int"
+ | TP_Bool -> "bool"
+ | TP_Array el -> string_of_normal_type el ^ "[]"
+
+type extended_type = normal_type list
+
+let string_of_extended_type xs =
+ String.concat ", " @@ List.map string_of_normal_type xs
+
+type result_type
+ = RT_Unit
+ | RT_Void
+
+type env_type
+ = ENVTP_Var of normal_type
+ | ENVTP_Fn of extended_type * extended_type
+
+let string_of_env_type = function
+ | ENVTP_Var t -> string_of_normal_type t
+ | ENVTP_Fn (xs, []) -> Format.sprintf "fn(%s)"
+ (string_of_extended_type xs)
+ | ENVTP_Fn (xs, rs) -> Format.sprintf "fn(%s) -> (%s)"
+ (string_of_extended_type xs)
+ (string_of_extended_type rs) \ No newline at end of file
diff --git a/tests/pracownia1/parse_error.xi b/tests/pracownia1/parse_error.xi
new file mode 100644
index 0000000..7bc8eee
--- /dev/null
+++ b/tests/pracownia1/parse_error.xi
@@ -0,0 +1,75 @@
+x:int
+
+main(x:int y:int)
+{
+}
+
+main() int int {
+
+}
+
+main()
+{
+ (x:int, y:int) = pair()
+}
+
+pair(): int, int
+{
+ return (0,0)
+}
+
+f()
+{
+ return 1;
+ x = 1
+}
+
+f()
+{
+ x = ''
+}
+
+f()
+{
+ x = 'ab'
+}
+
+f()
+{
+ x = '
+'
+}
+
+f()
+{
+ x = '\a'
+}
+
+f()
+{
+ x = "a
+b"
+}
+
+f()
+{
+ x = "a\tb"
+}
+
+f()
+{
+ while cond return 1
+}
+
+f()
+{
+ if cond return 1
+}
+
+f()
+{
+ if cond return 1 else z = 1
+}
+
+//@PRACOWNIA
+//@should_not_parse
diff --git a/tests/pracownia1/parse_ok.xi b/tests/pracownia1/parse_ok.xi
new file mode 100644
index 0000000..e4d0761
--- /dev/null
+++ b/tests/pracownia1/parse_ok.xi
@@ -0,0 +1,163 @@
+
+f()
+
+f(x:int)
+
+f():int
+{
+ return 0
+}
+
+f(x:int, y:int)
+
+f(): bool
+
+f(): int, int
+
+f()
+{
+ x:int
+}
+
+f() { x:int y:int }
+
+f() {
+ x:int = 1
+}
+
+f()
+{
+ return "Wroclaw"
+}
+
+f()
+{
+ return 5, 10, 15, "zaraz sie zacznie"
+}
+
+f()
+{
+ x:int x = 10 y = 17
+}
+
+f()
+{
+ x = 1 + 2 + 3
+ x = 1 - 2 - 3
+ x = 1 * 2 * 3
+ x = 1 / 2 / 3
+ x = 1 % 2 % 3
+ x = 1 & 2 & 3
+ x = 1 | 2 | 3
+}
+
+
+f()
+{
+ if (x > 10) y = 1
+ if x > 10 y = 1
+ if x > 10 {
+ return "42"
+ }
+ if pred() y = 1
+ if pred() & y | z x = 1
+}
+
+f()
+{
+ if (x > 10) y = 1 else z = 1
+ if x > 10 y = 1 else z = 1
+ if x > 10 {
+ return "42"
+ } else z = 1
+
+ if pred() y = 1 else {
+ z = 1
+ }
+ if pred() & y | z x = 1 else {
+ z = 3
+ }
+}
+
+f()
+{
+ if x if y z = 1 else z = 2
+}
+
+f()
+{
+ while (x > 10) y = 1
+ while x > 10 y = 1
+ while x y = 1
+ while pred() y = 1
+ while pred() {
+ zmienna = wartosc
+ return
+ }
+}
+
+f()
+{
+ g()
+ g(1, 2)
+ g(1, 2, 3)
+}
+
+f()
+{
+ x:int, y:int = f()
+ x:int, y:int = f(1, 2)
+ _, y:int = f(1, 2)
+ _, _ = f(1, 2)
+ x:int, _ = f(1, 2)
+}
+
+f()
+{
+ z = length("x")
+ z = length(x + y)
+ z = length(x - y)
+ z = length(x & y)
+ z = length(x / y)
+ z = length({1,2,3} + 1)
+}
+
+g()
+{
+ z = 'a'
+ z = 'b'
+ z = '\n'
+ z = '\\'
+ z = '\''
+}
+
+g()
+{
+ z = "a"
+ z = "abece de"
+ z = "abece\nde"
+ z = "abece\\de"
+ z = "abece\"de"
+}
+
+g(x:int[][]):bool[][]
+
+g(x:int[1][]):bool[][x]
+
+g()
+{
+ x:int[][][]
+ x:int[][][1]
+ x:int[2][][1]
+ x:int[][n][]
+}
+
+g()
+{
+ x[0] = 1
+ x[0][1] = 2
+ x[a][b] = c[d]
+}
+
+//@PRACOWNIA
+//@stop_after parser
diff --git a/tests/pracownia1/parse_operators.xi b/tests/pracownia1/parse_operators.xi
new file mode 100644
index 0000000..59bbe0c
--- /dev/null
+++ b/tests/pracownia1/parse_operators.xi
@@ -0,0 +1,14 @@
+test()
+{
+ x = a | b & c;
+ x = a & b | c & d;
+ x = a | b | c;
+ x = a < b < c;
+ x = a < b == c < d;
+ x = a < b * c == c + d < e * f
+ x = a * b / d % e
+
+}
+
+//@PRACOWNIA
+//@stop_after parser
diff --git a/tools/tester.py b/tools/tester.py
new file mode 100755
index 0000000..7f48400
--- /dev/null
+++ b/tools/tester.py
@@ -0,0 +1,404 @@
+#!/usr/bin/env python3
+
+import argparse
+import glob
+import os
+import sys
+import subprocess
+import shutil
+
+class Configuration:
+ def __init__(self, xic, testdir, spim, workdir, registers_description, plugin):
+ self.xic = xic
+ self.testdir = testdir
+ self.spim = spim
+ self.workdir = workdir
+ self.registers_description = registers_description
+ self.plugin = plugin
+
+ def printself(self):
+ print('Configuration:')
+ print(' - xic: ', self.xic)
+ print(' - testdir: ', self.testdir)
+ print(' - spim: ', self.spim)
+ print(' - workdir: ', self.workdir)
+ if self.registers_description is not None:
+ print(' - regdescr:', self.registers_description)
+ if self.plugin:
+ print(' - plugin:', self.plugin)
+
+class TestOutput:
+ class Status:
+ COMPILER_FAILURE = 0
+ COMPILER_SUCCES = 1
+ SPIM_FAILURE = 2
+ SPIM_SUCCESS = 3
+
+ def __init__(self):
+ self.status = None
+ self.compiler_stdout = None
+ self.compiler_stderr = None
+ self.compiler_ok = None
+ self.spim_stdout = None
+ self.spim_stderr = None
+ self.spim_ok = None
+
+
+class TestInstrumentation:
+ def __init__(self, test):
+ self.test = test
+ self.instrumented = False
+ self.expected_output = []
+ self.should_parse = True
+ self.stop_after = None
+ self.should_typecheck = True
+ self.typechecking_errors = []
+ self.selftest = None
+ self.env = {}
+
+ self.parse()
+ self.validate()
+
+ def content(self):
+ # get content of all comments started with //@
+ lines = open(self.test).readlines()
+ lines = [ line.strip() for line in lines ]
+ lines = [ line for line in lines if line.startswith("//@") ]
+ lines = [ line[3:] for line in lines ]
+ return lines
+
+ def parse(self):
+ content = self.content()
+ self.instrumented = "PRACOWNIA" in content
+ if not self.instrumented:
+ raise Exception('Test instrumentation is missing: %s' % self.test)
+
+ for line in content:
+ if line.startswith("out "):
+ self.expected_output.append(line[4:])
+ elif line == "should_not_parse":
+ self.should_parse = False
+ elif line == "should_not_typecheck":
+ self.should_typecheck = False
+ elif line.startswith("tcError "):
+ self.typechecking_errors.append(line[len("tcError "):])
+ elif line.startswith("stop_after"):
+ self.stop_after = line[len("stop_after "):]
+ elif line.startswith("env"):
+ keyvalue = line[len("env "):]
+ keyvalue = keyvalue.split('=')
+ self.env[keyvalue[0]] = keyvalue[1]
+ elif line.startswith('selftest'):
+ arg = line[len('selftest'):].strip()
+ if arg == 'pass':
+ self.selftest = True
+ elif arg == 'fail':
+ self.selftest = False
+ else:
+ raise Exception("invalid @selftest directive")
+
+ elif line == "PRACOWNIA":
+ pass
+ else:
+ raise Exception("invalid test instrumentation: unknown directive: " + line)
+
+ def validate(self):
+ if not self.instrumented:
+ return
+
+ if not self.should_parse:
+ if len(self.expected_output) > 0:
+ raise Exception("test %s marked as @should_not_parse, but expected runtime output is specified (@out)" % self.test)
+ if len(self.typechecking_errors) > 0:
+ raise Exception("test %s marked as @should_not_parse, but expected typechecking errors are specified (@tcError)" % self.test)
+ if not self.should_typecheck:
+ raise Exception("test %s marked as @should_not_parse, but expected typechecking failure is marked (@should_not_typecheck)" % self.test)
+
+ if not self.should_typecheck:
+ if len(self.expected_output) > 0:
+ raise Exception("test %s expects typechecking failure, but expected runtime output is specified (@out)" % self.test)
+
+ if len(self.typechecking_errors):
+ if len(self.expected_output) > 0:
+ raise Exception("test %s expects typechecking errors, but expected runtime output is specified (@out)" % self.test)
+ self.should_typecheck = False
+
+class Test:
+ def __init__(self, test, instrumentation):
+ self.test = test
+ self.instrumentation = instrumentation
+
+ def expecting_parsing_error(self):
+ return not self.instrumentation.should_parse
+
+ def expecting_typechecking_error(self):
+ return not self.instrumentation.should_typecheck
+
+ def expecting_compilation_failure(self):
+ return self.expecting_parsing_error() or self.expecting_typechecking_error()
+
+ def expecting_runtime_output(self):
+ return not self.expecting_compilation_failure() and not self.instrumentation.stop_after
+
+class ExpectationMatcher:
+ def __init__(self, test , output):
+ self.test = test
+ self.output = output
+
+ def __match_output(self, stdout, expected):
+ actual = list(reversed(stdout))
+ expected = list(reversed(expected))
+
+ for i in range(0, len(expected)):
+ if len(actual) <= i:
+ # nie sprawdzam tego przed petla bo chcialbym aby najpierw zmatchowal te linijki
+ # co sie rzeczywiscie na stdout pojawily
+ return False, "program output is too short, it contains %u lines, while expected out has %u" % (len(actual), len(expected))
+
+ expected_line = expected[i]
+ actual_line = actual[i]
+ if expected_line != actual_line:
+ explanation = "mismatch on line (counting from bottom): %u\nexpected: %s\nactual: %s" % (i + 1, expected_line, actual_line)
+ return False, explanation
+ return True, ""
+
+ def __real_match(self):
+ # print('self.test.expecting_compilation_failure()', self.test.expecting_compilation_failure())
+ # print('self.test.instrumentation.should_typecheck', self.test.instrumentation.should_typecheck)
+ # print('self.output.compiler_ok', self.output.compiler_ok)
+ if self.test.expecting_compilation_failure():
+ xic_stderr = self.output.compiler_stderr.decode('utf8')
+ xic_stderr = xic_stderr.splitlines()
+ if len(xic_stderr) == 0:
+ xic_last_line_stderr = None
+ else:
+ xic_last_line_stderr = xic_stderr[-1].strip()
+ if self.output.compiler_ok:
+ return False, "expected compiler failure"
+ if self.test.expecting_parsing_error():
+ if xic_last_line_stderr == "Failed: parser":
+ return True, ""
+ return False, "expected parsing error"
+ if self.test.expecting_typechecking_error():
+ if xic_last_line_stderr == "Failed: typechecker":
+ return True, ""
+ return False, "expected typchecking error"
+ else:
+ if not self.output.compiler_ok:
+ return False, "program should be compiled, but compiler failed"
+
+ if self.test.instrumentation.stop_after:
+ return True, ""
+
+ if len(self.output.spim_stderr) > 0:
+ return False, "spim's stderr is not empty, execute program manually"
+
+
+ if self.test.expecting_runtime_output():
+ if not self.output.spim_ok:
+ return False, "spim was not executed properly"
+
+ if len(self.test.instrumentation.expected_output) > 0:
+ spim_stdout = self.output.spim_stdout.decode('utf8')
+ spim_stdout = spim_stdout.splitlines()
+ spim_stdout = [ line.strip() for line in spim_stdout ]
+ return self.__match_output(spim_stdout,self.test.instrumentation.expected_output)
+
+ return True, ""
+
+ return None, "cannot match test expectations"
+
+ def match(self):
+ x_result, x_explanation = self.__real_match()
+
+ if self.test.instrumentation.selftest == None:
+ result, explanation = x_result, x_explanation
+ else:
+ result = x_result == self.test.instrumentation.selftest
+ if result:
+ explanation = ""
+ else:
+ explanation = "selftest failed: expected %s, got: %s, %s" % (self.test.instrumentation.selftest, x_result, x_explanation)
+
+ return result, explanation
+
+class TestRawExecutor:
+
+ def __init__(self, conf, test, env, run_spim, stop_point):
+ self.conf = conf
+ self.test = test
+ self.env = env
+ self.output_file = os.path.join(conf.workdir, 'main.s')
+ self.test_output = TestOutput()
+ self.run_spim = run_spim
+ self.stop_point = stop_point
+
+ def execute(self):
+ self.prepare_env()
+ ok, stdout, stderr = self.compile_program()
+ self.test_output.compiler_stdout = stdout
+ self.test_output.compiler_stderr = stderr
+ self.test_output.compiler_ok = ok
+ if not ok or not self.run_spim or self.stop_point:
+ self.clean_env()
+ return self.test_output
+
+ ok, stdout, stderr = self.execute_program()
+ self.test_output.spim_stdout = stdout
+ self.test_output.spim_stderr = stderr
+ self.test_output.spim_ok = ok
+ self.clean_env()
+
+ return self.test_output
+
+ def compile_program(self):
+ xs = [self.conf.xic, '-o', self.output_file]
+ if self.stop_point:
+ xs.append('--stop-after')
+ xs.append(self.stop_point)
+ if self.conf.registers_description is not None:
+ xs.append('--registers-description')
+ xs.append(self.conf.registers_description)
+ if self.conf.plugin is not None:
+ xs.append('--plugin')
+ xs.append(self.conf.plugin)
+
+ xs.append('--xi-log')
+ xs.append(os.path.join(self.conf.workdir, 'xilog'))
+ xs.append(self.test)
+ env = dict(self.env)
+ return self.__call(xs, env)
+
+ def execute_program(self):
+ return self.__call([self.conf.spim, '-file', self.output_file])
+
+ def prepare_env(self):
+ shutil.rmtree(self.conf.workdir, ignore_errors=True)
+ os.makedirs(self.conf.workdir)
+
+ def clean_env(self):
+ shutil.rmtree(self.conf.workdir, ignore_errors=True)
+
+ def __call(self, xs, extenv={}):
+ env = os.environ
+ for k in extenv:
+ env[k] = extenv[k]
+
+ try:
+ p = subprocess.Popen(xs, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
+ stdin, stdout = p.communicate(timeout=5)
+ status = p.returncode == 0
+ return (status, stdin, stdout)
+ except subprocess.TimeoutExpired:
+ return (False, [], [])
+ except Exception:
+ # potem cos tu doklepie aby wykonywarka testow mogla sie kapnac, ze to nie test wykryl blad
+ # a cos innego
+ return (False, [], [])
+
+class TestExecutor:
+ def __init__(self, test, conf):
+ self.test = test
+ self.conf = conf
+
+ def execute(self):
+ try:
+ run_spim = self.test.expecting_runtime_output()
+ stop_point = None
+ if not run_spim:
+ if self.test.expecting_parsing_error():
+ stop_point = "parser"
+ elif self.test.expecting_typechecking_error():
+ stop_point = "typechecker"
+ elif self.test.instrumentation.stop_after:
+ stop_point = self.test.instrumentation.stop_after
+
+ rawExecutor = TestRawExecutor(self.conf, self.test.test, self.test.instrumentation.env, run_spim, stop_point)
+ test_output = rawExecutor.execute()
+ matcher = ExpectationMatcher(self.test, test_output)
+ return matcher.match()
+ except Exception as e:
+ raise e
+ return None, "internal error: " + str(e)
+
+
+class TestRepository:
+ def __init__(self, testdirs):
+ self.tests = []
+ self.collect_tests(testdirs)
+
+ def collect_tests(self, testdirs):
+ testfiles = []
+ for testdir in testdirs:
+ for path, _, files in os.walk(testdir):
+ for file in files:
+ if file.endswith(".xi"):
+ testfiles.append(os.path.join(path, file))
+ testfiles = list(sorted(testfiles))
+
+ for testfile in testfiles:
+ instrumentation = TestInstrumentation(testfile)
+ test = Test(testfile, instrumentation)
+ self.tests.append(test)
+
+ def gen(self):
+ for t in self.tests:
+ yield t
+
+class Application:
+ def __init__(self):
+ args = self.create_argparse().parse_args()
+ self.conf = Configuration(xic=args.xic,
+ testdir=args.testdir,
+ spim=args.spim,
+ workdir=args.workdir,
+ registers_description=args.registers_description,
+ plugin=args.plugin)
+
+
+ def create_argparse(self):
+ parser = argparse.ArgumentParser(description='Xi tester')
+ parser.add_argument('--xic', help='path to xi binary', default='./_build/install/default/bin/xi', type=str)
+ parser.add_argument('--spim', help='path to spim binary', default='spim', type=str)
+ parser.add_argument('--testdir', help='path to test directory', default='./tests', type=str)
+ parser.add_argument('--workdir', help='working directory', default='workdir', type=str)
+ parser.add_argument('--registers-description', help='xi --registers-description', default=None, type=str)
+ parser.add_argument('--plugin', help='xi --plugin', type=str)
+ return parser
+
+ def run(self):
+ print('Xi tester')
+ self.conf.printself()
+ self.test_repository = TestRepository([self.conf.testdir])
+ passed_tests = []
+ failed_tests = []
+ inconclusive_tests = []
+ for test in self.test_repository.gen():
+ print('==> running test', test.test)
+ executor = TestExecutor(test, self.conf)
+ result, explanation = executor.execute()
+
+ if result == None:
+ inconclusive_tests.append(test)
+ status = "inconclusive: " + explanation
+ elif result:
+ passed_tests.append(test)
+ status = "pass"
+ elif not result:
+ failed_tests.append(test)
+ status = "fail: " + explanation
+
+ print('--- result:', status)
+
+ total = len(passed_tests) + len(failed_tests) + len(inconclusive_tests)
+
+ print('===================')
+ print('Total: ', total)
+ print('Passed:', len(passed_tests))
+ print('Inconc:', len(inconclusive_tests))
+ print('Failed:', len(failed_tests))
+ for test in failed_tests:
+ print(' -', test.test)
+
+
+Application().run()
diff --git a/xi.opam b/xi.opam
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xi.opam
diff --git a/xi_lib.opam b/xi_lib.opam
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/xi_lib.opam
diff --git a/xisdk/mod_uwr.cma b/xisdk/mod_uwr.cma
new file mode 100644
index 0000000..5e94a9d
--- /dev/null
+++ b/xisdk/mod_uwr.cma
Binary files differ