Skip to content
Snippets Groups Projects
Commit cefba848 authored by Sellami Youssef's avatar Sellami Youssef
Browse files

functions : CFG

parent ebad7c57
Branches
No related tags found
1 merge request!2Master
...@@ -8,6 +8,7 @@ type expr = ...@@ -8,6 +8,7 @@ type expr =
| Eunop of unop * expr | Eunop of unop * expr
| Eint of int | Eint of int
| Evar of string | Evar of string
| Ecall of string * expr list
type cfg_node = type cfg_node =
| Cassign of string * expr * int | Cassign of string * expr * int
...@@ -15,6 +16,7 @@ type cfg_node = ...@@ -15,6 +16,7 @@ type cfg_node =
| Cprint of expr * int | Cprint of expr * int
| Ccmp of expr * int * int | Ccmp of expr * int * int
| Cnop of int | Cnop of int
| Ccall of string * expr list * int
type cfg_fun = { type cfg_fun = {
cfgfunargs: string list; cfgfunargs: string list;
...@@ -35,7 +37,7 @@ let succs cfg n = ...@@ -35,7 +37,7 @@ let succs cfg n =
| Some (Creturn _) -> Set.empty | Some (Creturn _) -> Set.empty
| Some (Ccmp (_, s1, s2)) -> Set.of_list [s1;s2] | Some (Ccmp (_, s1, s2)) -> Set.of_list [s1;s2]
| Some (Cnop s) -> Set.singleton s | Some (Cnop s) -> Set.singleton s
| Some (Ccall (_, _, s)) -> Set.singleton s
(* [preds cfg n] donne l'ensemble des prédécesseurs d'un nœud [n] dans un CFG [cfg] (* [preds cfg n] donne l'ensemble des prédécesseurs d'un nœud [n] dans un CFG [cfg]
*) *)
...@@ -44,7 +46,8 @@ let preds cfgfunbody n = ...@@ -44,7 +46,8 @@ let preds cfgfunbody n =
match m' with match m' with
| Cassign (_, _, s) | Cassign (_, _, s)
| Cprint (_, s) | Cprint (_, s)
| Cnop s -> if s = n then Set.add m acc else acc | Cnop s
| Ccall (_, _, s) -> if s = n then Set.add m acc else acc
| Creturn _ -> acc | Creturn _ -> acc
| Ccmp (_, s1, s2) -> if s1 = n || s2 = n then Set.add m acc else acc | Ccmp (_, s1, s2) -> if s1 = n || s2 = n then Set.add m acc else acc
) cfgfunbody Set.empty ) cfgfunbody Set.empty
...@@ -62,6 +65,7 @@ let rec size_expr (e: expr) : int = ...@@ -62,6 +65,7 @@ let rec size_expr (e: expr) : int =
| Eunop (u, e) -> size_unop u (size_expr e) | Eunop (u, e) -> size_unop u (size_expr e)
| Eint _ -> 1 | Eint _ -> 1
| Evar _ -> 1 | Evar _ -> 1
| Ecall (_, args) -> 1 + List.fold_left (fun acc arg -> acc + size_expr arg) 0 args
let size_instr (i: cfg_node) : int = let size_instr (i: cfg_node) : int =
match (i : cfg_node) with match (i : cfg_node) with
...@@ -70,6 +74,7 @@ let size_instr (i: cfg_node) : int = ...@@ -70,6 +74,7 @@ let size_instr (i: cfg_node) : int =
| Cprint (e, _) -> 1 + (size_expr e) | Cprint (e, _) -> 1 + (size_expr e)
| Ccmp (e, _, _) -> 1 + size_expr e | Ccmp (e, _, _) -> 1 + size_expr e
| Cnop _ -> 1 | Cnop _ -> 1
| Ccall (_, args, _) -> 1 + List.fold_left (fun acc arg -> acc + size_expr arg) 0 args
let size_fun f = let size_fun f =
Hashtbl.fold (fun _ v acc -> acc + size_instr v) f 0 Hashtbl.fold (fun _ v acc -> acc + size_instr v) f 0
......
...@@ -25,6 +25,9 @@ let rec cfg_expr_of_eexpr (e: Elang.expr) : expr res = ...@@ -25,6 +25,9 @@ let rec cfg_expr_of_eexpr (e: Elang.expr) : expr res =
| Elang.Eint i -> OK (Eint i) | Elang.Eint i -> OK (Eint i)
| Elang.Evar v -> | Elang.Evar v ->
OK (Evar v) OK (Evar v)
| Elang.Ecall (f, args) ->
list_map_res cfg_expr_of_eexpr args >>= fun es ->
OK (Ecall (f, es))
(* [cfg_node_of_einstr next cfg succ i] builds the CFG node(s) that correspond (* [cfg_node_of_einstr next cfg succ i] builds the CFG node(s) that correspond
to the E instruction [i]. to the E instruction [i].
...@@ -70,6 +73,11 @@ let rec cfg_node_of_einstr (next: int) (cfg : (int, cfg_node) Hashtbl.t) ...@@ -70,6 +73,11 @@ let rec cfg_node_of_einstr (next: int) (cfg : (int, cfg_node) Hashtbl.t)
cfg_expr_of_eexpr e >>= fun e -> cfg_expr_of_eexpr e >>= fun e ->
Hashtbl.replace cfg next (Cprint (e,succ)); Hashtbl.replace cfg next (Cprint (e,succ));
OK (next, next + 1) OK (next, next + 1)
| Elang.Icall (f, args) ->
list_map_res cfg_expr_of_eexpr args >>= fun es ->
Hashtbl.replace cfg next (Ccall (f, es, succ));
OK (next, next + 1)
(* Some nodes may be unreachable after the CFG is entirely generated. The (* Some nodes may be unreachable after the CFG is entirely generated. The
[reachable_nodes n cfg] constructs the set of node identifiers that are [reachable_nodes n cfg] constructs the set of node identifiers that are
...@@ -86,6 +94,7 @@ let rec reachable_nodes n (cfg: (int,cfg_node) Hashtbl.t) = ...@@ -86,6 +94,7 @@ let rec reachable_nodes n (cfg: (int,cfg_node) Hashtbl.t) =
| Some (Creturn _) -> reach | Some (Creturn _) -> reach
| Some (Ccmp (_, s1, s2)) -> | Some (Ccmp (_, s1, s2)) ->
reachable_aux s1 (reachable_aux s2 reach) reachable_aux s1 (reachable_aux s2 reach)
| Some (Ccall (_, _, succ)) -> reachable_aux succ reach
in reachable_aux n Set.empty in reachable_aux n Set.empty
(* [cfg_fun_of_efun f] builds the CFG for E function [f]. *) (* [cfg_fun_of_efun f] builds the CFG for E function [f]. *)
......
...@@ -12,6 +12,7 @@ let rec vars_in_expr (e: expr) = ...@@ -12,6 +12,7 @@ let rec vars_in_expr (e: expr) =
| Evar s -> Set.singleton s | Evar s -> Set.singleton s
| Ebinop (b, e1, e2) -> Set.union (vars_in_expr e1) (vars_in_expr e2) | Ebinop (b, e1, e2) -> Set.union (vars_in_expr e1) (vars_in_expr e2)
| Eunop (u, e) -> vars_in_expr e | Eunop (u, e) -> vars_in_expr e
| Ecall (f, args) -> set_concat (List.map vars_in_expr args)
(* [live_after_node cfg n] renvoie l'ensemble des variables vivantes après le (* [live_after_node cfg n] renvoie l'ensemble des variables vivantes après le
nœud [n] dans un CFG [cfg]. [lives] est l'état courant de l'analyse, nœud [n] dans un CFG [cfg]. [lives] est l'état courant de l'analyse,
...@@ -34,6 +35,7 @@ let live_cfg_node (node: cfg_node) (live_after: string Set.t) = ...@@ -34,6 +35,7 @@ let live_cfg_node (node: cfg_node) (live_after: string Set.t) =
| Cprint (e, i) -> vars_in_expr e | Cprint (e, i) -> vars_in_expr e
| Ccmp (e, i1, i2) -> vars_in_expr e | Ccmp (e, i1, i2) -> vars_in_expr e
| Cnop (i) -> Set.empty | Cnop (i) -> Set.empty
| Ccall (f, args, i) -> vars_in_expr (Ecall (f, args))
in let def node = in let def node =
match node with match node with
| Cassign (s, e, i) -> Set.singleton s | Cassign (s, e, i) -> Set.singleton s
......
...@@ -67,7 +67,8 @@ let replace_succs nop_succs (n: cfg_node) = ...@@ -67,7 +67,8 @@ let replace_succs nop_succs (n: cfg_node) =
| Cprint (e, i) -> Cprint (e, replace_succ nop_succs i) | Cprint (e, i) -> Cprint (e, replace_succ nop_succs i)
| Ccmp (e, i1, i2) -> Ccmp (e, replace_succ nop_succs i1, replace_succ nop_succs i2) | Ccmp (e, i1, i2) -> Ccmp (e, replace_succ nop_succs i1, replace_succ nop_succs i2)
| Cnop i -> Cnop (replace_succ nop_succs i) | Cnop i -> Cnop (replace_succ nop_succs i)
| _ -> n | Creturn e -> Creturn e
| Ccall (f, args, i) -> Ccall (f, args, replace_succ nop_succs i)
(* [nop_elim_fun f] applique la fonction [replace_succs] à chaque nœud du CFG. *) (* [nop_elim_fun f] applique la fonction [replace_succs] à chaque nœud du CFG. *)
let nop_elim_fun ({ cfgfunargs; cfgfunbody; cfgentry } as f: cfg_fun) = let nop_elim_fun ({ cfgfunargs; cfgfunbody; cfgentry } as f: cfg_fun) =
......
...@@ -8,6 +8,7 @@ let rec dump_cfgexpr : expr -> string = function ...@@ -8,6 +8,7 @@ let rec dump_cfgexpr : expr -> string = function
| Eunop(u, e) -> Format.sprintf "(%s %s)" (dump_unop u) (dump_cfgexpr e) | Eunop(u, e) -> Format.sprintf "(%s %s)" (dump_unop u) (dump_cfgexpr e)
| Eint i -> Format.sprintf "%d" i | Eint i -> Format.sprintf "%d" i
| Evar s -> Format.sprintf "%s" s | Evar s -> Format.sprintf "%s" s
| Ecall (f, args) -> Format.sprintf "%s(%s)" f (String.concat ", " (List.map dump_cfgexpr args))
let dump_list_cfgexpr l = let dump_list_cfgexpr l =
l |> List.map dump_cfgexpr |> String.concat ", " l |> List.map dump_cfgexpr |> String.concat ", "
...@@ -17,7 +18,8 @@ let dump_arrows oc fname n (node: cfg_node) = ...@@ -17,7 +18,8 @@ let dump_arrows oc fname n (node: cfg_node) =
match node with match node with
| Cassign (_, _, succ) | Cassign (_, _, succ)
| Cprint (_, succ) | Cprint (_, succ)
| Cnop succ -> | Cnop succ
| Ccall (_, _, succ) ->
Format.fprintf oc "n_%s_%d -> n_%s_%d\n" fname n fname succ Format.fprintf oc "n_%s_%d -> n_%s_%d\n" fname n fname succ
| Creturn _ -> () | Creturn _ -> ()
| Ccmp (_, succ1, succ2) -> | Ccmp (_, succ1, succ2) ->
...@@ -32,7 +34,7 @@ let dump_cfg_node oc (node: cfg_node) = ...@@ -32,7 +34,7 @@ let dump_cfg_node oc (node: cfg_node) =
| Creturn e -> Format.fprintf oc "return %s" (dump_cfgexpr e) | Creturn e -> Format.fprintf oc "return %s" (dump_cfgexpr e)
| Ccmp (e, _, _) -> Format.fprintf oc "%s" (dump_cfgexpr e) | Ccmp (e, _, _) -> Format.fprintf oc "%s" (dump_cfgexpr e)
| Cnop _ -> Format.fprintf oc "nop" | Cnop _ -> Format.fprintf oc "nop"
| Ccall (f, args, _) -> Format.fprintf oc "%s(%s)" f (String.concat ", " (List.map dump_cfgexpr args))
let dump_liveness_state oc ht state = let dump_liveness_state oc ht state =
Hashtbl.iter (fun n cn -> Hashtbl.iter (fun n cn ->
......
...@@ -7,52 +7,81 @@ open Cfg ...@@ -7,52 +7,81 @@ open Cfg
open Utils open Utils
open Builtins open Builtins
let rec eval_cfgexpr st (e: expr) : int res = let rec eval_cfgexpr oc st cp (e: expr) : (int * int state) res =
match e with match e with
| Ebinop(b, e1, e2) -> | Ebinop(b, e1, e2) ->
eval_cfgexpr st e1 >>= fun v1 -> eval_cfgexpr oc st cp e1 >>= fun (v1, st') ->
eval_cfgexpr st e2 >>= fun v2 -> eval_cfgexpr oc st' cp e2 >>= fun (v2, st'') ->
let v = eval_binop b v1 v2 in let v = eval_binop b v1 v2 in
OK v OK (v, st'')
| Eunop(u, e) -> | Eunop(u, e) ->
eval_cfgexpr st e >>= fun v1 -> eval_cfgexpr oc st cp e >>= fun (v1, st') ->
let v = (eval_unop u v1) in let v = (eval_unop u v1) in
OK v OK (v, st')
| Eint i -> OK i | Eint i -> OK (i, st)
| Evar s -> | Evar s ->
begin match Hashtbl.find_option st.env s with begin match Hashtbl.find_option st.env s with
| Some v -> OK v | Some v -> OK (v, st)
| None -> Error (Printf.sprintf "Unknown variable %s\n" s) | None -> Error (Printf.sprintf "Unknown variable %s\n" s)
end end
| Ecall (f, args) ->
let rec eval_cfginstr oc st ht (n: int): (int * int state) res = List.fold_left (
fun (acc : (int list * int state) res) (arg : expr) ->
match acc with
| Error msg -> Error msg
| OK (l, st') ->
match eval_cfgexpr oc st' cp arg with
| Error msg -> Error msg
| OK (i, st'') -> OK ((l@[i]), st'')
) (OK([], st)) args >>= fun (int_args, st') ->
find_function cp f >>= fun found_f ->
match eval_cfgfun oc st' cp f found_f int_args with
| Error msg -> Error msg
| OK (None, st'') -> Error (Format.sprintf "CFG: Function %s doesn't have a return value.\n" f)
| OK (Some ret, st'') -> OK (ret, st'')
and eval_cfginstr oc st cp ht (n: int): (int * int state) res =
match Hashtbl.find_option ht n with match Hashtbl.find_option ht n with
| None -> Error (Printf.sprintf "Invalid node identifier\n") | None -> Error (Printf.sprintf "Invalid node identifier\n")
| Some node -> | Some node ->
match node with match node with
| Cnop succ -> | Cnop succ ->
eval_cfginstr oc st ht succ eval_cfginstr oc st cp ht succ
| Cassign(v, e, succ) -> | Cassign(v, e, succ) ->
eval_cfgexpr st e >>= fun i -> eval_cfgexpr oc st cp e >>= fun (i, st') ->
Hashtbl.replace st.env v i; Hashtbl.replace st'.env v i;
eval_cfginstr oc st ht succ eval_cfginstr oc st' cp ht succ
| Ccmp(cond, i1, i2) -> | Ccmp(cond, i1, i2) ->
eval_cfgexpr st cond >>= fun i -> eval_cfgexpr oc st cp cond >>= fun (i, st') ->
if i = 0 then eval_cfginstr oc st ht i2 else eval_cfginstr oc st ht i1 if i = 0 then eval_cfginstr oc st' cp ht i2 else eval_cfginstr oc st' cp ht i1
| Creturn(e) -> | Creturn(e) ->
eval_cfgexpr st e >>= fun e -> eval_cfgexpr oc st cp e >>= fun (e, st') ->
OK (e, st) OK (e, st')
| Cprint(e, succ) -> | Cprint(e, succ) ->
eval_cfgexpr st e >>= fun e -> eval_cfgexpr oc st cp e >>= fun (e, st') ->
Format.fprintf oc "%d\n" e; Format.fprintf oc "%d\n" e;
eval_cfginstr oc st ht succ eval_cfginstr oc st' cp ht succ
| Ccall (f, args, succ) ->
List.fold_left (
fun (acc : (int list * int state) res) (arg : expr) ->
match acc with
| Error msg -> Error msg
| OK (l, st') ->
match eval_cfgexpr oc st' cp arg with
| Error msg -> Error msg
| OK (i, st'') -> OK ((l@[i]), st'')
) (OK([], st)) args
>>= fun (int_args, st') ->
find_function cp f >>= fun found_f ->
eval_cfgfun oc st' cp f found_f int_args >>= fun (ret, st'') ->
eval_cfginstr oc st'' cp ht succ
let eval_cfgfun oc st cfgfunname { cfgfunargs; and eval_cfgfun oc st cp cfgfunname { cfgfunargs;
cfgfunbody; cfgfunbody;
cfgentry} vargs = cfgentry} vargs =
let st' = { st with env = Hashtbl.create 17 } in let st' = { st with env = Hashtbl.create 17 } in
match List.iter2 (fun a v -> Hashtbl.replace st'.env a v) cfgfunargs vargs with match List.iter2 (fun a v -> Hashtbl.replace st'.env a v) cfgfunargs vargs with
| () -> eval_cfginstr oc st' cfgfunbody cfgentry >>= fun (v, st') -> | () -> eval_cfginstr oc st' cp cfgfunbody cfgentry >>= fun (v, st') ->
OK (Some v, {st' with env = st.env}) OK (Some v, {st' with env = st.env})
| exception Invalid_argument _ -> | exception Invalid_argument _ ->
Error (Format.sprintf "CFG: Called function %s with %d arguments, expected %d.\n" Error (Format.sprintf "CFG: Called function %s with %d arguments, expected %d.\n"
...@@ -64,7 +93,7 @@ let eval_cfgprog oc cp memsize params = ...@@ -64,7 +93,7 @@ let eval_cfgprog oc cp memsize params =
find_function cp "main" >>= fun f -> find_function cp "main" >>= fun f ->
let n = List.length f.cfgfunargs in let n = List.length f.cfgfunargs in
let params = take n params in let params = take n params in
eval_cfgfun oc st "main" f params >>= fun (v, st) -> eval_cfgfun oc st cp "main" f params >>= fun (v, st) ->
OK v OK v
...@@ -100,7 +100,7 @@ and eval_einstr oc (st: int state) (ep: eprog) (ins: instr) : ...@@ -100,7 +100,7 @@ and eval_einstr oc (st: int state) (ep: eprog) (ins: instr) :
| Iif (e, i1, i2) -> | Iif (e, i1, i2) ->
(match eval_eexpr oc st ep e with (match eval_eexpr oc st ep e with
| Error msg -> Error msg | Error msg -> Error msg
| OK (v, st') -> if v = 1 then eval_einstr oc st' ep i1 else eval_einstr oc st' ep i2) | OK (v, st') -> if v = 0 then eval_einstr oc st' ep i2 else eval_einstr oc st' ep i1)
| Iwhile (e, i) -> | Iwhile (e, i) ->
(match eval_eexpr oc st ep e with (match eval_eexpr oc st ep e with
| Error msg -> Error msg | Error msg -> Error msg
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment