From a1058f7d376f9f204ede155bd80db136e5739d25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr> Date: Thu, 9 Jan 2025 20:25:59 +0100 Subject: [PATCH] [Eva] In Hptmap.cached_fold, uses cache from Binary_cache. Also take a Hptmap_sig.cache_type argument instead of ~name and ~temporary. This is consistent with all other cached functions in hptmap. --- src/kernel_services/abstract_interp/lmap.ml | 4 +- .../abstract_interp/lmap_sig.ml | 2 +- .../abstract_interp/locations.ml | 4 +- .../abstract_interp/locations.mli | 6 +- .../abstract_interp/map_lattice.ml | 6 +- .../abstract_interp/map_lattice.mli | 2 +- src/libraries/utils/binary_cache.mli | 6 -- src/libraries/utils/hptmap.ml | 70 +++++++++---------- src/libraries/utils/hptmap_sig.ml | 3 +- src/plugins/eva/domains/equality/equality.ml | 5 +- src/plugins/from/functionwise.ml | 4 +- 11 files changed, 47 insertions(+), 65 deletions(-) diff --git a/src/kernel_services/abstract_interp/lmap.ml b/src/kernel_services/abstract_interp/lmap.ml index b40ef8a586e..0f5c56a0959 100644 --- a/src/kernel_services/abstract_interp/lmap.ml +++ b/src/kernel_services/abstract_interp/lmap.ml @@ -745,9 +745,7 @@ struct let iter = M.iter - let cached_fold ~f ~cache_name ~temporary ~joiner ~empty = - let cached_f = M.cached_fold ~f ~cache_name ~temporary ~joiner ~empty in - fun m -> cached_f m + let cached_fold = M.cached_fold let cached_map ~f ~cache ~temporary = let cached_f = M.cached_map ~f ~cache ~temporary in diff --git a/src/kernel_services/abstract_interp/lmap_sig.ml b/src/kernel_services/abstract_interp/lmap_sig.ml index fb35acef317..8c39958e2a8 100644 --- a/src/kernel_services/abstract_interp/lmap_sig.ml +++ b/src/kernel_services/abstract_interp/lmap_sig.ml @@ -187,8 +187,8 @@ module type S = sig modules, as they create persistent caches. *) val cached_fold : + cache:Hptmap_sig.cache_type -> f:(Base.t -> offsetmap -> 'a) -> - cache_name:string -> temporary:bool -> joiner:('a -> 'a -> 'a) -> empty:'a -> map -> 'a val cached_map : diff --git a/src/kernel_services/abstract_interp/locations.ml b/src/kernel_services/abstract_interp/locations.ml index ea8a60fe63e..afc8590b20d 100644 --- a/src/kernel_services/abstract_interp/locations.ml +++ b/src/kernel_services/abstract_interp/locations.ml @@ -272,10 +272,10 @@ module Location_Bytes = struct let contains_addresses_of_any_locals = let f base _offsets = Base.is_any_formal_or_local base in let projection _base = Ival.top in + let cache = Hptmap_sig.PersistentCache "loc_top_any_locals" in let cached_f = cached_fold - ~cache_name:"loc_top_any_locals" - ~temporary:false + ~cache ~f ~projection ~joiner:(||) diff --git a/src/kernel_services/abstract_interp/locations.mli b/src/kernel_services/abstract_interp/locations.mli index 7e09abc3f7e..081c430c0ed 100644 --- a/src/kernel_services/abstract_interp/locations.mli +++ b/src/kernel_services/abstract_interp/locations.mli @@ -149,8 +149,7 @@ module Location_Bytes : sig @raise Error_Top in the cases [Top _]. *) val cached_fold: - cache_name:string -> - temporary:bool -> + cache:Hptmap_sig.cache_type -> f:(Base.t -> Ival.t -> 'a) -> projection:(Base.t -> Ival.t) -> joiner:('a -> 'a -> 'a) -> empty:'a -> t -> 'a @@ -288,8 +287,7 @@ module Zone : sig @raise Error_Top in the case [Top Top]. *) val cached_fold : - cache_name:string -> - temporary:bool -> + cache:Hptmap_sig.cache_type -> f:(Base.t -> Int_Intervals.t -> 'b) -> projection:(Base.t -> Int_Intervals.t) -> joiner:('b -> 'b -> 'b) -> empty:'b -> t -> 'b diff --git a/src/kernel_services/abstract_interp/map_lattice.ml b/src/kernel_services/abstract_interp/map_lattice.ml index 483d860cf82..713ad30918a 100644 --- a/src/kernel_services/abstract_interp/map_lattice.ml +++ b/src/kernel_services/abstract_interp/map_lattice.ml @@ -80,7 +80,7 @@ module type MapSet_Lattice = sig val fold_keys : (key -> 'a -> 'a) -> t -> 'a -> 'a val fold : (key -> v -> 'a -> 'a) -> t -> 'a -> 'a val cached_fold: - cache_name:string -> temporary:bool -> + cache:Hptmap_sig.cache_type -> f:(key -> v -> 'a) -> projection:(key -> v) -> joiner:('a -> 'a -> 'a) -> empty:'a -> t -> 'a val for_all: (key -> v -> bool) -> t -> bool @@ -436,8 +436,8 @@ module Make_MapSet_Lattice | Top (s, _) -> KSet.fold (fun x acc -> f x Value.top acc) s acc | Map m -> KVMap.fold f m acc - let cached_fold ~cache_name ~temporary ~f ~projection ~joiner ~empty = - let folded_f = KVMap.cached_fold ~cache_name ~temporary ~f ~joiner ~empty in + let cached_fold ~cache ~f ~projection ~joiner ~empty = + let folded_f = KVMap.cached_fold ~cache ~f ~joiner ~empty in function | Top (KSet.Top, _) -> raise Abstract_interp.Error_Top | Top (KSet.Set s, _) -> diff --git a/src/kernel_services/abstract_interp/map_lattice.mli b/src/kernel_services/abstract_interp/map_lattice.mli index 1825d8dadae..1ef2068c67b 100644 --- a/src/kernel_services/abstract_interp/map_lattice.mli +++ b/src/kernel_services/abstract_interp/map_lattice.mli @@ -125,7 +125,7 @@ module type MapSet_Lattice = sig val fold : (key -> v -> 'a -> 'a) -> t -> 'a -> 'a val cached_fold: - cache_name:string -> temporary:bool -> + cache:Hptmap_sig.cache_type -> f:(key -> v -> 'a) -> projection:(key -> v) -> joiner:('a -> 'a -> 'a) -> empty:'a -> t -> 'a diff --git a/src/libraries/utils/binary_cache.mli b/src/libraries/utils/binary_cache.mli index 26cbfbbe786..bd063032205 100644 --- a/src/libraries/utils/binary_cache.mli +++ b/src/libraries/utils/binary_cache.mli @@ -24,12 +24,6 @@ you understand what happens in this module, and do not forget that those caches are not aware of projects. *) -val memory_footprint_var_name: string - -val cache_size: int -(** Size of the caches. Controlled by environment variable - [memory_footprint_var_name]. *) - module type Cacheable = sig type t val hash : t -> int diff --git a/src/libraries/utils/hptmap.ml b/src/libraries/utils/hptmap.ml index 7766433682c..15a34cae3f1 100644 --- a/src/libraries/utils/hptmap.ml +++ b/src/libraries/utils/hptmap.ml @@ -339,42 +339,6 @@ module Shape(Key: Id_Datatype) = struct let register_clear_cache f = clear_caches_ref := f :: !clear_caches_ref let clear_caches () = List.iter (fun f -> f ()) !clear_caches_ref - let cached_fold ~cache_name ~temporary ~f ~joiner ~empty = - if debug_cache then Format.eprintf "CACHE cached_fold %s@." cache_name; - let cache_size = Binary_cache.cache_size in - let cache = Array.make cache_size (Empty, empty) in - let hash t = abs (hash t mod cache_size) in - let reset () = Array.fill cache 0 cache_size (Empty, empty) in - if not temporary then register_clear_cache reset; - fun m -> - let rec traverse t = - let mem result = - cache.(hash t) <- (t, result); - result - in - let find () = - let t', r = cache.(hash t) in - if equal t t' then r - else raise Not_found - in - match t with - | Empty -> empty - | Leaf(key, value, _) -> - (try - find () - with Not_found -> - mem (f key value) - ) - | Branch(_p, _m, s0, s1, _) -> - try - find () - with Not_found -> - let result0 = traverse s0 in - let result1 = traverse s1 in - mem (joiner result0 result1) - in - traverse m - module Cacheable (X: sig type v end) = struct type t = (key, X.v) tree let hash : t -> int = hash_generic @@ -382,6 +346,26 @@ module Shape(Key: Id_Datatype) = struct let equal : t -> t -> bool = (==) end + let is_persistent_cache = function + | Hptmap_sig.PersistentCache _ -> true + | _ -> false + + let make_unary_cache (type v result) empty name cache = + match cache with + | Hptmap_sig.NoCache -> (fun f x -> f x) + | Hptmap_sig.TemporaryCache cache_name + | Hptmap_sig.PersistentCache cache_name -> + if debug_cache + then Format.eprintf "Hptmap CACHE %s : %s@." name cache_name; + let module Arg = Cacheable (struct type nonrec v = v end) in + let module R = struct + type t = result + let sentinel : t = empty + end in + let module Cache = Binary_cache.Arity_One (Arg) (R) in + if is_persistent_cache cache then register_clear_cache Cache.clear; + Cache.merge + type ('v1, 'v2, 'result) cache_type = | Any: ('v1, 'v2, 'result) cache_type | Predicate: ('v1, 'v2, bool) cache_type @@ -417,10 +401,20 @@ module Shape(Key: Id_Datatype) = struct let module Cache = Binary_cache.Symmetric_Binary_Predicate (Arg1) in Cache.clear, Cache.merge in - if cache = Hptmap_sig.PersistentCache cache_name - then register_clear_cache clear_cache; + if is_persistent_cache cache then register_clear_cache clear_cache; merge_cache + let cached_fold ~cache ~f ~joiner ~empty = + let cache_merge = make_unary_cache empty "cached_fold" cache in + let rec compute t = cache_merge traverse t + and traverse t = + match t with + | Empty -> empty + | Leaf (key, value, _) -> f key value + | Branch (_p, _m, s0, s1, _) -> joiner (compute s0) (compute s1) + in + compute + let fold2_join_heterogeneous ~cache ~empty_left ~empty_right ~both ~join ~empty = let cache_merge = make_binary_cache empty "fold2" cache in let rec compute s t = cache_merge aux s t diff --git a/src/libraries/utils/hptmap_sig.ml b/src/libraries/utils/hptmap_sig.ml index 1579855eb92..f53a23a5a27 100644 --- a/src/libraries/utils/hptmap_sig.ml +++ b/src/libraries/utils/hptmap_sig.ml @@ -118,8 +118,7 @@ module type Shape = sig the map's ordering. *) val cached_fold : - cache_name:string -> - temporary:bool -> + cache:cache_type -> f:(key -> 'v -> 'b) -> joiner:('b -> 'b -> 'b) -> empty:'b -> diff --git a/src/plugins/eva/domains/equality/equality.ml b/src/plugins/eva/domains/equality/equality.ml index b621bd895d4..5101d2f13c1 100644 --- a/src/plugins/eva/domains/equality/equality.ml +++ b/src/plugins/eva/domains/equality/equality.ml @@ -400,12 +400,11 @@ module Set = struct fmt map let keys = - let cache_name = "Equality.Set.keys" in - let temporary = false in + let cache = Hptmap_sig.PersistentCache "Equality.Set.keys" in let f k _ = if HCE.is_lval k then Leaf k else Empty in let joiner t1 t2 = Node (t1, t2) in let empty = Empty in - cached_fold ~cache_name ~temporary ~f ~joiner ~empty + cached_fold ~cache ~f ~joiner ~empty let lvalues_only_left = let cache = Hptmap_sig.PersistentCache "Equality.Set.elements_only_left" in diff --git a/src/plugins/from/functionwise.ml b/src/plugins/from/functionwise.ml index 8907b731dbb..de69304cdf8 100644 --- a/src/plugins/from/functionwise.ml +++ b/src/plugins/from/functionwise.ml @@ -66,9 +66,9 @@ module To_Use = struct in let joiner = Zone.join in let projection _ = Int_Intervals.top in + let cache = Hptmap_sig.TemporaryCache "from cleanup" in let zone_substitution = - Zone.cached_fold ~cache_name:"from cleanup" ~temporary:true - ~f ~joiner ~empty:Zone.bottom ~projection + Zone.cached_fold ~cache ~f ~joiner ~empty:Zone.bottom ~projection in let zone_substitution x = try -- GitLab