diff --git a/src/plugins/region/ranges.ml b/src/plugins/region/ranges.ml index 0283685ee422d8a7a803a7de90e8c5eabb36a52d..8ab1aa1fe4cac3b84f8488d4b5ed9a2fe4e7c7fd 100644 --- a/src/plugins/region/ranges.ml +++ b/src/plugins/region/ranges.ml @@ -23,6 +23,11 @@ let (+.) = Int64.add let (-.) = Int64.sub +let rec gcd a b = + if a = Int64.zero then b else + if b = Int64.zero then a else + gcd b (Int64.rem a b) + (* -------------------------------------------------------------------------- *) (* --- Range Maps --- *) (* -------------------------------------------------------------------------- *) @@ -37,6 +42,13 @@ type 'a t = R of 'a range list (* sorted, no-overlap *) let empty = R [] +let rec find (k: int64) = function + | [] -> raise Not_found + | ({ offset ; length } as r) :: rs -> + if offset <= k && k <= offset +. length then r else find k rs + +let find k (R rs) = find k rs + let rec merge f ra rb = match ra, rb with | [], rs | rs, [] -> rs @@ -53,15 +65,13 @@ let rec merge f ra rb = let length = max a' b' -. offset in let data = f a.data b.data in let r = { offset ; length ; data } in - merge f (r::ra) rb + if a' < b' + then merge f ra (r::rb) + else merge f (r::ra) rb let merge f (R x) (R y) = R (merge f x y) -let rec find (k: int64) = function - | [] -> raise Not_found - | ({ offset ; length } as r) :: rs -> - if offset <= k && k <= offset +. length then r else find k rs - -let find k (R rs) = find k rs +let iteri f (R xs) = List.iter f xs +let iter f (R xs) = List.iter (fun r -> f r.data) xs (* -------------------------------------------------------------------------- *) diff --git a/src/plugins/region/ranges.mli b/src/plugins/region/ranges.mli index bebb3b61227aa53fc9b5ef073fc5a560ac94527b..e7c05ad1e716cf767a082b334bfb56d7681b4510 100644 --- a/src/plugins/region/ranges.mli +++ b/src/plugins/region/ranges.mli @@ -22,10 +22,13 @@ val ( +. ) : int64 -> int64 -> int64 val ( -. ) : int64 -> int64 -> int64 +val gcd : int64 -> int64 -> int64 type 'a range = { offset : int64; length : int64; data : 'a; } type 'a t = private R of 'a range list (* sorted, no overlap *) val empty : 'a t -val merge : ('a -> 'a -> 'a) -> 'a t -> 'a t -> 'a t val find : int64 -> 'a t -> 'a range +val merge : ('a -> 'a -> 'a) -> 'a t -> 'a t -> 'a t +val iter : ('a -> unit) -> 'a t -> unit +val iteri : ('a range -> unit) -> 'a t -> unit diff --git a/src/plugins/region/rmap.ml b/src/plugins/region/rmap.ml index 6fe58f06b5710f84af437337ad9ff565e0c6f5f6..26dd76be23f8d8df755d23f7d582b4f17997586e 100644 --- a/src/plugins/region/rmap.ml +++ b/src/plugins/region/rmap.ml @@ -21,23 +21,116 @@ (**************************************************************************) open Cil_types -module Ufind = UnionFind.StoreMap - -[@@@ warning "-69"] +open Cil_datatype +module Ufind = UnionFind.Make(Store) +module Vmap = Varinfo.Map (* -------------------------------------------------------------------------- *) (* --- Region Maps --- *) (* -------------------------------------------------------------------------- *) +[@@@ warning "-37"] + (* All offsets in bits *) type node = region Ufind.rref +and layout = + | Blob + | Atom + | AtomPtr of node + | Compound of node Ranges.t + and region = { parents: node list ; - roots: logic_var list ; + roots: varinfo list ; size: int64 ; - layout: node Ranges.t option ; + layout: layout ; +} + +type map = { + store: region Ufind.store ; + mutable index: node Vmap.t ; +} + +(* -------------------------------------------------------------------------- *) +(* --- Constructors --- *) +(* -------------------------------------------------------------------------- *) + +let create () = { + store = Ufind.new_store () ; + index = Vmap.empty ; +} + +let copy m = { + store = Ufind.copy m.store ; + index = m.index ; +} + +let blob () = { + parents = [] ; + roots = [] ; + size = Int64.zero ; + layout = Blob ; } +let node map node = + try Ufind.find map.store node + with Not_found -> node + +let nodes map ns = Store.list @@ List.map (node map) ns + +let region map node = + try Ufind.get map.store node + with Not_found -> blob () + +let root (m: map) lv = + try Vmap.find lv m.index with Not_found -> + let r = Ufind.make m.store (blob ()) in + m.index <- Vmap.add lv r m.index ; r + +(* -------------------------------------------------------------------------- *) +(* --- Merge --- *) +(* -------------------------------------------------------------------------- *) + +type queue = (node * node) Queue.t + +let qmerge (m: map) (q: queue) (a : node) (b : node) : node = + if not @@ Ufind.eq m.store a b then Queue.push (a,b) q ; min a b + +let lmerge (m: map) (q: queue) (r: node) (a : layout) (b : layout) : layout = + match a, b with + | Blob, c | c, Blob -> c + | Atom, c | c, Atom -> c + | AtomPtr a, AtomPtr b -> AtomPtr (qmerge m q a b) + | Compound u, Compound v -> Compound (Ranges.merge (qmerge m q) u v) + | AtomPtr a, Compound w | Compound w, AtomPtr a -> + Ranges.iter (fun s -> ignore @@ qmerge m q r s) w ; AtomPtr a + +let rmerge (m: map) (q: queue) (r: node) (a : region) (b : region) : region = { + parents = nodes m (Store.bag a.parents b.parents) ; + roots = Store.bag a.roots b.roots ; + size = Ranges.gcd a.size b.size ; + layout = lmerge m q r a.layout b.layout ; +} + +let umerge (m: map) (q: queue) (a: node) (b: node): unit = + begin + let ra = Ufind.get m.store a in + let rb = Ufind.get m.store b in + let r = Ufind.union m.store a b in + let rc = rmerge m q r ra rb in + Ufind.set m.store r rc ; + end + +let merge (m: map) (a: node) (b: node) : node = + if Ufind.eq m.store a b then Ufind.find m.store a else + let q = Queue.create () in + umerge m q a b ; + while not @@ Queue.is_empty q do + let a,b = Queue.pop q in + umerge m q a b ; + done ; + Ufind.find m.store a + (* -------------------------------------------------------------------------- *) diff --git a/src/plugins/region/rmap.mli b/src/plugins/region/rmap.mli index 4b4baad836e5938c8bee7dbf03353ebc7b883fb7..00e7d1e08128559a5031baf1d55bd5db30abdaf7 100644 --- a/src/plugins/region/rmap.mli +++ b/src/plugins/region/rmap.mli @@ -1,4 +1,3 @@ - (**************************************************************************) (* *) (* This file is part of Frama-C. *) @@ -21,5 +20,30 @@ (* *) (**************************************************************************) +open Cil_types + type node -type region + +type layout = + | Blob + | Atom + | AtomPtr of node + | Compound of node Ranges.t + +type region = private { + parents: node list ; + roots: varinfo list ; + size: int64 ; + layout: layout ; +} + +type map + +val create : unit -> map +val copy : map -> map + +val root : map -> Cil_types.varinfo -> node +val node : map -> node -> node +val nodes : map -> node list -> node list +val region : map -> node -> region +val merge : map -> node -> node -> node diff --git a/src/plugins/region/store.ml b/src/plugins/region/store.ml new file mode 100644 index 0000000000000000000000000000000000000000..268871b817af2efbbd6c85ccc7acc8dc5cc638bc --- /dev/null +++ b/src/plugins/region/store.ml @@ -0,0 +1,49 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2024 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +(* -------------------------------------------------------------------------- *) +(* --- UnionFind Store with explicit integer keys --- *) +(* -------------------------------------------------------------------------- *) + +module Imap = Map.Make(Int) + +type 'a rref = int +type 'a store = 'a Imap.t ref + +let new_store () = ref Imap.empty +let copy r = ref !r +let rid = ref 0 +let make s v = + let k = incr rid ; !rid in + s := Imap.add k v !s ; k + +let get s k = Imap.find k !s +let set s k v = s := Imap.add k v !s + +let eq _s i j = (i == j) + +let id x = x +let list = List.sort_uniq Int.compare +let rec bag a b = + match a, b with + | [], c | c, [] -> c + | x::xs, y::ys -> x :: y :: bag xs ys diff --git a/src/plugins/region/store.mli b/src/plugins/region/store.mli new file mode 100644 index 0000000000000000000000000000000000000000..badfeb9ac5eb5edc94748710438bd1bfae707463 --- /dev/null +++ b/src/plugins/region/store.mli @@ -0,0 +1,32 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2024 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +include UnionFind.STORE + +(** Global unique identifier *) +val id : 'a rref -> int + +(** Unordered union *) +val bag: 'a list -> 'a list -> 'a list + +(** Sorted, unique *) +val list : 'a rref list -> 'a rref list