From 996ee48041ec49b305738f8c32fa4d83b2aa1e4d Mon Sep 17 00:00:00 2001 From: Thibaut Benjamin <thibaut.benjamin@cea.fr> Date: Thu, 29 Jul 2021 11:03:05 +0200 Subject: [PATCH] [e-acsl] move the extra guard computation in typing --- .../e-acsl/src/analyses/bound_variables.ml | 60 ------------------- src/plugins/e-acsl/src/analyses/typing.ml | 56 +++++++++++++++++ 2 files changed, 56 insertions(+), 60 deletions(-) diff --git a/src/plugins/e-acsl/src/analyses/bound_variables.ml b/src/plugins/e-acsl/src/analyses/bound_variables.ml index 44a2194bfaa..88e38a22e72 100644 --- a/src/plugins/e-acsl/src/analyses/bound_variables.ml +++ b/src/plugins/e-acsl/src/analyses/bound_variables.ml @@ -627,66 +627,6 @@ let compute_quantif_guards ~is_forall quantif bounded_vars p = let goal = Option.get goal in guards, goal -(******************************************************************************) -(** Type intersection *) -(******************************************************************************) - -(* It could happen that the bounds provided for a quantifier [lv] are bigger - than its type. [bounds_for_small_type] handles such cases - and provides smaller bounds whenever possible. - Let B be the inferred interval and R the range of [lv.typ] - - Case 1: B \subseteq R - Example: [\forall unsigned char c; 4 <= c <= 100 ==> 0 <= c <= 255] - Return: B - - Case 2: B \not\subseteq R and the bounds of B are inferred exactly - Example: [\forall unsigned char c; 4 <= c <= 300 ==> 0 <= c <= 255] - Return: B \intersect R - - Case 3: B \not\subseteq R and the bounds of B are NOT inferred exactly - Example: [\let m = n > 0 ? 4 : 341; \forall char u; 1 < u < m ==> u > 0] - Return: R with a guard guaranteeing that [lv] does not overflow *) -let bounds_for_small_types ~loc (t1, lv, t2) = - match lv.lv_type with - | Ltype _ | Lvar _ | Lreal | Larrow _ -> - Error.not_yet "quantification over non-integer type" - | Linteger -> - t1, t2, None - | Ctype ty -> - let iv1 = Interval.(extract_ival (infer t1)) in - let iv2 = Interval.(extract_ival (infer t2)) in - (* Ival.join is NOT correct here: - Eg: (Ival.join [-3..-3] [300..300]) gives {-3, 300} - but NOT [-3..300] *) - let iv = Ival.inject_range (Ival.min_int iv1) (Ival.max_int iv2) in - let ity = Interval.extract_ival (Interval.extended_interv_of_typ ty) in - if Ival.is_included iv ity then - (* case 1 *) - t1, t2, None - else if Ival.is_singleton_int iv1 && Ival.is_singleton_int iv2 then begin - (* case 2 *) - let i = Ival.meet iv ity in - (* now we potentially have a better interval for [lv] - ==> update the binding *) - Interval.Env.replace lv (Interval.Ival i); - (* the smaller bounds *) - let min, max = Misc.finite_min_and_max i in - let t1 = Logic_const.tint ~loc min in - let t2 = Logic_const.tint ~loc max in - let ctx = Typing.number_ty_of_typ ~post:false ty in - (* we are assured that we will not have a GMP, - once again because we intersected with [ity] *) - Typing.type_term ~use_gmp_opt:false ~ctx t1; - Typing.type_term ~use_gmp_opt:false ~ctx t2; - t1, t2, None - end else - (* case 3 *) - let min, max = Misc.finite_min_and_max ity in - let guard_lower = Logic_const.tint ~loc min in - let guard_upper = Logic_const.tint ~loc max in - let lv_term = Logic_const.tvar ~loc lv in - let guard_lower = Logic_const.prel ~loc (Rle, guard_lower, lv_term) in - let guard_upper = Logic_const.prel ~loc (Rlt, lv_term, guard_upper) in - let guard = Logic_const.pand ~loc (guard_lower, guard_upper) in - t1, t2, Some guard let () = Typing.compute_quantif_guards_ref := compute_quantif_guards diff --git a/src/plugins/e-acsl/src/analyses/typing.ml b/src/plugins/e-acsl/src/analyses/typing.ml index d49de2da589..0f1094d579d 100644 --- a/src/plugins/e-acsl/src/analyses/typing.ml +++ b/src/plugins/e-acsl/src/analyses/typing.ml @@ -595,6 +595,62 @@ and type_term_offset = function let ctx = type_offset t in ignore (type_term ~use_gmp_opt:false ~ctx t); type_term_offset toff +(* It could happen that the bounds provided for a quantifier [lv] are bigger + than its type. [bounds_for_small_type] handles such cases + and provides smaller bounds whenever possible. + Let B be the inferred interval and R the range of [lv.typ] + - Case 1: B \subseteq R + Example: [\forall unsigned char c; 4 <= c <= 100 ==> 0 <= c <= 255] + Return: B + - Case 2: B \not\subseteq R and the bounds of B are inferred exactly + Example: [\forall unsigned char c; 4 <= c <= 300 ==> 0 <= c <= 255] + Return: B \intersect R + - Case 3: B \not\subseteq R and the bounds of B are NOT inferred exactly + Example: [\let m = n > 0 ? 4 : 341; \forall char u; 1 < u < m ==> u > 0] + Return: R with a guard guaranteeing that [lv] does not overflow *) +let bounds_for_small_types ~loc (t1, lv, t2) = + match lv.lv_type with + | Ltype _ | Lvar _ | Lreal | Larrow _ -> + Error.not_yet "quantification over non-integer type" + | Linteger -> + t1, t2, None + | Ctype ty -> + let iv1 = Interval.(extract_ival (infer t1)) in + let iv2 = Interval.(extract_ival (infer t2)) in + (* Ival.join is NOT correct here: + Eg: (Ival.join [-3..-3] [300..300]) gives {-3, 300} + but NOT [-3..300] *) + let iv = Ival.inject_range (Ival.min_int iv1) (Ival.max_int iv2) in + let ity = Interval.extract_ival (Interval.extended_interv_of_typ ty) in + if Ival.is_included iv ity then + (* case 1 *) + t1, t2, None + else if Ival.is_singleton_int iv1 && Ival.is_singleton_int iv2 then begin + (* case 2 *) + let i = Ival.meet iv ity in + (* now we potentially have a better interval for [lv] + ==> update the binding *) + Interval.Env.replace lv (Interval.Ival i); + (* the smaller bounds *) + let min, max = Misc.finite_min_and_max i in + let t1 = Logic_const.tint ~loc min in + let t2 = Logic_const.tint ~loc max in + let ctx = Typing.number_ty_of_typ ~post:false ty in + (* we are assured that we will not have a GMP, + once again because we intersected with [ity] *) + Typing.type_term ~use_gmp_opt:false ~ctx t1; + Typing.type_term ~use_gmp_opt:false ~ctx t2; + t1, t2, None + end else + (* case 3 *) + let min, max = Misc.finite_min_and_max ity in + let guard_lower = Logic_const.tint ~loc min in + let guard_upper = Logic_const.tint ~loc max in + let lv_term = Logic_const.tvar ~loc lv in + let guard_lower = Logic_const.prel ~loc (Rle, guard_lower, lv_term) in + let guard_upper = Logic_const.prel ~loc (Rlt, lv_term, guard_upper) in + let guard = Logic_const.pand ~loc (guard_lower, guard_upper) in + t1, t2, Some guard let rec type_predicate p = Cil.CurrentLoc.set p.pred_loc; -- GitLab