From 52c031d1ee1d1433be62d99fcfec33d76534b591 Mon Sep 17 00:00:00 2001
From: Julien Signoles <julien.signoles@cea.fr>
Date: Fri, 1 Mar 2019 14:45:31 +0100
Subject: [PATCH] [interval] improve non-recursive logic functions case

---
 src/plugins/e-acsl/interval.ml                |  90 +++++------
 src/plugins/e-acsl/tests/gmp/functions.c      |   4 +-
 .../tests/gmp/oracle/functions.0.res.oracle   |   2 -
 .../e-acsl/tests/gmp/oracle/gen_functions.c   | 144 ++++++++----------
 4 files changed, 107 insertions(+), 133 deletions(-)

diff --git a/src/plugins/e-acsl/interval.ml b/src/plugins/e-acsl/interval.ml
index f2cea60613c..03083cf1602 100644
--- a/src/plugins/e-acsl/interval.ml
+++ b/src/plugins/e-acsl/interval.ml
@@ -208,7 +208,7 @@ let rec infer t =
     let i2 = infer t2 in
     Ival.meet i1 i2
 
-  | Tapp (li, _, _args) ->
+  | Tapp (li, _, args) ->
     (match li.l_type with
     | None -> assert false (* [None] only possible for predicates *)
     | Some Linteger ->
@@ -216,53 +216,47 @@ let rec infer t =
       | LBpred _ ->
         Ival.zero_or_one
       | LBterm t' ->
-        let i =
-          if Misc.is_recursive li then
-            (*  1) Build a system of interval equations that
-                constrain the solution:
-                do so by returning a variable when encoutering
-                a call of a recursive function instead of
-                performing the usual interval inference
-                BEWARE: we might be tempted to memoize the
-                  solution for a given function signature
-                  HOWEVER: it cannot be done in a straightforward
-                    manner due to the cases of functions that use
-                    C (global) variables in their definition (as the values of
-                    those variables can change between two function calls). *)
-            let ieqs = Fixpoint.Ieqs.empty in
-            let ivar, ieqs, _ = build_ieqs t ieqs [] in
-            (*  2) Solve it:
-                The problem is probably undecidable in the general case.
-                Thus we just look for reasonably precise approximations
-                without being too computationally expensive:
-                simply iterate over a finite set of pre-defined intervals.
-                See [Fixpoint.solve] for details. *)
-            let chain_of_ivalmax =
-              [| Integer.one; Integer.billion_one; Integer.max_int64 |]
-              (* This set can be changed based on experimental evidences,
-                 but it works fine for now. *)
-            in
-            let i = Fixpoint.solve ieqs ivar chain_of_ivalmax in
-            i
-          else begin
-            List.iter2
-              (fun lv arg ->
-                try
-                  let i = interv_of_typ_containing_interv (infer arg) in
-                  Env.add lv i
-                with Not_an_integer ->
-                  ())
-              li.l_profile
-              _args;
-            let i =
-              try infer t'
-              with Not_an_integer -> Ival.inject_range None None
-            in
-            List.iter (fun lv -> Env.remove lv) li.l_profile;
-            i
-          end
-        in
-        i
+        (* TODO: should not be necessary to distinguish the recursive case.
+           Stack overflow if not distingued *)
+        if Misc.is_recursive li then
+          (* 1) Build a system of interval equations that constrain the
+                solution: do so by returning a variable when encoutering a call
+                of a recursive function instead of performing the usual interval
+                inference BEWARE: we might be tempted to memoize the solution
+                for a given function signature HOWEVER: it cannot be done in a
+                straightforward manner due to the cases of functions that use C
+                (global) variables in their definition (as the values of those
+                variables can change between two function calls). *)
+          let ieqs = Fixpoint.Ieqs.empty in
+          let ivar, ieqs, _ = build_ieqs t ieqs [] in
+          (*  2) Solve it:
+              The problem is probably undecidable in the general case.
+              Thus we just look for reasonably precise approximations
+              without being too computationally expensive:
+              simply iterate over a finite set of pre-defined intervals.
+              See [Fixpoint.solve] for details. *)
+          let chain_of_ivalmax =
+            [| Integer.one; Integer.billion_one; Integer.max_int64 |]
+            (* This set can be changed based on experimental evidences,
+               but it works fine for now. *)
+          in
+          Fixpoint.solve ieqs ivar chain_of_ivalmax
+        else begin (* non-recursive case *)
+          (* add the arguments to the context *)
+          List.iter2
+            (fun lv arg ->
+               try
+                 let i = infer arg in
+                 Env.add lv i
+               with Not_an_integer ->
+                 ())
+            li.l_profile
+            args;
+          let i = infer t' in
+          (* remove arguments from the context *)
+          List.iter (fun lv -> Env.remove lv) li.l_profile;
+          i
+        end
       | LBnone ->
         Error.not_yet "logic functions with no definition nor reads clause"
       | LBreads _ ->
diff --git a/src/plugins/e-acsl/tests/gmp/functions.c b/src/plugins/e-acsl/tests/gmp/functions.c
index 61bb3857359..28bc4017c14 100644
--- a/src/plugins/e-acsl/tests/gmp/functions.c
+++ b/src/plugins/e-acsl/tests/gmp/functions.c
@@ -20,7 +20,7 @@ typedef struct mystruct mystruct;
 /*@ logic mystruct t1(mystruct m) = m; */
 /*@ logic integer t2(mystruct m) = m.k + m.l; */
 
-// To test function call in other than assert:
+// To test function call in other clauses than assert:
 /*@ predicate k_pred(integer x) = x > 0; */
 /*@ requires k_pred(x); */
 void k(int x) {}
@@ -68,4 +68,4 @@ int main (void) {
   /*@ assert f2(d) > 0; */ ;
   /*@ assert p_notyet(27); */ ;
   /*@ assert f_notyet(27) == 27; */ ;
-}
\ No newline at end of file
+}
diff --git a/src/plugins/e-acsl/tests/gmp/oracle/functions.0.res.oracle b/src/plugins/e-acsl/tests/gmp/oracle/functions.0.res.oracle
index c60cf271f5f..e336cb46d69 100644
--- a/src/plugins/e-acsl/tests/gmp/oracle/functions.0.res.oracle
+++ b/src/plugins/e-acsl/tests/gmp/oracle/functions.0.res.oracle
@@ -32,8 +32,6 @@
 [eva] using specification for function __gmpz_clear
 [eva:alarm] tests/gmp/functions.c:44: Warning: 
   function __e_acsl_assert: precondition got status unknown.
-[eva:alarm] tests/gmp/functions.c:47: Warning: 
-  function __e_acsl_assert: precondition got status unknown.
 [eva:alarm] tests/gmp/functions.c:48: Warning: 
   accessing uninitialized left-value.
   assert \initialized((__e_acsl_mpz_struct *)__gen_e_acsl_f1_tapp_3);
diff --git a/src/plugins/e-acsl/tests/gmp/oracle/gen_functions.c b/src/plugins/e-acsl/tests/gmp/oracle/gen_functions.c
index 9e926f5e7cf..fd3c27e93ad 100644
--- a/src/plugins/e-acsl/tests/gmp/oracle/gen_functions.c
+++ b/src/plugins/e-acsl/tests/gmp/oracle/gen_functions.c
@@ -17,19 +17,19 @@ int __gen_e_acsl_p1(int __gen_e_acsl_x_arg, int __gen_e_acsl_y_arg);
 */
 int __gen_e_acsl_p2(int __gen_e_acsl_x_arg, int __gen_e_acsl_y_arg);
 
-int __gen_e_acsl_p2_3(int __gen_e_acsl_x_arg, long __gen_e_acsl_y_arg);
-
 int __gen_e_acsl_p2_2(int __gen_e_acsl_x_arg,
                       __e_acsl_mpz_struct * __gen_e_acsl_y_arg);
 
 /*@ logic ℤ f1(ℤ x, ℤ y) = x + y;
 
 */
-void __gen_e_acsl_f1_3(__e_acsl_mpz_struct * __retres_arg,
+void __gen_e_acsl_f1_4(__e_acsl_mpz_struct * __retres_arg,
                        __e_acsl_mpz_struct * __gen_e_acsl_x_arg,
                        __e_acsl_mpz_struct * __gen_e_acsl_y_arg);
 
-void __gen_e_acsl_f1_2(__e_acsl_mpz_struct * __retres_arg,
+int __gen_e_acsl_f1_2(int __gen_e_acsl_x_arg, int __gen_e_acsl_y_arg);
+
+void __gen_e_acsl_f1_3(__e_acsl_mpz_struct * __retres_arg,
                        int __gen_e_acsl_x_arg,
                        __e_acsl_mpz_struct * __gen_e_acsl_y_arg);
 
@@ -126,59 +126,59 @@ int main(void)
   }
   /*@ assert p2(x, f1(3, 4)); */
   {
-    long __gen_e_acsl_f1_tapp_2;
+    int __gen_e_acsl_f1_tapp_2;
     int __gen_e_acsl_p2_tapp_3;
-    __gen_e_acsl_f1_tapp_2 = __gen_e_acsl_f1(3,4);
-    __gen_e_acsl_p2_tapp_3 = __gen_e_acsl_p2_3(x,__gen_e_acsl_f1_tapp_2);
+    __gen_e_acsl_f1_tapp_2 = __gen_e_acsl_f1_2(3,4);
+    __gen_e_acsl_p2_tapp_3 = __gen_e_acsl_p2(x,__gen_e_acsl_f1_tapp_2);
     __e_acsl_assert(__gen_e_acsl_p2_tapp_3,(char *)"Assertion",
                     (char *)"main",(char *)"p2(x, f1(3, 4))",47);
   }
   /*@ assert f1(9, 99999999999999999999999999999) > 0; */
   {
-    __e_acsl_mpz_t __gen_e_acsl__4;
+    __e_acsl_mpz_t __gen_e_acsl__3;
     __e_acsl_mpz_t __gen_e_acsl_f1_tapp_3;
-    __e_acsl_mpz_t __gen_e_acsl__5;
-    int __gen_e_acsl_gt_3;
-    __gmpz_init_set_str(__gen_e_acsl__4,"99999999999999999999999999999",10);
+    __e_acsl_mpz_t __gen_e_acsl__4;
+    int __gen_e_acsl_gt_2;
+    __gmpz_init_set_str(__gen_e_acsl__3,"99999999999999999999999999999",10);
     __gmpz_init(__gen_e_acsl_f1_tapp_3);
     /*@ assert
         Eva: initialization:
           \initialized((__e_acsl_mpz_struct *)__gen_e_acsl_f1_tapp_3);
     */
-    __gen_e_acsl_f1_2((__e_acsl_mpz_struct *)__gen_e_acsl_f1_tapp_3,9,
-                      (__e_acsl_mpz_struct *)__gen_e_acsl__4);
-    __gmpz_init_set_si(__gen_e_acsl__5,0L);
-    __gen_e_acsl_gt_3 = __gmpz_cmp((__e_acsl_mpz_struct const *)(__gen_e_acsl_f1_tapp_3),
-                                   (__e_acsl_mpz_struct const *)(__gen_e_acsl__5));
-    __e_acsl_assert(__gen_e_acsl_gt_3 > 0,(char *)"Assertion",(char *)"main",
+    __gen_e_acsl_f1_3((__e_acsl_mpz_struct *)__gen_e_acsl_f1_tapp_3,9,
+                      (__e_acsl_mpz_struct *)__gen_e_acsl__3);
+    __gmpz_init_set_si(__gen_e_acsl__4,0L);
+    __gen_e_acsl_gt_2 = __gmpz_cmp((__e_acsl_mpz_struct const *)(__gen_e_acsl_f1_tapp_3),
+                                   (__e_acsl_mpz_struct const *)(__gen_e_acsl__4));
+    __e_acsl_assert(__gen_e_acsl_gt_2 > 0,(char *)"Assertion",(char *)"main",
                     (char *)"f1(9, 99999999999999999999999999999) > 0",48);
-    __gmpz_clear(__gen_e_acsl__4);
+    __gmpz_clear(__gen_e_acsl__3);
     __gmpz_clear(__gen_e_acsl_f1_tapp_3);
-    __gmpz_clear(__gen_e_acsl__5);
+    __gmpz_clear(__gen_e_acsl__4);
   }
   /*@ assert
       f1(99999999999999999999999999999, 99999999999999999999999999999) ≡
       199999999999999999999999999998;
   */
   {
-    __e_acsl_mpz_t __gen_e_acsl__6;
+    __e_acsl_mpz_t __gen_e_acsl__5;
     __e_acsl_mpz_t __gen_e_acsl_f1_tapp_4;
-    __e_acsl_mpz_t __gen_e_acsl__7;
+    __e_acsl_mpz_t __gen_e_acsl__6;
     int __gen_e_acsl_eq;
-    __gmpz_init_set_str(__gen_e_acsl__6,"99999999999999999999999999999",10);
+    __gmpz_init_set_str(__gen_e_acsl__5,"99999999999999999999999999999",10);
     __gmpz_init(__gen_e_acsl_f1_tapp_4);
-    __gen_e_acsl_f1_3((__e_acsl_mpz_struct *)__gen_e_acsl_f1_tapp_4,
-                      (__e_acsl_mpz_struct *)__gen_e_acsl__6,
-                      (__e_acsl_mpz_struct *)__gen_e_acsl__6);
-    __gmpz_init_set_str(__gen_e_acsl__7,"199999999999999999999999999998",10);
+    __gen_e_acsl_f1_4((__e_acsl_mpz_struct *)__gen_e_acsl_f1_tapp_4,
+                      (__e_acsl_mpz_struct *)__gen_e_acsl__5,
+                      (__e_acsl_mpz_struct *)__gen_e_acsl__5);
+    __gmpz_init_set_str(__gen_e_acsl__6,"199999999999999999999999999998",10);
     __gen_e_acsl_eq = __gmpz_cmp((__e_acsl_mpz_struct const *)(__gen_e_acsl_f1_tapp_4),
-                                 (__e_acsl_mpz_struct const *)(__gen_e_acsl__7));
+                                 (__e_acsl_mpz_struct const *)(__gen_e_acsl__6));
     __e_acsl_assert(__gen_e_acsl_eq == 0,(char *)"Assertion",(char *)"main",
                     (char *)"f1(99999999999999999999999999999, 99999999999999999999999999999) ==\n199999999999999999999999999998",
                     49);
-    __gmpz_clear(__gen_e_acsl__6);
+    __gmpz_clear(__gen_e_acsl__5);
     __gmpz_clear(__gen_e_acsl_f1_tapp_4);
-    __gmpz_clear(__gen_e_acsl__7);
+    __gmpz_clear(__gen_e_acsl__6);
   }
   /*@ assert g(x) ≡ x; */
   {
@@ -309,51 +309,58 @@ long __gen_e_acsl_f1(int __gen_e_acsl_x_arg, int __gen_e_acsl_y_arg)
   return __retres;
 }
 
-void __gen_e_acsl_f1_2(__e_acsl_mpz_struct * __retres_arg,
+void __gen_e_acsl_f1_3(__e_acsl_mpz_struct * __retres_arg,
                        int __gen_e_acsl_x_arg,
                        __e_acsl_mpz_struct * __gen_e_acsl_y_arg)
 {
-  __e_acsl_mpz_t __gen_e_acsl_y_3;
+  __e_acsl_mpz_t __gen_e_acsl_y_2;
+  __e_acsl_mpz_t __gen_e_acsl_x_2;
+  __e_acsl_mpz_t __gen_e_acsl_add_2;
+  __gmpz_init_set(__gen_e_acsl_y_2,
+                  (__e_acsl_mpz_struct const *)(__gen_e_acsl_y_arg));
+  __gmpz_init_set_si(__gen_e_acsl_x_2,(long)__gen_e_acsl_x_arg);
+  __gmpz_init(__gen_e_acsl_add_2);
+  __gmpz_add(__gen_e_acsl_add_2,
+             (__e_acsl_mpz_struct const *)(__gen_e_acsl_x_2),
+             (__e_acsl_mpz_struct const *)(__gen_e_acsl_y_2));
+  __gmpz_init_set(__retres_arg,
+                  (__e_acsl_mpz_struct const *)(__gen_e_acsl_add_2));
+  __gmpz_clear(__gen_e_acsl_y_2);
+  __gmpz_clear(__gen_e_acsl_x_2);
+  __gmpz_clear(__gen_e_acsl_add_2);
+  return;
+}
+
+int __gen_e_acsl_f1_2(int __gen_e_acsl_x_arg, int __gen_e_acsl_y_arg)
+{
+  long __retres;
+  __retres = (int)(__gen_e_acsl_x_arg + (long)__gen_e_acsl_y_arg);
+  return __retres;
+}
+
+void __gen_e_acsl_f1_4(__e_acsl_mpz_struct * __retres_arg,
+                       __e_acsl_mpz_struct * __gen_e_acsl_x_arg,
+                       __e_acsl_mpz_struct * __gen_e_acsl_y_arg)
+{
   __e_acsl_mpz_t __gen_e_acsl_x_3;
+  __e_acsl_mpz_t __gen_e_acsl_y_3;
   __e_acsl_mpz_t __gen_e_acsl_add_3;
+  __gmpz_init_set(__gen_e_acsl_x_3,
+                  (__e_acsl_mpz_struct const *)(__gen_e_acsl_x_arg));
   __gmpz_init_set(__gen_e_acsl_y_3,
                   (__e_acsl_mpz_struct const *)(__gen_e_acsl_y_arg));
-  __gmpz_init_set_si(__gen_e_acsl_x_3,(long)__gen_e_acsl_x_arg);
   __gmpz_init(__gen_e_acsl_add_3);
   __gmpz_add(__gen_e_acsl_add_3,
              (__e_acsl_mpz_struct const *)(__gen_e_acsl_x_3),
              (__e_acsl_mpz_struct const *)(__gen_e_acsl_y_3));
   __gmpz_init_set(__retres_arg,
                   (__e_acsl_mpz_struct const *)(__gen_e_acsl_add_3));
-  __gmpz_clear(__gen_e_acsl_y_3);
   __gmpz_clear(__gen_e_acsl_x_3);
+  __gmpz_clear(__gen_e_acsl_y_3);
   __gmpz_clear(__gen_e_acsl_add_3);
   return;
 }
 
-void __gen_e_acsl_f1_3(__e_acsl_mpz_struct * __retres_arg,
-                       __e_acsl_mpz_struct * __gen_e_acsl_x_arg,
-                       __e_acsl_mpz_struct * __gen_e_acsl_y_arg)
-{
-  __e_acsl_mpz_t __gen_e_acsl_x_4;
-  __e_acsl_mpz_t __gen_e_acsl_y_4;
-  __e_acsl_mpz_t __gen_e_acsl_add_4;
-  __gmpz_init_set(__gen_e_acsl_x_4,
-                  (__e_acsl_mpz_struct const *)(__gen_e_acsl_x_arg));
-  __gmpz_init_set(__gen_e_acsl_y_4,
-                  (__e_acsl_mpz_struct const *)(__gen_e_acsl_y_arg));
-  __gmpz_init(__gen_e_acsl_add_4);
-  __gmpz_add(__gen_e_acsl_add_4,
-             (__e_acsl_mpz_struct const *)(__gen_e_acsl_x_4),
-             (__e_acsl_mpz_struct const *)(__gen_e_acsl_y_4));
-  __gmpz_init_set(__retres_arg,
-                  (__e_acsl_mpz_struct const *)(__gen_e_acsl_add_4));
-  __gmpz_clear(__gen_e_acsl_x_4);
-  __gmpz_clear(__gen_e_acsl_y_4);
-  __gmpz_clear(__gen_e_acsl_add_4);
-  return;
-}
-
 int __gen_e_acsl_p2_2(int __gen_e_acsl_x_arg,
                       __e_acsl_mpz_struct * __gen_e_acsl_y_arg)
 {
@@ -380,31 +387,6 @@ int __gen_e_acsl_p2_2(int __gen_e_acsl_x_arg,
   return __retres;
 }
 
-int __gen_e_acsl_p2_3(int __gen_e_acsl_x_arg, long __gen_e_acsl_y_arg)
-{
-  int __retres;
-  __e_acsl_mpz_t __gen_e_acsl_x_2;
-  __e_acsl_mpz_t __gen_e_acsl_y_2;
-  __e_acsl_mpz_t __gen_e_acsl_add_2;
-  __e_acsl_mpz_t __gen_e_acsl__3;
-  int __gen_e_acsl_gt_2;
-  __gmpz_init_set_si(__gen_e_acsl_x_2,(long)__gen_e_acsl_x_arg);
-  __gmpz_init_set_si(__gen_e_acsl_y_2,__gen_e_acsl_y_arg);
-  __gmpz_init(__gen_e_acsl_add_2);
-  __gmpz_add(__gen_e_acsl_add_2,
-             (__e_acsl_mpz_struct const *)(__gen_e_acsl_x_2),
-             (__e_acsl_mpz_struct const *)(__gen_e_acsl_y_2));
-  __gmpz_init_set_si(__gen_e_acsl__3,0L);
-  __gen_e_acsl_gt_2 = __gmpz_cmp((__e_acsl_mpz_struct const *)(__gen_e_acsl_add_2),
-                                 (__e_acsl_mpz_struct const *)(__gen_e_acsl__3));
-  __retres = __gen_e_acsl_gt_2 > 0;
-  __gmpz_clear(__gen_e_acsl_x_2);
-  __gmpz_clear(__gen_e_acsl_y_2);
-  __gmpz_clear(__gen_e_acsl_add_2);
-  __gmpz_clear(__gen_e_acsl__3);
-  return __retres;
-}
-
 int __gen_e_acsl_p2(int __gen_e_acsl_x_arg, int __gen_e_acsl_y_arg)
 {
   int __retres;
-- 
GitLab