2024-12-12 16:37:36 +01:00
|
|
|
open Analysis
|
|
|
|
|
|
|
|
|
|
module Variable = struct
|
|
|
|
|
type t = string
|
|
|
|
|
let pp (ppf: out_channel) (v: t) : unit =
|
|
|
|
|
Printf.fprintf ppf "%s" v
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
let pp_list (ppf: out_channel) (vv: t list) : unit =
|
2024-12-12 16:37:36 +01:00
|
|
|
List.iter (Printf.fprintf ppf "%s, ") vv
|
2024-12-16 05:15:33 +01:00
|
|
|
|
|
|
|
|
let compare a b =
|
|
|
|
|
String.compare a b
|
2024-12-12 16:37:36 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
module RISCCfg = CfgRISC.RISCCfg
|
|
|
|
|
|
|
|
|
|
module DVCfg = Dataflow.Make (CfgRISC.RISCSimpleStatements) (Variable)
|
2024-12-16 05:15:33 +01:00
|
|
|
module DVCeltSet = Set.Make(Variable)
|
|
|
|
|
|
|
|
|
|
|
2024-12-16 16:40:59 +01:00
|
|
|
let variables (instr : DVCfg.elt) : DVCfg.internal list =
|
2025-01-27 16:28:23 +01:00
|
|
|
let aux (acc: DVCeltSet.t) (instr: DVCfg.elt) =
|
2024-12-16 16:40:59 +01:00
|
|
|
match instr with
|
|
|
|
|
| Nop ->
|
|
|
|
|
acc
|
|
|
|
|
| BRegOp (_, r1, r2, r3) ->
|
|
|
|
|
DVCeltSet.add r1.index acc |>
|
|
|
|
|
DVCeltSet.add r2.index |>
|
|
|
|
|
DVCeltSet.add r3.index
|
|
|
|
|
| BImmOp (_, r1, _, r3)
|
|
|
|
|
| URegOp (_, r1, r3)
|
|
|
|
|
| Load (r1, r3)
|
|
|
|
|
| Store (r1, r3) ->
|
|
|
|
|
DVCeltSet.add r1.index acc |>
|
|
|
|
|
DVCeltSet.add r3.index
|
|
|
|
|
| LoadI (_, r3) ->
|
|
|
|
|
DVCeltSet.add r3.index acc
|
|
|
|
|
in
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
aux DVCeltSet.empty instr |> DVCeltSet.to_list
|
2024-12-16 16:40:59 +01:00
|
|
|
|
|
|
|
|
let variables_all (instructions : DVCfg.elt list) : DVCfg.internal list =
|
|
|
|
|
List.fold_left (fun (acc: DVCeltSet.t) (instr: DVCfg.elt) ->
|
|
|
|
|
DVCeltSet.union acc (variables instr |> DVCeltSet.of_list)
|
|
|
|
|
) DVCeltSet.empty instructions |> DVCeltSet.to_list
|
|
|
|
|
|
2024-12-16 05:15:33 +01:00
|
|
|
let variables_used (instr : DVCfg.elt) : DVCfg.internal list =
|
2025-01-27 16:28:23 +01:00
|
|
|
let aux (acc: DVCeltSet.t) (instr: DVCfg.elt) =
|
2024-12-16 05:15:33 +01:00
|
|
|
match instr with
|
|
|
|
|
| Nop
|
|
|
|
|
| LoadI (_, _) ->
|
|
|
|
|
acc
|
2024-12-27 21:11:38 +01:00
|
|
|
| Store (r1, r2)
|
2024-12-16 05:15:33 +01:00
|
|
|
| BRegOp (_, r1, r2, _) ->
|
|
|
|
|
DVCeltSet.add r1.index acc |>
|
|
|
|
|
DVCeltSet.add r2.index
|
|
|
|
|
| BImmOp (_, r1, _, _)
|
|
|
|
|
| URegOp (_, r1, _)
|
2024-12-27 21:11:38 +01:00
|
|
|
| Load (r1, _) ->
|
2024-12-16 05:15:33 +01:00
|
|
|
DVCeltSet.add r1.index acc
|
|
|
|
|
in
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
aux DVCeltSet.empty instr |> DVCeltSet.to_list
|
2024-12-16 05:15:33 +01:00
|
|
|
|
|
|
|
|
let variables_used_all (instructions : DVCfg.elt list) : DVCfg.internal list =
|
|
|
|
|
List.fold_left (fun (acc: DVCeltSet.t) (instr: DVCfg.elt) ->
|
|
|
|
|
DVCeltSet.union acc (variables_used instr |> DVCeltSet.of_list)
|
|
|
|
|
) DVCeltSet.empty instructions |> DVCeltSet.to_list
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let variables_defined (instructions : DVCfg.elt) : DVCfg.internal list =
|
2025-01-27 16:28:23 +01:00
|
|
|
let aux (acc: DVCeltSet.t) (instr: DVCfg.elt) =
|
2024-12-16 05:15:33 +01:00
|
|
|
match instr with
|
2024-12-27 21:11:38 +01:00
|
|
|
| Nop
|
|
|
|
|
| Store (_, _) -> acc
|
2024-12-16 05:15:33 +01:00
|
|
|
| BRegOp (_, _, _, r3)
|
|
|
|
|
| BImmOp (_, _, _, r3)
|
|
|
|
|
| URegOp (_, _, r3)
|
|
|
|
|
| Load (_, r3)
|
2024-12-27 21:11:38 +01:00
|
|
|
| LoadI (_, r3) ->
|
2024-12-16 05:15:33 +01:00
|
|
|
DVCeltSet.add r3.index acc
|
|
|
|
|
in
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
aux DVCeltSet.empty instructions |> DVCeltSet.to_list
|
2024-12-16 05:15:33 +01:00
|
|
|
|
|
|
|
|
|
2024-12-16 16:40:59 +01:00
|
|
|
(* init function, assign the bottom to everything *)
|
2025-01-27 16:28:23 +01:00
|
|
|
let _init_bottom : (DVCfg.elt list -> DVCfg.internal_node) =
|
|
|
|
|
(fun l -> {internal_in = [];
|
|
|
|
|
internal_out = [];
|
|
|
|
|
internal_between = (List.init (List.length l) (fun _ -> ([], [])))}
|
|
|
|
|
)
|
2024-12-16 05:15:33 +01:00
|
|
|
|
2024-12-16 16:40:59 +01:00
|
|
|
(* init function, assign the top to everything *)
|
2025-01-27 16:28:23 +01:00
|
|
|
let init_top (all_variables) : (DVCfg.elt list -> DVCfg.internal_node) =
|
|
|
|
|
(fun l -> {internal_in = all_variables;
|
|
|
|
|
internal_out = all_variables;
|
|
|
|
|
internal_between = (List.init (List.length l)
|
2024-12-16 16:40:59 +01:00
|
|
|
(fun _ -> (all_variables, all_variables)))})
|
|
|
|
|
|
2024-12-16 05:15:33 +01:00
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
let lub (t: DVCfg.t) (node: Cfg.Node.t) : DVCfg.internal_node =
|
|
|
|
|
let prev_internal_var = Cfg.NodeMap.find node t.internal_var in
|
2024-12-16 05:15:33 +01:00
|
|
|
let code = match Cfg.NodeMap.find_opt node t.t.content with
|
|
|
|
|
None -> []
|
|
|
|
|
| Some c -> c
|
|
|
|
|
in
|
2024-12-27 21:11:38 +01:00
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
let new_internal_between = (
|
2024-12-27 21:11:38 +01:00
|
|
|
List.map
|
|
|
|
|
(fun (code, (i, _o)) ->
|
|
|
|
|
(i, Utility.unique_union i (variables_defined code)))
|
2025-01-27 16:28:23 +01:00
|
|
|
(List.combine code prev_internal_var.internal_between)
|
2024-12-27 21:11:38 +01:00
|
|
|
) in
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
let new_internal_out =
|
|
|
|
|
match new_internal_between with
|
2025-01-27 01:17:53 +01:00
|
|
|
| [] ->
|
2025-01-27 16:28:23 +01:00
|
|
|
prev_internal_var.internal_in
|
2025-01-27 01:17:53 +01:00
|
|
|
| _ ->
|
2025-01-27 16:28:23 +01:00
|
|
|
let _, newinternalout = (Utility.last_list new_internal_between) in
|
2025-01-27 01:17:53 +01:00
|
|
|
newinternalout
|
2024-12-27 21:11:38 +01:00
|
|
|
in
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
{ prev_internal_var with
|
|
|
|
|
internal_between = new_internal_between;
|
|
|
|
|
internal_out = new_internal_out }
|
2024-12-16 05:15:33 +01:00
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
let lucf (t: DVCfg.t) (node: Cfg.Node.t) : DVCfg.internal_node =
|
|
|
|
|
let prev_internal_var = Cfg.NodeMap.find node t.internal_var in
|
2024-12-27 21:11:38 +01:00
|
|
|
|
2024-12-16 05:15:33 +01:00
|
|
|
if Option.equal (=) (Some node) t.t.initial then
|
2024-12-27 21:11:38 +01:00
|
|
|
(* if L is initial set dvin to the "in" register *)
|
2025-01-27 16:28:23 +01:00
|
|
|
let new_internal_in = (
|
|
|
|
|
match t.t.input_output_var with
|
2024-12-27 21:11:38 +01:00
|
|
|
Some (i, _) -> [i]
|
|
|
|
|
| None -> []
|
|
|
|
|
) in
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
let new_internal_between = (
|
|
|
|
|
(* set the dvin of each to the previous dvout *)
|
|
|
|
|
match prev_internal_var.internal_between with
|
2024-12-27 21:11:38 +01:00
|
|
|
[] -> []
|
2025-01-27 16:28:23 +01:00
|
|
|
| [(_i, o)] -> [(new_internal_in, o)]
|
2024-12-27 21:11:38 +01:00
|
|
|
| (_i, o) :: btwrest ->
|
2025-01-27 16:28:23 +01:00
|
|
|
(new_internal_in, o) :: (
|
2024-12-27 21:11:38 +01:00
|
|
|
List.map (fun ((_i, o), (_previ, prevo)) -> (prevo, o))
|
2025-01-27 16:28:23 +01:00
|
|
|
(Utility.combine_twice btwrest prev_internal_var.internal_between)
|
2024-12-27 21:11:38 +01:00
|
|
|
)
|
|
|
|
|
) in
|
2025-01-27 16:28:23 +01:00
|
|
|
{ prev_internal_var with
|
|
|
|
|
internal_in = new_internal_in;
|
|
|
|
|
internal_between = new_internal_between }
|
2024-12-16 05:15:33 +01:00
|
|
|
else
|
2024-12-27 21:11:38 +01:00
|
|
|
(* if L is not initial set dvin to the intersection of the previous node's
|
|
|
|
|
dvouts *)
|
2025-01-27 16:28:23 +01:00
|
|
|
let prev_nodes = Cfg.NodeMap.find node t.t.reverse_edges in
|
|
|
|
|
let new_internal_in = (
|
|
|
|
|
match prev_nodes with
|
2024-12-27 21:11:38 +01:00
|
|
|
| [] ->
|
|
|
|
|
[]
|
|
|
|
|
| [prevnode] ->
|
2025-01-27 16:28:23 +01:00
|
|
|
(Cfg.NodeMap.find prevnode t.internal_var).internal_out
|
2024-12-27 21:11:38 +01:00
|
|
|
| [prevnode1; prevnode2] ->
|
|
|
|
|
Utility.unique_intersection
|
2025-01-27 16:28:23 +01:00
|
|
|
(Cfg.NodeMap.find prevnode1 t.internal_var).internal_out
|
|
|
|
|
(Cfg.NodeMap.find prevnode2 t.internal_var).internal_out
|
2024-12-27 21:11:38 +01:00
|
|
|
| prevnode :: restnodes ->
|
|
|
|
|
List.fold_left (* intersection of all previous nodes' dvout *)
|
|
|
|
|
(fun acc prevnode ->
|
|
|
|
|
Utility.unique_intersection
|
|
|
|
|
acc
|
2025-01-27 16:28:23 +01:00
|
|
|
(Cfg.NodeMap.find prevnode t.internal_var).internal_out)
|
|
|
|
|
(Cfg.NodeMap.find prevnode t.internal_var).internal_out
|
2024-12-27 21:11:38 +01:00
|
|
|
restnodes
|
|
|
|
|
) in
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
let new_internal_between =
|
|
|
|
|
match prev_internal_var.internal_between with
|
2024-12-27 21:11:38 +01:00
|
|
|
[] -> []
|
2025-01-27 16:28:23 +01:00
|
|
|
| [(_i, o)] -> [(new_internal_in, o)]
|
2024-12-27 21:11:38 +01:00
|
|
|
| (_i, o) :: btwrest ->
|
2025-01-27 16:28:23 +01:00
|
|
|
(new_internal_in, o) :: (
|
2024-12-27 21:11:38 +01:00
|
|
|
List.map (fun ((_i, o), (_previ, prevo)) -> (prevo, o))
|
2025-01-27 16:28:23 +01:00
|
|
|
(Utility.combine_twice btwrest prev_internal_var.internal_between)
|
2024-12-27 21:11:38 +01:00
|
|
|
)
|
|
|
|
|
in
|
2025-01-27 16:28:23 +01:00
|
|
|
{ prev_internal_var with
|
|
|
|
|
internal_in = new_internal_in;
|
|
|
|
|
internal_between = new_internal_between }
|
2024-12-16 05:15:33 +01:00
|
|
|
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
let update (t: DVCfg.t) (node: Cfg.Node.t) : DVCfg.internal_node =
|
2025-01-27 01:17:53 +01:00
|
|
|
let newt =
|
2025-01-27 16:28:23 +01:00
|
|
|
{t with internal_var = (Cfg.NodeMap.add node (lucf t node) t.internal_var)}
|
2025-01-27 01:17:53 +01:00
|
|
|
in
|
2024-12-16 05:15:33 +01:00
|
|
|
lub newt node
|
|
|
|
|
|
2024-12-12 16:37:36 +01:00
|
|
|
|
|
|
|
|
let compute_defined_variables (cfg: RISCCfg.t) : DVCfg.t =
|
2025-01-15 00:10:44 +01:00
|
|
|
(* creates the DVCfg structure and finds the fixed point *)
|
2024-12-16 16:40:59 +01:00
|
|
|
let all_variables = List.fold_left
|
2024-12-27 21:11:38 +01:00
|
|
|
(fun acc (_, code) ->
|
|
|
|
|
Utility.unique_union acc (variables_all code))
|
2024-12-16 16:40:59 +01:00
|
|
|
[]
|
|
|
|
|
(Cfg.NodeMap.to_list cfg.content)
|
|
|
|
|
in
|
2024-12-27 21:11:38 +01:00
|
|
|
let all_variables =
|
2025-01-27 16:28:23 +01:00
|
|
|
match cfg.input_output_var with
|
2024-12-27 21:11:38 +01:00
|
|
|
| None -> all_variables
|
|
|
|
|
| Some (i, o) -> Utility.unique_union all_variables [i;o]
|
|
|
|
|
in
|
2024-12-12 16:37:36 +01:00
|
|
|
DVCfg.from_cfg cfg
|
2024-12-16 16:40:59 +01:00
|
|
|
|> DVCfg.fixed_point ~init:(init_top all_variables) ~update:update
|
2024-12-16 05:15:33 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-12-21 02:16:04 +01:00
|
|
|
let check_undefined_variables (dvcfg: DVCfg.t) : Variable.t list option =
|
2025-01-15 00:10:44 +01:00
|
|
|
(* returns all undefined variables previously computed *)
|
2025-01-27 16:28:23 +01:00
|
|
|
let aux (node: Cfg.Node.t) (dvcfg: DVCfg.t) : Variable.t list option =
|
2024-12-16 05:15:33 +01:00
|
|
|
let code = match Cfg.NodeMap.find_opt node dvcfg.t.content with
|
|
|
|
|
None -> []
|
|
|
|
|
| Some c -> c
|
|
|
|
|
in
|
2025-01-27 16:28:23 +01:00
|
|
|
let internal_var = Cfg.NodeMap.find node dvcfg.internal_var in
|
2024-12-16 05:15:33 +01:00
|
|
|
let vua = variables_used_all code in
|
|
|
|
|
|
|
|
|
|
let outvar =
|
|
|
|
|
match (Option.equal (=) (Some node) dvcfg.t.terminal,
|
2025-01-27 16:28:23 +01:00
|
|
|
dvcfg.t.input_output_var,
|
|
|
|
|
internal_var.internal_out) with
|
2024-12-16 05:15:33 +01:00
|
|
|
| (true, Some (_, outvar), vout) ->
|
|
|
|
|
if List.mem outvar vout
|
|
|
|
|
then None
|
|
|
|
|
else Some outvar
|
|
|
|
|
| (_, _, _) ->
|
|
|
|
|
None
|
|
|
|
|
in
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
if Utility.inclusion vua (internal_var.internal_in) then
|
2024-12-21 02:16:04 +01:00
|
|
|
match outvar with None -> None
|
|
|
|
|
| Some outvar -> Some [outvar]
|
2024-12-16 05:15:33 +01:00
|
|
|
else
|
|
|
|
|
(* the variable might be defined inside the block, so check all vin and
|
|
|
|
|
return true only if all variables are properly defined *)
|
2025-01-27 16:28:23 +01:00
|
|
|
let vua_between = List.map variables_used code in
|
2024-12-16 05:15:33 +01:00
|
|
|
let undef_vars = List.fold_left
|
|
|
|
|
(fun acc (codevars, (vin, _vout)) ->
|
|
|
|
|
(Utility.subtraction codevars vin) @ acc)
|
|
|
|
|
[]
|
2025-01-27 16:28:23 +01:00
|
|
|
(List.combine vua_between internal_var.internal_between)
|
2024-12-16 05:15:33 +01:00
|
|
|
in
|
2024-12-21 02:16:04 +01:00
|
|
|
match outvar, undef_vars with
|
|
|
|
|
None, [] -> None
|
|
|
|
|
| None, undef_vars -> Some undef_vars
|
|
|
|
|
| Some outvar, [] -> Some [outvar]
|
|
|
|
|
| Some outvar, undef_vars -> Some (outvar :: undef_vars)
|
2024-12-16 05:15:33 +01:00
|
|
|
in
|
2024-12-21 02:16:04 +01:00
|
|
|
Cfg.NodeSet.fold (fun node acc ->
|
2025-01-27 16:28:23 +01:00
|
|
|
match acc, (aux node dvcfg) with
|
2024-12-21 02:16:04 +01:00
|
|
|
None, None -> None
|
|
|
|
|
| None, Some x -> Some x
|
|
|
|
|
| Some acc, None -> Some acc
|
|
|
|
|
| Some acc, Some x -> Some (acc @ x)
|
|
|
|
|
) dvcfg.t.nodes None
|
2024-12-16 05:15:33 +01:00
|
|
|
|
2024-12-12 16:37:36 +01:00
|
|
|
|
2024-12-16 05:15:33 +01:00
|
|
|
let compute_cfg (dvcfg: DVCfg.t) : RISCCfg.t =
|
2025-01-15 00:10:44 +01:00
|
|
|
(* no change to the cfg so returned as is *)
|
2024-12-12 16:37:36 +01:00
|
|
|
DVCfg.to_cfg dvcfg
|