This repository has been archived on 2024-01-18. You can view files and clone it, but cannot push or open issues or pull requests.
compilation/flap/src/retrolix/retrolixUtils.ml
2023-10-04 15:40:22 +02:00

199 lines
5.1 KiB
OCaml

(** This module provides helper functions for Retrolix program
analysis and manipulation. *)
open RetrolixAST
module LValueOrd = struct
type t = lvalue
let compare = compare
let print = RetrolixPrettyPrinter.lvalue
end
module LValueMap = ExtStd.Map (LValueOrd)
module LValueSet = ExtStd.Set (LValueOrd)
module LabelOrd = struct
type t = label
let compare (Label l1) (Label l2) = String.compare l1 l2
end
type location = lvalue
module LSet = Set.Make (struct
type t = location
let compare = compare
end)
let find_default d k m =
try LabelMap.find k m with Not_found -> d
let join rs =
List.fold_left (fun s x -> LSet.add x s) LSet.empty rs
let string_of_register (RId r) = r
let string_of_lvalue = function
| `Register (RId r) -> r
| `Variable (Id r) -> r
let string_of_label (Label s) = s
let string_of_lset s =
String.concat " " (List.map string_of_lvalue (LSet.elements s))
let string_of_lmap m =
String.concat "\n" (
List.map (fun (l, s) ->
Printf.sprintf " %s : %s\n" (string_of_label l) (string_of_lset s)
) (LabelMap.bindings m)
)
let register r =
`Register (RId (X86_64_Architecture.string_of_register r))
let global_variables p =
let translate p =
let rec program ds =
List.(concat (map definition ds))
and definition = function
| DValues (xs, _) ->
xs
| _ ->
[]
in
program p
in
translate p
let map_on_value lvalue rvalue = function
| Call (r, rs, b) ->
Call (rvalue r, List.map rvalue rs, b)
| Ret ->
Ret
| Assign (l, o, rs) ->
Assign (lvalue l, o, List.map rvalue rs)
| Jump l ->
Jump l
| ConditionalJump (c, rs, l1, l2) ->
ConditionalJump (c, List.map rvalue rs, l1, l2)
| Switch (r, ls, l) ->
Switch (rvalue r, ls, l)
| Comment c ->
Comment c
| Exit ->
Exit
(** [predecessors b] returns a function [pred] such that [pred l]
returns the predecessors of [l] in the control flow graph of
the block [b]. *)
let predecessors b =
let block m (_, instructions) =
let new_predecessor prev m curr =
try
let s = LabelMap.find curr m in
let s = LabelSet.add prev s in
LabelMap.add curr s m
with Not_found ->
LabelMap.add curr (LabelSet.singleton prev) m
in
let rec traverse m = function
| (label, Jump goto_label) :: instructions ->
let m = new_predecessor label m goto_label in
traverse m instructions
| (label, ConditionalJump (_, _, l1, l2)) :: instructions ->
let m = List.fold_left (new_predecessor label) m [l1; l2] in
traverse m instructions
| (label, Switch (_, labels, default)) :: instructions ->
let labels =
(match default with None -> [] | Some x -> [x])
@ (Array.to_list labels)
in
let m = List.fold_left (new_predecessor label) m labels in
traverse m instructions
| (ilabel, _) :: (((nlabel, _) :: _) as instructions) ->
let m = new_predecessor ilabel m nlabel in
traverse m instructions
| [ _ ] | [] ->
m
in
traverse m instructions
in
let m = block LabelMap.empty b in
fun l -> try LabelMap.find l m with Not_found -> LabelSet.empty
let nondefault_targets insn =
match insn with
| Call _ | Ret | Assign _ | Comment _ | Exit ->
[]
| Jump l ->
[l]
| ConditionalJump (_, _, l1, l2) ->
[l1; l2]
| Switch (_, a, o) ->
ExtStd.Option.fold (fun l acc -> acc @ [l]) o (Array.to_list a)
let instruction_targets (insns : labelled_instruction list) =
let targets _ insn next_lab =
match insn with
| Call (_, _, false) | Assign _ | Comment _ ->
next_lab
| Call (_, _, true) | Ret | Exit ->
[]
| Jump lab ->
[lab]
| ConditionalJump (_, _, lab1, lab2) ->
[lab1; lab2]
| Switch (_, laba, labo) ->
ExtStd.Option.fold (fun lab acc -> acc @ [lab]) labo (Array.to_list laba)
in
let rec loop insns =
match insns with
| [] ->
[]
| (lab, insn) :: insns ->
(lab,
insn,
targets lab insn (match insns with [] -> [] | (lab, _) :: _ -> [lab]))
:: loop insns
in
loop insns
let map_blocks f definitions =
let definition def =
match def with
| DValues (xs, block) ->
DValues (xs, f block)
| DFunction (fn, xs, block) ->
DFunction (fn, xs, f block)
| DExternalFunction _ ->
def
in
List.map definition definitions
let map_instructions f ((locals, insns) : block) =
(locals, List.map (fun ((l, _) as li) -> l, f li) insns)
let transform_block f g block =
let open PPrint in
let info = f block in
if Options.get_debug_mode () then
ExtPPrint.to_channel
(!^ "Input block:"
^//^ RetrolixPrettyPrinter.block
RetrolixPrettyPrinter.nodecorations
block);
let block = map_instructions (g info) block in
if Options.get_debug_mode () then
ExtPPrint.to_channel
(!^ "Output block:"
^//^ RetrolixPrettyPrinter.block
RetrolixPrettyPrinter.nodecorations
block);
block
let transform_blocks f g definitions =
map_blocks (transform_block f g) definitions