From ccd32410c534b94b52ba505a70a47e75768186ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr>
Date: Tue, 11 May 2021 10:37:14 +0200
Subject: [PATCH] [Eva] Adds support for ACSL predicate is_infinite.

Adds functions [is_infinite] and [backward_is_infinite] in float_interval.
---
 .../abstract_interp/float_interval.ml         | 20 +++++++++++++++++++
 .../abstract_interp/float_interval_sig.mli    |  2 ++
 src/plugins/value/legacy/eval_terms.ml        |  4 ++++
 3 files changed, 26 insertions(+)

diff --git a/src/kernel_services/abstract_interp/float_interval.ml b/src/kernel_services/abstract_interp/float_interval.ml
index 7e733d4faa6..316b5b9b46b 100644
--- a/src/kernel_services/abstract_interp/float_interval.ml
+++ b/src/kernel_services/abstract_interp/float_interval.ml
@@ -421,6 +421,13 @@ module Make (F: Float_sig.S) = struct
     | FRange.NaN -> Comp.False
     | FRange.Itv (_b, _e, nan) -> if nan then Comp.Unknown else Comp.True
 
+  let is_infinite = function
+    | FRange.NaN -> Comp.False
+    | FRange.Itv (b, e, nan) ->
+      if F.is_infinite b || F.is_infinite e
+      then if Cmp.equal b e && not nan then Comp.True else Comp.Unknown
+      else Comp.False
+
   let is_finite = function
     | FRange.NaN -> Comp.False
     | FRange.Itv (b, e, nan) ->
@@ -444,6 +451,19 @@ module Make (F: Float_sig.S) = struct
     | FRange.Itv (b, e, true) ->
       if positive then `Value nan else `Value (FRange.inject ~nan:false b e)
 
+  let backward_is_infinite ~positive prec = function
+    | FRange.NaN as v -> if positive then `Bottom else `Value v
+    | FRange.Itv (b, e, nan) as f ->
+      if positive
+      then
+        match F.is_infinite b, F.is_infinite e with
+        | true, true -> `Value (if nan then FRange.inject ~nan:false b e else f)
+        | true, false -> `Value (FRange.inject ~nan:false b b)
+        | false, true -> `Value (FRange.inject ~nan:false e e)
+        | false, false -> `Bottom
+      else
+        narrow (FRange.add_nan (top_finite prec)) f
+
   let backward_is_finite ~positive prec = function
     | FRange.NaN as v -> if positive then `Bottom else `Value v
     | FRange.Itv (b, e, nan) as f ->
diff --git a/src/kernel_services/abstract_interp/float_interval_sig.mli b/src/kernel_services/abstract_interp/float_interval_sig.mli
index e105e4b09b5..1ea3e2fcfa2 100644
--- a/src/kernel_services/abstract_interp/float_interval_sig.mli
+++ b/src/kernel_services/abstract_interp/float_interval_sig.mli
@@ -90,8 +90,10 @@ module type S = sig
   val is_negative: t -> Abstract_interp.Comp.result
 
   val is_finite: t -> Abstract_interp.Comp.result
+  val is_infinite: t -> Abstract_interp.Comp.result
   val is_not_nan: t -> Abstract_interp.Comp.result
   val backward_is_finite: positive:bool -> prec -> t -> t or_bottom
+  val backward_is_infinite: positive:bool -> prec -> t -> t or_bottom
   val backward_is_nan: positive:bool -> t -> t or_bottom
 
   (** [has_greater_min_bound f1 f2] returns 1 if the interval [f1] has a better
diff --git a/src/plugins/value/legacy/eval_terms.ml b/src/plugins/value/legacy/eval_terms.ml
index 2ae8f263be7..bc8883d793f 100644
--- a/src/plugins/value/legacy/eval_terms.ml
+++ b/src/plugins/value/legacy/eval_terms.ml
@@ -737,6 +737,7 @@ let known_logic_funs = [
 let known_predicates = [
   "\\warning", ACSL;
   "\\is_finite", ACSL;
+  "\\is_infinite", ACSL;
   "\\is_plus_infinity", ACSL;
   "\\is_minus_infinity", ACSL;
   "\\is_NaN", ACSL;
@@ -2036,6 +2037,8 @@ let reduce_by_known_papp ~alarm_mode env positive li _labels args =
   match li.l_var_info.lv_name, args with
   | "\\is_finite", [arg] ->
     reduce_float (Fval.backward_is_finite ~positive) arg
+  | "\\is_infinite", [arg] ->
+    reduce_float (Fval.backward_is_infinite ~positive) arg
   | "\\is_plus_infinity", [arg] ->
     reduce_float (reduce_by_infinity ~pos:true) arg
   | "\\is_minus_infinity", [arg] ->
@@ -2555,6 +2558,7 @@ and eval_predicate env pred =
     in
     match li.l_var_info.lv_name, args with
     | "\\is_finite", [arg] -> unary_float Fval.is_finite arg
+    | "\\is_infinite", [arg] -> unary_float Fval.is_infinite arg
     | "\\is_plus_infinity", [arg] ->
       let pos_inf = Fval.pos_infinity Float_sig.Single in
       unary_float (fun f -> Fval.forward_comp Comp.Eq f pos_inf) arg
-- 
GitLab