From 765d47e3ab0bf2b631b6da1979eb01009b43b4f2 Mon Sep 17 00:00:00 2001 From: Patrick Baudin <patrick.baudin@cea.fr> Date: Wed, 16 Feb 2022 09:24:11 +0100 Subject: [PATCH] [wp] no sementical changes --- src/plugins/wp/Cint.ml | 191 ++++++++++++++++++++++++----------------- 1 file changed, 114 insertions(+), 77 deletions(-) diff --git a/src/plugins/wp/Cint.ml b/src/plugins/wp/Cint.ml index 2d2859ae474..25ff5e2cb60 100644 --- a/src/plugins/wp/Cint.ml +++ b/src/plugins/wp/Cint.ml @@ -145,15 +145,19 @@ let is_positive t = (* integration with qed should be improved! *) let rec is_positive_or_null e = match F.repr e with | Logic.Fun( f , [e] ) when Fun.equal f f_lnot -> is_negative e - | Logic.Fun( f , es ) when Fun.equal f f_land -> List.exists is_positive_or_null es - | Logic.Fun( f , es ) when Fun.equal f f_lor -> List.for_all is_positive_or_null es - | Logic.Fun( f , es ) when Fun.equal f f_lxor -> (match mul_xor_sign es with | Some b -> b | _ -> false) + | Logic.Fun( f , es ) when Fun.equal f f_land -> + List.exists is_positive_or_null es + | Logic.Fun( f , es ) when Fun.equal f f_lor -> + List.for_all is_positive_or_null es + | Logic.Fun( f , es ) when Fun.equal f f_lxor -> + (match mul_xor_sign es with | Some b -> b | _ -> false) | Logic.Fun( f , es ) when Fun.equal f f_lsr || Fun.equal f f_lsl -> List.for_all is_positive_or_null es | _ -> (* try some improvement first then ask to qed *) let improved_is_positive_or_null e = match F.repr e with | Logic.Add es -> List.for_all is_positive_or_null es - | Logic.Mul es -> (match mul_xor_sign es with | Some b -> b | _ -> false) + | Logic.Mul es -> + (match mul_xor_sign es with | Some b -> b | _ -> false) | Logic.Mod(e1,e2) when is_positive e2 || is_negative e2 -> (* e2<>0 ==> ( 0<=(e1 % e2) <=> 0<=e1 ) *) is_positive_or_null e1 @@ -166,13 +170,15 @@ and is_negative e = match F.repr e with | Logic.Fun( f , [e] ) when Fun.equal f f_lnot -> is_positive_or_null e | Logic.Fun( f , es ) when Fun.equal f f_lor -> List.exists is_negative es | Logic.Fun( f , es ) when Fun.equal f f_land -> List.for_all is_negative es - | Logic.Fun( f , es ) when Fun.equal f f_lxor -> (match mul_xor_sign es with | Some b -> (not b) | _ -> false) + | Logic.Fun( f , es ) when Fun.equal f f_lxor -> + (match mul_xor_sign es with | Some b -> (not b) | _ -> false) | Logic.Fun( f , [k;n] ) when Fun.equal f f_lsr || Fun.equal f f_lsl -> is_positive_or_null n && is_negative k | _ -> (* try some improvement first then ask to qed *) let improved_is_negative e = match F.repr e with | Logic.Add es -> List.for_all is_negative es - | Logic.Mul es -> (match mul_xor_sign es with | Some b -> (not b) | _ -> false) + | Logic.Mul es -> + (match mul_xor_sign es with | Some b -> (not b) | _ -> false) | _ -> false in if improved_is_negative e then true else match F.is_true (F.e_lt e e_zero) with @@ -274,7 +280,8 @@ let match_integer_extraction = match_list_head match_integer let match_power2_extraction = match_list_extraction match_power2 let match_power2_minus1_extraction = match_list_extraction match_power2_minus1 -let match_binop_one_extraction binop = match_list_extraction (match_binop_one_arg1 binop) +let match_binop_one_extraction binop = + match_list_extraction (match_binop_one_arg1 binop) (* -------------------------------------------------------------------------- *) @@ -512,7 +519,7 @@ let bitk_positive k e = F.e_fun ~result:Logic.Bool f_bit_positive [e;k] let smp_mk_bit_stdlib = function | [ a ; k ] when is_positive_or_null k -> (* No need to expand the logic definition of the ACSL stdlib symbol when - [k] is positive (the definition must comply with that simplification). *) + [k] is positive (the definition must comply with the simplification) *) bitk_positive k a | [ a ; k ] -> (* TODO: expand the current logic definition of the ACSL stdlib symbol *) @@ -530,9 +537,11 @@ let smp_bitk_positive = function in if Integer.is_zero (Integer.logand za (Integer.shift_left Integer.one zk)) then e_false else e_true - | Logic.Fun( f , [e;n] ) when Fun.equal f f_lsr && is_positive_or_null n -> + | Logic.Fun( f , [e;n] ) when Fun.equal f f_lsr + && is_positive_or_null n -> bitk_positive (e_add k n) e - | Logic.Fun( f , [e;n] ) when Fun.equal f f_lsl && is_positive_or_null n -> + | Logic.Fun( f , [e;n] ) when Fun.equal f f_lsl + && is_positive_or_null n -> begin match is_leq n k with | Logic.Yes -> bitk_positive (e_sub k n) e | Logic.No -> e_false @@ -597,7 +606,8 @@ let smp_land es = with Not_found -> r with Not_found -> introduction_bit_test_positive_from_land es -let smp_shift zf = (* f(e1,0)~>e1, c2>0==>f(c1,c2)~>zf(c1,c2), c2>0==>f(0,c2)~>0 *) +let smp_shift zf = + (* f(e1,0)~>e1, c2>0==>f(c1,c2)~>zf(c1,c2), c2>0==>f(0,c2)~>0 *) function | [e1;e2] -> begin match (F.repr e1), (F.repr e2) with | _, Logic.Kint c2 when Z.equal c2 Z.zero -> e1 @@ -625,7 +635,8 @@ let smp_lnot = function (* -------------------------------------------------------------------------- *) let smp_leq_improved f a b = - ignore (match_fun f b) ; (* It must be an improved of [is_positive_or_null f(args)] *) + ignore (match_fun f b) ; + (* It must be an improved of [is_positive_or_null f(args)] *) (* a <= 0 && 0 <= f(args) *) if F.decide (F.e_leq a F.e_zero) && is_positive_or_null b then e_true @@ -661,7 +672,8 @@ let smp_eq_with_land a b = (* k>=0 & b1>=0 ==> (b1 & ((1 << k) -1) == b1 % (1 << k) <==> true) *) let b1,b2 = match_mod b in let k = match_power2 b2 in - (* note: a positive or null k is required by match_power2, match_power2_minus1 *) + (* note: a positive or null k is required + by match_power2, match_power2_minus1 *) let k',_,es = match_power2_minus1_extraction es in if not ((is_positive_or_null b1) && (F.decide (F.e_eq k k')) && @@ -669,7 +681,8 @@ let smp_eq_with_land a b = then raise Not_found ; F.e_true with Not_found -> - (* k in {8,16,32,64} ==> (b1 & ((1 << k) -1) == to_cint_unsigned_bits(k, b1) <==> true *) + (* k in {8,16,32,64} ==> + ( (b1 & ((1 << k) -1) == to_cint_unsigned_bits(k, b1) <==> true ) *) let iota,b1 = match_to_cint b in if Ctypes.signed iota then raise Not_found ; let n = Ctypes.i_bits iota in @@ -773,26 +786,26 @@ let smp_cmp_with_lsl cmp a0 b0 = let a,p = match_fun f_lsl a0 |> match_positive_or_null_arg2 in let b,q = match_fun f_lsl b0 |> match_positive_or_null_arg2 in if p == q then - (* p>=0 && q>=0 && p==q ==> ( ((a<<p)cmp(b<<q)) <==> (a cmp b) ) *) + (* p>=0 && q>=0 && p==q ==> ( ((a<<p)cmp(b<<q))<==>(a cmp b) ) *) cmp a b else if a == b && (cmp==e_eq || is_positive_or_null a) then - (* p>=0 && q>=0 && a==b ==> ( ((a<<p)== (b<<q)) <==> (p == q) ) *) - (* p>=0 && q>=0 && a==b && a>=0 ==> ( ((a<<p)cmp(b<<q)) <==> (p cmp q) ) *) + (* p>=0 && q>=0 && a==b ==> ( ((a<<p)== (b<<q))<==>(p == q) ) *) + (* p>=0 && q>=0 && a==b && a>=0 ==> ( ((a<<p)cmp(b<<q))<==>(p cmp q) ) *) cmp p q else if a == b && is_negative a then - (* p>=0 && q>=0 && a==b && a<0 ==> ( ((a<<p)cmp(b<<q)) <==> (q cmp p) ) *) + (* p>=0 && q>=0 && a==b && a<0 ==> ( ((a<<p)cmp(b<<q))<==>(q cmp p) ) *) cmp q p else let p = match_integer p in let q = match_integer q in if Z.lt p q then - (* p>=0 && q>=0 && p>q ==> ( ((a<<p)cmp(b<<q)) <==> (a cmp(b<<(q-p))) ) *) + (* p>=0 && q>=0 && p>q ==>( ((a<<p)cmp(b<<q))<==>(a cmp(b<<(q-p))) ) *) cmp a (e_fun f_lsl [b;e_zint (Z.sub q p)]) else if Z.lt q p then - (* p>=0 && q>=0 && p<q ==> ( ((a<<p)cmp(b<<q)) <==> ((a<<(p-q)) cmp b) ) *) + (* p>=0 && q>=0 && p<q ==>( ((a<<p)cmp(b<<q))<==>((a<<(p-q)) cmp b) ) *) cmp (e_fun f_lsl [a;e_zint (Z.sub p q)]) b else - (* p>=0 && q>=0 && p==q ==> ( ((a<<p)cmp(b<<q)) <==> (a cmp b) ) *) + (* p>=0 && q>=0 && p==q ==>( ((a<<p)cmp(b<<q))<==>(a cmp b) ) *) cmp a b let smp_eq_with_lsl a b = @@ -825,7 +838,7 @@ let smp_eq_with_lsr a0 b0 = That rule is similar to (a/P) == (b/(N*P)) <==> (a/P)*P == ((b/N)/P)*P with P==2**p, N=2**n, q=p+n. - So, (a/P)*P==a&~((2**p)-1), b/N==b>>n, ((b/N)/P)*P==(b>>n)&~((2**p)-1) *) + So, (a/P)*P==a&~((2**p)-1), b/N==b>>n, ((b/N)/P)*P==(b>>n)&~((2**p)-1) *) let a,p = match_fun f_lsr a0 |> match_positive_or_null_integer_arg2 in let b,q = match_fun f_lsr b0 |> match_positive_or_null_integer_arg2 in let n = Integer.min p q in @@ -885,8 +898,8 @@ let () = begin let mk_builtin n f ?eq ?leq smp = n, { f ; eq; leq; smp } in - (* From [smp_mk_bit_stdlib], the built-in [f_bit_stdlib] is such that there is - no creation of [e_fun f_bit_stdlib args] *) + (* From [smp_mk_bit_stdlib], the built-in [f_bit_stdlib] is such that + there is no creation of [e_fun f_bit_stdlib args] *) let bi_lbit_stdlib = mk_builtin "f_bit_stdlib" f_bit_stdlib smp_mk_bit_stdlib in let bi_lbit = mk_builtin "f_bit" f_bit_positive smp_bitk_positive in let bi_lnot = mk_builtin "f_lnot" f_lnot ~eq:smp_eq_with_lnot smp_lnot ~leq:(smp_leq_improved f_lnot) in @@ -911,7 +924,8 @@ let () = | None -> () | Some leq -> F.set_builtin_leq f leq) end - [bi_lbit_stdlib ; bi_lbit; bi_lnot; bi_lxor; bi_lor; bi_land; bi_lsl; bi_lsr]; + [bi_lbit_stdlib ; bi_lbit; bi_lnot; + bi_lxor; bi_lor; bi_land; bi_lsl; bi_lsr]; Lang.For_export.set_builtin_eq f_land export_eq_with_land end @@ -1035,9 +1049,12 @@ module IntDomain = struct (add t2 (Ival.backward_comp_int_left cmp_sym v2 v1) dom) let assume_literal t dom = match Lang.F.repr t with - | Eq(a,b) when is_int a && is_int b -> assume_cmp "==" Abstract_interp.Comp.Eq a b dom - | Leq(a,b) when is_int a && is_int b -> assume_cmp "<=" Abstract_interp.Comp.Le a b dom - | Lt(a,b) when is_int a && is_int b -> assume_cmp "<" Abstract_interp.Comp.Lt a b dom + | Eq(a,b) when is_int a && is_int b -> + assume_cmp "==" Abstract_interp.Comp.Eq a b dom + | Leq(a,b) when is_int a && is_int b -> + assume_cmp "<=" Abstract_interp.Comp.Le a b dom + | Lt(a,b) when is_int a && is_int b -> + assume_cmp "<" Abstract_interp.Comp.Lt a b dom | Fun(g,[a]) -> begin try let ubound = c_int_bounds_ival (is_cint g) (* may raise Not_found *) in @@ -1066,7 +1083,7 @@ let is_cint_simplifier = (** Returns [new_t] such that [c_bind quant (alpha,t)] equals [c_bind quant v (alpha,new_t)] under the knowledge that [(not t) ==> (var in dom)]. - Note: [~add_bonus] has not effect on the correctness of the transformation. + Note: [~add_bonus] has not effect on the correctness. It is a parameter that can be used in order to get better results. Bonus: Add additionnal hypothesis when we could deduce better constraint on the variable *) @@ -1122,7 +1139,7 @@ let is_cint_simplifier = if !bonus_max then tools.Tool.add_hyp [e_leq tv (e_zint max)] t else t | Some min, Some max -> - if Integer.equal min max then (* Reduced to only one value: [min] *) + if Integer.equal min max then (* Reduced to only one value: min *) QED.e_subst_var v (e_zint min) t else if Integer.lt min max then let h = if !bonus_min then [e_leq (e_zint min) tv] else [] @@ -1224,14 +1241,14 @@ let is_cint_simplifier = | (quant,var), None -> e_bind quant var t | (quant,var), Some (tvar,var_domain) -> domain <- IntDomain.remove tvar domain; - (** Bonus: Add additionnal hypothesis in forall when we could deduce - better constraint on the variable *) + (** Bonus: Add additionnal hypothesis in forall when we could + deduce a better constraint on the variable *) let add_bonus = match term_pol with | Polarity.Both -> false | _ -> (term_pol=Polarity.Pos) = (quant=Forall) in - let t = reduce_bound ~add_bonus quant var tvar !var_domain t in - e_bind quant var t + e_bind quant var + (reduce_bound ~add_bonus quant var tvar !var_domain t) in List.fold_left f_close t ctx_with_dom | Fun(g,[a]) -> @@ -1244,12 +1261,18 @@ let is_cint_simplifier = else t with Not_found -> t end - | Imply (l1,l2) -> e_imply (List.map walk_flip_pol l1) (walk_same_pol l2) + | Imply (l1,l2) -> e_imply (List.map walk_flip_pol l1) + (walk_same_pol l2) | Not p -> e_not (walk_flip_pol p) | And _ | Or _ -> Lang.F.QED.f_map walk_same_pol t | _ -> - Lang.F.QED.f_map ~pool ~forall:false ~exists:false walk_both_pol t in - Lang.F.p_bool (walk ~term_pol:(Polarity.from_bool is_goal) (Lang.F.e_prop p)) + Lang.F.QED.f_map ~pool ~forall:false ~exists:false + walk_both_pol t + in + let walk_pred ~term_pol p = + Lang.F.p_bool (walk ~term_pol (Lang.F.e_prop p)) + in + walk_pred ~term_pol:(Polarity.from_bool is_goal) p method equivalent_exp (e : term) = e @@ -1342,6 +1365,30 @@ module Masks = struct ~unset:(Integer.logand v.unset unset)) neutral_lor es + let eval_to_cint eval ctx iota e = + let v = eval ctx e in + if is_bottom v then v + else + let min,max = Ctypes.bounds iota in + if not (Ctypes.signed iota) then + (* The highest bits are unset *) + mk ~set:(Integer.logand v.set max) + ~unset:(Integer.logor v.unset (Integer.lognot max)) + else (* Unsigned int type. + So , [min = Integer.lognot max] *) + let sign_bit_mask = Integer.succ max in + if is_one_unset sign_bit_mask v then + (* The sign bit is set to 0. + So, the highest bits are unset *) + mk ~set:(Integer.logand v.set max) + ~unset:(Integer.logor v.unset min) + else if is_one_set sign_bit_mask v then + (* The sign bit is set to 1. + So, the highest bits are set *) + mk ~set:(Integer.logor v.set min) + ~unset:(Integer.logand v.unset max) + else top + let of_integer set = mk ~set ~unset:(Integer.lognot set) let rewrite eval ctx e = let v = eval ctx e in @@ -1399,37 +1446,17 @@ module MasksDomain = struct let eval ~level (ctx:t) t = let eval get ctx e = - try - match F.repr e with - | Kint set -> Masks.mk ~set ~unset:(Integer.lognot set) - | Fun(f,es) when f == f_land -> Masks.eval_land get ctx es - | Fun(f,es) when f == f_lor -> Masks.eval_lor get ctx es - | Fun(f,[e]) when f == f_lnot -> Masks.eval_not get ctx e - | Fun(f,[e]) -> - let iota = to_cint f in (* may raise Not_found *) - let v = get ctx e in - if Masks.is_bottom v then v - else - let min,max = Ctypes.bounds iota in - if not (Ctypes.signed iota) then - (* the uppest bits are unset *) - Masks.mk ~set:(Integer.logand v.Masks.set max) - ~unset:(Integer.logor v.Masks.unset (Integer.lognot max)) - else - let sign_bit_mask = Integer.succ max in - if Masks.is_one_unset sign_bit_mask v then - (* The sign bit is set to 0. - So, the uppest bits are unset *) - Masks.mk ~set:(Integer.logand v.Masks.set max) - ~unset:(Integer.logor v.Masks.unset min) - else if Masks.is_one_set sign_bit_mask v then - (* The sign bit is set to 1. - So, the uppest bits are set *) - Masks.mk ~set:(Integer.logor v.Masks.set min) - ~unset:(Integer.logand v.Masks.unset max) - else Masks.top - | _ -> Masks.top - with Not_found -> Masks.top + match F.repr e with + | Kint set -> Masks.mk ~set ~unset:(Integer.lognot set) + | Fun(f,es) when f == f_land -> Masks.eval_land get ctx es + | Fun(f,es) when f == f_lor -> Masks.eval_lor get ctx es + | Fun(f,[e]) when f == f_lnot -> Masks.eval_not get ctx e + | Fun(f,[e]) -> + (try + let iota = to_cint f in (* may raise Not_found *) + Masks.eval_to_cint get ctx iota e + with Not_found -> Masks.top) + | _ -> Masks.top in let eval_narrow eval_subterm ctx t = let ({Masks.set;unset} as v) = eval eval_subterm ctx t in @@ -1572,9 +1599,11 @@ let mask_simplifier = match F.repr a with | Fun(f,es) when f == f_land -> (* [k & t == b] specifies some bits of [t] *) - let k,es = match_list_head match_integer es in (* may raise Not_found *) - if not (Integer.is_zero (Integer.logand b (Integer.lognot k))) then - (* [b] and [k] are such that the equality is false *) + let k,es = + match_list_head match_integer es (* may raise Not_found *) + in + if not (Integer.is_zero (Integer.logand b (Integer.lognot k))) + then (* [b] and [k] are such that the equality is false *) e_false else let set = b (* the bits of [t] that have to be set *) @@ -1661,30 +1690,38 @@ let mask_simplifier = if Tmap.is_empty masks then e else (Wp_parameters.debug ~dkey "Rewrite Exp: %a@." Lang.F.pp_term e; let r = Lang.e_subst (rewrite ~highest:true masks) e in - if not (r==e) then Wp_parameters.debug ~dkey "Exp rewritten into: %a@." Lang.F.pp_term r; + if not (r==e) then + Wp_parameters.debug ~dkey "Exp rewritten into: %a@." + Lang.F.pp_term r; r) method weaker_hyp p = if Tmap.is_empty masks then p else (Wp_parameters.debug ~dkey "Rewrite Hyp: %a@." Lang.F.pp_pred p; - (* Does not rewrite [hyp] as much as possible. - Any way, contradiction may be found later when [hyp] will be assumed *) + (* Does not rewrite [hyp] as much as possible. Any way, contradiction + may be found later when [hyp] will be assumed *) let r = Lang.p_subst (rewrite ~highest:false masks) p in - if not (r==p) then Wp_parameters.debug ~dkey "Hyp rewritten into: %a@." Lang.F.pp_pred r; + if not (r==p) then + Wp_parameters.debug ~dkey "Hyp rewritten into: %a@." + Lang.F.pp_pred r; r) method equivalent_branch p = if Tmap.is_empty masks then p else (Wp_parameters.debug ~dkey "Rewrite Branch: %a@." Lang.F.pp_pred p; let r = Lang.p_subst (rewrite ~highest:true masks) p in - if not (r==p) then Wp_parameters.debug ~dkey "Branch rewritten into: %a@." Lang.F.pp_pred r; + if not (r==p) then + Wp_parameters.debug ~dkey "Branch rewritten into: %a@." + Lang.F.pp_pred r; r) method stronger_goal p = if Tmap.is_empty masks then p else (Wp_parameters.debug ~dkey "Rewrite Goal: %a@." Lang.F.pp_pred p; let r = Lang.p_subst (rewrite ~highest:true masks) p in - if not (r==p) then Wp_parameters.debug ~dkey "Goal rewritten into: %a@." Lang.F.pp_pred r; + if not (r==p) then + Wp_parameters.debug ~dkey "Goal rewritten into: %a@." + Lang.F.pp_pred r; r ) -- GitLab