diff --git a/src/kernel_services/abstract_interp/int_interval.ml b/src/kernel_services/abstract_interp/int_interval.ml index a6eb3d32bead52571d35d58dfe6fd631b93c04c8..ba4889551ba81a2219bc360683ff6261b3d24978 100644 --- a/src/kernel_services/abstract_interp/int_interval.ml +++ b/src/kernel_services/abstract_interp/int_interval.ml @@ -415,6 +415,23 @@ let cardinal_zero_or_one t = let diff v _ = `Value v let diff_if_one v _ = `Value v +let complement_under ~min ~max t = + let inject_range min max = + if Int.le min max + then `Value (inject_range (Some min) (Some max)) + else `Bottom + in + match t.min, t.max with + | None, None -> `Bottom + | Some b, None -> inject_range min (Int.pred b) + | None, Some e -> inject_range (Int.succ e) max + | Some b, Some e -> + let delta_min = Int.sub b min in + let delta_max = Int.sub max e in + if Int.le delta_min delta_max + then inject_range (Int.succ e) max + else inject_range min (Int.pred b) + let fold_int ?(increasing=true) f t acc = match t.min, t.max with | None, _ | _, None -> raise Error_Top diff --git a/src/kernel_services/abstract_interp/int_interval.mli b/src/kernel_services/abstract_interp/int_interval.mli index 1ff9f2500762b8cd68048f483e63c7041dcf0a05..074fa0f07d2ceed5e2747658d8fb7eb755b5e172 100644 --- a/src/kernel_services/abstract_interp/int_interval.mli +++ b/src/kernel_services/abstract_interp/int_interval.mli @@ -60,6 +60,10 @@ val mem: Integer.t -> t -> bool Returns [None] if the interval represents an infinite number of integers. *) val cardinal: t -> Integer.t option +val complement_under: min:Integer.t -> max:Integer.t -> t -> t or_bottom +(** Returns an under-approximation of the integers between [min] and [max] + that are *not* represented by the given interval. *) + (** {2 Interval semantics.} *) (** See {!Int_val} for more details. *) diff --git a/src/kernel_services/abstract_interp/int_set.ml b/src/kernel_services/abstract_interp/int_set.ml index e45dc95743f1d7bcaa62134a90ccab6597799470..76786297af9b4e4694a6eec8bf0506067bb9d344 100644 --- a/src/kernel_services/abstract_interp/int_set.ml +++ b/src/kernel_services/abstract_interp/int_set.ml @@ -586,6 +586,29 @@ let remove s v = `Value (share_array r l) else `Value s +let complement_under ~min ~max set = + let l = Array.length set in + let get idx = + if idx < 0 then Int.pred min + else if idx >= l then Int.succ max + else set.(idx) + in + let index = ref (-1) in + let max_delta = ref Int.zero in + for i = 0 to l do + let delta = Int.pred (Int.sub (get i) (get (i-1))) in + if Int.gt delta !max_delta then begin + index := i; + max_delta := delta + end + done; + let b, e = Int.succ (get (!index-1)), Int.pred (get !index) in + let card = Int.(to_int (succ (sub e b))) in + if card <= 0 then `Bottom + else if card <= !small_cardinal + then `Set (Array.init card (fun i -> Int.add b (Int.of_int i))) + else `Top (b, e, Int.one) + (* ------------------------------ Arithmetics ------------------------------- *) let add_singleton = apply_bin_1_strict_incr Int.add diff --git a/src/kernel_services/abstract_interp/int_set.mli b/src/kernel_services/abstract_interp/int_set.mli index 5157d4eaba9cead2269f23a2386e8a782a2adc87..4c0a12ca1f0299298791031ce5de17ae88bd8a28 100644 --- a/src/kernel_services/abstract_interp/int_set.mli +++ b/src/kernel_services/abstract_interp/int_set.mli @@ -106,6 +106,8 @@ val meet: t -> t -> t or_bottom val narrow: t -> t -> t or_bottom val intersects: t -> t -> bool val diff_if_one: t -> t -> t or_bottom +val complement_under: + min:Integer.t -> max:Integer.t -> t -> set_or_top_or_bottom (** {2 Semantics.} *) diff --git a/src/kernel_services/abstract_interp/int_val.ml b/src/kernel_services/abstract_interp/int_val.ml index 60c1c969c402fb6221d716482b743b1248aa650c..a62c3dcb1c882dd5f6e6ff8f28537fe83f5e20ba 100644 --- a/src/kernel_services/abstract_interp/int_val.ml +++ b/src/kernel_services/abstract_interp/int_val.ml @@ -431,6 +431,16 @@ let intersects v1 v2 = | Set s, Itv itv | Itv itv, Set s -> Int_set.exists (fun i -> Int_interval.mem i itv) s +let complement_under ~size ~signed i = + let max = Int.two_power_of_int (if signed then size - 1 else size) in + let min = if signed then Int.neg max else Int.zero in + let max = Int.pred max in + match i with + | Set set -> + inject_set_or_top_or_bottom (Int_set.complement_under ~min ~max set) + | Itv itv -> + Int_interval.complement_under ~min ~max itv >>-: inject_itv + (* -------------------------------- Arithmetics ----------------------------- *) let add_singleton i = function diff --git a/src/kernel_services/abstract_interp/int_val.mli b/src/kernel_services/abstract_interp/int_val.mli index 2f760b0c025d45340e1c81599e018c70ddd5d4cb..8187397e75d8a7adf819502afcc0095a1715074a 100644 --- a/src/kernel_services/abstract_interp/int_val.mli +++ b/src/kernel_services/abstract_interp/int_val.mli @@ -172,6 +172,10 @@ val all_values: size:Integer.t -> t -> bool val overlaps: partial:bool -> size:Integer.t -> t -> t -> bool +val complement_under: size:int -> signed:bool -> t -> t or_bottom +(** Returns an under-approximation of the integers of the given size and + signedness that are *not* represented by the given value. *) + (** Iterates on all integers represented by an abstraction, in increasing order by default. If [increasing] is set to false, iterate by decreasing order. @raise Abstract_interp.Error_Top if the abstraction is unbounded. *) diff --git a/src/kernel_services/abstract_interp/ival.ml b/src/kernel_services/abstract_interp/ival.ml index a0601a432396347902a0cd2058a4f81537b5fc3b..f635675a6caca1cc0abfd15a0d2bf4c64aba22d0 100644 --- a/src/kernel_services/abstract_interp/ival.ml +++ b/src/kernel_services/abstract_interp/ival.ml @@ -21,6 +21,7 @@ (**************************************************************************) open Abstract_interp +open Bottom.Type let emitter = Lattice_messages.register "Ival" let log_imprecision s = Lattice_messages.emit_imprecision emitter s @@ -356,41 +357,9 @@ let join v1 v2 = pretty v1 pretty v2 pretty result; *) result -let complement_int_under ~size ~signed i = - let e = Int.two_power_of_int (if signed then size - 1 else size) in - let b = if signed then Int.neg e else Int.zero in - let e = Int.pred e in - let inject_range min max = `Value (inject_range (Some min) (Some max)) in - match i with - | Float _ -> `Bottom - | Set [||] -> inject_range b e - | Set set -> - let l = Array.length set in - let array = Array.make (l + 2) Int.zero in - array.(0) <- b; - Array.blit set 0 array 1 l; - array.(l+1) <- e; - let index = ref (-1) in - let max_delta = ref Int.zero in - for i = 0 to l do - let delta = Int.sub array.(i+1) array.(i) in - if Int.gt delta !max_delta then begin - index := i; - max_delta := delta - end - done; - inject_range array.(!index) array.(!index + 1) - | Top (min, max, _rem, _modu) -> - match min, max with - | None, None -> `Bottom - | Some min, None -> inject_range b (Int.pred min) - | None, Some max -> inject_range (Int.succ max) e - | Some min, Some max -> - let delta_min = Int.sub min b in - let delta_max = Int.sub e max in - if Int.le delta_min delta_max - then inject_range (Int.succ max) e - else inject_range b (Int.pred min) +let complement_int_under ~size ~signed = function + | Bottom | Float _ -> `Bottom + | Int i -> Int_val.complement_under ~size ~signed i >>-: fun i -> Int i let fold_int f v acc = match v with