summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--language/jib.ott1
-rw-r--r--src/graph.ml2
-rw-r--r--src/jib/c_backend.ml47
-rw-r--r--src/jib/c_backend.mli9
-rw-r--r--src/jib/jib_compile.ml12
-rw-r--r--src/jib/jib_compile.mli7
-rw-r--r--src/jib/jib_optimize.ml129
-rw-r--r--src/jib/jib_optimize.mli63
-rw-r--r--src/jib/jib_ssa.ml602
-rw-r--r--src/jib/jib_ssa.mli85
-rw-r--r--src/jib/jib_util.ml167
-rw-r--r--src/sail.ml2
-rw-r--r--src/sail.odocl1
13 files changed, 954 insertions, 173 deletions
diff --git a/language/jib.ott b/language/jib.ott
index 7b5d0162..e54e2ea5 100644
--- a/language/jib.ott
+++ b/language/jib.ott
@@ -136,6 +136,7 @@ clexp :: 'CL_' ::=
| current_exception : ctyp :: :: current_exception
| have_exception :: :: have_exception
| return : ctyp :: :: return
+ | void :: :: void
ctype_def :: 'CTD_' ::=
{{ com C type definition }}
diff --git a/src/graph.ml b/src/graph.ml
index 21863e47..703deba9 100644
--- a/src/graph.ml
+++ b/src/graph.ml
@@ -234,6 +234,6 @@ module Make(Ord: OrderedType) = struct
NM.bindings graph |> List.iter (fun (from_node, _) -> make_node from_node);
NM.bindings graph |> List.iter (fun (from_node, to_nodes) -> NS.iter (make_line from_node) to_nodes);
output_string out_chan "}\n";
- Util.opt_colors := true;
+ Util.opt_colors := true
end
diff --git a/src/jib/c_backend.ml b/src/jib/c_backend.ml
index aab2894e..846b619f 100644
--- a/src/jib/c_backend.ml
+++ b/src/jib/c_backend.ml
@@ -63,7 +63,6 @@ module Big_int = Nat_big_num
let c_verbosity = ref 0
-let opt_debug_flow_graphs = ref false
let opt_static = ref false
let opt_no_main = ref false
let opt_memo_cache = ref false
@@ -849,48 +848,6 @@ let hoist_allocations recursive_functions = function
| cdef -> [cdef]
-let flat_counter = ref 0
-let flat_id () =
- let id = mk_id ("local#" ^ string_of_int !flat_counter) in
- incr flat_counter;
- id
-
-let rec flatten_instrs = function
- | I_aux (I_decl (ctyp, decl_id), aux) :: instrs ->
- let fid = flat_id () in
- I_aux (I_decl (ctyp, fid), aux) :: flatten_instrs (instrs_rename decl_id fid instrs)
-
- | I_aux ((I_block block | I_try_block block), _) :: instrs ->
- flatten_instrs block @ flatten_instrs instrs
-
- | I_aux (I_if (cval, then_instrs, else_instrs, _), _) :: instrs ->
- let then_label = label "then_" in
- let endif_label = label "endif_" in
- [ijump cval then_label]
- @ flatten_instrs else_instrs
- @ [igoto endif_label]
- @ [ilabel then_label]
- @ flatten_instrs then_instrs
- @ [ilabel endif_label]
- @ flatten_instrs instrs
-
- | I_aux (I_comment _, _) :: instrs -> flatten_instrs instrs
-
- | instr :: instrs -> instr :: flatten_instrs instrs
- | [] -> []
-
-let flatten_cdef =
- function
- | CDEF_fundef (function_id, heap_return, args, body) ->
- flat_counter := 0;
- CDEF_fundef (function_id, heap_return, args, flatten_instrs body)
-
- | CDEF_let (n, bindings, instrs) ->
- flat_counter := 0;
- CDEF_let (n, bindings, flatten_instrs instrs)
-
- | cdef -> cdef
-
let rec specialize_variants ctx prior =
let unifications = ref (Bindings.empty) in
@@ -1386,6 +1343,7 @@ let rec sgen_clexp = function
| CL_have_exception -> "have_exception"
| CL_current_exception _ -> "current_exception"
| CL_return _ -> assert false
+ | CL_void -> assert false
let rec sgen_clexp_pure = function
| CL_id (id, _) -> sgen_id id
@@ -1395,6 +1353,7 @@ let rec sgen_clexp_pure = function
| CL_have_exception -> "have_exception"
| CL_current_exception _ -> "current_exception"
| CL_return _ -> assert false
+ | CL_void -> assert false
(** Generate instructions to copy from a cval to a clexp. This will
insert any needed type conversions from big integers to small
@@ -2079,8 +2038,6 @@ let codegen_def' ctx = function
string (Printf.sprintf "%svoid %s(%s%s *rop, %s);" static (sgen_function_id id) (extra_params ()) (sgen_ctyp ret_ctyp) (Util.string_of_list ", " sgen_ctyp arg_ctyps))
| CDEF_fundef (id, ret_arg, args, instrs) as def ->
- if !opt_debug_flow_graphs then make_dot id (instrs_graph instrs) else ();
-
(* Extract type information about the function from the environment. *)
let quant, Typ_aux (fn_typ, _) = Env.get_val_spec id ctx.tc_env in
let arg_typs, ret_typ = match fn_typ with
diff --git a/src/jib/c_backend.mli b/src/jib/c_backend.mli
index 2fc5be94..7314eb5a 100644
--- a/src/jib/c_backend.mli
+++ b/src/jib/c_backend.mli
@@ -53,10 +53,6 @@ open Type_check
(** Global compilation options *)
-(** Output a dataflow graph for each generated function in Graphviz
- (dot) format. *)
-val opt_debug_flow_graphs : bool ref
-
(** Define generated functions as static *)
val opt_static : bool ref
@@ -109,10 +105,5 @@ val optimize_experimental : bool ref
(** Convert a typ to a IR ctyp *)
val ctyp_of_typ : Jib_compile.ctx -> Ast.typ -> ctyp
-(** Rewriting steps for compiled ASTs *)
-val flatten_instrs : instr list -> instr list
-
-val flatten_cdef : cdef -> cdef
-
val jib_of_ast : Env.t -> tannot Ast.defs -> cdef list * Jib_compile.ctx
val compile_ast : Env.t -> out_channel -> string list -> tannot Ast.defs -> unit
diff --git a/src/jib/jib_compile.ml b/src/jib/jib_compile.ml
index 36a28d9f..27f833d8 100644
--- a/src/jib/jib_compile.ml
+++ b/src/jib/jib_compile.ml
@@ -58,6 +58,7 @@ open Value2
open Anf
let opt_debug_function = ref ""
+let opt_debug_flow_graphs = ref false
let opt_memo_cache = ref false
(**************************************************************************)
@@ -1174,7 +1175,16 @@ and compile_def' n total ctx = function
prerr_endline (Util.header header (List.length arg_ctyps + 2));
prerr_endline (Pretty_print_sail.to_string PPrint.(separate_map hardline pp_instr instrs))
else ();
-
+
+ if !opt_debug_flow_graphs then
+ begin
+ let instrs = Jib_optimize.(instrs |> optimize_unit |> flatten_instrs) in
+ let cfg = Jib_ssa.ssa instrs in
+ let out_chan = open_out (Util.zencode_string (string_of_id id) ^ ".gv") in
+ Jib_ssa.make_dot out_chan cfg;
+ close_out out_chan;
+ end;
+
[CDEF_fundef (id, None, List.map fst compiled_args, instrs)], orig_ctx
| DEF_fundef (FD_aux (FD_function (_, _, _, []), (l, _))) ->
diff --git a/src/jib/jib_compile.mli b/src/jib/jib_compile.mli
index 173e5c5f..f3bd8c76 100644
--- a/src/jib/jib_compile.mli
+++ b/src/jib/jib_compile.mli
@@ -55,10 +55,13 @@ open Ast
open Ast_util
open Jib
open Type_check
-
+
+(** Output a dataflow graph for each generated function in Graphviz
+ (dot) format. *)
+val opt_debug_flow_graphs : bool ref
+
(** Print the IR representation of a specific function. *)
val opt_debug_function : string ref
-
(** {2 Jib context} *)
diff --git a/src/jib/jib_optimize.ml b/src/jib/jib_optimize.ml
new file mode 100644
index 00000000..889e650e
--- /dev/null
+++ b/src/jib/jib_optimize.ml
@@ -0,0 +1,129 @@
+(**************************************************************************)
+(* Sail *)
+(* *)
+(* Copyright (c) 2013-2017 *)
+(* Kathyrn Gray *)
+(* Shaked Flur *)
+(* Stephen Kell *)
+(* Gabriel Kerneis *)
+(* Robert Norton-Wright *)
+(* Christopher Pulte *)
+(* Peter Sewell *)
+(* Alasdair Armstrong *)
+(* Brian Campbell *)
+(* Thomas Bauereiss *)
+(* Anthony Fox *)
+(* Jon French *)
+(* Dominic Mulligan *)
+(* Stephen Kell *)
+(* Mark Wassell *)
+(* *)
+(* All rights reserved. *)
+(* *)
+(* This software was developed by the University of Cambridge Computer *)
+(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *)
+(* (REMS) project, funded by EPSRC grant EP/K008528/1. *)
+(* *)
+(* Redistribution and use in source and binary forms, with or without *)
+(* modification, are permitted provided that the following conditions *)
+(* are met: *)
+(* 1. Redistributions of source code must retain the above copyright *)
+(* notice, this list of conditions and the following disclaimer. *)
+(* 2. Redistributions in binary form must reproduce the above copyright *)
+(* notice, this list of conditions and the following disclaimer in *)
+(* the documentation and/or other materials provided with the *)
+(* distribution. *)
+(* *)
+(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)
+(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)
+(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)
+(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)
+(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)
+(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)
+(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)
+(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)
+(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)
+(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)
+(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)
+(* SUCH DAMAGE. *)
+(**************************************************************************)
+
+open Ast_util
+open Jib
+open Jib_util
+
+let optimize_unit instrs =
+ let unit_cval cval =
+ match cval_ctyp cval with
+ | CT_unit -> (F_lit V_unit, CT_unit)
+ | _ -> cval
+ in
+ let unit_instr = function
+ | I_aux (I_funcall (clexp, extern, id, args), annot) as instr ->
+ begin match clexp_ctyp clexp with
+ | CT_unit ->
+ I_aux (I_funcall (CL_void, extern, id, List.map unit_cval args), annot)
+ | _ -> instr
+ end
+ | I_aux (I_copy (clexp, cval), annot) as instr ->
+ begin match clexp_ctyp clexp with
+ | CT_unit ->
+ I_aux (I_copy (CL_void, unit_cval cval), annot)
+ | _ -> instr
+ end
+ | I_aux (I_alias (clexp, cval), annot) as instr ->
+ begin match clexp_ctyp clexp with
+ | CT_unit ->
+ I_aux (I_alias (CL_void, unit_cval cval), annot)
+ | _ -> instr
+ end
+ | instr -> instr
+ in
+ let non_pointless_copy (I_aux (aux, annot)) =
+ match aux with
+ | I_copy (CL_void, _) -> false
+ | _ -> true
+ in
+ filter_instrs non_pointless_copy (map_instr_list unit_instr instrs)
+
+let flat_counter = ref 0
+let flat_id () =
+ let id = mk_id ("local#" ^ string_of_int !flat_counter) in
+ incr flat_counter;
+ id
+
+let rec flatten_instrs = function
+ | I_aux (I_decl (ctyp, decl_id), aux) :: instrs ->
+ let fid = flat_id () in
+ I_aux (I_decl (ctyp, fid), aux) :: flatten_instrs (instrs_rename decl_id fid instrs)
+
+ | I_aux ((I_block block | I_try_block block), _) :: instrs ->
+ flatten_instrs block @ flatten_instrs instrs
+
+ | I_aux (I_if (cval, then_instrs, else_instrs, _), _) :: instrs ->
+ let then_label = label "then_" in
+ let endif_label = label "endif_" in
+ [ijump cval then_label]
+ @ flatten_instrs else_instrs
+ @ [igoto endif_label]
+ @ [ilabel then_label]
+ @ flatten_instrs then_instrs
+ @ [ilabel endif_label]
+ @ flatten_instrs instrs
+
+ | I_aux (I_comment _, _) :: instrs -> flatten_instrs instrs
+
+ | instr :: instrs -> instr :: flatten_instrs instrs
+ | [] -> []
+
+let flatten_cdef =
+ function
+ | CDEF_fundef (function_id, heap_return, args, body) ->
+ flat_counter := 0;
+ CDEF_fundef (function_id, heap_return, args, flatten_instrs body)
+
+ | CDEF_let (n, bindings, instrs) ->
+ flat_counter := 0;
+ CDEF_let (n, bindings, flatten_instrs instrs)
+
+ | cdef -> cdef
diff --git a/src/jib/jib_optimize.mli b/src/jib/jib_optimize.mli
new file mode 100644
index 00000000..beffa81e
--- /dev/null
+++ b/src/jib/jib_optimize.mli
@@ -0,0 +1,63 @@
+(**************************************************************************)
+(* Sail *)
+(* *)
+(* Copyright (c) 2013-2017 *)
+(* Kathyrn Gray *)
+(* Shaked Flur *)
+(* Stephen Kell *)
+(* Gabriel Kerneis *)
+(* Robert Norton-Wright *)
+(* Christopher Pulte *)
+(* Peter Sewell *)
+(* Alasdair Armstrong *)
+(* Brian Campbell *)
+(* Thomas Bauereiss *)
+(* Anthony Fox *)
+(* Jon French *)
+(* Dominic Mulligan *)
+(* Stephen Kell *)
+(* Mark Wassell *)
+(* *)
+(* All rights reserved. *)
+(* *)
+(* This software was developed by the University of Cambridge Computer *)
+(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *)
+(* (REMS) project, funded by EPSRC grant EP/K008528/1. *)
+(* *)
+(* Redistribution and use in source and binary forms, with or without *)
+(* modification, are permitted provided that the following conditions *)
+(* are met: *)
+(* 1. Redistributions of source code must retain the above copyright *)
+(* notice, this list of conditions and the following disclaimer. *)
+(* 2. Redistributions in binary form must reproduce the above copyright *)
+(* notice, this list of conditions and the following disclaimer in *)
+(* the documentation and/or other materials provided with the *)
+(* distribution. *)
+(* *)
+(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)
+(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)
+(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)
+(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)
+(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)
+(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)
+(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)
+(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)
+(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)
+(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)
+(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)
+(* SUCH DAMAGE. *)
+(**************************************************************************)
+
+open Jib
+
+(** Remove redundant assignments and variables of type
+ unit. unit-typed identifiers that are assigned to are replaced with
+ CL_void, and cvals (which should be pure!) are replaced with unit
+ types are replaced by unit-literals. *)
+val optimize_unit : instr list -> instr list
+
+(** Remove all instructions that can contain other nested
+ instructions, prodcing a flat list of instructions. *)
+val flatten_instrs : instr list -> instr list
+val flatten_cdef : cdef -> cdef
+
diff --git a/src/jib/jib_ssa.ml b/src/jib/jib_ssa.ml
new file mode 100644
index 00000000..1f477696
--- /dev/null
+++ b/src/jib/jib_ssa.ml
@@ -0,0 +1,602 @@
+(**************************************************************************)
+(* Sail *)
+(* *)
+(* Copyright (c) 2013-2017 *)
+(* Kathyrn Gray *)
+(* Shaked Flur *)
+(* Stephen Kell *)
+(* Gabriel Kerneis *)
+(* Robert Norton-Wright *)
+(* Christopher Pulte *)
+(* Peter Sewell *)
+(* Alasdair Armstrong *)
+(* Brian Campbell *)
+(* Thomas Bauereiss *)
+(* Anthony Fox *)
+(* Jon French *)
+(* Dominic Mulligan *)
+(* Stephen Kell *)
+(* Mark Wassell *)
+(* *)
+(* All rights reserved. *)
+(* *)
+(* This software was developed by the University of Cambridge Computer *)
+(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *)
+(* (REMS) project, funded by EPSRC grant EP/K008528/1. *)
+(* *)
+(* Redistribution and use in source and binary forms, with or without *)
+(* modification, are permitted provided that the following conditions *)
+(* are met: *)
+(* 1. Redistributions of source code must retain the above copyright *)
+(* notice, this list of conditions and the following disclaimer. *)
+(* 2. Redistributions in binary form must reproduce the above copyright *)
+(* notice, this list of conditions and the following disclaimer in *)
+(* the documentation and/or other materials provided with the *)
+(* distribution. *)
+(* *)
+(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)
+(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)
+(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)
+(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)
+(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)
+(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)
+(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)
+(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)
+(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)
+(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)
+(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)
+(* SUCH DAMAGE. *)
+(**************************************************************************)
+
+open Ast_util
+open Jib
+open Jib_util
+
+module IntSet = Set.Make(struct type t = int let compare = compare end)
+
+(**************************************************************************)
+(* 1. Mutable graph type *)
+(**************************************************************************)
+
+type 'a array_graph = {
+ mutable next : int;
+ mutable nodes : ('a * IntSet.t * IntSet.t) option array
+ }
+
+let make ~initial_size () = {
+ next = 0;
+ nodes = Array.make initial_size None
+ }
+
+(** Add a vertex to a graph, returning the node index *)
+let add_vertex data graph =
+ let n = graph.next in
+ if n >= Array.length graph.nodes then
+ begin
+ let new_nodes = Array.make (Array.length graph.nodes * 2) None in
+ Array.blit graph.nodes 0 new_nodes 0 (Array.length graph.nodes);
+ graph.nodes <- new_nodes
+ end;
+ let n = graph.next in
+ graph.nodes.(n) <- Some (data, IntSet.empty, IntSet.empty);
+ graph.next <- n + 1;
+ n
+
+(** Add an edge between two existing vertices. Raises Invalid_argument
+ if either of the vertices do not exist. *)
+let add_edge n m graph =
+ begin match graph.nodes.(n) with
+ | Some (data, parents, children) ->
+ graph.nodes.(n) <- Some (data, parents, IntSet.add m children)
+ | None ->
+ raise (Invalid_argument "Parent node does not exist in graph")
+ end;
+ match graph.nodes.(m) with
+ | Some (data, parents, children) ->
+ graph.nodes.(m) <- Some (data, IntSet.add n parents, children)
+ | None ->
+ raise (Invalid_argument "Child node does not exist in graph")
+
+let cardinal graph = graph.next
+
+let reachable roots graph =
+ let visited = ref IntSet.empty in
+
+ let rec reachable' n =
+ if IntSet.mem n !visited then ()
+ else
+ begin
+ visited := IntSet.add n !visited;
+ match graph.nodes.(n) with
+ | Some (_, _, successors) ->
+ IntSet.iter reachable' successors
+ | None -> ()
+ end
+ in
+ IntSet.iter reachable' roots; !visited
+
+let prune visited graph =
+ for i = 0 to graph.next - 1 do
+ match graph.nodes.(i) with
+ | Some (n, preds, succs) ->
+ if IntSet.mem i visited then
+ graph.nodes.(i) <- Some (n, IntSet.inter visited preds, IntSet.inter visited succs)
+ else
+ graph.nodes.(i) <- None
+ | None -> ()
+ done
+
+(**************************************************************************)
+(* 2. Mutable control flow graph *)
+(**************************************************************************)
+
+type cf_node =
+ | CF_label of string
+ | CF_block of instr list
+ | CF_start
+
+let control_flow_graph instrs =
+ let module StringMap = Map.Make(String) in
+ let labels = ref StringMap.empty in
+
+ let graph = make ~initial_size:512 () in
+
+ iter_instr (fun (I_aux (instr, annot)) ->
+ match instr with
+ | I_label label ->
+ labels := StringMap.add label (add_vertex ([], CF_label label) graph) !labels
+ | _ -> ()
+ ) (iblock instrs);
+
+ let cf_split (I_aux (aux, _)) =
+ match aux with
+ | I_block _ | I_label _ | I_goto _ | I_jump _ | I_if _ | I_end | I_match_failure | I_undefined _ -> true
+ | _ -> false
+ in
+
+ let rec cfg preds instrs =
+ let before, after = instr_split_at cf_split instrs in
+ let last = match after with
+ | I_aux (I_label _, _) :: _ -> []
+ | instr :: _ -> [instr]
+ | _ -> []
+ in
+ let preds = match before @ last with
+ | [] -> preds
+ | instrs ->
+ let n = add_vertex ([], CF_block instrs) graph in
+ List.iter (fun p -> add_edge p n graph) preds;
+ [n]
+ in
+ match after with
+ | I_aux (I_if (cond, then_instrs, else_instrs, _), _) :: after ->
+ let t = cfg preds then_instrs in
+ let e = cfg preds else_instrs in
+ cfg (t @ e) after
+
+ | I_aux ((I_end | I_match_failure | I_undefined _), _) :: after ->
+ cfg [] after
+
+ | I_aux (I_goto label, _) :: after ->
+ List.iter (fun p -> add_edge p (StringMap.find label !labels) graph) preds;
+ cfg [] after
+
+ | I_aux (I_jump (cval, label), _) :: after ->
+ List.iter (fun p -> add_edge p (StringMap.find label !labels) graph) preds;
+ cfg preds after
+
+ | I_aux (I_label label, _) :: after ->
+ cfg (StringMap.find label !labels :: preds) after
+
+ | I_aux (I_block instrs, _) :: after ->
+ let m = cfg preds instrs in
+ cfg m after
+
+ | _ :: after -> assert false
+
+ | [] -> preds
+ in
+
+ let start = add_vertex ([], CF_start) graph in
+ let finish = cfg [start] instrs in
+
+ let visited = reachable (IntSet.singleton start) graph in
+ prune visited graph;
+
+ start, finish, graph
+
+(**************************************************************************)
+(* 3. Computing dominators *)
+(**************************************************************************)
+
+(** Calculate the (immediate) dominators of a graph using the
+ Lengauer-Tarjan algorithm. This is the slightly less sophisticated
+ version from Appel's book 'Modern compiler implementation in ML'
+ which runs in O(n log(n)) time. *)
+let immediate_dominators graph root =
+ let none = -1 in
+ let vertex = Array.make (cardinal graph) 0 in
+ let parent = Array.make (cardinal graph) none in
+ let ancestor = Array.make (cardinal graph) none in
+ let semi = Array.make (cardinal graph) none in
+ let idom = Array.make (cardinal graph) none in
+ let samedom = Array.make (cardinal graph) none in
+ let best = Array.make (cardinal graph) none in
+ let dfnum = Array.make (cardinal graph) 0 in
+ let bucket = Array.make (cardinal graph) IntSet.empty in
+
+ let rec ancestor_with_lowest_semi v =
+ let a = ancestor.(v) in
+ if ancestor.(a) <> none then
+ let b = ancestor_with_lowest_semi a in
+ ancestor.(v) <- ancestor.(a);
+ if dfnum.(semi.(b)) < dfnum.(semi.(best.(v))) then
+ best.(v) <- b
+ else ();
+ else ();
+ if best.(v) <> none then best.(v) else v
+ in
+
+ let link p n =
+ ancestor.(n) <- p;
+ best.(n) <- n
+ in
+
+ let count = ref 0 in
+
+ let rec dfs p n =
+ if dfnum.(n) = 0 then
+ begin
+ dfnum.(n) <- !count;
+ vertex.(!count) <- n;
+ parent.(n) <- p;
+ incr count;
+ match graph.nodes.(n) with
+ | Some (_, _, successors) ->
+ IntSet.iter (fun w -> dfs n w) successors
+ | None -> assert false
+ end
+ in
+ dfs none root;
+
+ for i = !count - 1 downto 1 do
+ let n = vertex.(i) in
+ let p = parent.(n) in
+ let s = ref p in
+
+ begin match graph.nodes.(n) with
+ | Some (_, predecessors, _) ->
+ IntSet.iter (fun v ->
+ let s' =
+ if dfnum.(v) <= dfnum.(n) then
+ v
+ else
+ semi.(ancestor_with_lowest_semi v)
+ in
+ if dfnum.(s') < dfnum.(!s) then s := s'
+ ) predecessors
+ | None -> assert false
+ end;
+ semi.(n) <- !s;
+ bucket.(!s) <- IntSet.add n bucket.(!s);
+ link p n;
+ IntSet.iter (fun v ->
+ let y = ancestor_with_lowest_semi v in
+ if semi.(y) = semi.(v) then
+ idom.(v) <- p
+ else
+ samedom.(n) <- y
+ ) bucket.(p);
+ done;
+ for i = 1 to !count - 1 do
+ let n = vertex.(i) in
+ if samedom.(n) <> none then
+ idom.(n) <- idom.(samedom.(n))
+ done;
+ idom
+
+(** [(dominator_children idoms).(n)] are the nodes whose immediate dominator
+ (idom) is n. *)
+let dominator_children idom =
+ let none = -1 in
+ let children = Array.make (Array.length idom) IntSet.empty in
+
+ for n = 0 to Array.length idom - 1 do
+ let p = idom.(n) in
+ if p <> none then
+ children.(p) <- IntSet.add n (children.(p))
+ done;
+ children
+
+(** [dominate idom n w] is true if n dominates w in the tree of
+ immediate dominators idom. *)
+let rec dominate idom n w =
+ let none = -1 in
+ let p = idom.(n) in
+ if p = none then
+ false
+ else if p = w then
+ true
+ else
+ dominate idom p w
+
+let dominance_frontiers graph root idom children =
+ let df = Array.make (cardinal graph) IntSet.empty in
+
+ let rec compute_df n =
+ let set = ref IntSet.empty in
+
+ begin match graph.nodes.(n) with
+ | Some (content, _, succs) ->
+ IntSet.iter (fun y ->
+ if idom.(y) <> n then
+ set := IntSet.add y !set
+ ) succs
+ | None -> ()
+ end;
+ IntSet.iter (fun c ->
+ compute_df c;
+ IntSet.iter (fun w ->
+ if not (dominate idom n w) then
+ set := IntSet.add w !set
+ ) (df.(c))
+ ) (children.(n));
+ df.(n) <- !set
+ in
+ compute_df root;
+ df
+
+(**************************************************************************)
+(* 4. Conversion to SSA form *)
+(**************************************************************************)
+
+type ssa_elem =
+ | Phi of Ast.id * Ast.id list
+
+let place_phi_functions graph df =
+ let defsites = ref Bindings.empty in
+
+ let all_vars = ref IdSet.empty in
+
+ let rec all_decls = function
+ | I_aux (I_decl (_, id), _) :: instrs ->
+ IdSet.add id (all_decls instrs)
+ | _ :: instrs -> all_decls instrs
+ | [] -> IdSet.empty
+ in
+
+ let orig_A n =
+ match graph.nodes.(n) with
+ | Some ((_, CF_block instrs), _, _) ->
+ let vars = List.fold_left IdSet.union IdSet.empty (List.map instr_writes instrs) in
+ let vars = IdSet.diff vars (all_decls instrs) in
+ all_vars := IdSet.union vars !all_vars;
+ vars
+ | Some _ -> IdSet.empty
+ | None -> IdSet.empty
+ in
+ let phi_A = ref Bindings.empty in
+
+ for n = 0 to graph.next - 1 do
+ IdSet.iter (fun a ->
+ let ds = match Bindings.find_opt a !defsites with Some ds -> ds | None -> IntSet.empty in
+ defsites := Bindings.add a (IntSet.add n ds) !defsites
+ ) (orig_A n)
+ done;
+
+ IdSet.iter (fun a ->
+ let workset = ref (Bindings.find a !defsites) in
+ while not (IntSet.is_empty !workset) do
+ let n = IntSet.choose !workset in
+ workset := IntSet.remove n !workset;
+ IntSet.iter (fun y ->
+ let phi_A_a = match Bindings.find_opt a !phi_A with Some set -> set | None -> IntSet.empty in
+ if not (IntSet.mem y phi_A_a) then
+ begin
+ begin match graph.nodes.(y) with
+ | Some ((phis, cfnode), preds, succs) ->
+ graph.nodes.(y) <- Some ((Phi (a, Util.list_init (IntSet.cardinal preds) (fun _ -> a)) :: phis, cfnode), preds, succs)
+ | None -> assert false
+ end;
+ phi_A := Bindings.add a (IntSet.add y phi_A_a) !phi_A;
+ if not (IdSet.mem a (orig_A y)) then
+ workset := IntSet.add y !workset
+ end
+ ) df.(n)
+ done
+ ) !all_vars
+
+let rename_variables graph root children =
+ let counts = ref Bindings.empty in
+ let stacks = ref Bindings.empty in
+
+ let get_count id =
+ match Bindings.find_opt id !counts with Some n -> n | None -> 0
+ in
+ let top_stack id =
+ match Bindings.find_opt id !stacks with Some (x :: _) -> x | (Some [] | None) -> 0
+ in
+ let push_stack id n =
+ stacks := Bindings.add id (n :: match Bindings.find_opt id !stacks with Some s -> s | None -> []) !stacks
+ in
+
+ let rec fold_frag = function
+ | F_id id ->
+ let i = top_stack id in
+ F_id (append_id id ("_" ^ string_of_int i))
+ | F_ref id ->
+ let i = top_stack id in
+ F_ref (append_id id ("_" ^ string_of_int i))
+ | F_lit vl -> F_lit vl
+ | F_have_exception -> F_have_exception
+ | F_current_exception -> F_current_exception
+ | F_op (f1, op, f2) -> F_op (fold_frag f1, op, fold_frag f2)
+ | F_unary (op, f) -> F_unary (op, fold_frag f)
+ | F_call (id, fs) -> F_call (id, List.map fold_frag fs)
+ | F_field (f, field) -> F_field (fold_frag f, field)
+ | F_raw str -> F_raw str
+ | F_poly f -> F_poly (fold_frag f)
+ in
+
+ let rec fold_clexp = function
+ | CL_id (id, ctyp) ->
+ let i = get_count id + 1 in
+ counts := Bindings.add id i !counts;
+ push_stack id i;
+ CL_id (append_id id ("_" ^ string_of_int i), ctyp)
+ | CL_field (clexp, field) -> CL_field (fold_clexp clexp, field)
+ | CL_addr clexp -> CL_addr (fold_clexp clexp)
+ | CL_tuple (clexp, n) -> CL_tuple (fold_clexp clexp, n)
+ | CL_current_exception ctyp -> CL_current_exception ctyp
+ | CL_have_exception -> CL_have_exception
+ | CL_return ctyp -> CL_return ctyp
+ | CL_void -> CL_void
+ in
+
+ let fold_cval (f, ctyp) = (fold_frag f, ctyp) in
+
+ let ssa_instr (I_aux (aux, annot)) =
+ let aux = match aux with
+ | I_funcall (clexp, extern, id, args) ->
+ let args = List.map fold_cval args in
+ I_funcall (fold_clexp clexp, extern, id, args)
+ | I_copy (clexp, cval) ->
+ let cval = fold_cval cval in
+ I_copy (fold_clexp clexp, cval)
+ | I_decl (ctyp, id) ->
+ let i = get_count id + 1 in
+ counts := Bindings.add id i !counts;
+ push_stack id i;
+ I_decl (ctyp, append_id id ("_" ^ string_of_int i))
+ | I_init (ctyp, id, cval) ->
+ let cval = fold_cval cval in
+ let i = get_count id + 1 in
+ counts := Bindings.add id i !counts;
+ push_stack id i;
+ I_init (ctyp, append_id id ("_" ^ string_of_int i), cval)
+ | instr -> instr
+ in
+ I_aux (aux, annot)
+ in
+
+ let ssa_cfnode = function
+ | CF_start -> CF_start
+ | CF_block instrs -> CF_block (List.map ssa_instr instrs)
+ | CF_label label -> CF_label label
+ in
+
+ let ssa_ssanode = function
+ | Phi (id, args) ->
+ let i = get_count id + 1 in
+ counts := Bindings.add id i !counts;
+ push_stack id i;
+ Phi (append_id id ("_" ^ string_of_int i), args)
+ in
+
+ let fix_phi j = function
+ | Phi (id, ids) ->
+ Phi (id, List.mapi (fun k a ->
+ if k = j then
+ let i = top_stack a in
+ append_id a ("_" ^ string_of_int i)
+ else a)
+ ids)
+ in
+
+ let rec rename n =
+ let old_stacks = !stacks in
+ begin match graph.nodes.(n) with
+ | Some ((ssa, cfnode), preds, succs) ->
+ let ssa = List.map ssa_ssanode ssa in
+ graph.nodes.(n) <- Some ((ssa, ssa_cfnode cfnode), preds, succs);
+ List.iter (fun succ ->
+ match graph.nodes.(succ) with
+ | Some ((ssa, cfnode), preds, succs) ->
+ (* Suppose n is the j-th predecessor of succ *)
+ let rec find_j n succ = function
+ | pred :: preds ->
+ if pred = succ then n else find_j (n + 1) succ preds
+ | [] -> assert false
+ in
+ let j = find_j 0 n (IntSet.elements preds) in
+ graph.nodes.(succ) <- Some ((List.map (fix_phi j) ssa, cfnode), preds, succs)
+ | None -> assert false
+ ) (IntSet.elements succs)
+ | None -> assert false
+ end;
+ IntSet.iter (fun child -> rename child) (children.(n));
+ stacks := old_stacks
+ in
+ rename root
+
+let ssa instrs =
+ let start, finish, cfg = control_flow_graph instrs in
+ let idom = immediate_dominators cfg start in
+ let children = dominator_children idom in
+ let df = dominance_frontiers cfg start idom children in
+ place_phi_functions cfg df;
+ rename_variables cfg start children;
+ cfg
+
+(* Debugging utilities for outputing Graphviz files. *)
+
+let string_of_phis = function
+ | [] -> ""
+ | phis -> Util.string_of_list "\\l" (fun (Phi (id, args)) -> string_of_id id ^ " = phi(" ^ Util.string_of_list ", " string_of_id args ^ ")") phis ^ "\\l"
+
+let string_of_node = function
+ | (phis, CF_label label) -> string_of_phis phis ^ label
+ | (phis, CF_block instrs) -> string_of_phis phis ^ Util.string_of_list "\\l" (fun instr -> String.escaped (Pretty_print_sail.to_string (pp_instr ~short:true instr))) instrs
+ | (phis, CF_start) -> string_of_phis phis ^ "START"
+
+let vertex_color = function
+ | (_, CF_start) -> "peachpuff"
+ | (_, CF_block _) -> "white"
+ | (_, CF_label _) -> "springgreen"
+
+let edge_color node_from node_to =
+ match node_from, node_to with
+ | CF_block _, CF_block _ -> "black"
+ | CF_label _, CF_block _ -> "red"
+ | CF_block _, CF_label _ -> "blue"
+ | _, _ -> "deeppink"
+
+let make_dot out_chan graph =
+ Util.opt_colors := false;
+ output_string out_chan "digraph DEPS {\n";
+ let make_node i n =
+ output_string out_chan (Printf.sprintf " n%i [label=\"%s\";shape=box;style=filled;fillcolor=%s];\n" i (string_of_node n) (vertex_color n))
+ in
+ let make_line i s =
+ output_string out_chan (Printf.sprintf " n%i -> n%i [color=black];\n" i s)
+ in
+ for i = 0 to graph.next - 1 do
+ match graph.nodes.(i) with
+ | Some (n, _, successors) ->
+ make_node i n;
+ IntSet.iter (fun s -> make_line i s) successors
+ | None -> ()
+ done;
+ output_string out_chan "}\n";
+ Util.opt_colors := true
+
+let make_dominators_dot out_chan idom graph =
+ Util.opt_colors := false;
+ output_string out_chan "digraph DOMS {\n";
+ let make_node i n =
+ output_string out_chan (Printf.sprintf " n%i [label=\"%s\";shape=box;style=filled;fillcolor=%s];\n" i (string_of_node n) (vertex_color n))
+ in
+ let make_line i s =
+ output_string out_chan (Printf.sprintf " n%i -> n%i [color=black];\n" i s)
+ in
+ for i = 0 to Array.length idom - 1 do
+ match graph.nodes.(i) with
+ | Some (n, _, _) ->
+ if idom.(i) = -1 then
+ make_node i n
+ else
+ (make_node i n; make_line i idom.(i))
+ | None -> ()
+ done;
+ output_string out_chan "}\n";
+ Util.opt_colors := true
diff --git a/src/jib/jib_ssa.mli b/src/jib/jib_ssa.mli
new file mode 100644
index 00000000..3796a114
--- /dev/null
+++ b/src/jib/jib_ssa.mli
@@ -0,0 +1,85 @@
+(**************************************************************************)
+(* Sail *)
+(* *)
+(* Copyright (c) 2013-2017 *)
+(* Kathyrn Gray *)
+(* Shaked Flur *)
+(* Stephen Kell *)
+(* Gabriel Kerneis *)
+(* Robert Norton-Wright *)
+(* Christopher Pulte *)
+(* Peter Sewell *)
+(* Alasdair Armstrong *)
+(* Brian Campbell *)
+(* Thomas Bauereiss *)
+(* Anthony Fox *)
+(* Jon French *)
+(* Dominic Mulligan *)
+(* Stephen Kell *)
+(* Mark Wassell *)
+(* *)
+(* All rights reserved. *)
+(* *)
+(* This software was developed by the University of Cambridge Computer *)
+(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *)
+(* (REMS) project, funded by EPSRC grant EP/K008528/1. *)
+(* *)
+(* Redistribution and use in source and binary forms, with or without *)
+(* modification, are permitted provided that the following conditions *)
+(* are met: *)
+(* 1. Redistributions of source code must retain the above copyright *)
+(* notice, this list of conditions and the following disclaimer. *)
+(* 2. Redistributions in binary form must reproduce the above copyright *)
+(* notice, this list of conditions and the following disclaimer in *)
+(* the documentation and/or other materials provided with the *)
+(* distribution. *)
+(* *)
+(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)
+(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)
+(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)
+(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)
+(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)
+(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)
+(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)
+(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)
+(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)
+(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)
+(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)
+(* SUCH DAMAGE. *)
+(**************************************************************************)
+
+open Array
+
+(** A mutable array based graph type, with nodes indexed by integers. *)
+type 'a array_graph
+
+(** Create an empty array_graph, specifying the initial size of the
+ underlying array. *)
+val make : initial_size:int -> unit -> 'a array_graph
+
+(** Add a vertex to a graph, returning the index of the inserted
+ vertex. If the number of vertices exceeds the size of the
+ underlying array, then it is dynamically resized. *)
+val add_vertex : 'a -> 'a array_graph -> int
+
+(** Add an edge between two existing vertices. Raises Invalid_argument
+ if either of the vertices do not exist. *)
+val add_edge : int -> int -> 'a array_graph -> unit
+
+type cf_node =
+ | CF_label of string
+ | CF_block of Jib.instr list
+ | CF_start
+
+val control_flow_graph : Jib.instr list -> int * int list * ('a list * cf_node) array_graph
+
+type ssa_elem =
+ | Phi of Ast.id * Ast.id list
+
+(** Convert a list of instructions into SSA form *)
+val ssa : Jib.instr list -> (ssa_elem list * cf_node) array_graph
+
+(** Output the control-flow graph in graphviz format for
+ debugging. Can use 'dot -Tpng X.gv -o X.png' to generate a png
+ image of the graph. *)
+val make_dot : out_channel -> (ssa_elem list * cf_node) array_graph -> unit
diff --git a/src/jib/jib_util.ml b/src/jib/jib_util.ml
index 17227875..81cd07ef 100644
--- a/src/jib/jib_util.ml
+++ b/src/jib/jib_util.ml
@@ -154,6 +154,7 @@ let rec clexp_rename from_id to_id = function
| CL_current_exception ctyp -> CL_current_exception ctyp
| CL_have_exception -> CL_have_exception
| CL_return ctyp -> CL_return ctyp
+ | CL_void -> CL_void
let rec instr_rename from_id to_id (I_aux (instr, aux)) =
let instr = match instr with
@@ -482,6 +483,7 @@ let rec pp_clexp = function
| CL_current_exception ctyp -> string "current_exception : " ^^ pp_ctyp ctyp
| CL_have_exception -> string "have_exception"
| CL_return ctyp -> string "return : " ^^ pp_ctyp ctyp
+ | CL_void -> string "void"
let rec pp_instr ?short:(short=false) (I_aux (instr, aux)) =
match instr with
@@ -581,40 +583,6 @@ let pp_cdef = function
^^ surround 2 0 lbrace (separate_map (semi ^^ hardline) pp_instr instrs) rbrace
^^ hardline
-(**************************************************************************)
-(* 2. Dependency Graphs *)
-(**************************************************************************)
-
-type graph_node =
- | G_label of string
- | G_instr of int * instr
- | G_start
-
-let string_of_node = function
- | G_label label -> label
- | G_instr (n, instr) -> string_of_int n ^ ": " ^ Pretty_print_sail.to_string (pp_instr ~short:true instr)
- | G_start -> "START"
-
-module Node = struct
- type t = graph_node
- let compare gn1 gn2 =
- match gn1, gn2 with
- | G_label str1, G_label str2 -> String.compare str1 str2
- | G_instr (n1, _), G_instr (n2, _) -> compare n1 n2
- | G_start , G_start -> 0
- | G_start , _ -> 1
- | _ , G_start -> -1
- | G_instr _, _ -> 1
- | _ , G_instr _ -> -1
-end
-
-module NodeGraph = Graph.Make(Node)
-
-module NM = Map.Make(Node)
-module NS = Set.Make(Node)
-
-type dep_graph = NodeGraph.graph
-
let rec fragment_deps = function
| F_id id | F_ref id -> IdSet.singleton id
| F_lit _ -> IdSet.empty
@@ -635,6 +603,7 @@ let rec clexp_deps = function
| CL_have_exception -> IdSet.empty
| CL_current_exception _ -> IdSet.empty
| CL_return _ -> IdSet.empty
+ | CL_void -> IdSet.empty
(* Return the direct, read/write dependencies of a single instruction *)
let instr_deps = function
@@ -646,7 +615,7 @@ let instr_deps = function
| I_funcall (clexp, _, _, cvals) -> List.fold_left IdSet.union IdSet.empty (List.map cval_deps cvals), clexp_deps clexp
| I_copy (clexp, cval) -> cval_deps cval, clexp_deps clexp
| I_alias (clexp, cval) -> cval_deps cval, clexp_deps clexp
- | I_clear (_, id) -> IdSet.singleton id, IdSet.singleton id
+ | I_clear (_, id) -> IdSet.singleton id, IdSet.empty
| I_throw cval | I_return cval -> cval_deps cval, IdSet.empty
| I_block _ | I_try_block _ -> IdSet.empty, IdSet.empty
| I_comment _ | I_raw _ -> IdSet.empty, IdSet.empty
@@ -656,80 +625,6 @@ let instr_deps = function
| I_match_failure -> IdSet.empty, IdSet.empty
| I_end -> IdSet.empty, IdSet.empty
-(* instrs_graph returns the control-flow graph for a list of
- instructions. *)
-let instrs_graph instrs =
- let icounter = ref 0 in
- let graph = ref NodeGraph.empty in
-
- let rec add_instr last_instrs (I_aux (instr, _) as iaux) =
- incr icounter;
- let node = G_instr (!icounter, iaux) in
- match instr with
- | I_block instrs | I_try_block instrs ->
- List.fold_left add_instr last_instrs instrs
- | I_if (_, then_instrs, else_instrs, _) ->
- List.iter (fun i -> graph := NodeGraph.add_edge' i node !graph) last_instrs;
- let n1 = List.fold_left add_instr [node] then_instrs in
- let n2 = List.fold_left add_instr [node] else_instrs in
- incr icounter;
- let join = G_instr (!icounter, icomment "join") in
- List.iter (fun i -> graph := NodeGraph.add_edge' i join !graph) n1;
- List.iter (fun i -> graph := NodeGraph.add_edge' i join !graph) n2;
- [join]
- | I_return _ ->
- List.iter (fun i -> graph := NodeGraph.add_edge' i node !graph) last_instrs;
- []
- | I_label label ->
- graph := NodeGraph.add_edge' (G_label label) node !graph;
- node :: last_instrs
- | I_goto label ->
- List.iter (fun i -> graph := NodeGraph.add_edge' i node !graph) last_instrs;
- graph := NodeGraph.add_edge' node (G_label label) !graph;
- []
- | I_jump (cval, label) ->
- List.iter (fun i -> graph := NodeGraph.add_edge' i node !graph) last_instrs;
- graph := NodeGraph.add_edges' (G_label label) [] !graph;
- [node]
- | I_match_failure ->
- List.iter (fun i -> graph := NodeGraph.add_edge' i node !graph) last_instrs;
- []
- | _ ->
- List.iter (fun i -> graph := NodeGraph.add_edge' i node !graph) last_instrs;
- [node]
- in
- ignore (List.fold_left add_instr [G_start] instrs);
- let graph = NodeGraph.fix_leaves !graph in
- graph
-
-let make_dot id graph =
- Util.opt_colors := false;
- let to_string node = String.escaped (string_of_node node) in
- let node_color = function
- | G_start -> "lightpink"
- | G_instr (_, I_aux (I_decl _, _)) -> "olivedrab1"
- | G_instr (_, I_aux (I_init _, _)) -> "springgreen"
- | G_instr (_, I_aux (I_clear _, _)) -> "peachpuff"
- | G_instr (_, I_aux (I_goto _, _)) -> "orange1"
- | G_instr (_, I_aux (I_label _, _)) -> "white"
- | G_instr (_, I_aux (I_raw _, _)) -> "khaki"
- | G_instr (_, I_aux (I_return _, _)) -> "deeppink"
- | G_instr (_, I_aux (I_undefined _, _)) -> "deeppink"
- | G_instr _ -> "azure"
- | G_label _ -> "lightpink"
- in
- let edge_color from_node to_node =
- match from_node, to_node with
- | G_start , _ -> "goldenrod4"
- | G_label _, _ -> "darkgreen"
- | _ , G_label _ -> "goldenrod4"
- | G_instr _, G_instr _ -> "black"
- | _ , _ -> "coral3"
- in
- let out_chan = open_out (Util.zencode_string (string_of_id id) ^ ".gv") in
- NodeGraph.make_dot node_color edge_color to_string out_chan graph;
- close_out out_chan
-
let rec map_clexp_ctyp f = function
| CL_id (id, ctyp) -> CL_id (id, f ctyp)
| CL_field (clexp, field) -> CL_field (map_clexp_ctyp f clexp, field)
@@ -738,6 +633,7 @@ let rec map_clexp_ctyp f = function
| CL_current_exception ctyp -> CL_current_exception (f ctyp)
| CL_have_exception -> CL_have_exception
| CL_return ctyp -> CL_return (f ctyp)
+ | CL_void -> CL_void
let rec map_instr_ctyp f (I_aux (instr, aux)) =
let instr = match instr with
@@ -778,6 +674,18 @@ let rec map_instr f (I_aux (instr, aux)) =
in
f (I_aux (instr, aux))
+(** Iterate over each instruction within an instruction, bottom-up *)
+let rec iter_instr f (I_aux (instr, aux)) =
+ match instr with
+ | I_decl _ | I_init _ | I_reset _ | I_reinit _
+ | I_funcall _ | I_copy _ | I_alias _ | I_clear _ | I_jump _ | I_throw _ | I_return _
+ | I_comment _ | I_label _ | I_goto _ | I_raw _ | I_match_failure | I_undefined _ | I_end -> f (I_aux (instr, aux))
+ | I_if (cval, instrs1, instrs2, ctyp) ->
+ List.iter (iter_instr f) instrs1;
+ List.iter (iter_instr f) instrs2
+ | I_block instrs | I_try_block instrs ->
+ List.iter (iter_instr f) instrs
+
(** Map over each instruction in a cdef using map_instr *)
let cdef_map_instr f = function
| CDEF_reg_dec (id, ctyp, instrs) -> CDEF_reg_dec (id, ctyp, List.map (map_instr f) instrs)
@@ -816,17 +724,21 @@ let rec map_instrs f (I_aux (instr, aux)) =
in
I_aux (instr, aux)
+let map_instr_list f instrs =
+ List.map (map_instr f) instrs
+
+let map_instrs_list f instrs =
+ f (List.map (map_instrs f) instrs)
+
let rec instr_ids (I_aux (instr, _)) =
let reads, writes = instr_deps instr in
- IdSet.of_list (IdSet.elements reads @ IdSet.elements writes)
+ IdSet.union reads writes
let rec instr_reads (I_aux (instr, _)) =
- let reads, _ = instr_deps instr in
- IdSet.of_list (IdSet.elements reads)
+ fst (instr_deps instr)
let rec instr_writes (I_aux (instr, _)) =
- let _, writes = instr_deps instr in
- IdSet.of_list (IdSet.elements writes)
+ snd (instr_deps instr)
let rec filter_instrs f instrs =
let filter_instrs' = function
@@ -878,6 +790,7 @@ let rec clexp_ctyp = function
end
| CL_have_exception -> CT_bool
| CL_current_exception ctyp -> ctyp
+ | CL_void -> CT_unit
let rec instr_ctyps (I_aux (instr, aux)) =
match instr with
@@ -933,3 +846,29 @@ let instr_split_at f =
| instr :: instrs -> instr_split_at' f (instr :: before) instrs
in
instr_split_at' f []
+
+let rec instrs_rename from_id to_id =
+ let rename id = if Id.compare id from_id = 0 then to_id else id in
+ let crename = cval_rename from_id to_id in
+ let irename instrs = instrs_rename from_id to_id instrs in
+ let lrename = clexp_rename from_id to_id in
+ function
+ | (I_aux (I_decl (ctyp, new_id), _) :: _) as instrs when Id.compare from_id new_id = 0 -> instrs
+ | I_aux (I_decl (ctyp, new_id), aux) :: instrs -> I_aux (I_decl (ctyp, new_id), aux) :: irename instrs
+ | I_aux (I_reset (ctyp, id), aux) :: instrs -> I_aux (I_reset (ctyp, rename id), aux) :: irename instrs
+ | I_aux (I_init (ctyp, id, cval), aux) :: instrs -> I_aux (I_init (ctyp, rename id, crename cval), aux) :: irename instrs
+ | I_aux (I_reinit (ctyp, id, cval), aux) :: instrs -> I_aux (I_reinit (ctyp, rename id, crename cval), aux) :: irename instrs
+ | I_aux (I_if (cval, then_instrs, else_instrs, ctyp), aux) :: instrs ->
+ I_aux (I_if (crename cval, irename then_instrs, irename else_instrs, ctyp), aux) :: irename instrs
+ | I_aux (I_jump (cval, label), aux) :: instrs -> I_aux (I_jump (crename cval, label), aux) :: irename instrs
+ | I_aux (I_funcall (clexp, extern, id, cvals), aux) :: instrs ->
+ I_aux (I_funcall (lrename clexp, extern, rename id, List.map crename cvals), aux) :: irename instrs
+ | I_aux (I_copy (clexp, cval), aux) :: instrs -> I_aux (I_copy (lrename clexp, crename cval), aux) :: irename instrs
+ | I_aux (I_alias (clexp, cval), aux) :: instrs -> I_aux (I_alias (lrename clexp, crename cval), aux) :: irename instrs
+ | I_aux (I_clear (ctyp, id), aux) :: instrs -> I_aux (I_clear (ctyp, rename id), aux) :: irename instrs
+ | I_aux (I_return cval, aux) :: instrs -> I_aux (I_return (crename cval), aux) :: irename instrs
+ | I_aux (I_block block, aux) :: instrs -> I_aux (I_block (irename block), aux) :: irename instrs
+ | I_aux (I_try_block block, aux) :: instrs -> I_aux (I_try_block (irename block), aux) :: irename instrs
+ | I_aux (I_throw cval, aux) :: instrs -> I_aux (I_throw (crename cval), aux) :: irename instrs
+ | (I_aux ((I_comment _ | I_raw _ | I_end | I_label _ | I_goto _ | I_match_failure | I_undefined _), _) as instr) :: instrs -> instr :: irename instrs
+ | [] -> []
diff --git a/src/sail.ml b/src/sail.ml
index 50719776..b654831b 100644
--- a/src/sail.ml
+++ b/src/sail.ml
@@ -290,7 +290,7 @@ let options = Arg.align ([
Arg.String (fun l -> opt_ddump_rewrite_ast := Some (l, 0)),
"<prefix> (debug) dump the ast after each rewriting step to <prefix>_<i>.lem");
( "-ddump_flow_graphs",
- Arg.Set C_backend.opt_debug_flow_graphs,
+ Arg.Set Jib_compile.opt_debug_flow_graphs,
" (debug) dump flow analysis for Sail functions when compiling to C");
( "-dtc_verbose",
Arg.Int (fun verbosity -> Type_check.opt_tc_debug := verbosity),
diff --git a/src/sail.odocl b/src/sail.odocl
index 4e91e22e..0a45eba3 100644
--- a/src/sail.odocl
+++ b/src/sail.odocl
@@ -11,6 +11,7 @@ specialize
anf
jib
jib_compile
+jib_ssa
jib_util
util
graph \ No newline at end of file