2024-12-21 02:16:04 +01:00
|
|
|
open Analysis
|
|
|
|
|
|
|
|
|
|
module Variable = struct
|
|
|
|
|
type t = string
|
|
|
|
|
let pp (ppf: out_channel) (v: t) : unit =
|
|
|
|
|
Printf.fprintf ppf "%s" v
|
|
|
|
|
|
|
|
|
|
let pplist (ppf: out_channel) (vv: t list) : unit =
|
|
|
|
|
List.iter (Printf.fprintf ppf "%s, ") vv
|
|
|
|
|
|
|
|
|
|
let compare a b =
|
|
|
|
|
String.compare a b
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
module RISCCfg = CfgRISC.RISCCfg
|
|
|
|
|
|
|
|
|
|
module DVCfg = Dataflow.Make (CfgRISC.RISCSimpleStatements) (Variable)
|
|
|
|
|
module DVCeltSet = Set.Make(Variable)
|
|
|
|
|
|
|
|
|
|
|
2025-01-16 23:48:23 +01:00
|
|
|
let variables_used (instr : DVCfg.elt)
|
|
|
|
|
: DVCfg.internal list =
|
|
|
|
|
|
2024-12-21 02:16:04 +01:00
|
|
|
let helper (acc: DVCeltSet.t) (instr: DVCfg.elt) =
|
|
|
|
|
match instr with
|
|
|
|
|
| Nop
|
|
|
|
|
| LoadI (_, _) ->
|
|
|
|
|
acc
|
2024-12-27 21:11:38 +01:00
|
|
|
| BRegOp (_, r1, r2, _)
|
|
|
|
|
| Store (r1, r2) ->
|
2024-12-21 02:16:04 +01:00
|
|
|
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-21 02:16:04 +01:00
|
|
|
DVCeltSet.add r1.index acc
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
helper DVCeltSet.empty instr |> DVCeltSet.to_list
|
|
|
|
|
|
|
|
|
|
let variables_defined (instructions : DVCfg.elt) : DVCfg.internal list =
|
|
|
|
|
let helper (acc: DVCeltSet.t) (instr: DVCfg.elt) =
|
|
|
|
|
match instr with
|
2024-12-27 21:11:38 +01:00
|
|
|
| Nop
|
|
|
|
|
| Store (_, _) -> acc
|
2024-12-21 02:16:04 +01:00
|
|
|
| BRegOp (_, _, _, r3)
|
|
|
|
|
| BImmOp (_, _, _, r3)
|
|
|
|
|
| URegOp (_, _, r3)
|
|
|
|
|
| Load (_, r3)
|
2024-12-27 21:11:38 +01:00
|
|
|
| LoadI (_, r3) ->
|
2024-12-21 02:16:04 +01:00
|
|
|
DVCeltSet.add r3.index acc
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
helper DVCeltSet.empty instructions |> DVCeltSet.to_list
|
|
|
|
|
|
2025-01-16 23:48:23 +01:00
|
|
|
let variables (instruction : DVCfg.elt) : DVCfg.internal list =
|
|
|
|
|
let helper (acc: DVCeltSet.t) (instr: DVCfg.elt) =
|
|
|
|
|
match instr with
|
|
|
|
|
| Nop -> acc
|
|
|
|
|
| Store (r1, r2) ->
|
|
|
|
|
DVCeltSet.add r1.index acc |>
|
|
|
|
|
DVCeltSet.add r2.index
|
|
|
|
|
| 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) ->
|
|
|
|
|
DVCeltSet.add r1.index acc |>
|
|
|
|
|
DVCeltSet.add r3.index
|
|
|
|
|
| LoadI (_, r3) ->
|
|
|
|
|
DVCeltSet.add r3.index acc
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
helper DVCeltSet.empty instruction |> DVCeltSet.to_list
|
|
|
|
|
|
|
|
|
|
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-21 02:16:04 +01:00
|
|
|
(* init function, assign the bottom to everything *)
|
|
|
|
|
let init : (DVCfg.elt list -> DVCfg.internalnode) =
|
|
|
|
|
(fun l -> {internalin = [];
|
|
|
|
|
internalout = [];
|
|
|
|
|
internalbetween = (List.init (List.length l) (fun _ -> ([], [])))})
|
|
|
|
|
|
|
|
|
|
let lub (t: DVCfg.t) (node: Cfg.Node.t) : DVCfg.internalnode =
|
|
|
|
|
let previnternalvar = Cfg.NodeMap.find node t.internalvar in
|
|
|
|
|
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
|
|
|
|
|
|
|
|
let newinternalbetween = (
|
|
|
|
|
List.map
|
|
|
|
|
(fun (code, (_i, o)) ->
|
|
|
|
|
(Utility.unique_union
|
|
|
|
|
(variables_used code)
|
|
|
|
|
(Utility.subtraction o (variables_defined code)), o))
|
|
|
|
|
(Utility.combine_twice code previnternalvar.internalbetween)
|
|
|
|
|
) in
|
|
|
|
|
|
|
|
|
|
let newinternalin =
|
|
|
|
|
match newinternalbetween with
|
|
|
|
|
| [] -> previnternalvar.internalout
|
|
|
|
|
| (i, _)::_ -> i
|
|
|
|
|
in
|
|
|
|
|
|
2024-12-21 02:16:04 +01:00
|
|
|
{ previnternalvar with
|
2024-12-27 21:11:38 +01:00
|
|
|
internalbetween = newinternalbetween;
|
|
|
|
|
internalin = newinternalin; }
|
2024-12-21 02:16:04 +01:00
|
|
|
|
|
|
|
|
let lucf (t: DVCfg.t) (node: Cfg.Node.t) : DVCfg.internalnode =
|
|
|
|
|
let previnternalvar = Cfg.NodeMap.find node t.internalvar in
|
2024-12-27 21:11:38 +01:00
|
|
|
|
|
|
|
|
let newinternalout = (
|
|
|
|
|
if Option.equal (=) (Some node) t.t.terminal then (
|
|
|
|
|
match t.t.inputOutputVar with
|
2024-12-21 02:16:04 +01:00
|
|
|
Some (_, o) -> [o]
|
|
|
|
|
| None -> []
|
2024-12-27 21:11:38 +01:00
|
|
|
) else (
|
|
|
|
|
let nextnodes = Cfg.NodeMap.find_opt node t.t.edges in
|
|
|
|
|
match nextnodes with
|
|
|
|
|
| None -> []
|
|
|
|
|
| Some (node, None) ->
|
|
|
|
|
(Cfg.NodeMap.find node t.internalvar).internalin
|
2024-12-21 02:16:04 +01:00
|
|
|
| Some (node1, Some node2) ->
|
|
|
|
|
Utility.unique_union
|
|
|
|
|
(Cfg.NodeMap.find node1 t.internalvar).internalin
|
|
|
|
|
(Cfg.NodeMap.find node2 t.internalvar).internalin
|
2024-12-27 21:11:38 +01:00
|
|
|
)
|
|
|
|
|
) in
|
|
|
|
|
|
|
|
|
|
let newinternalbetween = (
|
|
|
|
|
match List.rev previnternalvar.internalbetween with
|
|
|
|
|
| [] -> []
|
|
|
|
|
| (i, _o) :: btwrest ->
|
|
|
|
|
let btwrest = List.rev btwrest in
|
|
|
|
|
let newbtwrest = List.map2
|
|
|
|
|
(fun (i, _o) (nexti, _nexto) -> (i, nexti))
|
|
|
|
|
btwrest
|
|
|
|
|
(Utility.drop_first_element_list previnternalvar.internalbetween)
|
|
|
|
|
in
|
|
|
|
|
newbtwrest @ [(i, newinternalout)]
|
|
|
|
|
) in
|
|
|
|
|
|
|
|
|
|
{ previnternalvar with
|
|
|
|
|
internalout = newinternalout;
|
|
|
|
|
internalbetween = newinternalbetween; }
|
2024-12-21 02:16:04 +01:00
|
|
|
|
|
|
|
|
let update (t: DVCfg.t) (node: Cfg.Node.t) : DVCfg.internalnode =
|
2024-12-27 21:11:38 +01:00
|
|
|
let newt = {t with internalvar = (Cfg.NodeMap.add node
|
|
|
|
|
(lucf t node)
|
|
|
|
|
t.internalvar)} in
|
2024-12-21 02:16:04 +01:00
|
|
|
lub newt node
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let compute_live_variables (cfg: RISCCfg.t) : DVCfg.t =
|
|
|
|
|
DVCfg.from_cfg cfg
|
|
|
|
|
|> DVCfg.fixed_point ~init:init ~update:update
|
|
|
|
|
|
|
|
|
|
|
2024-12-27 21:11:38 +01:00
|
|
|
|
|
|
|
|
module VariableMap = struct
|
|
|
|
|
include Map.Make(Variable)
|
|
|
|
|
|
|
|
|
|
let first_empty next start m l =
|
|
|
|
|
let bindings =
|
|
|
|
|
List.fold_left (
|
|
|
|
|
fun acc x ->
|
|
|
|
|
match find_opt x m with
|
|
|
|
|
| None -> acc
|
|
|
|
|
| Some x -> x :: acc) [] l |> List.sort Variable.compare in
|
|
|
|
|
|
|
|
|
|
let rec aux x =
|
|
|
|
|
if List.mem x bindings
|
|
|
|
|
then aux (next x)
|
|
|
|
|
else x
|
|
|
|
|
in
|
|
|
|
|
aux start
|
|
|
|
|
|
|
|
|
|
let first_empty_Variable m l =
|
|
|
|
|
let next = fun x -> x |> int_of_string |> (+) 1 |> string_of_int in
|
|
|
|
|
let start = "1" in
|
|
|
|
|
first_empty next start m l
|
|
|
|
|
|
2025-01-16 23:48:23 +01:00
|
|
|
let get_or_set_mapping m l r =
|
2024-12-27 21:11:38 +01:00
|
|
|
match find_opt r m with
|
|
|
|
|
| None -> (
|
|
|
|
|
let newr = first_empty_Variable m l in
|
|
|
|
|
let newm = add r newr m in
|
|
|
|
|
(newm, newr)
|
|
|
|
|
)
|
|
|
|
|
| Some r -> (m, r)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
2024-12-21 02:16:04 +01:00
|
|
|
(* just rename the registers that dont share live status *)
|
|
|
|
|
let optimize_cfg (t: DVCfg.t) : DVCfg.t =
|
2024-12-27 21:11:38 +01:00
|
|
|
let replace_code ((vin, vout): Variable.t list * Variable.t list)
|
|
|
|
|
(a: Variable.t VariableMap.t)
|
|
|
|
|
(code: DVCfg.elt)
|
|
|
|
|
: (Variable.t VariableMap.t * DVCfg.elt) =
|
|
|
|
|
match code with
|
|
|
|
|
| Nop -> (
|
|
|
|
|
(a, Nop)
|
|
|
|
|
)
|
|
|
|
|
| BRegOp (brop, r1, r2, r3) -> (
|
2025-01-16 23:48:23 +01:00
|
|
|
let (newa, newr1) = VariableMap.get_or_set_mapping a vin r1.index in
|
|
|
|
|
let (newa, newr2) = VariableMap.get_or_set_mapping newa vin r2.index in
|
|
|
|
|
let (newa, newr3) = VariableMap.get_or_set_mapping newa vout r3.index in
|
2024-12-27 21:11:38 +01:00
|
|
|
(newa, BRegOp (brop, {index = newr1}, {index = newr2}, {index = newr3}))
|
|
|
|
|
)
|
|
|
|
|
| BImmOp (biop, r1, i, r3) -> (
|
2025-01-16 23:48:23 +01:00
|
|
|
let (newa, newr1) = VariableMap.get_or_set_mapping a vin r1.index in
|
|
|
|
|
let (newa, newr3) = VariableMap.get_or_set_mapping newa vout r3.index in
|
2024-12-27 21:11:38 +01:00
|
|
|
(newa, BImmOp (biop, {index = newr1}, i, {index = newr3}))
|
|
|
|
|
)
|
|
|
|
|
| URegOp (urop, r1, r3) -> (
|
2025-01-16 23:48:23 +01:00
|
|
|
let (newa, newr1) = VariableMap.get_or_set_mapping a vin r1.index in
|
|
|
|
|
let (newa, newr3) = VariableMap.get_or_set_mapping newa vout r3.index in
|
2024-12-27 21:11:38 +01:00
|
|
|
(newa, URegOp (urop, {index = newr1}, {index = newr3}))
|
|
|
|
|
)
|
|
|
|
|
| Load (r1, r3) -> (
|
2025-01-16 23:48:23 +01:00
|
|
|
let (newa, newr1) = VariableMap.get_or_set_mapping a vin r1.index in
|
|
|
|
|
let (newa, newr3) = VariableMap.get_or_set_mapping newa vout r3.index in
|
2024-12-27 21:11:38 +01:00
|
|
|
(newa, Load ({index = newr1}, {index = newr3}))
|
|
|
|
|
)
|
|
|
|
|
| LoadI (i, r3) -> (
|
2025-01-16 23:48:23 +01:00
|
|
|
let (newa, newr3) = VariableMap.get_or_set_mapping a vout r3.index in
|
2024-12-27 21:11:38 +01:00
|
|
|
(newa, LoadI (i, {index = newr3}))
|
|
|
|
|
)
|
|
|
|
|
| Store (r1, r3) -> (
|
2025-01-16 23:48:23 +01:00
|
|
|
let (newa, newr1) = VariableMap.get_or_set_mapping a vin r1.index in
|
|
|
|
|
let (newa, newr3) = VariableMap.get_or_set_mapping newa vout r3.index in
|
2024-12-27 21:11:38 +01:00
|
|
|
(newa, Store ({index = newr1}, {index = newr3}))
|
|
|
|
|
)
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let aux (assignments: Variable.t VariableMap.t) (t: DVCfg.t) (node: Cfg.Node.t)
|
|
|
|
|
: (Variable.t VariableMap.t * DVCfg.t) =
|
|
|
|
|
let livevars = Cfg.NodeMap.find node t.internalvar in
|
|
|
|
|
let code =
|
|
|
|
|
match Cfg.NodeMap.find_opt node t.t.content with
|
|
|
|
|
| None -> []
|
|
|
|
|
| Some x -> x
|
|
|
|
|
in
|
|
|
|
|
let newcode, newassignments =
|
|
|
|
|
(List.fold_left2
|
|
|
|
|
(fun (acc, assignments) btw code ->
|
|
|
|
|
let na, nc = replace_code btw assignments code in
|
|
|
|
|
(acc @ [nc], na)
|
|
|
|
|
)
|
|
|
|
|
([], assignments)
|
|
|
|
|
livevars.internalbetween
|
|
|
|
|
code)
|
|
|
|
|
in
|
2025-01-16 23:48:23 +01:00
|
|
|
|
2024-12-27 21:11:38 +01:00
|
|
|
let newcontent = Cfg.NodeMap.add
|
|
|
|
|
node
|
|
|
|
|
newcode
|
|
|
|
|
t.t.content
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let newt = { t with t = { t.t with content = newcontent } } in
|
|
|
|
|
(newassignments, newt)
|
|
|
|
|
in
|
|
|
|
|
|
2025-01-15 00:10:44 +01:00
|
|
|
(* ------------------- *)
|
2024-12-27 21:11:38 +01:00
|
|
|
|
2025-01-16 23:48:23 +01:00
|
|
|
(* at least the input variable should be in the mapping *)
|
|
|
|
|
let assignments =
|
|
|
|
|
match t.t.inputOutputVar with
|
|
|
|
|
None -> VariableMap.empty
|
|
|
|
|
| Some (i, _o) -> (
|
|
|
|
|
VariableMap.get_or_set_mapping VariableMap.empty [] i |> fst
|
|
|
|
|
)
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let all_variables = List.fold_left
|
|
|
|
|
(fun acc (_, code) ->
|
|
|
|
|
Utility.unique_union acc (variables_all code))
|
|
|
|
|
[]
|
|
|
|
|
(Cfg.NodeMap.to_list t.t.content)
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let mapping =
|
|
|
|
|
(* for each variable we get the union of all in and out that contains it
|
|
|
|
|
then we find a register such that it's not in conflict *)
|
|
|
|
|
List.fold_left (fun assignments v -> (
|
|
|
|
|
(* union of all in and out such that v is in the set *)
|
|
|
|
|
let union : 'a list =
|
|
|
|
|
List.fold_left
|
|
|
|
|
(fun (acc: 'a list) (node, (x: DVCfg.internalnode)) ->
|
|
|
|
|
(* not interested in internalin or internalout since information
|
|
|
|
|
is mirrored into internalbetween *)
|
|
|
|
|
List.fold_left2
|
|
|
|
|
(fun acc (i, o) code ->
|
|
|
|
|
(* we also consider the out set if we "use" v as a guard *)
|
|
|
|
|
match List.mem v i,
|
|
|
|
|
List.mem v o,
|
|
|
|
|
List.mem v (variables_defined code) with
|
|
|
|
|
| false, false, false -> acc
|
|
|
|
|
| true, false, false -> Utility.unique_union i acc
|
|
|
|
|
| false, false, true
|
|
|
|
|
| false, true, _ -> Utility.unique_union o acc
|
|
|
|
|
| true, false, true
|
|
|
|
|
| true, true, _ -> Utility.unique_union
|
|
|
|
|
(Utility.unique_union i o) acc
|
|
|
|
|
)
|
|
|
|
|
acc
|
|
|
|
|
x.internalbetween
|
|
|
|
|
(Cfg.NodeMap.find_opt node t.t.content |>
|
|
|
|
|
Option.value ~default:[])
|
|
|
|
|
)
|
|
|
|
|
[]
|
|
|
|
|
(Cfg.NodeMap.to_list t.internalvar)
|
|
|
|
|
in
|
2025-01-17 00:46:51 +01:00
|
|
|
let assignments, _ =
|
|
|
|
|
VariableMap.get_or_set_mapping assignments union v in
|
2025-01-16 23:48:23 +01:00
|
|
|
assignments
|
|
|
|
|
)) assignments all_variables
|
|
|
|
|
in
|
2024-12-27 21:11:38 +01:00
|
|
|
|
2025-01-16 23:48:23 +01:00
|
|
|
let mapping, newt =
|
2024-12-27 21:11:38 +01:00
|
|
|
Cfg.NodeSet.fold (* for each node we replace all the variables with the
|
|
|
|
|
optimized ones *)
|
2025-01-15 00:10:44 +01:00
|
|
|
(fun node (assign, t) -> aux assign t node)
|
2024-12-27 21:11:38 +01:00
|
|
|
t.t.nodes
|
2025-01-16 23:48:23 +01:00
|
|
|
(mapping, t)
|
2024-12-27 21:11:38 +01:00
|
|
|
in
|
2024-12-21 02:16:04 +01:00
|
|
|
|
2024-12-27 21:11:38 +01:00
|
|
|
{ newt with
|
|
|
|
|
t = { newt.t with
|
|
|
|
|
inputOutputVar =
|
|
|
|
|
match newt.t.inputOutputVar with
|
|
|
|
|
None -> None
|
|
|
|
|
| Some (i, o) -> (
|
2025-01-16 23:48:23 +01:00
|
|
|
match VariableMap.find_opt i mapping,
|
|
|
|
|
VariableMap.find_opt o mapping with
|
2024-12-27 21:11:38 +01:00
|
|
|
| None, None -> Some (i, o)
|
|
|
|
|
| Some i, None -> Some (i, o)
|
|
|
|
|
| None, Some o -> Some (i, o)
|
|
|
|
|
| Some i, Some o -> Some (i, o)
|
|
|
|
|
)
|
|
|
|
|
}}
|
2024-12-21 02:16:04 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
let compute_cfg (dvcfg: DVCfg.t) : RISCCfg.t =
|
|
|
|
|
DVCfg.to_cfg dvcfg
|