diff --git a/src/kernel_services/abstract_interp/fc_float.ml b/src/kernel_services/abstract_interp/fc_float.ml index 3d0b23e3631f7bfb202e8e67e383728d05b71b8b..58da42b53eed54dfd699c1b3afaa653eff7f601b 100644 --- a/src/kernel_services/abstract_interp/fc_float.ml +++ b/src/kernel_services/abstract_interp/fc_float.ml @@ -109,24 +109,60 @@ let prev_float prec f = then Down >>% fun () -> Floating_point.round_to_single_precision_float f else f -let m_pi = 3.1415929794311523 (* single-precision *) -let m_pi_2 = 1.5707964897155761 (* single-precision *) -let max_single_precision_float = Floating_point.max_single_precision_float - let le f1 f2 = compare f1 f2 <= 0 -let widen_up f = - if le f (-0.) then -0. - else if le f 0. then 0. - else if le f 1. then 1. - else if le f m_pi_2 then m_pi_2 - else if le f m_pi then m_pi - else if le f 10. then 10. - else if le f 1e10 then 1e10 - else if le f max_single_precision_float then max_single_precision_float - else if le f 1e80 then 1e80 - else if le f max_float then max_float - else infinity + +(* -------------------------------------------------------------------------- + Widen hints + -------------------------------------------------------------------------- *) + +module Widen_Hints = struct + + include Datatype.Float.Set + + let pretty fmt s = + if not (is_empty s) then + Pretty_utils.pp_iter + ~pre:"@[<hov 1>{" + ~suf:"}@]" + ~sep:";@ " + iter Floating_point.pretty fmt s + + let of_list l = + match l with + | [] -> empty + | [e] -> singleton e + | e :: q -> + List.fold_left (fun acc x -> add x acc) (singleton e) q + + let m_pi = 3.1415929794311523 (* single-precision *) + let m_pi_2 = 1.5707964897155761 (* single-precision *) + let max_single_float = Floating_point.max_single_precision_float + + let default_widen_hints = + let l = [0.0;1.0;m_pi_2;m_pi;10.;1e10;max_single_float;1e80] in + union (of_list l) (of_list (List.map (fun x -> -. x) l)) + +end + +type widen_hints = Widen_Hints.t + +let widen_up wh prec f = + let r = try Widen_Hints.nearest_elt_ge f wh + with Not_found -> + if le f max_float then max_float + else infinity + in + round_to_precision Up prec r + +let widen_down wh prec f = + let r = try Widen_Hints.nearest_elt_le f wh + with Not_found -> + if le (-. max_float) f then (-. max_float) + else neg_infinity + in + round_to_precision Down prec r + let neg = (~-.) let abs = abs_float diff --git a/src/kernel_services/abstract_interp/float_interval.ml b/src/kernel_services/abstract_interp/float_interval.ml index 89c49bcc1665585e90cd3eb29bd1c4fd622e20d0..13650e1b3183bdf9b665803d79f5d9eb61f90e05 100644 --- a/src/kernel_services/abstract_interp/float_interval.ml +++ b/src/kernel_services/abstract_interp/float_interval.ml @@ -314,14 +314,12 @@ module Make (F: Float_sig.S) = struct | (FRange.NaN, FRange.Itv (b1, e1, _)) -> FRange.inject ~nan:true b1 e1 | FRange.NaN, FRange.NaN -> FRange.nan - let widen_down f = F.neg (F.widen_up (F.neg f)) - - let widen f1 f2 = + let widen wh prec f1 f2 = assert (is_included f1 f2); match f1, f2 with | FRange.Itv (b1, e1, _), FRange.Itv (b2, e2, nan) -> - let b = if Cmp.equal b2 b1 then b2 else widen_down b2 in - let e = if Cmp.equal e2 e1 then e2 else F.widen_up e2 in + let b = if Cmp.equal b2 b1 then b2 else F.widen_down wh prec b2 in + let e = if Cmp.equal e2 e1 then e2 else F.widen_up wh prec e2 in (** widen_up and down produce double only if the input is a double *) FRange.inject ~nan b e | FRange.NaN, f2 -> f2 diff --git a/src/kernel_services/abstract_interp/float_interval.mli b/src/kernel_services/abstract_interp/float_interval.mli index 51cb520393b5c50cb8390dadddfdf829c78602ba..66a803c74e15d961e77583d823dfb8e316278630 100644 --- a/src/kernel_services/abstract_interp/float_interval.mli +++ b/src/kernel_services/abstract_interp/float_interval.mli @@ -26,3 +26,4 @@ Supports NaN and infinite values. *) module Make (Float: Float_sig.S) : Float_interval_sig.S with type float := Float.t + and type widen_hints := Float.widen_hints diff --git a/src/kernel_services/abstract_interp/float_interval_sig.mli b/src/kernel_services/abstract_interp/float_interval_sig.mli index d2250132fe1b9cf1497adf4cd7b6469ff8e10045..aee6a1d773ce8bba231de5e1445ec9b92131bcba 100644 --- a/src/kernel_services/abstract_interp/float_interval_sig.mli +++ b/src/kernel_services/abstract_interp/float_interval_sig.mli @@ -29,6 +29,7 @@ type prec = Float_sig.prec module type S = sig type float (** Type of the interval bounds. *) + type widen_hints (** Type of the widen hints. *) type t (** Type of intervals. *) val packed_descr : Structural_descr.pack @@ -64,7 +65,7 @@ module type S = sig val is_included: t -> t -> bool val join: t -> t -> t - val widen: t -> t -> t + val widen: widen_hints -> prec -> t -> t -> t val narrow: t -> t -> t or_bottom val contains_a_zero: t -> bool diff --git a/src/kernel_services/abstract_interp/float_sig.mli b/src/kernel_services/abstract_interp/float_sig.mli index 37c9d5be3d16637b75a742a64d47f7914e8b0dc6..5febce60c3dc28d1750d0d3183472ac740a60956 100644 --- a/src/kernel_services/abstract_interp/float_sig.mli +++ b/src/kernel_services/abstract_interp/float_sig.mli @@ -30,6 +30,14 @@ type round = Up | Down | Near | Zero - the ACSL 'real' type. *) type prec = Single | Double | Long_Double | Real + +module type Widen_Hints = sig + include FCSet.S with type elt = Datatype.Float.t + include Datatype.S with type t:=t + + val default_widen_hints: t +end + module type S = sig type t @@ -80,9 +88,14 @@ module type S = sig behavior as [next_float]. *) val prev_float: prec -> t -> t + module Widen_Hints : Widen_Hints + type widen_hints = Widen_Hints.t + (** [widen_up f] returns a value strictly larger than [f], such that - successive applications of [widen_up] converge rapidly to infinity. *) - val widen_up: t -> t + successive applications of [widen_up] converge rapidly to infinity. + The first arguments give the set of steps that could be used. *) + val widen_up : widen_hints -> prec -> t -> t + val widen_down: widen_hints -> prec -> t -> t (** Floating-point operations. *) diff --git a/src/kernel_services/abstract_interp/fval.mli b/src/kernel_services/abstract_interp/fval.mli index 4bebb2da3ebd637dcf68cfed1baf656a8cf5d696..f631b8d354bb7bafacf092ec3d9aa3d35e664be3 100644 --- a/src/kernel_services/abstract_interp/fval.mli +++ b/src/kernel_services/abstract_interp/fval.mli @@ -61,6 +61,7 @@ module F : sig end include Float_interval_sig.S with type float := F.t + and type widen_hints := Fc_float.widen_hints val round_to_single_precision_float : t -> t diff --git a/src/kernel_services/abstract_interp/ival.ml b/src/kernel_services/abstract_interp/ival.ml index eb88284cee5c2e28b1f0e347c0cbfc3208430d4d..3d7cdeb70656b929e2f259a7dcb20977f6eea92b 100644 --- a/src/kernel_services/abstract_interp/ival.ml +++ b/src/kernel_services/abstract_interp/ival.ml @@ -52,8 +52,7 @@ module Widen_Arithmetic_Value_Set = struct include Datatype.Integer.Set let pretty fmt s = - if is_empty s then Format.fprintf fmt "{}" - else + if not (is_empty s) then Pretty_utils.pp_iter ~pre:"@[<hov 1>{" ~suf:"}@]" @@ -102,8 +101,8 @@ type t = module Widen_Hints = Widen_Arithmetic_Value_Set type size_widen_hint = Integer.t -type generic_widen_hint = Widen_Hints.t -type widen_hint = size_widen_hint * generic_widen_hint +type numerical_widen_hint = Widen_Hints.t * Fc_float.Widen_Hints.t +type widen_hint = size_widen_hint * numerical_widen_hint let some_zero = Some Int.zero @@ -619,13 +618,22 @@ let has_smaller_max_bound t1 t2 = | Some _, None -> 1 | Some m1, Some m2 -> Int.compare m2 m1 -let widen (bitsize,wh) t1 t2 = +let widen (bitsize,(wh,fh)) t1 t2 = if equal t1 t2 || cardinal_zero_or_one t1 then t2 else match t2 with | Float f2 -> let f1 = project_float t1 in - Float (Fval.widen f1 f2) + let prec = + if Integer.equal bitsize (Integer.of_int 32) + then Float_sig.Single + else if Integer.equal bitsize (Integer.of_int 64) + then Float_sig.Double + else if Integer.equal bitsize (Integer.of_int 128) + then Float_sig.Long_Double + else Float_sig.Single + in + Float (Fval.widen fh prec f1 f2) | Top _ | Set _ -> (* Add possible interval limits deducted from the bitsize *) let wh = diff --git a/src/kernel_services/abstract_interp/ival.mli b/src/kernel_services/abstract_interp/ival.mli index 32218fd774658eb5f127b9d0603a205fd1b8153e..cc7f8630939e8ca2024d3abea7fadb2075d7f635 100644 --- a/src/kernel_services/abstract_interp/ival.mli +++ b/src/kernel_services/abstract_interp/ival.mli @@ -58,12 +58,12 @@ module Widen_Hints : sig end type size_widen_hint = Integer.t -type generic_widen_hint = Widen_Hints.t +type numerical_widen_hint = Widen_Hints.t * Fc_float.Widen_Hints.t include Datatype.S_with_collections with type t := t include Lattice_type.Full_AI_Lattice_with_cardinality with type t := t - and type widen_hint = size_widen_hint * generic_widen_hint + and type widen_hint = size_widen_hint * numerical_widen_hint val is_bottom : t -> bool val overlaps: partial:bool -> size:Integer.t -> t -> t -> bool diff --git a/src/kernel_services/abstract_interp/lmap.ml b/src/kernel_services/abstract_interp/lmap.ml index 825aa7b0b7446d42855c91482a4f1c7d1458fef4..5d1f91af760b0dd01978e7f807f285a33a7f6445 100644 --- a/src/kernel_services/abstract_interp/lmap.ml +++ b/src/kernel_services/abstract_interp/lmap.ml @@ -38,7 +38,7 @@ module Make_LOffset end) (Offsetmap: module type of Offsetmap_sig with type v = V.t - and type widen_hint = V.generic_widen_hint) + and type widen_hint = V.numerical_widen_hint) (Default_offsetmap: sig val name: string val default_offsetmap : Base.t -> Offsetmap.t Bottom.or_bottom @@ -50,7 +50,7 @@ struct type v = V.t type offsetmap = Offsetmap.t - type widen_hint_base = V.generic_widen_hint + type widen_hint_base = V.numerical_widen_hint open Default_offsetmap @@ -432,7 +432,7 @@ struct (Hptmap_sig.PersistentCache name) UniversalPredicate ~decide_fast ~decide_fst ~decide_snd ~decide_both - type widen_hint = Base.Set.t * (Base.t -> V.generic_widen_hint) + type widen_hint = Base.Set.t * (Base.t -> V.numerical_widen_hint) (* Precondition : m1 <= m2 *) let widen (wh_key_set, wh_hints: widen_hint) m1 m2 = diff --git a/src/kernel_services/abstract_interp/lmap.mli b/src/kernel_services/abstract_interp/lmap.mli index 44f39505c5bc96129f0a44021069b449f4c71229..29251098017a421902788ccb53c76f850708758c 100644 --- a/src/kernel_services/abstract_interp/lmap.mli +++ b/src/kernel_services/abstract_interp/lmap.mli @@ -39,7 +39,7 @@ module Make_LOffset end) (Offsetmap: module type of Offsetmap_sig with type v = V.t - and type widen_hint = V.generic_widen_hint) + and type widen_hint = V.numerical_widen_hint) (Default_offsetmap: sig val name: string (** Used to create different datatypes each time the functor is applied *) @@ -72,7 +72,7 @@ module Make_LOffset end): module type of Lmap_sig with type v = V.t - and type widen_hint_base = V.generic_widen_hint + and type widen_hint_base = V.numerical_widen_hint and type offsetmap = Offsetmap.t (* diff --git a/src/kernel_services/abstract_interp/locations.ml b/src/kernel_services/abstract_interp/locations.ml index 70ca0060d5d777a9a3e5afc27d693aa004b0b1b2..7487068ab5c2ae2c4c61f32ca14f31f7bd570e39 100644 --- a/src/kernel_services/abstract_interp/locations.ml +++ b/src/kernel_services/abstract_interp/locations.ml @@ -405,8 +405,8 @@ module Location_Bytes = struct m1 m2 type size_widen_hint = Ival.size_widen_hint - type generic_widen_hint = Base.t -> Ival.generic_widen_hint - type widen_hint = size_widen_hint * generic_widen_hint + type numerical_widen_hint = Base.t -> Ival.numerical_widen_hint + type widen_hint = size_widen_hint * numerical_widen_hint let widen (size, wh) = let widen_map = diff --git a/src/kernel_services/abstract_interp/locations.mli b/src/kernel_services/abstract_interp/locations.mli index 654cd6dbc403b113fa9cacd7d0403f2b4809798b..8ae6ee928ead48cb7b26d60b3cdd0f41474b109c 100644 --- a/src/kernel_services/abstract_interp/locations.mli +++ b/src/kernel_services/abstract_interp/locations.mli @@ -46,8 +46,8 @@ module Location_Bytes : sig | Map of M.t (** Precise set of addresses+offsets *) type size_widen_hint = Ival.size_widen_hint - type generic_widen_hint = Base.t -> Ival.generic_widen_hint - type widen_hint = size_widen_hint * generic_widen_hint + type numerical_widen_hint = Base.t -> Ival.numerical_widen_hint + type widen_hint = size_widen_hint * numerical_widen_hint (** Those locations have a lattice structure, including standard operations such as [join], [narrow], etc. *) diff --git a/src/kernel_services/abstract_interp/offsetmap.ml b/src/kernel_services/abstract_interp/offsetmap.ml index bd89eb563c1519850e970cafdb39ef3b69fcbd07..506f4f18d86809dbf22a77df367a7c1aea3f7625 100644 --- a/src/kernel_services/abstract_interp/offsetmap.ml +++ b/src/kernel_services/abstract_interp/offsetmap.ml @@ -108,7 +108,7 @@ module Make (V : module type of Offsetmap_lattice_with_isotropy) = struct open Format type v = V.t - type widen_hint = V.generic_widen_hint + type widen_hint = V.numerical_widen_hint let empty = Empty (** All high-level functions of this module must handle a size of 0, in which @@ -2194,9 +2194,9 @@ module FullyIsotropic = struct let cardinal_zero_or_one _ = false let widen _wh _ m = m - type generic_widen_hint = unit + type numerical_widen_hint = unit type size_widen_hint = Integer.t - type widen_hint = size_widen_hint * generic_widen_hint + type widen_hint = size_widen_hint * numerical_widen_hint end diff --git a/src/kernel_services/abstract_interp/offsetmap.mli b/src/kernel_services/abstract_interp/offsetmap.mli index 88e2986c36d8cebb73384279ffd563b139a00eb3..7f518453dcb7e02ec3635170439fad134c507e68 100644 --- a/src/kernel_services/abstract_interp/offsetmap.mli +++ b/src/kernel_services/abstract_interp/offsetmap.mli @@ -27,7 +27,7 @@ module Make (V : module type of Offsetmap_lattice_with_isotropy) : module type of Offsetmap_sig with type v = V.t - and type widen_hint = V.generic_widen_hint + and type widen_hint = V.numerical_widen_hint (**/**) (* Exported as Int_Intervals, do not use this module directly *) diff --git a/src/kernel_services/abstract_interp/offsetmap_lattice_with_isotropy.mli b/src/kernel_services/abstract_interp/offsetmap_lattice_with_isotropy.mli index e2dfef042edd030211d9100ad5ac0ee2819d52f3..5c443aff195ad24d0c66c50121c1acad6af0adcd 100644 --- a/src/kernel_services/abstract_interp/offsetmap_lattice_with_isotropy.mli +++ b/src/kernel_services/abstract_interp/offsetmap_lattice_with_isotropy.mli @@ -24,11 +24,11 @@ open Lattice_type -type generic_widen_hint +type numerical_widen_hint type size_widen_hint = Integer.t include Bounded_Join_Semi_Lattice -include With_Widening with type t := t and type widen_hint = size_widen_hint * generic_widen_hint +include With_Widening with type t := t and type widen_hint = size_widen_hint * numerical_widen_hint include With_Cardinal_One with type t := t val pretty_typ: Cil_types.typ option -> t Pretty_utils.formatter diff --git a/src/plugins/value/domains/gauges/gauges_domain.ml b/src/plugins/value/domains/gauges/gauges_domain.ml index 78284d2e1d4a394ff72b29b142cf3d7e439d4830..11b85c2cbe735c3b9ecbf283b83f25d2cc1f3860 100644 --- a/src/plugins/value/domains/gauges/gauges_domain.ml +++ b/src/plugins/value/domains/gauges/gauges_domain.ml @@ -291,7 +291,7 @@ module G = struct let decide _ _ _ = assert false in join ~cache ~symmetric:true ~idempotent:false ~decide - let empty_wh = Integer.zero, (fun _ -> Ival.Widen_Hints.empty) + let empty_wh = Integer.zero, (fun _ -> Ival.Widen_Hints.empty, Fc_float.Widen_Hints.empty) let widen = let cache = cache_name "MV.widen" in diff --git a/src/plugins/value/domains/symbolic_locs.ml b/src/plugins/value/domains/symbolic_locs.ml index 1d197a22ce9d2aff5f1bef4948b660b9d368ebe9..952cf517636e04216c67d41e5f55e7d0dbc11d26 100644 --- a/src/plugins/value/domains/symbolic_locs.ml +++ b/src/plugins/value/domains/symbolic_locs.ml @@ -52,7 +52,7 @@ module K2V = struct let cache = Hptmap_sig.NoCache in let symmetric = false in let idempotent = true in - let wh = Integer.zero, fun _b -> Ival.Widen_Hints.empty in + let wh = Integer.zero, (fun _b -> Ival.Widen_Hints.empty, Fc_float.Widen_Hints.empty) in let decide _ v1 v2 = Some (V.widen wh v1 v2) in M.inter ~cache ~symmetric ~idempotent ~decide diff --git a/src/plugins/value/utils/widen.ml b/src/plugins/value/utils/widen.ml index 2356d40a5625ee76dca0b91c517da77d1160d3e7..94d70a29988d190344d375c4b9d481938bba0eb4 100644 --- a/src/plugins/value/utils/widen.ml +++ b/src/plugins/value/utils/widen.ml @@ -34,14 +34,32 @@ let dkey = Widen_hints_ext.dkey reuse loop indexes... *) +let rec constFoldTermToNearestFloat = function + | TConst (LReal r) -> Some (r.r_nearest) + | TUnOp (Neg,e) -> begin + match (constFoldTermToNearestFloat e.term_node) with + | None -> None + | Some e -> Some (-. e) + end + | _ -> None + class pragma_widen_visitor init_widen_hints init_enclosing_loops = object(self) inherit Visitor.frama_c_inplace val widen_hints = init_widen_hints val enclosing_loops = init_enclosing_loops - method private add_thresholds ?base thresholds = - widen_hints := Widen_type.join (Widen_type.num_hints None(*see note*) base thresholds) !widen_hints + method private add_int_thresholds ?base int_thresholds = + widen_hints := + Widen_type.join + (Widen_type.num_hints None(*see note*) base int_thresholds) + !widen_hints + + method private add_float_thresholds ?base float_thresholds = + widen_hints := + Widen_type.join + (Widen_type.float_hints None(*see note*) base float_thresholds) + !widen_hints method private add_var_hints ~stmt hints = widen_hints := Widen_type.join (Widen_type.var_hints stmt hints) !widen_hints @@ -63,20 +81,27 @@ class pragma_widen_visitor init_widen_hints init_enclosing_loops = object(self) "could not interpret loop pragma relative to widening variables" end | Widen_hints l -> begin - let f (lv, lnum, lt) t = match t with + let f (lv, lint, lfloat, lt) t = match t with | { term_node= TLval (TVar { lv_origin = Some vi}, _)} -> - (Base.of_varinfo vi :: lv, lnum, lt) + (Base.of_varinfo vi :: lv, lint, lfloat, lt) | { term_node= TConst (Integer(v,_))} -> - (lv, Ival.Widen_Hints.add v lnum, lt) - | _ -> (lv, lnum, t::lt) + (lv, Ival.Widen_Hints.add v lint, lfloat, lt) + | _ -> + match constFoldTermToNearestFloat t.term_node with + | Some f -> (lv, lint, Fc_float.Widen_Hints.add f lfloat, lt) + | None -> (lv, lint, lfloat, t::lt) in - match List.fold_left f ([], Ival.Widen_Hints.empty, []) l with - | (vars, thresholds, []) -> + match List.fold_left f ([], Ival.Widen_Hints.empty, Fc_float.Widen_Hints.empty, []) l with + | (vars, int_thresholds, float_thresholds, []) -> (* the annotation is empty or contains only variables *) - if vars = [] then - self#add_thresholds thresholds - else - List.iter (fun base -> self#add_thresholds ~base thresholds) vars + if vars = [] then begin + self#add_int_thresholds int_thresholds; + self#add_float_thresholds float_thresholds + end else + List.iter (fun base -> + self#add_int_thresholds ~base int_thresholds; + self#add_float_thresholds ~base float_thresholds; + ) vars | _ -> Value_parameters.warning ~once:true "could not interpret loop pragma relative to widening hint" @@ -137,17 +162,17 @@ class pragma_widen_visitor init_widen_hints init_enclosing_loops = object(self) match e with | {enode=(CastE(_, { enode=Lval (Var varinfo, _)}) | Lval (Var varinfo, _))} -> - let thresholds = Ival.Widen_Hints.singleton Integer.zero in + let int_thresholds = Ival.Widen_Hints.singleton Integer.zero in let base = Base.of_varinfo varinfo in - self#add_thresholds ~base thresholds; + self#add_int_thresholds ~base int_thresholds; Cil.DoChildren | _ -> Cil.DoChildren and comparison_visit add1 add2 e1 e2 = let add base set = - let thresholds = + let int_thresholds = List.fold_right Ival.Widen_Hints.add set Ival.Widen_Hints.empty in - self#add_thresholds ~base thresholds + self#add_int_thresholds ~base int_thresholds in let i1, i2 = Cil.constFoldToInt e1, Cil.constFoldToInt e2 in begin match i1, i2, e1, e2 with @@ -184,8 +209,8 @@ class pragma_widen_visitor init_widen_hints init_enclosing_loops = object(self) let add_hint vidx size shift = let bound1 = Integer.sub size shift in let bound2 = Integer.(sub bound1 one) in - let thresholds = Ival.Widen_Hints.of_list [bound1; bound2] in - self#add_thresholds ~base:(Base.of_varinfo vidx) thresholds + let int_thresholds = Ival.Widen_Hints.of_list [bound1; bound2] in + self#add_int_thresholds ~base:(Base.of_varinfo vidx) int_thresholds in (* Find inside [idx] a variable on which we will add hints. [shift] is an integer that indicates that we access to [idx+shift], instead of to @@ -252,6 +277,9 @@ let base_of_static_hvars hvars = (* syntactic constraints prevent this from happening *) Value_parameters.fatal "unsupported lhost: %a" Printer.pp_lval (Mem e, offset) +type threshold = Int_th of Integer.t | Float_th of float + +(* try parsing as int, then as float *) let threshold_of_threshold_term ht = let global_find_init vi = try (Globals.Vars.find vi).init with Not_found -> None @@ -260,16 +288,36 @@ let threshold_of_threshold_term ht = (new Logic_utils.simplify_const_lval global_find_init) ht in match Logic_utils.constFoldTermToInt ht with - | None -> Value_parameters.abort ~source:(fst ht.term_loc) - "could not parse widening hint: %a@ \ - If it contains variables, they must be global const integers." - Printer.pp_term ht - | Some i -> i + | Some i -> Int_th i + | None -> + match constFoldTermToNearestFloat ht.term_node with + | Some f -> Float_th f + | None -> + Value_parameters.abort ~source:(fst ht.term_loc) + "could not parse widening hint: %a@ \ + If it contains variables, they must be global const integers." + Printer.pp_term ht let thresholds_of_threshold_terms hts = - List.fold_left (fun acc' ht -> - Ival.Widen_Hints.add (threshold_of_threshold_term ht) acc' - ) Ival.Widen_Hints.empty hts + let has_int = ref false in + let has_float = ref false in + List.fold_left (fun (int_acc, float_acc) ht -> + match threshold_of_threshold_term ht with + | Int_th i -> + if !has_float then + Value_parameters.abort ~source:(fst ht.term_loc) + "widening hint mixing integers and floats: %a" + Printer.pp_term ht; + has_int := true; + Ival.Widen_Hints.add i int_acc, float_acc + | Float_th f -> + if !has_int then + Value_parameters.abort ~source:(fst ht.term_loc) + "widening hint mixing integers and floats: %a" + Printer.pp_term ht; + has_float := true; + int_acc, Fc_float.Widen_Hints.add f float_acc + ) (Ival.Widen_Hints.empty, Fc_float.Widen_Hints.empty) hts class hints_visitor init_widen_hints global = object(self) inherit Visitor.frama_c_inplace @@ -284,17 +332,27 @@ class hints_visitor init_widen_hints global = object(self) List.iter (fun ({Widen_hints_ext.vars; loc}, wh_terms) -> let base = base_of_static_hvars vars in - let thresholds = thresholds_of_threshold_terms wh_terms in + let int_thresholds, float_thresholds = + thresholds_of_threshold_terms wh_terms + in Value_parameters.feedback ~source:(fst loc) ~dkey - "adding%s hint from annotation: %a, %a (for all statements)" + "adding%s hint from annotation: %a, %t (for all statements)" (if global then " global" else "") (Pretty_utils.pp_opt ~none:(format_of_string "for all variables") Base.pretty) base - Ival.Widen_Hints.pretty thresholds; - let new_hints = - Widen_type.num_hints None (* see note above *) base thresholds + (fun fmt -> + if Ival.Widen_Hints.is_empty int_thresholds then + Format.fprintf fmt "float:%a" Fc_float.Widen_Hints.pretty float_thresholds + else + Ival.Widen_Hints.pretty fmt int_thresholds); + let new_int_hints = + Widen_type.num_hints None (* see note above *) base int_thresholds + in + widen_hints := Widen_type.join new_int_hints !widen_hints; + let new_float_hints = + Widen_type.float_hints None (* see note above *) base float_thresholds in - widen_hints := Widen_type.join new_hints !widen_hints + widen_hints := Widen_type.join new_float_hints !widen_hints ) static_hints method! vstmt s = @@ -363,7 +421,8 @@ type dynamic_hint = { (* dynamic, used to detect when a new base needs to be added to the global widening hints *); lv : exp * offset; (* static, parsed once from the AST *) - thresholds : Ival.Widen_Hints.t; (* static, computed only once *) + int_thresholds : Ival.Widen_Hints.t; (* static, computed only once *) + float_thresholds : Fc_float.Widen_Hints.t; (* static, computed only once *) } module ExpOffset = Datatype.Pair(Exp)(Offset) @@ -376,13 +435,16 @@ module DynamicHintDatatype = Datatype.Make(struct Structural_descr.t_tuple [| Base.Hptset.packed_descr; ExpOffset.packed_descr; - Ival.Widen_Hints.packed_descr |] + Ival.Widen_Hints.packed_descr; + Fc_float.Widen_Hints.packed_descr |] let reprs = - List.map - (fun wh -> { bases = Base.Hptset.empty; - lv = (Exp.dummy, NoOffset); - thresholds = wh }) + Extlib.product + (fun wh fh -> { bases = Base.Hptset.empty; + lv = (Exp.dummy, NoOffset); + int_thresholds = wh; + float_thresholds = fh }) Ival.Widen_Hints.reprs + Fc_float.Widen_Hints.reprs let mem_project = Datatype.never_any_project end) @@ -430,8 +492,11 @@ let extract_dynamic_hints stmt = let open Widen_hints_ext in match hlv.vars with | HintMem (e, offset) -> - let thresholds = thresholds_of_threshold_terms threshold_terms in - { bases = Base.Hptset.empty; lv = (e, offset); thresholds; } :: l + let int_thresholds, float_thresholds = + thresholds_of_threshold_terms threshold_terms + in + let bases = Base.Hptset.empty in + { bases; lv = (e, offset); int_thresholds; float_thresholds; } :: l | _-> l in List.fold_left aux [] wh @@ -489,13 +554,18 @@ let dynamic_widen_hints_hook (stmt, _callstack, states) = let new_hints = Base.Hptset.fold (fun base acc -> Value_parameters.debug ~source ~dkey - "adding new base due to dynamic widen hint: %a, %a" + "adding new base due to dynamic widen hint: %a, %a%a" Base.pretty base - Ival.Widen_Hints.pretty dhint.thresholds; - let hint_for_base = - Widen_type.num_hints None (Some base) dhint.thresholds + Ival.Widen_Hints.pretty dhint.int_thresholds + Fc_float.Widen_Hints.pretty dhint.float_thresholds; + let int_hint_for_base = + Widen_type.num_hints None (Some base) dhint.int_thresholds + in + let float_hint_for_base = + Widen_type.float_hints None (Some base) dhint.float_thresholds in - Widen_type.join acc hint_for_base + let acc = Widen_type.join acc int_hint_for_base in + Widen_type.join acc float_hint_for_base ) new_bases acc_hints in dhint.bases <- Base.Hptset.union dhint.bases new_bases; diff --git a/src/plugins/value/utils/widen.mli b/src/plugins/value/utils/widen.mli index 283459456db5881ad44fa1aeef2dd4be2f6ed06c..b9dc1c6f77b55918273f0fac16cae1a21b5a410b 100644 --- a/src/plugins/value/utils/widen.mli +++ b/src/plugins/value/utils/widen.mli @@ -27,7 +27,7 @@ open Cil_types (** [getWidenHints kf s] retrieves the set of widening hints related to function [kf] and statement [s]. *) val getWidenHints: kernel_function -> stmt -> - Base.Set.t * (Base.t -> Locations.Location_Bytes.generic_widen_hint) + Base.Set.t * (Base.t -> Locations.Location_Bytes.numerical_widen_hint) (** Parses all widening hints defined via the widen_hint syntax extension. The result is memoized for subsequent calls. *) diff --git a/src/plugins/value_types/cvalue.ml b/src/plugins/value_types/cvalue.ml index fd1b472fbcca009b6b9a6e26401e81fed87f8346..56124a5079b644189247e11c29afd8807e7ae581 100644 --- a/src/plugins/value_types/cvalue.ml +++ b/src/plugins/value_types/cvalue.ml @@ -744,7 +744,7 @@ module V_Or_Uninitialized = struct (* let (==>) = (fun x y -> (not x) || y) *) type size_widen_hint = V.size_widen_hint - type generic_widen_hint = V.generic_widen_hint + type numerical_widen_hint = V.numerical_widen_hint type widen_hint = V.widen_hint let widen wh t1 t2 = create (get_flags t2) (V.widen wh (get_v t1) (get_v t2)) diff --git a/src/plugins/value_types/cvalue.mli b/src/plugins/value_types/cvalue.mli index 050be2bc75fa411d4c3a971f1c5366e597aac08c..83a60eeb36294f517b7505332afaddb14c46c4de 100644 --- a/src/plugins/value_types/cvalue.mli +++ b/src/plugins/value_types/cvalue.mli @@ -46,12 +46,12 @@ module V : sig of all of them. Use some shortcuts *) with type M.t = Location_Bytes.M.t and type t = Location_Bytes.t - and type generic_widen_hint = Location_Bytes.generic_widen_hint + and type numerical_widen_hint = Location_Bytes.numerical_widen_hint and type size_widen_hint = Location_Bytes.size_widen_hint include module type of Offsetmap_lattice_with_isotropy with type t := t - and type generic_widen_hint := generic_widen_hint + and type numerical_widen_hint := numerical_widen_hint and type size_widen_hint := size_widen_hint and type widen_hint := widen_hint @@ -175,7 +175,7 @@ module V_Or_Uninitialized : sig include module type of Offsetmap_lattice_with_isotropy with type t := t and type size_widen_hint = Location_Bytes.size_widen_hint - and type generic_widen_hint = Location_Bytes.generic_widen_hint + and type numerical_widen_hint = Location_Bytes.numerical_widen_hint and type widen_hint = Locations.Location_Bytes.widen_hint include Lattice_type.With_Under_Approximation with type t:= t include Lattice_type.With_Narrow with type t := t @@ -237,7 +237,7 @@ module V_Or_Uninitialized : sig module V_Offsetmap: sig include module type of Offsetmap_sig with type v = V_Or_Uninitialized.t - and type widen_hint = V_Or_Uninitialized.generic_widen_hint + and type widen_hint = V_Or_Uninitialized.numerical_widen_hint val narrow: t -> t -> t Bottom.Type.or_bottom val narrow_reinterpret: t -> t -> t Bottom.Type.or_bottom @@ -257,7 +257,7 @@ module Model: sig include module type of Lmap_sig with type v = V_Or_Uninitialized.t and type offsetmap = V_Offsetmap.t - and type widen_hint_base = V_Or_Uninitialized.generic_widen_hint + and type widen_hint_base = V_Or_Uninitialized.numerical_widen_hint include Lattice_type.With_Narrow with type t := t diff --git a/src/plugins/value_types/widen_type.ml b/src/plugins/value_types/widen_type.ml index ed9929b21d0917513bdb7f8b466769f415639d33..157b11f55c9f05d26593a6acb2d63bd061852448 100644 --- a/src/plugins/value_types/widen_type.ml +++ b/src/plugins/value_types/widen_type.ml @@ -23,25 +23,36 @@ open Cil_datatype module Num_hints_stmt = Stmt.Map.Make(Ival.Widen_Hints) +module Float_hints_stmt = Stmt.Map.Make(Fc_float.Widen_Hints) module Num_hints_bases = Base.Map.Make(Ival.Widen_Hints) +module Float_hints_bases = Base.Map.Make(Fc_float.Widen_Hints) module Num_hints_bases_stmt = Stmt.Map.Make(Num_hints_bases) +module Float_hints_bases_stmt = Stmt.Map.Make(Float_hints_bases) module Priority_bases_stmt = Stmt.Map.Make(Base.Set) type widen_hints = { priority_bases: Base.Set.t Stmt.Map.t; default_hints: Ival.Widen_Hints.t; + default_float_hints: Fc_float.Widen_Hints.t; default_hints_by_stmt: Ival.Widen_Hints.t Stmt.Map.t; + default_float_hints_by_stmt: Fc_float.Widen_Hints.t Stmt.Map.t; hints_by_addr: Ival.Widen_Hints.t Base.Map.t; + float_hints_by_addr: Fc_float.Widen_Hints.t Base.Map.t; hints_by_addr_by_stmt: Ival.Widen_Hints.t Base.Map.t Stmt.Map.t; + float_hints_by_addr_by_stmt: Fc_float.Widen_Hints.t Base.Map.t Stmt.Map.t; } (* an [empty] set of hints *) let empty = { priority_bases = Stmt.Map.empty; default_hints = Ival.Widen_Hints.empty; + default_float_hints = Fc_float.Widen_Hints.empty; default_hints_by_stmt = Stmt.Map.empty; + default_float_hints_by_stmt = Stmt.Map.empty; hints_by_addr = Base.Map.empty; + float_hints_by_addr = Base.Map.empty; hints_by_addr_by_stmt = Stmt.Map.empty; + float_hints_by_addr_by_stmt = Stmt.Map.empty; } include Datatype.Make(struct @@ -52,18 +63,27 @@ include Datatype.Make(struct Structural_descr.t_tuple [| Priority_bases_stmt.packed_descr; Ival.Widen_Hints.packed_descr; + Fc_float.Widen_Hints.packed_descr; Num_hints_stmt.packed_descr; + Float_hints_stmt.packed_descr; Num_hints_bases.packed_descr; - Num_hints_bases_stmt.packed_descr |] + Float_hints_bases.packed_descr; + Num_hints_bases_stmt.packed_descr; + Float_hints_bases_stmt.packed_descr |] let reprs = - List.map - (fun wh -> - { priority_bases = Stmt.Map.empty; - default_hints = wh; - default_hints_by_stmt = Stmt.Map.empty; - hints_by_addr = Base.Map.empty; - hints_by_addr_by_stmt = Stmt.Map.empty}) - Ival.Widen_Hints.reprs + Extlib.product + (fun wh fh -> + { priority_bases = Stmt.Map.empty; + default_hints = wh; + default_float_hints = fh; + default_hints_by_stmt = Stmt.Map.empty; + default_float_hints_by_stmt = Stmt.Map.empty; + hints_by_addr = Base.Map.empty; + float_hints_by_addr = Base.Map.empty; + float_hints_by_addr_by_stmt = Stmt.Map.empty; + hints_by_addr_by_stmt = Stmt.Map.empty + }) + Ival.Widen_Hints.reprs Fc_float.Widen_Hints.reprs let mem_project = Datatype.never_any_project end) @@ -79,17 +99,30 @@ let join wh1 wh2 = wh1.priority_bases wh2.priority_bases; default_hints = Ival.Widen_Hints.union wh1.default_hints wh2.default_hints; + default_float_hints = + Fc_float.Widen_Hints.union wh1.default_float_hints wh2.default_float_hints; default_hints_by_stmt = Stmt.Map.merge (fun _key -> map_merge Ival.Widen_Hints.union) wh1.default_hints_by_stmt wh2.default_hints_by_stmt; + default_float_hints_by_stmt = + Stmt.Map.merge (fun _key -> map_merge Fc_float.Widen_Hints.union) + wh1.default_float_hints_by_stmt wh2.default_float_hints_by_stmt; hints_by_addr = Base.Map.merge (fun _key -> map_merge Ival.Widen_Hints.union) wh1.hints_by_addr wh2.hints_by_addr; + float_hints_by_addr = + Base.Map.merge (fun _key -> map_merge Fc_float.Widen_Hints.union) + wh1.float_hints_by_addr wh2.float_hints_by_addr; hints_by_addr_by_stmt = Stmt.Map.merge (fun _key -> map_merge (Base.Map.merge (fun _key -> map_merge Ival.Widen_Hints.union))) wh1.hints_by_addr_by_stmt wh2.hints_by_addr_by_stmt; + float_hints_by_addr_by_stmt = + Stmt.Map.merge (fun _key -> + map_merge (Base.Map.merge + (fun _key -> map_merge Fc_float.Widen_Hints.union))) + wh1.float_hints_by_addr_by_stmt wh2.float_hints_by_addr_by_stmt; } let pretty fmt wh = @@ -110,19 +143,32 @@ let pretty fmt wh = Format.fprintf fmt "@[priority bases: %a@\n\ default_hints: %a@\n\ + default_float_hints: %a@\n\ default_hints_by_stmt: %a@\n\ + default_float_hints_by_stmt: %a@\n\ hints_by_addr: %a@\n\ - hints_by_addr_by_stmt: %a@]" + float_hints_by_addr: %a@\n\ + hints_by_addr_by_stmt: %a@\n\ + float_hints_by_addr_by_stmt: %a@]" (pp_bindings pp_stmt Base.Set.pretty) (Stmt.Map.bindings wh.priority_bases) Ival.Widen_Hints.pretty wh.default_hints + Fc_float.Widen_Hints.pretty wh.default_float_hints (Pretty_utils.pp_list ~sep:",@ " (Pretty_utils.pp_pair ~sep:" -> " pp_stmt Ival.Widen_Hints.pretty)) (Stmt.Map.bindings wh.default_hints_by_stmt) + (Pretty_utils.pp_list ~sep:",@ " + (Pretty_utils.pp_pair ~sep:" -> " pp_stmt Fc_float.Widen_Hints.pretty)) + (Stmt.Map.bindings wh.default_float_hints_by_stmt) (Pretty_utils.pp_list ~sep:",@ " (Pretty_utils.pp_pair ~sep:" -> " Base.pretty Ival.Widen_Hints.pretty)) (Base.Map.bindings wh.hints_by_addr) + (Pretty_utils.pp_list ~sep:",@ " + (Pretty_utils.pp_pair ~sep:" -> " Base.pretty Fc_float.Widen_Hints.pretty)) + (Base.Map.bindings wh.float_hints_by_addr) (pp_bindings pp_stmt (pp_base_map Ival.Widen_Hints.pretty)) (Stmt.Map.bindings wh.hints_by_addr_by_stmt) + (pp_bindings pp_stmt (pp_base_map Fc_float.Widen_Hints.pretty)) + (Stmt.Map.bindings wh.float_hints_by_addr_by_stmt) let hints_for_base default_hints hints_by_base b = let widen_hints_null = @@ -147,7 +193,7 @@ let hints_for_base default_hints hints_by_base b = ) let hints_from_keys stmt h = - let hints_by_base = + let int_hints_by_base = try let at_stmt = Stmt.Map.find stmt h.hints_by_addr_by_stmt in Base.Map.merge (fun _b os1 os2 -> @@ -158,17 +204,40 @@ let hints_from_keys stmt h = ) at_stmt h.hints_by_addr with Not_found -> h.hints_by_addr in + let float_hints_by_base = + try + let at_stmt = Stmt.Map.find stmt h.float_hints_by_addr_by_stmt in + Base.Map.merge (fun _b os1 os2 -> + match os1, os2 with + | Some s1, Some s2 -> Some (Fc_float.Widen_Hints.union s1 s2) + | Some s, None | None, Some s -> Some s + | None, None -> None + ) at_stmt h.float_hints_by_addr + with Not_found -> h.float_hints_by_addr + in let prio = try Stmt.Map.find stmt h.priority_bases with Not_found -> Base.Set.empty in - let default = + let int_default = try let at_stmt = Stmt.Map.find stmt h.default_hints_by_stmt in Ival.Widen_Hints.union h.default_hints at_stmt with Not_found -> h.default_hints in - prio, (fun b -> hints_for_base default hints_by_base b) + let float_default = + try + let at_stmt = Stmt.Map.find stmt h.default_float_hints_by_stmt in + Fc_float.Widen_Hints.union h.default_float_hints at_stmt + with Not_found -> h.default_float_hints + in + let float_hints_for_base b = + try Fc_float.Widen_Hints.union (Base.Map.find b float_hints_by_base) float_default + with Not_found -> float_default + in + prio, (fun b b' -> + hints_for_base int_default int_hints_by_base b b', + float_hints_for_base b) let var_hints stmt prio_bases = { empty with priority_bases = Stmt.Map.singleton stmt prio_bases } @@ -185,10 +254,23 @@ let num_hints stmto baseo hints = | None, None -> (* Hints for all bases and all statements *) { empty with default_hints = hints } +let float_hints stmto baseo hints = + match stmto, baseo with + | None, Some b -> (* Hints for a base at all statements *) + { empty with float_hints_by_addr = Base.Map.singleton b hints } + | Some stmt, Some b -> (* Hints for a base at a statement *) + { empty with float_hints_by_addr_by_stmt = Stmt.Map.singleton stmt + (Base.Map.singleton b hints) } + | Some stmt, None -> (* Hints for all bases and a given statement *) + { empty with default_float_hints_by_stmt = Stmt.Map.singleton stmt hints } + | None, None -> (* Hints for all bases and all statements *) + { empty with default_float_hints = hints } + (* default set of hints. Depends on the machdep *) let default () = - let default = Ival.Widen_Hints.default_widen_hints in - num_hints None None default + let int_default = Ival.Widen_Hints.default_widen_hints in + let float_default = Fc_float.Widen_Hints.default_widen_hints in + join (num_hints None None int_default) (float_hints None None float_default) (* Local Variables: diff --git a/src/plugins/value_types/widen_type.mli b/src/plugins/value_types/widen_type.mli index e017c3c17f7aab7600aeca22737eac6b22f8001c..00f9cf979a0e89617a2853ec5f8de1f76be70d9a 100644 --- a/src/plugins/value_types/widen_type.mli +++ b/src/plugins/value_types/widen_type.mli @@ -41,6 +41,11 @@ val pretty : Format.formatter -> t -> unit val num_hints: Cil_types.stmt option -> Base.t option -> Ival.Widen_Hints.t -> t +(** Define floating hints for one or all variables ([None]), + for a certain stmt or for all statements ([None]). *) +val float_hints: + Cil_types.stmt option -> Base.t option -> Fc_float.Widen_Hints.t -> t + (** Define a set of bases to widen in priority for a given statement. *) val var_hints : Cil_types.stmt -> Base.Set.t -> t @@ -48,7 +53,7 @@ val var_hints : Cil_types.stmt -> Base.Set.t -> t {!Cvalue.Model.widen}. *) val hints_from_keys : Cil_types.stmt -> t -> - Base.Set.t * (Base.t -> Locations.Location_Bytes.generic_widen_hint) + Base.Set.t * (Base.t -> Locations.Location_Bytes.numerical_widen_hint) (* Local Variables: diff --git a/tests/misc/oracle/widen_hints_float.res.oracle b/tests/misc/oracle/widen_hints_float.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..1b5726f1922996fa5305e1cbde175f5d7d882b14 --- /dev/null +++ b/tests/misc/oracle/widen_hints_float.res.oracle @@ -0,0 +1,61 @@ +[kernel] Parsing tests/misc/widen_hints_float.c (with preprocessing) +[eva] Analyzing a complete application starting at main +[eva] Computing initial state +[eva] Initial state computed +[eva:initial-state] Values of globals at initialization + +[eva] computing for function Frama_C_double_interval <- main. + Called from tests/misc/widen_hints_float.c:12. +[eva] using specification for function Frama_C_double_interval +[eva] tests/misc/widen_hints_float.c:12: + function Frama_C_double_interval: precondition 'finite' got status valid. +[eva] tests/misc/widen_hints_float.c:12: + function Frama_C_double_interval: precondition 'order' got status valid. +[eva] Done for function Frama_C_double_interval +[eva] tests/misc/widen_hints_float.c:15: starting to merge loop iterations +[eva] computing for function Frama_C_double_interval <- main. + Called from tests/misc/widen_hints_float.c:19. +[eva] tests/misc/widen_hints_float.c:19: + function Frama_C_double_interval: precondition 'finite' got status valid. +[eva] tests/misc/widen_hints_float.c:19: + function Frama_C_double_interval: precondition 'order' got status valid. +[eva] Done for function Frama_C_double_interval +[eva] tests/misc/widen_hints_float.c:22: starting to merge loop iterations +[eva] computing for function Frama_C_double_interval <- main. + Called from tests/misc/widen_hints_float.c:26. +[eva] tests/misc/widen_hints_float.c:26: + function Frama_C_double_interval: precondition 'finite' got status valid. +[eva] tests/misc/widen_hints_float.c:26: + function Frama_C_double_interval: precondition 'order' got status valid. +[eva] Done for function Frama_C_double_interval +[eva] tests/misc/widen_hints_float.c:28: starting to merge loop iterations +[eva:alarm] tests/misc/widen_hints_float.c:29: Warning: + non-finite double value. + assert + \is_finite((double)((double)(f3 - (double)64) * (double)(f3 - (double)64))); +[eva] Recording results for main +[eva] done for function main +[eva] ====== VALUES COMPUTED ====== +[eva:final-states] Values at end of function main: + Frama_C_entropy_source ∈ [--..--] + f1 ∈ [-0. .. 71.] + f2 ∈ [-80. .. 0.] + f3 ∈ [-1.79769313486e+308 .. 1.79769313486e+308] + __retres ∈ {0} +[from] Computing for function main +[from] Computing for function Frama_C_double_interval <-main +[from] Done for function Frama_C_double_interval +[from] Done for function main +[from] ====== DEPENDENCIES COMPUTED ====== + These dependencies hold at termination for the executions that terminate: +[from] Function Frama_C_double_interval: + Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF) + \result FROM Frama_C_entropy_source; min; max +[from] Function main: + Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF) + \result FROM \nothing +[from] ====== END OF DEPENDENCIES ====== +[inout] Out (internal) for function main: + Frama_C_entropy_source; f1; i; f2; i_0; f3; i_1; __retres +[inout] Inputs for function main: + Frama_C_entropy_source diff --git a/tests/misc/widen_hints_float.c b/tests/misc/widen_hints_float.c new file mode 100644 index 0000000000000000000000000000000000000000..a0e5a550a5c4e69bb5a6db4def23ba1ac80b4bf0 --- /dev/null +++ b/tests/misc/widen_hints_float.c @@ -0,0 +1,33 @@ +#include "__fc_builtin.h" + +int main() { + + /* + The expression is a parabola p + where p([0.;64.]) = [0.;64.] and p([64.;128.]) = [0.;64.]. + For any value x<0, p(x) < x; + For any value 128.<x, p(x) < -x; + */ + + double f1 = Frama_C_double_interval(0.,1./64.); + + //@ loop widen_hints f1, 71.; + for(int i = 0; i < 100; i++){ + f1 = (64*64 - (f1 - 64) * (f1 - 64))/64; + } + + double f2 = Frama_C_double_interval(-1./64.,-0); + + //@ loop widen_hints f2, -80.; + for(int i = 0; i < 100; i++){ + f2 = -(64*64 - (-f2 - 64) * (-f2 - 64))/64; + } + + double f3 = Frama_C_double_interval(0.,1./64.); + + for(int i = 0; i < 100; i++){ + f3 = (64*64 - (f3 - 64) * (f3 - 64))/64; + } + + return 0; +}