From 2621f349fde01ca82b19e92ba458d7e57cc90da7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr> Date: Tue, 7 Jan 2020 16:05:58 +0100 Subject: [PATCH] [Ival] Optimization: shares small singleton integers and top in memory. --- .../abstract_interp/int_interval.ml | 40 ++- .../abstract_interp/int_set.ml | 92 +++---- .../abstract_interp/int_set.mli | 2 - .../abstract_interp/int_val.ml | 67 +++-- .../abstract_interp/int_val.mli | 3 - src/kernel_services/abstract_interp/ival.ml | 230 ++++++++++-------- 6 files changed, 206 insertions(+), 228 deletions(-) diff --git a/src/kernel_services/abstract_interp/int_interval.ml b/src/kernel_services/abstract_interp/int_interval.ml index ba4889551ba..1e3cf647bad 100644 --- a/src/kernel_services/abstract_interp/int_interval.ml +++ b/src/kernel_services/abstract_interp/int_interval.ml @@ -102,9 +102,6 @@ include Datatype.Make_with_collections (* ------------------------------ Building ---------------------------------- *) -let share_top t = - if equal t top then top else t - let fail min max r modu = let bound fmt = function | None -> Format.fprintf fmt "--" @@ -130,14 +127,13 @@ let check t = let make ~min ~max ~rem ~modu = let t = { min; max; rem; modu } in check t; - share_top t + t let inject_singleton e = { min = Some e; max = Some e; rem = Int.zero; modu = Int.one } let inject_range min max = - let t = { min; max; rem = Int.zero; modu = Int.one } in - share_top t + { min; max; rem = Int.zero; modu = Int.one } let build_interval ~min ~max ~rem:r ~modu = assert (is_safe_modulo r modu); @@ -209,7 +205,6 @@ let rem_is_included r1 m1 r2 m2 = (Int.is_zero (Int.e_rem m1 m2)) && (Int.equal (Int.e_rem r1 m2) r2) let is_included t1 t2 = - (t1 == t2) || (min_is_lower t2.min t1.min) && (max_is_greater t2.max t1.max) && rem_is_included t1.rem t1.modu t2.rem t2.modu @@ -225,17 +220,13 @@ let max_max x y = | Some x, Some y -> Some (Int.max x y) let join t1 t2 = - if t1 == t2 then t1 else - begin - check t1; - check t2; - let modu = Int.(pgcd (pgcd t1.modu t2.modu) (abs (sub t1.rem t2.rem))) in - let rem = Int.e_rem t1.rem modu in - let min = min_min t1.min t2.min in - let max = max_max t1.max t2.max in - let r = make ~min ~max ~rem ~modu in - r - end + check t1; + check t2; + let modu = Int.(pgcd (pgcd t1.modu t2.modu) (abs (sub t1.rem t2.rem))) in + let rem = Int.e_rem t1.rem modu in + let min = min_min t1.min t2.min in + let max = max_max t1.max t2.max in + make ~min ~max ~rem ~modu let link t1 t2 = if Int.equal t1.rem t2.rem && Int.equal t1.modu t2.modu @@ -335,13 +326,12 @@ let compute_last_common mx1 mx2 r modu = Some (Int.round_down_to_r m r modu) let meet t1 t2 = - if t1 == t2 then `Value t1 else - try - let rem, modu = compute_r_common t1.rem t1.modu t2.rem t2.modu in - let min = compute_first_common t1.min t2.min rem modu in - let max = compute_last_common t1.max t2.max rem modu in - make_or_bottom ~min ~max ~rem ~modu - with Error_Bottom -> `Bottom + try + let rem, modu = compute_r_common t1.rem t1.modu t2.rem t2.modu in + let min = compute_first_common t1.min t2.min rem modu in + let max = compute_last_common t1.max t2.max rem modu in + make_or_bottom ~min ~max ~rem ~modu + with Error_Bottom -> `Bottom let narrow = meet diff --git a/src/kernel_services/abstract_interp/int_set.ml b/src/kernel_services/abstract_interp/int_set.ml index 76786297af9..5ccb3eafff9 100644 --- a/src/kernel_services/abstract_interp/int_set.ml +++ b/src/kernel_services/abstract_interp/int_set.ml @@ -33,8 +33,6 @@ let debug_cardinal = false let emitter = Lattice_messages.register "Int_set";; let log_imprecision s = Lattice_messages.emit_imprecision emitter s -let small_nums = Array.init 33 (fun i -> [| (Integer.of_int i) |]) - (* Small sets of integers, implemented as sorted non-empty arrays. *) type set = Int.t array @@ -59,23 +57,12 @@ module Array = struct let sub a start len = assert (len > 0); sub a start len end -let zero = small_nums.(0) -let one = small_nums.(1) +let zero = [| Int.zero |] +let one = [| Int.one |] let minus_one = [| Int.minus_one |] let zero_or_one = [| Int.zero ; Int.one |] -let inject_singleton e = - if Int.le Int.zero e && Int.le e Int.thirtytwo - then small_nums.(Int.to_int e) - else [| e |] - -let share_array a s = - let e = a.(0) in - if s = 1 && Int.le Int.zero e && Int.le e Int.thirtytwo - then small_nums.(Int.to_int e) - else if s = 2 && Int.is_zero e && Int.is_one a.(1) - then zero_or_one - else a +let inject_singleton e = [| e |] let inject_periodic ~from ~period ~number = let l = Int.to_int number in @@ -88,7 +75,7 @@ let inject_periodic ~from ~period ~number = v := Int.add period !v; incr i done; - share_array s l + s module O = FCSet.Make (Integer) @@ -98,7 +85,7 @@ let inject_list list = let a = Array.make cardinal Int.zero in let i = ref 0 in O.iter (fun e -> a.(!i) <- e; incr i) o; - share_array a cardinal + a let to_list = Array.to_list @@ -106,24 +93,21 @@ let to_list = Array.to_list let hash s = Array.fold_left (fun acc v -> 1031 * acc + (Int.hash v)) 17 s -let rehash s = share_array s (Array.length s) - exception Unequal of int let compare s1 s2 = - if s1 == s2 then 0 else - let l1 = Array.length s1 in - let l2 = Array.length s2 in - if l1 <> l2 - then l1 - l2 (* no overflow here *) - else - (try - for i = 0 to l1 - 1 do - let r = Int.compare s1.(i) s2.(i) in - if r <> 0 then raise (Unequal r) - done; - 0 - with Unequal v -> v) + let l1 = Array.length s1 in + let l2 = Array.length s2 in + if l1 <> l2 + then l1 - l2 (* no overflow here *) + else + (try + for i = 0 to l1 - 1 do + let r = Int.compare s1.(i) s2.(i) in + if r <> 0 then raise (Unequal r) + done; + 0 + with Unequal v -> v) let equal e1 e2 = compare e1 e2 = 0 @@ -145,7 +129,7 @@ include Datatype.Make_with_collections let compare = compare let hash = hash let pretty = pretty - let rehash = rehash + let rehash x = x let internal_pretty_code = Datatype.pp_fail let mem_project = Datatype.never_any_project let copy = Datatype.undefined @@ -265,24 +249,12 @@ let add_ps ps x = let new_max = Int.max max x in Pre_top (new_min, new_max, new_modu) -let o_zero = O.singleton Int.zero -let o_one = O.singleton Int.one -let o_zero_or_one = O.union o_zero o_one - let share_set o s = - if s = 1 - then begin - let e = O.min_elt o in - inject_singleton e - end - else if O.equal o o_zero_or_one - then zero_or_one - else - let a = Array.make s Int.zero in - let i = ref 0 in - O.iter (fun e -> a.(!i) <- e; incr i) o; - assert (!i = s); - a + let a = Array.make s Int.zero in + let i = ref 0 in + O.iter (fun e -> a.(!i) <- e; incr i) o; + assert (!i = s); + a let inject_ps = function | Pre_set (o, s) -> `Set (share_set o s) @@ -301,7 +273,7 @@ let set_to_ival_under set = then let a = Array.make card Int.zero in ignore (Int.Set.fold (fun elt i -> Array.set a i elt; i + 1) set 0); - `Set (share_array a card) + `Set a else (* If by chance the set is contiguous. *) if (Int.equal @@ -326,7 +298,7 @@ let apply_bin_1_strict_incr f x (s : Integer.t array) = let r, l = Array.zero_copy s in let rec c i = if i = l - then share_array r l + then r else let v = f x s.(i) in r.(i) <- v; @@ -338,7 +310,7 @@ let apply_bin_1_strict_decr f x (s : Integer.t array) = let r, l = Array.zero_copy s in let rec c i = if i = l - then share_array r l + then r else let v = f x s.(i) in r.(l - i - 1) <- v; @@ -396,7 +368,7 @@ let map_set_strict_decr f (s : Integer.t array) = let r, l = Array.zero_copy s in let rec c i = if i = l - then share_array r l + then r else let v = f s.(i) in r.(l - i - 1) <- v; @@ -497,12 +469,12 @@ let join l1 s1 l2 s2 = if i1 = l1 then begin Array.blit s2 i2 r i (l2 - i2); - share_array r uniq + r end else if i2 = l2 then begin Array.blit s1 i1 r i (l1 - i1); - share_array r uniq + r end else let si = succ i in @@ -583,7 +555,7 @@ let remove s v = let r = Array.make l Int.zero in Array.blit s 0 r 0 index; Array.blit s (succ index) r index (l-index); - `Value (share_array r l) + `Value r else `Value s let complement_under ~min ~max set = @@ -672,9 +644,7 @@ let subdivide s = let lenhi = len - m in let lo = Array.sub s 0 m in let hi = Array.sub s m lenhi in - share_array lo m, - share_array hi lenhi - + lo, hi (* -------------------------------- Export ---------------------------------- *) diff --git a/src/kernel_services/abstract_interp/int_set.mli b/src/kernel_services/abstract_interp/int_set.mli index 4c0a12ca1f0..777909b5289 100644 --- a/src/kernel_services/abstract_interp/int_set.mli +++ b/src/kernel_services/abstract_interp/int_set.mli @@ -130,5 +130,3 @@ val bitwise_signed_not: t -> t (** {2 Misc} *) val subdivide: t -> t * t - -val rehash: t -> t diff --git a/src/kernel_services/abstract_interp/int_val.ml b/src/kernel_services/abstract_interp/int_val.ml index a62c3dcb1c8..427fc4522b0 100644 --- a/src/kernel_services/abstract_interp/int_val.ml +++ b/src/kernel_services/abstract_interp/int_val.ml @@ -59,10 +59,6 @@ let pretty fmt = function | Itv i -> Int_interval.pretty fmt i | Set s -> Int_set.pretty fmt s -let rehash = function - | Set s -> Set (Int_set.rehash s) - | x -> x - include Datatype.Make_with_collections (struct type t = int_val @@ -77,7 +73,7 @@ include Datatype.Make_with_collections let compare = compare let hash = hash let pretty = pretty - let rehash = rehash + let rehash x = x let internal_pretty_code = Datatype.pp_fail let mem_project = Datatype.never_any_project let copy = Datatype.undefined @@ -348,9 +344,9 @@ let diff value rem = (* ------------------------------- Lattice ---------------------------------- *) let is_included t1 t2 = - (t1 == t2) || match t1, t2 with | Itv i1, Itv i2 -> Int_interval.is_included i1 i2 + | Set s1, Set s2 -> Int_set.is_included s1 s2 | Itv _, Set _ -> false (* Itv _ represents more elements than can be represented by Set _ *) | Set s, Itv i -> @@ -359,29 +355,27 @@ let is_included t1 t2 = min_le_elt min (Int_set.min s) && max_ge_elt max (Int_set.max s) && (Int.equal Int.one modu (* Top side contains all integers, we're done *) || Int_set.for_all (fun x -> Int.equal (Int.e_rem x modu) rem) s) - | Set s1, Set s2 -> Int_set.is_included s1 s2 let join v1 v2 = - if v1 == v2 then v1 else - match v1,v2 with - | Itv i1, Itv i2 -> Itv (Int_interval.join i1 i2) - | Set i1, Set i2 -> inject_set_or_top (Int_set.join i1 i2) - | Set s, Itv i - | Itv i, Set s -> - let min, max, r, modu = Int_interval.min_max_rem_modu i in - let f elt modu = Int.pgcd modu (Int.abs (Int.sub r elt)) in - let modu = Int_set.fold f s modu in - let rem = Int.e_rem r modu in - let min = match min with - None -> None - | Some m -> Some (Int.min m (Int_set.min s)) - in - let max = match max with - None -> None - | Some m -> Some (Int.max m (Int_set.max s)) - in - check ~min ~max ~rem ~modu; - Itv (Int_interval.make ~min ~max ~rem ~modu) + match v1, v2 with + | Itv i1, Itv i2 -> Itv (Int_interval.join i1 i2) + | Set s1, Set s2 -> inject_set_or_top (Int_set.join s1 s2) + | Set s, Itv i + | Itv i, Set s -> + let min, max, r, modu = Int_interval.min_max_rem_modu i in + let f elt modu = Int.pgcd modu (Int.abs (Int.sub r elt)) in + let modu = Int_set.fold f s modu in + let rem = Int.e_rem r modu in + let min = match min with + None -> None + | Some m -> Some (Int.min m (Int_set.min s)) + in + let max = match max with + None -> None + | Some m -> Some (Int.max m (Int_set.max s)) + in + check ~min ~max ~rem ~modu; + Itv (Int_interval.make ~min ~max ~rem ~modu) let link v1 v2 = match v1, v2 with @@ -401,18 +395,14 @@ let link v1 v2 = check_make ~min ~max ~rem ~modu let meet v1 v2 = - if v1 == v2 then `Value v1 else - match v1, v2 with - | Itv i1, Itv i2 -> Int_interval.meet i1 i2 >>-: inject_itv - | Set s1 , Set s2 -> Int_set.meet s1 s2 >>-: inject_set - | Set s, Itv itv - | Itv itv, Set s -> - Int_set.filter (fun i -> Int_interval.mem i itv) s >>-: inject_set - -let narrow v1 v2 = match v1, v2 with - | Set s1, Set s2 -> Int_set.narrow s1 s2 >>-: inject_set - | (Itv _| Set _), (Itv _ | Set _) -> meet v1 v2 (* meet is exact *) + | Itv i1, Itv i2 -> Int_interval.meet i1 i2 >>-: inject_itv + | Set s1 , Set s2 -> Int_set.meet s1 s2 >>-: inject_set + | Set s, Itv itv + | Itv itv, Set s -> + Int_set.filter (fun i -> Int_interval.mem i itv) s >>-: inject_set + +let narrow = meet (* meet is exact *) let widen widen_hints t1 t2 = if equal t1 t2 || cardinal_zero_or_one t1 then t2 @@ -424,7 +414,6 @@ let widen widen_hints t1 t2 = inject_itv (Int_interval.widen widen_hints i1 i2) let intersects v1 v2 = - v1 == v2 || match v1, v2 with | Itv _, Itv _ -> not (meet v1 v2 = `Bottom) (* YYY: slightly inefficient *) | Set s1 , Set s2 -> Int_set.intersects s1 s2 diff --git a/src/kernel_services/abstract_interp/int_val.mli b/src/kernel_services/abstract_interp/int_val.mli index 8187397e75d..0c8f672ede2 100644 --- a/src/kernel_services/abstract_interp/int_val.mli +++ b/src/kernel_services/abstract_interp/int_val.mli @@ -180,6 +180,3 @@ val complement_under: size:int -> signed:bool -> t -> t or_bottom by default. If [increasing] is set to false, iterate by decreasing order. @raise Abstract_interp.Error_Top if the abstraction is unbounded. *) val fold_int: ?increasing:bool -> (Integer.t -> 'a -> 'a) -> t -> 'a -> 'a - -(** Low-level operation for demarshalling *) -val rehash: t -> t diff --git a/src/kernel_services/abstract_interp/ival.ml b/src/kernel_services/abstract_interp/ival.ml index f635675a6ca..f7c2c341eda 100644 --- a/src/kernel_services/abstract_interp/ival.ml +++ b/src/kernel_services/abstract_interp/ival.ml @@ -26,24 +26,79 @@ open Bottom.Type let emitter = Lattice_messages.register "Ival" let log_imprecision s = Lattice_messages.emit_imprecision emitter s -type t = - | Bottom - | Int of Int_val.t - | Float of Fval.t +module type Type = sig (* Binary abstract operations do not model precisely float/integer operations. - It is the responsibility of the callers to have two operands of the same - implicit type. The only exception is for [singleton_zero], which is the - correct representation of [0.] *) + It is the responsibility of the callers to have two operands of the same + implicit type. The only exception is for [singleton_zero], which is the + correct representation of [0.] *) + type t = private + | Bottom + | Int of Int_val.t + | Float of Fval.t + + val bottom: t + val zero: t + val one: t + val top: t + val inject_singleton: Int.t -> t + val inject_int: Int_val.t -> t + val inject_float: Fval.t -> t + val inject_float_interval: float -> float -> t +end + +(* This module ensures that small integer singletons (and especially zero) and + the top value are shared in memory. This enables some optimizations where we + check the physical identity instead of the equality. Outside this module, + values of type t can only be created by calling [inject_] constructors. *) +module Type : Type = struct + type t = + | Bottom + | Int of Int_val.t + | Float of Fval.t + + let small_nums = + Array.init 33 (fun i -> Int (Int_val.inject_singleton (Int.of_int i))) + + let bottom = Bottom + let zero = small_nums.(0) + let one = small_nums.(1) + let top = Int Int_val.top + + let inject_singleton e = + if Int.le Int.zero e && Int.le e Int.thirtytwo + then small_nums.(Int.to_int e) + else Int (Int_val.inject_singleton e) + + let inject_int i = + try + let e = Int_val.project_int i in + if Int.le Int.zero e && Int.le e Int.thirtytwo + then small_nums.(Int.to_int e) + else Int i + with Int_val.Not_Singleton -> + if Int_val.(equal top i) then top else Int i + + let inject_float f = + if Fval.(equal plus_zero f) + then zero + else Float f + + let inject_float_interval flow fup = + let flow = Fval.F.of_float flow in + let fup = Fval.F.of_float fup in + (* make sure that zero float is also zero int *) + if Fval.F.equal Fval.F.plus_zero flow && Fval.F.equal Fval.F.plus_zero fup + then zero + else Float (Fval.inject Fval.Double flow fup) +end +include Type module Widen_Hints = Datatype.Integer.Set type size_widen_hint = Integer.t type numerical_widen_hint = Widen_Hints.t * Fc_float.Widen_Hints.t type widen_hint = size_widen_hint * numerical_widen_hint -let bottom = Bottom -let top = Int Int_val.top - let hash = function | Bottom -> 311 | Int i -> Int_val.hash i @@ -78,42 +133,23 @@ let is_singleton_int = function | Float _ -> false | Int i -> Int_val.is_singleton i -let is_bottom x = equal x bottom - -let zero = Int Int_val.zero -let one = Int Int_val.one -let minus_one = Int Int_val.minus_one -let zero_or_one = Int Int_val.zero_or_one -let float_zeros = Float Fval.zeros +let is_bottom = (==) bottom +let is_zero = (==) zero +let is_one = (==) one -let positive_integers = Int Int_val.positive_integers -let negative_integers = Int Int_val.negative_integers +let minus_one = inject_int Int_val.minus_one +let zero_or_one = inject_int Int_val.zero_or_one +let float_zeros = inject_float Fval.zeros -let is_zero x = equal x zero - -let inject_singleton e = Int (Int_val.inject_singleton e) - -let inject_float f = - if Fval.(equal plus_zero f) - then zero - else Float f - -let inject_float_interval flow fup = - let flow = Fval.F.of_float flow in - let fup = Fval.F.of_float fup in - (* make sure that zero float is also zero int *) - if Fval.F.equal Fval.F.plus_zero flow && Fval.F.equal Fval.F.plus_zero fup - then zero - else Float (Fval.inject Fval.Double flow fup) +let positive_integers = inject_int Int_val.positive_integers +let negative_integers = inject_int Int_val.negative_integers let inject_int_or_bottom = function | `Bottom -> bottom - | `Value i -> Int i + | `Value i -> inject_int i (* let minus_zero = Float (Fval.minus_zero, Fval.minus_zero) *) -let is_one = equal one - let project_float v = if is_zero v then Fval.plus_zero @@ -194,13 +230,13 @@ let cardinal_is_less_than v n = let inject_top min max rem modu = match min, max with - | Some mn, Some mx when Int.gt mn mx -> Bottom - | _, _ -> Int (Int_val.make ~min ~max ~rem ~modu) + | Some mn, Some mx when Int.gt mn mx -> bottom + | _, _ -> inject_int (Int_val.make ~min ~max ~rem ~modu) let inject_interval ~min ~max ~rem ~modu = match min, max with - | Some mn, Some mx when Int.gt mn mx -> Bottom - | _, _ -> Int (Int_val.inject_interval ~min ~max ~rem ~modu) + | Some mn, Some mx when Int.gt mn mx -> bottom + | _, _ -> inject_int (Int_val.inject_interval ~min ~max ~rem ~modu) let subdivide ~size = function | Bottom -> raise Can_not_subdiv @@ -212,12 +248,14 @@ let subdivide ~size = function in let f1, f2 = Fval.subdiv_float_interval fkind fval in inject_float f1, inject_float f2 - | Int i -> let i1, i2 = Int_val.subdivide i in Int i1, Int i2 + | Int i -> + let i1, i2 = Int_val.subdivide i in + inject_int i1, inject_int i2 let inject_range min max = inject_top min max Int.zero Int.one -let top_float = Float Fval.top -let top_single_precision_float = Float Fval.top +let top_float = inject_float Fval.top +let top_single_precision_float = inject_float Fval.top let min_max_r_mod = function @@ -276,14 +314,14 @@ let widen (bitsize,(wh,fh)) t1 t2 = then Float_sig.Long_Double else Float_sig.Single in - Float (Fval.widen fh prec f1 f2) + inject_float (Fval.widen fh prec f1 f2) | Int i2 -> let i1 = match t1 with | Bottom -> assert false | Int i1 -> i1 | Float _ -> Int_val.top in - Int (Int_val.widen (bitsize,wh) i1 i2) + inject_int (Int_val.widen (bitsize,wh) i1 i2) let meet v1 v2 = if v1 == v2 then v1 else @@ -291,7 +329,7 @@ let meet v1 v2 = match v1, v2 with | Bottom, _ | _, Bottom -> bottom | Int i1, Int i2 -> inject_int_or_bottom (Int_val.meet i1 i2) - | Float(f1), Float(f2) -> begin + | Float f1, Float f2 -> begin match Fval.meet f1 f2 with | `Value f -> inject_float f | `Bottom -> bottom @@ -320,46 +358,41 @@ let intersects v1 v2 = equal top other || (Fval.contains_plus_zero f && contains_zero other) let narrow v1 v2 = - match v1, v2 with - | Bottom, _ | _, Bottom -> bottom - | Float _, Float _ -> meet v1 v2 (* meet is exact *) - | v, (Int _ as t) when equal t top -> v - | (Int _ as t), v when equal t top -> v - | Int i1, Int i2 -> inject_int_or_bottom (Int_val.narrow i1 i2) - | Float f, (Int _ as s) | (Int _ as s), Float f when is_zero s -> begin - match Fval.narrow f Fval.zeros with - | `Value f -> inject_float f - | `Bottom -> bottom - end - | Float _, Int _ | Int _, Float _ -> - (* ill-typed case. It is better to keep the operation symmetric *) - top + if v1 == v2 then v1 else + match v1, v2 with + | Bottom, _ | _, Bottom -> bottom + | Float _, Float _ -> meet v1 v2 (* meet is exact *) + | v, (Int _ as t) when equal t top -> v + | (Int _ as t), v when equal t top -> v + | Int i1, Int i2 -> inject_int_or_bottom (Int_val.narrow i1 i2) + | Float f, (Int _ as s) | (Int _ as s), Float f when is_zero s -> begin + match Fval.narrow f Fval.zeros with + | `Value f -> inject_float f + | `Bottom -> bottom + end + | Float _, Int _ | Int _, Float _ -> + (* ill-typed case. It is better to keep the operation symmetric *) + top let link v1 v2 = match v1, v2 with - | Int i1, Int i2 -> Int (Int_val.link i1 i2) + | Int i1, Int i2 -> inject_int (Int_val.link i1 i2) | _ -> bottom let join v1 v2 = - let result = - if v1 == v2 then v1 else - match v1,v2 with - | Bottom, t | t, Bottom -> t - | Int i1, Int i2 -> Int (Int_val.join i1 i2) - | Float(f1), Float(f2) -> - inject_float (Fval.join f1 f2) - | Float (f) as ff, other | other, (Float (f) as ff) -> - if is_zero other - then inject_float (Fval.join Fval.plus_zero f) - else if is_bottom other then ff - else top - in - (* Format.printf "mod_join %a %a -> %a@." - pretty v1 pretty v2 pretty result; *) - result + if v1 == v2 then v1 else + match v1, v2 with + | Bottom, t | t, Bottom -> t + | Int i1, Int i2 -> inject_int (Int_val.join i1 i2) + | Float f1, Float f2 -> inject_float (Fval.join f1 f2) + | Float f as ff, other | other, (Float f as ff) -> + if is_zero other + then inject_float (Fval.join Fval.plus_zero f) + else if is_bottom other then ff + else top let complement_int_under ~size ~signed = function | Bottom | Float _ -> `Bottom - | Int i -> Int_val.complement_under ~size ~signed i >>-: fun i -> Int i + | Int i -> Int_val.complement_under ~size ~signed i >>-: inject_int let fold_int f v acc = match v with @@ -393,13 +426,13 @@ let is_included t1 t2 = let add_singleton_int i = function | Bottom -> bottom | Float _ -> assert false - | Int itv -> Int (Int_val.add_singleton i itv) + | Int itv -> inject_int (Int_val.add_singleton i itv) let add_int v1 v2 = match v1, v2 with | Bottom, _ | _, Bottom -> bottom | Float _, _ | _, Float _ -> assert false - | Int i1, Int i2 -> Int (Int_val.add i1 i2) + | Int i1, Int i2 -> inject_int (Int_val.add i1 i2) let add_int_under v1 v2 = match v1, v2 with @@ -410,7 +443,7 @@ let add_int_under v1 v2 = let neg_int = function | Bottom -> bottom | Float _ -> assert false - | Int i -> Int (Int_val.neg i) + | Int i -> inject_int (Int_val.neg i) let sub_int v1 v2 = add_int v1 (neg_int v2) let sub_int_under v1 v2 = add_int_under v1 (neg_int v2) @@ -434,11 +467,11 @@ let scale f v = match v with | Bottom -> bottom | Float _ -> top - | Int i -> Int (Int_val.scale f i) + | Int i -> inject_int (Int_val.scale f i) let scale_div ~pos f = function | Bottom -> bottom - | Int i -> Int (Int_val.scale_div ~pos f i) + | Int i -> inject_int (Int_val.scale_div ~pos f i) | Float _ -> top let scale_div_under ~pos f = function @@ -463,7 +496,7 @@ let scale_rem ~pos f v = else match v with | Bottom -> bottom - | Int i -> Int (Int_val.scale_rem ~pos f i) + | Int i -> inject_int (Int_val.scale_rem ~pos f i) | Float _ -> top let c_rem v1 v2 = @@ -473,14 +506,14 @@ let c_rem v1 v2 = | Int i1, Int i2 -> inject_int_or_bottom (Int_val.c_rem i1 i2) let create_all_values ~signed ~size = - Int (Int_val.create_all_values ~signed ~size) + inject_int (Int_val.create_all_values ~signed ~size) let big_int_64 = Int.of_int 64 let big_int_32 = Int.thirtytwo let cast_int_to_int ~size ~signed = function | Bottom -> bottom - | Int i -> Int (Int_val.cast_int_to_int ~size ~signed i) + | Int i -> inject_int (Int_val.cast_int_to_int ~size ~signed i) | Float _ -> assert false let reinterpret_float_as_int ~signed ~size f = @@ -533,7 +566,7 @@ let mul v1 v2 = match v1, v2 with | Bottom, _ | _, Bottom -> bottom | Float _, _ | _, Float _ -> top - | Int i1, Int i2 -> Int (Int_val.mul i1 i2) + | Int i1, Int i2 -> inject_int (Int_val.mul i1 i2) let shift_right v1 v2 = match v1, v2 with @@ -621,13 +654,13 @@ let backward_le_int max v = match v with | Bottom -> bottom | Float _ -> v - | Int _ -> narrow v (Int (Int_val.inject_range None max)) + | Int _ -> narrow v (inject_int (Int_val.inject_range None max)) let backward_ge_int min v = match v with | Bottom -> bottom | Float _ -> v - | Int _ -> narrow v (Int (Int_val.inject_range min None)) + | Int _ -> narrow v (inject_int (Int_val.inject_range min None)) let backward_lt_int max v = backward_le_int (Extlib.opt_map Int.pred max) v let backward_gt_int min v = backward_ge_int (Extlib.opt_map Int.succ min) v @@ -698,7 +731,7 @@ let backward_comp_float_left_false op fkind f1 f2 = let rec extract_bits ~start ~stop ~size v = match v with | Bottom -> bottom - | Int i -> Int (Int_val.extract_bits ~start ~stop i) + | Int i -> inject_int (Int_val.extract_bits ~start ~stop i) | Float f -> let inject (b, e) = inject_range (Some b) (Some e) in let itvs = @@ -760,8 +793,9 @@ let forward_comp_int op i1 i2 = | Ne -> inv_truth (forward_eq_int i1 i2) let rehash = function - | Int i -> Int (Int_val.rehash i) - | x -> x + | Bottom -> bottom + | Int i -> inject_int i + | Float f -> inject_float f include ( Datatype.Make_with_collections @@ -895,7 +929,7 @@ let cast_float_to_int_inverse ~single_precision i = in assert (Fval.F.is_finite (Fval.F.of_float minf)); assert (Fval.F.is_finite (Fval.F.of_float maxf)); - Float (Fval.inject fkind (Fval.F.of_float minf) (Fval.F.of_float maxf)) + inject_float (Fval.inject fkind (Fval.F.of_float minf) (Fval.F.of_float maxf)) | _ -> if single_precision then top_single_precision_float else top_float @@ -1019,7 +1053,7 @@ let overlaps ~partial ~size t1 t2 = let bitwise_int f_int v1 v2 = match v1, v2 with - | Int i1, Int i2 -> Int (f_int i1 i2) + | Int i1, Int i2 -> inject_int (f_int i1 i2) | _, _ -> top let bitwise_or = bitwise_int Int_val.bitwise_or @@ -1029,12 +1063,12 @@ let bitwise_xor = bitwise_int Int_val.bitwise_xor let bitwise_signed_not = function | Bottom -> bottom | Float _ -> assert false - | Int i -> Int (Int_val.bitwise_signed_not i) + | Int i -> inject_int (Int_val.bitwise_signed_not i) let bitwise_unsigned_not ~size = function | Bottom -> bottom | Float _ -> assert false - | Int i -> Int (Int_val.bitwise_unsigned_not ~size i) + | Int i -> inject_int (Int_val.bitwise_unsigned_not ~size i) let bitwise_not ~size ~signed v = if signed then -- GitLab