From 275b020154775ef9a1e796ee64f154f862e25304 Mon Sep 17 00:00:00 2001
From: Julien Signoles <julien.signoles@cea.fr>
Date: Fri, 1 Mar 2019 17:20:14 +0100
Subject: [PATCH] [Interval] rename build_ieqs to Interval_system.build

---
 src/plugins/e-acsl/interval.ml         | 153 ++++---------------------
 src/plugins/e-acsl/interval_system.ml  | 128 ++++++++++++++++++++-
 src/plugins/e-acsl/interval_system.mli |  12 +-
 3 files changed, 150 insertions(+), 143 deletions(-)

diff --git a/src/plugins/e-acsl/interval.ml b/src/plugins/e-acsl/interval.ml
index 7dcf07af3b4..dfc1b52ca6d 100644
--- a/src/plugins/e-acsl/interval.ml
+++ b/src/plugins/e-acsl/interval.ml
@@ -25,58 +25,25 @@ open Cil_types
 (* Implement Figure 3 of J. Signoles' JFLA'15 paper "Rester statique pour
    devenir plus rapide, plus précis et plus mince". *)
 
-exception Not_an_integer
-
 (* ********************************************************************* *)
 (* Basic datatypes and operations *)
 (* ********************************************************************* *)
 
+exception Not_an_integer = Interval_system.Not_an_integer
+let interv_of_typ = Interval_system.interv_of_typ
+let ikind_of_interv = Interval_system.ikind_of_interv
+
 (* constructors *)
 
 let singleton_of_int n = Ival.inject_singleton (Integer.of_int n)
 
-let rec interv_of_typ ty = match Cil.unrollType ty with
-  | TInt (k,_) as ty ->
-    let n = Cil.bitsSizeOf ty in
-    let l, u =
-      if Cil.isSigned k then Cil.min_signed_number n, Cil.max_signed_number n
-      else Integer.zero, Cil.max_unsigned_number n
-    in
-    Ival.inject_range (Some l) (Some u)
-  | TEnum(enuminfo, _) -> interv_of_typ (TInt (enuminfo.ekind, []))
-  | _ ->
-    raise Not_an_integer
-
-let ikind_of_interv i =
-  if Ival.is_bottom i then IInt
-  else match Ival.min_and_max i with
-    | Some l, Some u ->
-      let is_pos = Integer.ge l Integer.zero in
-      let lkind = Cil.intKindForValue l is_pos in
-      let ukind = Cil.intKindForValue u is_pos in
-      (* kind corresponding to the interval *)
-      let kind = if Cil.intTypeIncluded lkind ukind then ukind else lkind in
-      (* convert the kind to [IInt] whenever smaller. *)
-      if Cil.intTypeIncluded kind IInt then IInt else kind
-    | None, None -> raise Cil.Not_representable (* GMP *)
-    | None, Some _ | Some _, None ->
-      Kernel.fatal ~current:true "ival: %a" Ival.pretty i
-
-(* TODO: why is it useful? Crash if not here, but why? *)
-(* Return the interval over which ranges the smallest typ containing [i]. *)
-let interv_of_typ_containing_interv i =
-  try
-    let kind = ikind_of_interv i in
-    interv_of_typ (TInt(kind, []))
-  with Cil.Not_representable ->
-    (* infinity *)
-    Ival.inject_range None None
-
 let interv_of_unknown_block =
   (* since we have no idea of the size of this block, we take the largest
      possible one which is unfortunately quite large *)
   lazy
-    (Ival.inject_range (Some Integer.zero) (Some (Bit_utils.max_byte_address ())))
+    (Ival.inject_range
+       (Some Integer.zero)
+       (Some (Bit_utils.max_byte_address ())))
 
 (* imperative environments *)
 module Env: sig
@@ -238,8 +205,7 @@ let rec infer t =
 
              TODO: I do not understand the remark above. The interval of a C
              global variable is computed from its type. *)
-          let ieqs = Interval_system.empty in
-          let iexp, ieqs, _ = build_ieqs t ieqs [] in
+          let iexp, ieqs = Interval_system.build ~infer t in
           (*  2) Solve it:
               The problem is probably undecidable in the general case.
               Thus we just look for reasonably precise approximations
@@ -325,18 +291,18 @@ and infer_term_lval (host, offset as tlv) =
 and infer_term_host h = match h with
   | TVar v ->
     (try Env.find v
-    with Not_found ->
-      match v.lv_type with
-      | Linteger ->
-        Ival.inject_range None None
-      | Ctype (TFloat _) -> (* TODO: handle in MR !226 *)
-        raise Not_an_integer
-      | Lreal ->
-        Error.not_yet "real numbers"
-      | Ctype _ ->
-        interv_of_typ (Logic_utils.logicCType v.lv_type)
-      | Ltype _ | Lvar _ | Larrow _ ->
-        Options.fatal "unexpected logic type")
+     with Not_found ->
+     match v.lv_type with
+     | Linteger ->
+       Ival.inject_range None None
+     | Ctype (TFloat _) -> (* TODO: handle in MR !226 *)
+       raise Not_an_integer
+     | Lreal ->
+       Error.not_yet "real numbers"
+     | Ctype _ ->
+       interv_of_typ (Logic_utils.logicCType v.lv_type)
+     | Ltype _ | Lvar _ | Larrow _ ->
+       Options.fatal "unexpected logic type")
   | TResult ty -> interv_of_typ ty
   | TMem t ->
     let ty = Logic_utils.logicCType t.term_type in
@@ -347,85 +313,6 @@ and infer_term_host h = match h with
         Printer.pp_typ ty
         Printer.pp_term t
 
-(* Build the system of interval equations for the logic function called
-  through [t].
-  Example: the following function:
-  f(Z n) = n < 0 ? 1 : f(n - 1) * f(n - 2) / f(n - 3)
-  when called with f(37)
-  will generate the following system of equations:
-  X = [1; 1] U Y*Y/Y /\
-  Y = [1; 1] U Z*Z/Z /\
-  Z = [1; 1] U Z*Z/Z
-  where X is the interval for f(int) (since 37 \in int),
-  Y the one for f(long) (from int-1, int-2 and int-3)
-  and Z the for the f(Z) (from long-1, long-2 and long-3) *)
-and build_ieqs t ieqs ivars =
-  match t.term_node with
-  | Tapp(li, _, args) ->
-    if li.l_type = Some Linteger && Misc.is_recursive li then begin
-      let args_lty = List.map2
-        (fun lv arg ->
-          try
-            (* speed-up convergence *)
-            let i = interv_of_typ_containing_interv (infer arg) in
-            Env.add lv i;
-            Ctype (TInt(ikind_of_interv i, []))
-          with
-          | Cil.Not_representable -> Linteger
-          | Not_an_integer -> lv.lv_type)
-        li.l_profile
-        args
-      in
-      (* x *)
-      let ivar =
-        { Interval_system.iv_name = li.l_var_info.lv_name; iv_types = args_lty }
-      in
-      (* Adding x = g(x) if it is not yet in the system of equations.
-        Without this check, the algorithm would not terminate. *)
-      let ieqs, ivars =
-        if Interval_system.ivars_contains_ivar ivars ivar then ieqs, ivars
-        else
-          let (iexp:Interval_system.ival_exp), ieqs, ivars =
-            build_ieqs (Misc.term_of_li li) ieqs (ivar :: ivars)
-          in
-          (* Adding x = g(x) *)
-          let ieqs = Interval_system.add_equation ivar iexp ieqs in
-          ieqs, ivars
-      in
-      List.iter (fun lv -> Env.remove lv) li.l_profile;
-      Interval_system.Ivar ivar, ieqs, ivars
-    end else
-      (try Interval_system.Iconst(infer t), ieqs, ivars
-      with Not_an_integer -> Interval_system.Iunsupported, ieqs, ivars)
-  | TConst _ ->
-    (try Interval_system.Iconst(infer t), ieqs, ivars
-    with Not_an_integer -> Interval_system.Iunsupported, ieqs, ivars)
-  | TLval(TVar _, _) ->
-    (try Interval_system.Iconst(infer t), ieqs, ivars
-    with Not_an_integer -> Interval_system.Iunsupported, ieqs, ivars)
-  | TBinOp (PlusA, t1, t2) ->
-    let iexp1, ieqs, ivars = build_ieqs t1 ieqs ivars in
-    let iexp2, ieqs, ivars = build_ieqs t2 ieqs ivars in
-    Interval_system.Ibinop(Interval_system.Ival_add, iexp1, iexp2), ieqs, ivars
-  | TBinOp (MinusA, t1, t2) ->
-    let iexp1, ieqs, ivars = build_ieqs t1 ieqs ivars in
-    let iexp2, ieqs, ivars = build_ieqs t2 ieqs ivars in
-    Interval_system.Ibinop(Interval_system.Ival_min, iexp1, iexp2), ieqs, ivars
-  | TBinOp (Mult, t1, t2) ->
-    let iexp1, ieqs, ivars = build_ieqs t1 ieqs ivars in
-    let iexp2, ieqs, ivars = build_ieqs t2 ieqs ivars in
-    Interval_system.Ibinop(Interval_system.Ival_mul, iexp1, iexp2), ieqs, ivars
-  | TBinOp (Div, t1, t2) ->
-    let iexp1, ieqs, ivars = build_ieqs t1 ieqs ivars in
-    let iexp2, ieqs, ivars = build_ieqs t2 ieqs ivars in
-    Interval_system.Ibinop(Interval_system.Ival_div, iexp1, iexp2), ieqs, ivars
-  | Tif(_, t1, t2) ->
-    let iexp1, ieqs, ivars = build_ieqs t1 ieqs ivars in
-    let iexp2, ieqs, ivars = build_ieqs t2 ieqs ivars in
-    Interval_system.Ibinop(Interval_system.Ival_union, iexp1, iexp2), ieqs, ivars
-  | _ ->
-    Interval_system.Iunsupported, ieqs, ivars
-
 (*
 Local Variables:
 compile-command: "make"
diff --git a/src/plugins/e-acsl/interval_system.ml b/src/plugins/e-acsl/interval_system.ml
index 32292572679..fe18fccc670 100644
--- a/src/plugins/e-acsl/interval_system.ml
+++ b/src/plugins/e-acsl/interval_system.ml
@@ -65,8 +65,129 @@ type t = ival_exp Ivar.Map.t
 (***************************** Solver *************************************)
 (**************************************************************************)
 
-let empty = Ivar.Map.empty
-let add_equation = Ivar.Map.add
+exception Not_an_integer
+
+let rec interv_of_typ ty = match Cil.unrollType ty with
+  | TInt (k,_) as ty ->
+    let n = Cil.bitsSizeOf ty in
+    let l, u =
+      if Cil.isSigned k then Cil.min_signed_number n, Cil.max_signed_number n
+      else Integer.zero, Cil.max_unsigned_number n
+    in
+    Ival.inject_range (Some l) (Some u)
+  | TEnum(enuminfo, _) -> interv_of_typ (TInt (enuminfo.ekind, []))
+  | _ ->
+    raise Not_an_integer
+
+let ikind_of_interv i =
+  if Ival.is_bottom i then IInt
+  else match Ival.min_and_max i with
+    | Some l, Some u ->
+      let is_pos = Integer.ge l Integer.zero in
+      let lkind = Cil.intKindForValue l is_pos in
+      let ukind = Cil.intKindForValue u is_pos in
+      (* kind corresponding to the interval *)
+      let kind = if Cil.intTypeIncluded lkind ukind then ukind else lkind in
+      (* convert the kind to [IInt] whenever smaller. *)
+      if Cil.intTypeIncluded kind IInt then IInt else kind
+    | None, None -> raise Cil.Not_representable (* GMP *)
+    | None, Some _ | Some _, None ->
+      Kernel.fatal ~current:true "ival: %a" Ival.pretty i
+
+let interv_of_typ_containing_interv i =
+  try
+    let kind = ikind_of_interv i in
+    interv_of_typ (TInt(kind, []))
+  with Cil.Not_representable ->
+    (* infinity *)
+    Ival.inject_range None None
+
+let ivars_contains_ivar ivars ivar =
+  List.fold_left (fun b ivar' -> b || Ivar.equal ivar ivar') false ivars
+
+(* Build the system of interval equations for the logic function called
+  through [t].
+  Example: the following function:
+  f(Z n) = n < 0 ? 1 : f(n - 1) * f(n - 2) / f(n - 3)
+  when called with f(37)
+  will generate the following system of equations:
+  X = [1; 1] U Y*Y/Y /\
+  Y = [1; 1] U Z*Z/Z /\
+  Z = [1; 1] U Z*Z/Z
+  where X is the interval for f(int) (since 37 \in int),
+  Y the one for f(long) (from int-1, int-2 and int-3)
+  and Z the for the f(Z) (from long-1, long-2 and long-3) *)
+let build ~infer t =
+  let rec aux ieqs ivars t = match t.term_node with
+  | Tapp(li, _, args) ->
+    if li.l_type = Some Linteger && Misc.is_recursive li then begin
+      let args_lty = List.map2
+        (fun lv arg ->
+          try
+            (* speed-up convergence *)
+            let i = interv_of_typ_containing_interv (infer arg) in
+  (* TODO: *)
+(*            Env.add lv i;*)
+            Ctype (TInt(ikind_of_interv i, []))
+          with
+          | Cil.Not_representable -> Linteger
+          | Not_an_integer -> lv.lv_type)
+        li.l_profile
+        args
+      in
+      (* x *)
+      let ivar =
+        { iv_name = li.l_var_info.lv_name; iv_types = args_lty }
+      in
+      (* Adding x = g(x) if it is not yet in the system of equations.
+        Without this check, the algorithm would not terminate. *)
+      let ieqs, ivars =
+        if ivars_contains_ivar ivars ivar then ieqs, ivars
+        else
+          let (iexp:ival_exp), ieqs, ivars =
+            aux ieqs (ivar :: ivars) (Misc.term_of_li li)
+          in
+          (* Adding x = g(x) *)
+          let ieqs = Ivar.Map.add ivar iexp ieqs in
+          ieqs, ivars
+      in
+(*      List.iter (fun lv -> Env.remove lv) li.l_profile;*)
+      Ivar ivar, ieqs, ivars
+    end else
+      (try Iconst(infer t), ieqs, ivars
+      with Not_an_integer -> Iunsupported, ieqs, ivars)
+  | TConst _ ->
+    (try Iconst(infer t), ieqs, ivars
+    with Not_an_integer -> Iunsupported, ieqs, ivars)
+  | TLval(TVar _, _) ->
+    (try Iconst(infer t), ieqs, ivars
+    with Not_an_integer -> Iunsupported, ieqs, ivars)
+  | TBinOp (PlusA, t1, t2) ->
+    let iexp1, ieqs, ivars = aux ieqs ivars t1 in
+    let iexp2, ieqs, ivars = aux ieqs ivars t2 in
+    Ibinop(Ival_add, iexp1, iexp2), ieqs, ivars
+  | TBinOp (MinusA, t1, t2) ->
+    let iexp1, ieqs, ivars = aux ieqs ivars t1 in
+    let iexp2, ieqs, ivars = aux ieqs ivars t2 in
+    Ibinop(Ival_min, iexp1, iexp2), ieqs, ivars
+  | TBinOp (Mult, t1, t2) ->
+    let iexp1, ieqs, ivars = aux ieqs ivars t1 in
+    let iexp2, ieqs, ivars = aux ieqs ivars t2 in
+    Ibinop(Ival_mul, iexp1, iexp2), ieqs, ivars
+  | TBinOp (Div, t1, t2) ->
+    let iexp1, ieqs, ivars = aux ieqs ivars t1 in
+    let iexp2, ieqs, ivars = aux ieqs ivars t2 in
+    Ibinop(Ival_div, iexp1, iexp2), ieqs, ivars
+  | Tif(_, t1, t2) ->
+    let iexp1, ieqs, ivars = aux ieqs ivars t1 in
+    let iexp2, ieqs, ivars = aux ieqs ivars t2 in
+    Ibinop(Ival_union, iexp1, iexp2), ieqs, ivars
+  | _ ->
+    Iunsupported, ieqs, ivars
+  in
+  let iexp, ieqs, _ = aux Ivar.Map.empty [] t in
+  iexp, ieqs
+
 
 (* Normalize the expression.
   An expression is said to be normalized if it is:
@@ -87,9 +208,6 @@ let normalize_iexp iexp =
 let normalize_ieqs ieqs =
   Ivar.Map.map (fun iexp -> normalize_iexp iexp) ieqs
 
-let ivars_contains_ivar ivars ivar =
-  List.fold_left (fun b ivar' -> b || Ivar.equal ivar ivar') false ivars
-
 let get_ival_of_iconst ieqs ivar = match Ivar.Map.find ieqs ivar with
   | Iconst i -> i
   | Ivar _ | Ibinop _| Iunsupported -> Options.fatal "not an Iconst"
diff --git a/src/plugins/e-acsl/interval_system.mli b/src/plugins/e-acsl/interval_system.mli
index 44a179eaf74..8487d396fc7 100644
--- a/src/plugins/e-acsl/interval_system.mli
+++ b/src/plugins/e-acsl/interval_system.mli
@@ -55,8 +55,7 @@ type t
 (*************************** Constructors *********************************)
 (**************************************************************************)
 
-val empty: t
-val add_equation: ivar -> ival_exp -> t -> t
+val build: infer:(term -> Ival.t) -> term -> ival_exp * t
 
 (**************************************************************************)
 (***************************** Solver *************************************)
@@ -78,6 +77,9 @@ val solve: t -> ivar -> Integer.t array -> Ival.t
 (****************************** Utils *************************************)
 (**************************************************************************)
 
-val ivars_contains_ivar: ivar list -> ivar -> bool
-(** [contains ivars ivar] checks whether the list of Ivar [ivars] contains the
-  Ivar [ivar]. *)
+(* the following functions should be defined in [Interval] but are here to break
+   mutual module dependencies *)
+
+exception Not_an_integer
+val interv_of_typ: typ -> Ival.t
+val ikind_of_interv: Ival.t -> Cil_types.ikind
-- 
GitLab