From 2afdad2c0410a1b4d39331f0e84e462965ff7a6f Mon Sep 17 00:00:00 2001
From: Johannes Kanig <kanig@adacore.com>
Date: Thu, 4 Feb 2016 18:27:42 +0900
Subject: [PATCH] N127-001 improve performance on fastWP

On N121-024 we fixed a bug where a state was incorrectly reused during
merge. The fix was to never reuse state when merging. This resulted in a
performance drop.

The new fix now marks states which should not be reused - basically
states that come from raise - and when such a state is present during
merging, we don't reuse. Otherwise, we reuse.  This seems to get us the
performance and passes all tests.

Marking is implemented simply by a flag in states

* mlw_wp.ml:
(mark) allows to set the marked flag of a state
(empty) empty state is not marked
(havoc) havoc doesn't change marked state
(merge_vars, merge_regs) new argument "marked", only create a new
  variable when marked is true, otherwise reuse
(fast_wp) in the case of Eraise, mark the used state

M415-042 pass labels down to conjunctions

Why3 parser groups the loop invariants into a single formula. This patch
allows to have the VC labels on every conjunct

mlw_wp.ml
(fastwp) call wp_expl instead of t_label
---
 src/whyml/mlw_wp.ml | 45 +++++++++++++++++++++++++++++----------------
 1 file changed, 29 insertions(+), 16 deletions(-)

diff --git a/src/whyml/mlw_wp.ml b/src/whyml/mlw_wp.ml
index f8ccfa3510..9c74e92efe 100644
--- a/src/whyml/mlw_wp.ml
+++ b/src/whyml/mlw_wp.ml
@@ -1139,6 +1139,8 @@ module Subst : sig
    (* the initial substitution for a program which mentions the given program
       variables *)
 
+   val mark : t -> t
+
    val havoc : model_data option -> wp_env -> Sreg.t -> t -> t * term
    (* [havoc md env regions s] generates a new state in which all regions in
       [regions] are touched and all other regions unchanged. The result pair
@@ -1192,6 +1194,7 @@ end = struct
     { now       : subst;
       other     : subst Mvs.t;
       reg_names : vsymbol Mreg.t;
+      marked    : bool;
     }
   (* the reg_names field is a simple name hint; a mapping reg |-> name means
      that [name] should be used as a base for new variables in region [reg].
@@ -1239,6 +1242,7 @@ end = struct
       in
       { other      = s.other;
         reg_names  = reg_names;
+        marked     = s.marked;
         now        =
           { subst_vars = vars;
             subst_regions =
@@ -1252,10 +1256,13 @@ end = struct
   let empty =
     { other         = Mvs.empty;
       reg_names     = Mreg.empty;
+      marked        = false;
       now           = { subst_regions = Mreg.empty;
                         subst_vars    = Mvs.empty; }
     }
 
+  let mark s = { s with marked = true }
+
   (* (* debugging code *)
   let print_state fmt s =
     Format.fprintf fmt "{ ";
@@ -1299,9 +1306,10 @@ end = struct
         acc
       end) s.now.subst_vars (s.now.subst_vars, t_true) in
     { s with now =
-      { subst_regions = regs;
-        subst_vars    = vars;
-      } }, f
+        { subst_regions = regs;
+          subst_vars    = vars;
+        };
+        marked = s.marked }, f
 
   let rec term s t =
     (* apply a substitution to a formula. This is straightforward, we only need
@@ -1367,25 +1375,27 @@ end = struct
   let first_different_vars base l = first_different base vs_equal l
   let first_different_terms base l = first_different base t_equal l
 
-  let merge_vars md base domain mapl =
+  let merge_vars md marked base domain mapl =
     Mvs.fold (fun k _ (map , fl) ->
         let all_terms = List.map (fun m -> Mvs.find k m) mapl in
         match first_different_terms (Mvs.find k base) all_terms with
         | None -> Mvs.add k (List.hd all_terms) map, fl
-        | Some _ ->
-            let new_ = t_var (fresh_var_from_var md k) in
+        | Some new_ ->
+            let new_ =
+              if marked then t_var (fresh_var_from_var md k) else new_ in
             Mvs.add k new_ map,
             List.map2 (fun old f ->
               t_and_simp (t_equ new_ old) f) all_terms fl)
     domain (Mvs.empty, List.map (fun _ -> t_true) mapl)
 
-  let merge_regs md names base domain mapl =
+  let merge_regs md names marked base domain mapl =
     Mreg.fold (fun k _ (map, fl) ->
       let all_vars = List.map (fun m -> Mreg.find k m) mapl in
       match first_different_vars (Mreg.find k base) all_vars with
       | None -> Mreg.add k (List.hd all_vars) map, fl
-      | Some _ ->
-          let new_ = fresh_var_from_region md names k in
+      | Some new_ ->
+          let new_ =
+            if marked then fresh_var_from_region md names k else new_ in
           Mreg.add k new_ map,
           List.map2 (fun old f ->
             if vs_equal old new_ then f
@@ -1401,17 +1411,20 @@ end = struct
            program variables/regions should be present in all of them. *)
         let domain =
           List.fold_left (fun acc s -> subst_inter acc s.now) base.now sl in
+        let marked = List.exists (fun x -> x.marked) sl in
         let vars, fl1 =
-          merge_vars md base.now.subst_vars domain.subst_vars
+          merge_vars md marked base.now.subst_vars domain.subst_vars
             (List.map (fun x -> x.now.subst_vars) sl)
         in
         let regs, fl2 =
-          merge_regs md base.reg_names base.now.subst_regions domain.subst_regions
+          merge_regs md base.reg_names marked base.now.subst_regions
+                     domain.subst_regions
                      (List.map (fun x -> x.now.subst_regions) sl)
         in
         { base with now =
-          { subst_vars = vars;
-            subst_regions = regs }
+            { subst_vars = vars;
+              subst_regions = regs };
+            marked = false;
         },
         List.map2 t_and_simp fl1 fl2
 
@@ -1772,7 +1785,7 @@ and fast_wp_desc (env : wp_env) (s : Subst.t) (r : res_type) (e : expr)
           s, ne
         with Not_found ->
           wp1.post.s, t_and_simp wp1.post.ne rpost in
-      let expost = { s = s; ne = wp_label e ne } in
+      let expost = { s = Subst.mark s; ne = wp_label e ne } in
       let xne = Mexn.add ex expost wp1.exn in
       { ok = wp1.ok;
         post = { ne = t_false; s = wp1.post.s };
@@ -1881,12 +1894,12 @@ and fast_wp_desc (env : wp_env) (s : Subst.t) (r : res_type) (e : expr)
       (* EX: ex(e1)[r -> r'] *)
       let md = create_model_data_opt ~loc:e1.e_loc ~context_labels:e1.e_label "loop" in
       let havoc_state, glue = Subst.havoc md env (regs_of_writes e1.e_effect) s in
-      let init_inv = t_label_add expl_loop_init (Subst.term s inv) in
+      let init_inv = wp_expl expl_loop_init (Subst.term s inv) in
       let inv_hypo =
         t_and_simp glue (Subst.term havoc_state inv) in
       let wp1 = fast_wp_expr env havoc_state r e1 in
       let post_inv =
-        t_label_add expl_loop_keep (Subst.term wp1.post.s inv) in
+        wp_expl expl_loop_keep (Subst.term wp1.post.s inv) in
         (* preservation also includes the "OK" of the loop body, the overall
            form is:
            I => (OK /\ (NE => I' /\ V))
-- 
GitLab