From a8318b993e655b828452799b40cbef9ed4f08f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr> Date: Wed, 6 Feb 2019 10:26:45 +0100 Subject: [PATCH] [Ival] Comments int_val signature. --- .../abstract_interp/int_val.ml | 25 +-- .../abstract_interp/int_val.mli | 144 +++++++++++++----- src/kernel_services/abstract_interp/ival.ml | 2 +- 3 files changed, 119 insertions(+), 52 deletions(-) diff --git a/src/kernel_services/abstract_interp/int_val.ml b/src/kernel_services/abstract_interp/int_val.ml index f18a3834a50..e5c43049220 100644 --- a/src/kernel_services/abstract_interp/int_val.ml +++ b/src/kernel_services/abstract_interp/int_val.ml @@ -155,8 +155,9 @@ let check_make_or_bottom ~min ~max ~rem ~modu = (* ------------------------- Sets and Intervals ---------------------------- *) -(* TODO: comments *) - +(* If an interval represents less than [small_cardinal_Int] integers, then + converts the interval into a set. Used for the return of Int_interval + functions that may reduce intervals.*) let inject_itv i = match Int_interval.cardinal i with | None -> Itv i @@ -169,6 +170,10 @@ let inject_itv i = let inject_set s = Set s +(* Int_set functions that enlarge sets returns either a small integer set, + or an interval as `Top (min, max, modu). The following functions inject + these results as proper integer abstractions of type t.*) + let inject_pre_itv ~min ~max ~modu = let rem = Int.e_rem min modu in Itv (Int_interval.make ~min:(Some min) ~max:(Some max) ~rem ~modu) @@ -182,8 +187,7 @@ let inject_set_or_top_or_bottom = function | `Set s -> `Value (Set s) | `Top (min, max, modu) -> `Value (inject_pre_itv ~min ~max ~modu) -(* TODO: more comment *) - +(* Computes [min], [max], [rem] and [modu] from an integer set. *) let make_top_from_set s = let min = Int_set.min s in let modu = @@ -200,6 +204,8 @@ let make_top_from_set s = let min = Some min in min, max, rem, modu +(* Converts an integer set into an interval, regardless of the set cardinal. + Useful for functions not implemented (or irrelevant) in Int_set. *) let make_itv_from_set s = let min, max, rem, modu = make_top_from_set s in Int_interval.make ~min ~max ~rem ~modu @@ -274,11 +280,11 @@ let min_max_rem_modu = function make_top_from_set s | Itv i -> Int_interval.min_max_rem_modu i -exception Not_Singleton_Int +exception Not_Singleton let project_int = function | Set s -> - if Int_set.cardinal s = 1 then Int_set.min s else raise Not_Singleton_Int - | Itv _ -> raise Not_Singleton_Int + if Int_set.cardinal s = 1 then Int_set.min s else raise Not_Singleton + | Itv _ -> raise Not_Singleton let is_small_set = function | Set _ -> true @@ -475,9 +481,6 @@ let neg = function | Set s -> Set (Int_set.neg s) | Itv i -> Itv (Int_interval.neg i) -let sub v1 v2 = add v1 (neg v2) -let sub_under v1 v2 = add_under v1 (neg v2) - let scale f v = if Int.is_zero f @@ -653,7 +656,7 @@ let extract_bits ~start ~stop = function top let overlaps ~partial ~size t1 t2 = - let diff = sub t1 t2 in + let diff = add t1 (neg t2) in match diff with | Set array -> not (Int_set.for_all diff --git a/src/kernel_services/abstract_interp/int_val.mli b/src/kernel_services/abstract_interp/int_val.mli index 99747b9d674..4d8d0c7d9e3 100644 --- a/src/kernel_services/abstract_interp/int_val.mli +++ b/src/kernel_services/abstract_interp/int_val.mli @@ -20,6 +20,12 @@ (* *) (**************************************************************************) +(** Integer values abstractions: an abstraction represents a set of integers. + Provided with a lattice structure and over-approximations of arithmetic + operations. *) + +(** Abstractions do not represent the empty set. Instead, operations creating + empty sets return `Bottom. *) open Bottom.Type include Datatype.S_with_collections @@ -32,86 +38,144 @@ include Eva_lattice_type.Full_AI_Lattice_with_cardinality with type t := t and type widen_hint = size_widen_hint * generic_widen_hint -val zero : t -val one : t -val minus_one : t -val zero_or_one : t +val zero: t +val one: t +val minus_one: t +val zero_or_one: t + +val positive_integers: t (** All positive integers, including 0. *) +val negative_integers: t (** All negative integers, including 0. *) + +(** {2 Building.} *) -val positive_integers : t -val negative_integers : t +(** Returns an exact abstraction of the given integer. *) +val inject_singleton: Integer.t -> t -val inject_singleton : Integer.t -> t -val inject_range : Integer.t option -> Integer.t option -> t +(** [inject_range min max] returns an abstraction of all integers between + [min] and [max] included. [None] means that the abstraction is unbounded. *) +val inject_range: Integer.t option -> Integer.t option -> t + +(** Builds an abstraction of all integers between [min] and [max] included and + congruent to [rem] modulo [modu]. For [min] and [max], [None] is the + corresponding infinity. Checks that [min] <= [max], [modu] > 0 and + 0 <= [rest] < [modu], and fails otherwise. If possible, reduces [min] and + [max] according to the modulo. *) val inject_interval: min: Integer.t option -> max: Integer.t option -> rem: Integer.t -> modu: Integer.t -> t + +(** As [inject_interval], but also checks that [min] and [max] are congruent to + [rem] modulo [modu]. *) val make: min: Integer.t option -> max: Integer.t option -> rem: Integer.t -> modu: Integer.t -> t -val create_all_values: signed:bool -> size:int -> t +(** {2 Accessors.} *) + +(** Returns the smallest integer represented by an abstraction. + Returns None if it does not exist, i.e. if the abstraction is unbounded. *) +val min_int: t -> Integer.t option + +(** Returns the highest integer represented by an abstraction. + Returns None if it does not exist, i.e. if the abstraction is unbouded. *) +val max_int: t -> Integer.t option + +(** Returns the smallest and highest integers represented by an abstraction. *) +val min_and_max: t -> Integer.t option * Integer.t option -val min_int : t -> Integer.t option -val max_int : t -> Integer.t option -val min_max_rem_modu : +(** Returns [min, max, rem, modu] such that for all integers [i] represented by + the given abstraction, [i] satisfies min ≤ i ≤ max and i ≅ rem [modu]. + The abstraction must not be a singleton. *) +val min_max_rem_modu: t -> Integer.t option * Integer.t option * Integer.t * Integer.t -val min_and_max : - t -> Integer.t option * Integer.t option -exception Not_Singleton_Int -val project_int : t -> Integer.t +exception Not_Singleton + +(** Projects a singleton abstraction into an integer. + @raise Not_Singleton if the cardinal of the argument is not 1. *) +val project_int: t -> Integer.t + +(** Is an abstraction internally represented as a small integer set? *) val is_small_set: t -> bool val project_small_set: t -> Integer.t list option +(** {2 Cardinality.} *) val is_singleton: t -> bool -val cardinal_zero_or_one : t -> bool +val cardinal_zero_or_one: t -> bool val cardinal: t -> Integer.t option val cardinal_estimate: size:Integer.t -> t -> Integer.t -val cardinal_less_than : t -> int -> int +val cardinal_less_than: t -> int -> int val cardinal_is_less_than: t -> int -> bool val is_zero: t -> bool -val contains_zero : t -> bool -val contains_non_zero : t -> bool - -val add : t -> t -> t -val add_under : t -> t -> t or_bottom -val add_singleton: Integer.t -> t -> t - -val neg : t -> t -val sub : t -> t -> t -val sub_under: t -> t -> t or_bottom +val contains_zero: t -> bool +val contains_non_zero: t -> bool -val scale : Integer.t -> t -> t -val scale_div : pos:bool -> Integer.t -> t -> t -val scale_div_under : pos:bool -> Integer.t -> t -> t or_bottom -val scale_rem : pos:bool -> Integer.t -> t -> t +(** {2 Arithmetics.} *) -val mul : t -> t -> t -val div : t -> t -> t or_bottom -val c_rem : t -> t -> t or_bottom +val add: t -> t -> t +(** Addition of two integer abstractions. *) +val add_under: t -> t -> t or_bottom +(** Under-approximation of the addition of two integer abstractions *) +val add_singleton: Integer.t -> t -> t +(** Addition of an integer abstraction with a singleton integer. + Exact operation. *) + +val neg: t -> t +(** Negation of an integer abstraction. *) + +val scale: Integer.t -> t -> t +(** [scale f v] returns an abstraction of the integers [f * x] + for all [x] in [v]. This operation is exact. *) +val scale_div: pos:bool -> Integer.t -> t -> t +(** [scale_div f v] is an over-approximation of the elements [x / f] for all + elements [x] in [v]. Uses the computer division (like in C99) if [pos] is + false, and the euclidean division if [pos] is true. *) +val scale_div_under: pos:bool -> Integer.t -> t -> t or_bottom +(** Under-approximation of the division. *) +val scale_rem: pos:bool -> Integer.t -> t -> t +(** Over-approximation of the remainder of the division. Uses the computer + division (like in C99) if [pos] is false, and the euclidean division if + [pos] is true. *) + +val mul: t -> t -> t +val div: t -> t -> t or_bottom +val c_rem: t -> t -> t or_bottom val shift_left: t -> t -> t or_bottom val shift_right: t -> t -> t or_bottom -val bitwise_and : t -> t -> t -val bitwise_or : t -> t -> t -val bitwise_xor : t -> t -> t +val bitwise_and: t -> t -> t +val bitwise_or: t -> t -> t +val bitwise_xor: t -> t -> t val bitwise_signed_not: t -> t val bitwise_unsigned_not: size:int -> t -> t -val cast_int_to_int : size:Integer.t -> signed:bool -> t -> t +(** {2 Misc} *) + +val cast_int_to_int: size:Integer.t -> signed:bool -> t -> t +(** Splits an abstraction into two abstractions. *) val subdivide: t -> t * t +(** Extracts bits from [start] to [stop] from the given integer abstraction, + [start] and [stop] being included. *) val extract_bits: start:Integer.t -> stop:Integer.t -> t -> t +(** Builds an abstraction of all integers in a C integer type. *) +val create_all_values: signed:bool -> size:int -> t + +(** [all_values ~size v] returns true iff v contains all integer values + representable in [size] bits. *) val all_values: size:Integer.t -> t -> bool val overlaps: partial:bool -> size:Integer.t -> t -> t -> bool -val fold_int : (Integer.t -> 'a -> 'a) -> t -> 'a -> 'a +(** Iterates on all integers represented by an abstraction. + @raise Abstract_interp.Error_Top if the abstraction is unbounded. *) +val fold_int: (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 7437373792e..0d957509785 100644 --- a/src/kernel_services/abstract_interp/ival.ml +++ b/src/kernel_services/abstract_interp/ival.ml @@ -140,7 +140,7 @@ let contains_non_zero = function | Float f -> Fval.contains_non_zero f -exception Not_Singleton_Int = Int_val.Not_Singleton_Int +exception Not_Singleton_Int = Int_val.Not_Singleton let project_int = function | Int i -> Int_val.project_int i -- GitLab