From db3d4f4a8673f50cdb2fbc7a8db25a60296e8bf6 Mon Sep 17 00:00:00 2001 From: Pierre Wilke <pierre.wilke@centralesupelec.fr> Date: Mon, 2 Mar 2020 17:44:34 +0100 Subject: [PATCH] fix errors in nfa_to_dot by catching errors in e_regexp + other stuff --- .gitignore | 1 + Makefile | 2 +- Sujet.pdf | Bin 498194 -> 497584 bytes src/Makefile | 15 +++---- src/cfg.ml | 42 ++++++++++++++++++++ src/cfg_dead_assign.ml | 50 +----------------------- src/cfg_liveness.ml | 50 ++++++++++++++++++++++++ src/cfg_loops.ml | 11 ++++++ src/cfg_run.ml | 3 +- src/e_regexp.ml | 7 +++- src/main.ml | 26 +++++++++--- src/options.ml | 1 + src/utils.ml | 9 +++++ tests/basic/loop.e | 15 +++++++ tests/basic/loop.e.expect_14_12_3_8_12 | 1 + tests/basic/loop.e.expect_1_2_3 | 1 + tests/basic/loop2.e | 12 ++++++ tests/basic/loop2.e.expect_14_12_3_8_12 | 1 + tests/basic/loop2.e.expect_1_2_3 | 1 + tests/basic/loop3.e | 14 +++++++ tests/basic/loop3.e.expect_14_12_3_8_12 | 1 + tests/basic/loop3.e.expect_1_2_3 | 1 + tests/basic/loop4.e | 20 ++++++++++ tests/basic/loop4.e.expect_14_12_3_8_12 | 1 + tests/basic/loop4.e.expect_1_2_3 | 1 + tests/test.py | 1 + 26 files changed, 223 insertions(+), 64 deletions(-) create mode 100644 src/cfg_liveness.ml create mode 100644 src/cfg_loops.ml create mode 100644 tests/basic/loop.e create mode 100644 tests/basic/loop.e.expect_14_12_3_8_12 create mode 100644 tests/basic/loop.e.expect_1_2_3 create mode 100644 tests/basic/loop2.e create mode 100644 tests/basic/loop2.e.expect_14_12_3_8_12 create mode 100644 tests/basic/loop2.e.expect_1_2_3 create mode 100644 tests/basic/loop3.e create mode 100644 tests/basic/loop3.e.expect_14_12_3_8_12 create mode 100644 tests/basic/loop3.e.expect_1_2_3 create mode 100644 tests/basic/loop4.e create mode 100644 tests/basic/loop4.e.expect_14_12_3_8_12 create mode 100644 tests/basic/loop4.e.expect_1_2_3 diff --git a/.gitignore b/.gitignore index 18688d3..8102f28 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ tests/**/*.cfg tests/**/*.cfg0 tests/**/*.cfg1 tests/**/*.cfg2 +tests/**/*.cfg3 tests/**/*.e.dump tests/**/*.e.html tests/**/*.exe diff --git a/Makefile b/Makefile index 5cbca0c..1cac380 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ main.native: -t grammar.html ./configure make -C src - cp src/main.native main.native + ln -sf src/main.native main.native clean: diff --git a/Sujet.pdf b/Sujet.pdf index 91b343c098fa8b5ffdb6a8055a32342e9d93248b..6cd99d9db240f72fa9761f1fbbec548db85b35dd 100644 GIT binary patch delta 18082 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 B`bPi& delta 18688 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 diff --git a/src/Makefile b/src/Makefile index 5626ef6..d90147d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,10 +1,11 @@ -SRC=archi.ml ast.ml builtins.ml config.ml cfg_constprop.ml cfg_dead_assign.ml \ -cfg.ml cfg_print.ml cfg_gen.ml cfg_nop_elim.ml cfg_run.ml elang.ml \ -elang_print.ml elang_gen.ml elang_run.ml e_regexp.ml generated_parser.ml \ -lexer_generator.ml linear_dse.ml linear_liveness.ml linear.ml linear_print.ml \ -linear_gen.ml linear_run.ml ltl.ml ltl_print.ml ltl_gen.ml ltl_run.ml \ -ltl_debug.ml main.ml options.ml parser.ml prog.ml regalloc.ml report.ml \ -riscv.ml rtl.ml rtl_print.ml rtl_gen.ml rtl_run.ml symbols.ml utils.ml +SRC=archi.ml ast.ml builtins.ml config.ml cfg_constprop.ml cfg_dead_assign.ml \ +cfg.ml cfg_print.ml cfg_gen.ml cfg_liveness.ml cfg_loops.ml cfg_nop_elim.ml \ +cfg_run.ml elang.ml elang_print.ml elang_gen.ml elang_run.ml e_regexp.ml \ +generated_parser.ml lexer_generator.ml linear_dse.ml linear_liveness.ml \ +linear.ml linear_print.ml linear_gen.ml linear_run.ml ltl.ml ltl_print.ml \ +ltl_gen.ml ltl_run.ml ltl_debug.ml main.ml options.ml parser.ml prog.ml \ +regalloc.ml report.ml riscv.ml rtl.ml rtl_print.ml rtl_gen.ml rtl_run.ml \ +symbols.ml utils.ml TG = main.native diff --git a/src/cfg.ml b/src/cfg.ml index f03588b..a174394 100644 --- a/src/cfg.ml +++ b/src/cfg.ml @@ -26,6 +26,29 @@ type cfg_fun = { type cprog = cfg_fun prog +(* [succs cfg n] gives the successors of a node [n] in a CFG [cfg]. *) +let succs cfg n = + match Hashtbl.find_option cfg n with + | None -> [] + | Some (Cprint (_, s)) + | Some (Cassign (_, _, s)) -> [s] + | Some (Creturn _) -> [] + | Some (Ccmp (_, s1, s2)) -> [s1;s2] + | Some (Cnop s) -> [s] + + +(* [preds n] gives the list of predecessors of a node [n]. *) +let preds cfgfunbody n = + Hashtbl.fold (fun m m' acc -> + match m' with + | Cassign (_, _, s) + | Cprint (_, s) + | Cnop s -> if s = n then Set.add m acc else acc + | Creturn _ -> acc + | Ccmp (_, s1, s2) -> if s1 = n || s2 = n then Set.add m acc else acc + ) cfgfunbody Set.empty + + let size_binop b e1 e2 = 1 + e1 + e2 @@ -49,3 +72,22 @@ let rec size_instr (i: cfg_node) : int = let size_fun f = Hashtbl.fold (fun k v acc -> acc + size_instr v) f 0 + +let fixpoint + (transfer: (int, cfg_node) Hashtbl.t -> (int, 'a) Hashtbl.t -> int -> 'a) + (init: (int, cfg_node) Hashtbl.t -> int -> cfg_node -> 'a) + (cfg: (int, cfg_node) Hashtbl.t) : + (int, 'a) Hashtbl.t = + let res = Hashtbl.map (fun k v -> init cfg k v) cfg in + let iter res = + Hashtbl.fold (fun n oldstate changed -> + let newstate = transfer cfg res n in + Hashtbl.replace res n newstate; + changed || not (Set.equal newstate oldstate) + ) res false in + let rec fix () = + if iter res + then fix () + else () in + fix (); + res diff --git a/src/cfg_dead_assign.ml b/src/cfg_dead_assign.ml index 2d81284..c94352c 100644 --- a/src/cfg_dead_assign.ml +++ b/src/cfg_dead_assign.ml @@ -2,54 +2,8 @@ open Batteries open Cfg open Prog open Utils - -(* Liveness analysis *) - -(* [vars_in_expr e] returns the set of variables appearing in [e]. *) -let rec vars_in_expr (e: expr) = - Set.empty - -(* [live_cfg_node node live_after] gives the set of variables live before the - node [node], given the set [live_after] of variables live after this node. *) -let live_cfg_node (node: cfg_node) (live_after: string Set.t) = - live_after - -(* [succs cfg n] gives the successors of a node [n] in a CFG [cfg]. *) -let succs cfg n = - match Hashtbl.find_option cfg n with - | None -> [] - | Some (Cprint (_, s)) - | Some (Cfg.Cassign (_, _, s)) -> [s] - | Some (Cfg.Creturn _) -> [] - | Some (Cfg.Ccmp (_, s1, s2)) -> [s1;s2] - | Some (Cnop s) -> [s] - -(* Computes the set of live variables after a node [n] in a CFG [cfg]. - [lives] is a mapping from CFG node identifier to the set of variables that - are live before this node. -*) -let live_after_node cfg n (lives: (int, string Set.t) Hashtbl.t) : string Set.t = - Set.empty - -(* [live_cfg_nodes cfg lives] makes one iteration of the fixpoint computation. - - This returns a boolean that is true if some progress has been made in this - iteration (the set of variables live at at least one node has changed), false - otherwise. *) -let live_cfg_nodes cfg (lives : (int, string Set.t) Hashtbl.t) = - false - -(* [live_cfg_fun f] computes the set of live variables at each point by - iterating [live_cfg_nodes] as long as progress is made. *) -let live_cfg_fun ({ cfgfunargs; cfgfunbody; cfgentry }: cfg_fun) = - let lives : (int, string Set.t) Hashtbl.t = Hashtbl.create 17 in - let rec aux () = - if live_cfg_nodes cfgfunbody lives - then aux () - else () in - aux (); - lives - +open Cfg_liveness + (* Dead Assign Elimination *) (* [dead_assign_elimination_fun f] performs DAE on function [f]. *) diff --git a/src/cfg_liveness.ml b/src/cfg_liveness.ml new file mode 100644 index 0000000..63f3a65 --- /dev/null +++ b/src/cfg_liveness.ml @@ -0,0 +1,50 @@ +open Batteries +open Cfg +open Prog +open Utils + +(* Liveness analysis *) + +(* [vars_in_expr e] returns the set of variables appearing in [e]. *) +let rec vars_in_expr (e: expr) = + Set.empty + +(* [live_cfg_node node live_after] gives the set of variables live before the + node [node], given the set [live_after] of variables live after this node. *) +let live_cfg_node (node: cfg_node) (live_after: string Set.t) = + live_after + +(* Computes the set of live variables after a node [n] in a CFG [cfg]. + [lives] is a mapping from CFG node identifier to the set of variables that + are live before this node. +*) +let live_after_node cfg n (lives: (int, string Set.t) Hashtbl.t) : string Set.t = + Set.empty + +(* [live_cfg_nodes cfg lives] makes one iteration of the fixpoint computation. + + This returns a boolean that is true if some progress has been made in this + iteration (the set of variables live at at least one node has changed), false + otherwise. *) +let live_cfg_nodes cfg (lives : (int, string Set.t) Hashtbl.t) = + false + +(* [live_cfg_fun f] computes the set of live variables at each point by + iterating [live_cfg_nodes] as long as progress is made. *) +let live_cfg_fun ({ cfgfunargs; cfgfunbody; cfgentry }: cfg_fun) = + let lives : (int, string Set.t) Hashtbl.t = Hashtbl.create 17 in + let rec aux () = + if live_cfg_nodes cfgfunbody lives + then aux () + else () in + aux (); + lives + +let live_cfg_fun ({ cfgfunargs; cfgfunbody; cfgentry }: cfg_fun) = + fixpoint (fun cfg lives n -> + match Hashtbl.find_option cfg n with + | Some cn -> live_cfg_node cn (live_after_node cfg n lives) + | None -> failwith "Unknown node" + ) + (fun cfg n cn -> Set.empty) + cfgfunbody diff --git a/src/cfg_loops.ml b/src/cfg_loops.ml new file mode 100644 index 0000000..9175654 --- /dev/null +++ b/src/cfg_loops.ml @@ -0,0 +1,11 @@ +open Batteries +open Elang +open Cfg_gen +open Cfg_print +open Cfg_liveness +open Cfg +open Utils +open Prog + + +let optimize_loop_cfg cfg = cfg diff --git a/src/cfg_run.ml b/src/cfg_run.ml index 137e622..e09ccf9 100644 --- a/src/cfg_run.ml +++ b/src/cfg_run.ml @@ -7,7 +7,8 @@ open Cfg open Utils open Builtins -let rec eval_cfgexpr st : expr -> int res = function +let rec eval_cfgexpr st (e: expr) : int res = + match e with | Ebinop(b, e1, e2) -> eval_cfgexpr st e1 >>= fun v1 -> eval_cfgexpr st e2 >>= fun v2 -> diff --git a/src/e_regexp.ml b/src/e_regexp.ml index 53ad472..1872417 100644 --- a/src/e_regexp.ml +++ b/src/e_regexp.ml @@ -108,7 +108,11 @@ let list_regexp = (Cat (char_regexp '\'', Cat (char_range (List.filter (fun c -> c <> '\'' && c <> '\\') alphabet), char_regexp '\'')), - fun s -> Some (SYM_CHARACTER (String.get s 1))); + fun s -> + match String.get s 1 with + | a -> Some (SYM_CHARACTER a) + | exception Invalid_argument _ -> Some (SYM_CHARACTER '\x00') + ); (Cat (char_regexp '\'', Cat (char_regexp '\\', Cat (char_range (char_list_of_string "\\tn0"), char_regexp '\''))), @@ -118,6 +122,7 @@ let list_regexp = | 't' -> Some (SYM_CHARACTER '\t') | '0' -> Some (SYM_CHARACTER '\x00') | _ -> None + | exception _ -> Some (SYM_CHARACTER '\x00') ); (Cat (char_regexp '"', Cat (Star ( diff --git a/src/main.ml b/src/main.ml index a86df17..1314160 100644 --- a/src/main.ml +++ b/src/main.ml @@ -36,6 +36,8 @@ open Report open Options open Lexer_generator +open Cfg_loops + let tokenize file = Lexer_generator.tokenize_file file >>= fun tokens -> OK (List.map (fun tok -> (tok, None)) tokens) @@ -49,6 +51,7 @@ let speclist = ("-e-run", Arg.Set e_run, "Run Elang program."); ("-cfg-dump", Arg.String (fun s -> cfg_dump := Some s), "Output CFG file."); ("-cfg-run", Arg.Set cfg_run, "Run CFG program."); + ("-cfg-run-after-loop", Arg.Set cfg_run_after_loop, "Run CFG program after loop optimization."); ("-cfg-run-after-cp", Arg.Set cfg_run_after_cp, "Run CFG program after constant propagation."); ("-cfg-run-after-dae", Arg.Set cfg_run_after_dae, "Run CFG program after dead assign elimination."); ("-cfg-run-after-ne", Arg.Set cfg_run_after_ne, "Run CFG program after nop elimination."); @@ -67,6 +70,7 @@ let speclist = ("-all-run", Arg.Unit (fun () -> e_run := true; cfg_run := true; + cfg_run_after_loop := true; cfg_run_after_cp := true; cfg_run_after_dae := true; cfg_run_after_ne := true; @@ -289,27 +293,37 @@ let _ = run "Elang" !e_run eval_eprog ep; cfg_prog_of_eprog ep >>! fun cfg -> + record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "CFG"; + dump !cfg_dump dump_cfg_prog cfg (call_dot "cfg" "CFG"); run "CFG" !cfg_run eval_cfgprog cfg; - let cfg = constant_propagation cfg in - record_compile_result "ConstProp"; + let cfg = optimize_loop_cfg cfg in + record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "CFG loops"; dump (!cfg_dump >*> fun s -> s ^ "0") dump_cfg_prog cfg + (call_dot "cfg-after-loop" "CFG after loop optim"); + run "CFG after loop optim" !cfg_run_after_loop eval_cfgprog cfg; + + + let cfg = constant_propagation cfg in + record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "Constprop"; + dump (!cfg_dump >*> fun s -> s ^ "1") dump_cfg_prog cfg (call_dot "cfg-after-cstprop" "CFG after Constant Propagation"); run "CFG after constant_propagation" !cfg_run_after_cp eval_cfgprog cfg; let cfg = dead_assign_elimination cfg in - record_compile_result "DeadAssign"; - dump (!cfg_dump >*> fun s -> s ^ "1") dump_cfg_prog cfg + record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "DeadAssign"; + dump (!cfg_dump >*> fun s -> s ^ "2") dump_cfg_prog cfg (call_dot "cfg-after-dae" "CFG after DAE"); run "CFG after dead_assign_elimination" !cfg_run_after_dae eval_cfgprog cfg; let cfg = nop_elimination cfg in - record_compile_result "NopElim"; - dump (!cfg_dump >*> fun s -> s ^ "2") dump_cfg_prog cfg + record_compile_result ~data:([(`Assoc (List.map (fun (fname,Prog.Gfun cfgfun) -> (fname, `Int (Cfg.size_fun cfgfun.cfgfunbody))) cfg))]) "NopElim"; + dump (!cfg_dump >*> fun s -> s ^ "3") dump_cfg_prog cfg (call_dot "cfg-after-nop" "CFG after NOP elim"); run "CFG after nop_elimination" !cfg_run_after_ne eval_cfgprog cfg; + let rtl = rtl_of_cfg cfg in dump !rtl_dump dump_rtl_prog rtl (fun file () -> add_to_report "rtl" "RTL" (Code (file_contents file))); diff --git a/src/options.ml b/src/options.ml index 39fd3f8..63572f6 100644 --- a/src/options.ml +++ b/src/options.ml @@ -7,6 +7,7 @@ let e_dump : string option ref = ref None let e_run = ref false let cfg_dump : string option ref = ref None let cfg_run = ref false +let cfg_run_after_loop = ref false let cfg_run_after_cp = ref false let cfg_run_after_dae = ref false let cfg_run_after_ne = ref false diff --git a/src/utils.ml b/src/utils.ml index 3fa505c..3b1b122 100644 --- a/src/utils.ml +++ b/src/utils.ml @@ -276,4 +276,13 @@ let string_of_int_list l = let string_of_int_set s = string_of_int_list (Set.to_list s) +let string_of_string_set v = + String.concat ", " (Set.to_list v) +let string_of_int_int_set v = + String.concat ", " (List.map (fun (x,y) -> Printf.sprintf "(%d,%d)" x y) (Set.to_list v)) + +let string_of_int_option v = + match v with + | None -> "undef" + | Some x -> string_of_int x diff --git a/tests/basic/loop.e b/tests/basic/loop.e new file mode 100644 index 0000000..24652c9 --- /dev/null +++ b/tests/basic/loop.e @@ -0,0 +1,15 @@ +main(){ + i = 10; + a = 2; + res = 0; + while(i > 0){ + x = a + a; + if(a > 4){ + res = res + x; + } else { + res = res - x; + } + i = i - 1; + } + return res; +} diff --git a/tests/basic/loop.e.expect_14_12_3_8_12 b/tests/basic/loop.e.expect_14_12_3_8_12 new file mode 100644 index 0000000..919b014 --- /dev/null +++ b/tests/basic/loop.e.expect_14_12_3_8_12 @@ -0,0 +1 @@ +{"output": "", "error": null, "retval": -40} \ No newline at end of file diff --git a/tests/basic/loop.e.expect_1_2_3 b/tests/basic/loop.e.expect_1_2_3 new file mode 100644 index 0000000..919b014 --- /dev/null +++ b/tests/basic/loop.e.expect_1_2_3 @@ -0,0 +1 @@ +{"output": "", "error": null, "retval": -40} \ No newline at end of file diff --git a/tests/basic/loop2.e b/tests/basic/loop2.e new file mode 100644 index 0000000..985a305 --- /dev/null +++ b/tests/basic/loop2.e @@ -0,0 +1,12 @@ +main(){ + i = 20; + while(i > 0){ + if(i < 5){ + a = 5; + } else { + a = 6; + } + i = i - 1; + } + return i; +} diff --git a/tests/basic/loop2.e.expect_14_12_3_8_12 b/tests/basic/loop2.e.expect_14_12_3_8_12 new file mode 100644 index 0000000..42f3b7b --- /dev/null +++ b/tests/basic/loop2.e.expect_14_12_3_8_12 @@ -0,0 +1 @@ +{"output": "", "error": null, "retval": 0} \ No newline at end of file diff --git a/tests/basic/loop2.e.expect_1_2_3 b/tests/basic/loop2.e.expect_1_2_3 new file mode 100644 index 0000000..42f3b7b --- /dev/null +++ b/tests/basic/loop2.e.expect_1_2_3 @@ -0,0 +1 @@ +{"output": "", "error": null, "retval": 0} \ No newline at end of file diff --git a/tests/basic/loop3.e b/tests/basic/loop3.e new file mode 100644 index 0000000..a99573b --- /dev/null +++ b/tests/basic/loop3.e @@ -0,0 +1,14 @@ +main(){ + i = 20; + c = 8; + a = 5; + b = 0; + while(i > 0){ + if(i < 5){ + a = 4 + c; + } + b = b + a; + i = i - 1; + } + return b; +} diff --git a/tests/basic/loop3.e.expect_14_12_3_8_12 b/tests/basic/loop3.e.expect_14_12_3_8_12 new file mode 100644 index 0000000..feb4775 --- /dev/null +++ b/tests/basic/loop3.e.expect_14_12_3_8_12 @@ -0,0 +1 @@ +{"output": "", "error": null, "retval": 128} \ No newline at end of file diff --git a/tests/basic/loop3.e.expect_1_2_3 b/tests/basic/loop3.e.expect_1_2_3 new file mode 100644 index 0000000..feb4775 --- /dev/null +++ b/tests/basic/loop3.e.expect_1_2_3 @@ -0,0 +1 @@ +{"output": "", "error": null, "retval": 128} \ No newline at end of file diff --git a/tests/basic/loop4.e b/tests/basic/loop4.e new file mode 100644 index 0000000..53bd91a --- /dev/null +++ b/tests/basic/loop4.e @@ -0,0 +1,20 @@ +main(){ + i = 10; + a = 2; + res = 0; + while(i > 0){ + x = a + a; + y = 1 + x; + if(i > 4){ + res = res + x; + } else { + if (i < 2){ + res = res - y; + } else { + res = res + x - y; + } + } + i = i - 1; + } + return res; +} diff --git a/tests/basic/loop4.e.expect_14_12_3_8_12 b/tests/basic/loop4.e.expect_14_12_3_8_12 new file mode 100644 index 0000000..4c5f671 --- /dev/null +++ b/tests/basic/loop4.e.expect_14_12_3_8_12 @@ -0,0 +1 @@ +{"output": "", "error": null, "retval": 16} \ No newline at end of file diff --git a/tests/basic/loop4.e.expect_1_2_3 b/tests/basic/loop4.e.expect_1_2_3 new file mode 100644 index 0000000..4c5f671 --- /dev/null +++ b/tests/basic/loop4.e.expect_1_2_3 @@ -0,0 +1 @@ +{"output": "", "error": null, "retval": 16} \ No newline at end of file diff --git a/tests/test.py b/tests/test.py index 4a70644..3ec9d0f 100755 --- a/tests/test.py +++ b/tests/test.py @@ -21,6 +21,7 @@ parser.add_argument("-p", "--passes", nargs='+', default=["e-run", "cfg-run", + "cfg-run-after-loop", "cfg-run-after-cp", "cfg-run-after-dae", "cfg-run-after-ne", -- GitLab