(****************************************************************************)
(*     Sail                                                                 *)
(*                                                                          *)
(*  Sail and the Sail architecture models here, comprising all files and    *)
(*  directories except the ASL-derived Sail code in the aarch64 directory,  *)
(*  are subject to the BSD two-clause licence below.                        *)
(*                                                                          *)
(*  The ASL derived parts of the ARMv8.3 specification in                   *)
(*  aarch64/no_vector and aarch64/full are copyright ARM Ltd.               *)
(*                                                                          *)
(*  Copyright (c) 2013-2021                                                 *)
(*    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                                                          *)
(*    Alastair Reid (Arm Ltd)                                               *)
(*                                                                          *)
(*  All rights reserved.                                                    *)
(*                                                                          *)
(*  This work was partially supported by EPSRC grant EP/K008528/1 <a        *)
(*  href="http://www.cl.cam.ac.uk/users/pes20/rems">REMS: Rigorous          *)
(*  Engineering for Mainstream Systems</a>, an ARM iCASE award, EPSRC IAA   *)
(*  KTF funding, and donations from Arm.  This project has received         *)
(*  funding from the European Research Council (ERC) under the European     *)
(*  Union’s Horizon 2020 research and innovation programme (grant           *)
(*  agreement No 789108, ELVER).                                            *)
(*                                                                          *)
(*  This software was developed by SRI International and the University of  *)
(*  Cambridge Computer Laboratory (Department of Computer Science and       *)
(*  Technology) under DARPA/AFRL contracts FA8650-18-C-7809 ("CIFV")        *)
(*  and FA8750-10-C-0237 ("CTSRD").                                         *)
(*                                                                          *)
(*  SPDX-License-Identifier: BSD-2-Clause                                   *)
(****************************************************************************)

open Array
open Jib_util

val ssa_name : int -> Jib.name -> Jib.name

val unssa_name : Jib.name -> Jib.name * int

(** 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

module IntSet = Util.IntSet

val get_cond : 'a array_graph -> int -> Jib.cval

val get_vertex : 'a array_graph -> int -> ('a * IntSet.t * IntSet.t) option

val iter_graph : ('a -> IntSet.t -> IntSet.t -> unit) -> 'a array_graph -> unit

(** 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

exception Not_a_DAG of int

val topsort : 'a array_graph -> int list

type terminator =
  | T_undefined of Jib.ctyp
  | T_exit of string
  | T_end of Jib.name
  | T_goto of string
  | T_jump of int * string
  | T_label of string
  | T_none

type cf_node =
  | CF_label of string
  | CF_block of Jib.instr list * terminator
  | CF_guard of int
  | CF_start of Jib.ctyp NameMap.t
  | CF_end

val control_flow_graph : Jib.instr list -> int * int * ('a list * cf_node) array_graph

(** [immediate_dominators graph root] will calculate the immediate dominators for a control flow graph with a specified
    root node. *)
val immediate_dominators : ?post:bool -> 'a array_graph -> int -> int array

type ssa_elem = Phi of Jib.name * Jib.ctyp * Jib.name list | Pi of Jib.cval list

module NameGraph : sig
  include Graph.S with type node = Jib.name and type node_set = Set.Make(Name).t and type graph = Graph.Make(Name).graph
end

(** Return a graph of variable dependencies (from writes to reads). The second element of the return tuple is the node
    containing the variable declaration. *)
val variable_dependencies : (ssa_elem list * cf_node) array_graph -> NameGraph.graph * int NameMap.t

(** Convert a list of instructions into SSA form *)
val ssa :
  ?globals:NameSet.t -> ?debug_prefix:string -> Jib.instr list -> int * int * (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

val make_dominators_dot : out_channel -> int array -> (ssa_elem list * cf_node) array_graph -> unit
