From 77e37a05de1a7c604f65ec0d544703315ca0363d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=A9lio=20Brun?= <lb@leliobrun.net>
Date: Tue, 14 Mar 2023 23:03:57 +0900
Subject: [PATCH] fix a bug where protecting ghost vars were not introduced at
 the proper sites

---
 src/optimize_machine.ml | 203 ++++++++++++++++++++++++----------------
 1 file changed, 120 insertions(+), 83 deletions(-)

diff --git a/src/optimize_machine.ml b/src/optimize_machine.ml
index 86445bdf..e2e75fbc 100644
--- a/src/optimize_machine.ml
+++ b/src/optimize_machine.ml
@@ -794,6 +794,18 @@ let instr_cons instr cont =
   | false, _ ->
     instr :: cont
 
+let rec remove_skips_instrs instrs =
+  let aux instr =
+    match instr.instr_desc with
+    | MBranch (e, hl, b) ->
+      let hl = List.map (fun (h, l) -> h, remove_skips_instrs l) hl in
+      { instr with instr_desc = MBranch (e, hl, b) }
+    | _ ->
+      instr
+  in
+  List.fold_left (fun instrs i -> instr_cons (aux i) instrs) [] instrs
+  |> List.rev
+
 (* XXX: UNUSED *)
 (* let rec instr_remove_skip instr cont =
  *   match get_instr_desc instr with
@@ -874,8 +886,8 @@ let rec instr_replace_var m fvar instrs instr =
     match instr.instr_desc with
     | MLocalAssign (i, v) ->
       let v = value_replace_var fvar v in
-      let i = fvar i in
-      MLocalAssign (i, v)
+      let i' = fvar i in
+      MLocalAssign (i', v)
     | MStateAssign (i, v) ->
       MStateAssign (i, value_replace_var fvar v)
     | MStep (il, i, vl) ->
@@ -886,13 +898,10 @@ let rec instr_replace_var m fvar instrs instr =
         List.fold_left
           (fun hl (h, il) ->
             let il = instrs_replace_var m fvar il in
-            (* Format.(printf "%s: before %a after %a@." h (IMap.pp
-               pp_print_int) asg (IMap.pp pp_print_int) asg''); *)
             (h, il) :: hl)
           []
           hl
       in
-      (* Format.(printf "%a@." (IMap.pp pp_print_int) asg); *)
       MBranch (value_replace_var fvar g, List.rev hl, e)
     | MSetReset _
     | MNoReset _
@@ -902,7 +911,7 @@ let rec instr_replace_var m fvar instrs instr =
     | MComment _ ->
       instr.instr_desc
   in
-  instr_cons { instr with instr_desc } instrs
+  { instr with instr_desc } :: instrs
 
 and instrs_replace_var m fvar instrs =
   let instrs = List.fold_left (instr_replace_var m fvar) [] instrs in
@@ -932,72 +941,82 @@ and add_ghost_assigns fvar = List.map (add_ghost_assign fvar)
 let ghost_vd v = { v with var_id = "__" ^ v.var_id }
 
 let add_ghost_assigns_reassigned rasg instrs =
-  let _, instrs, _ =
-    List.fold_left
-      (fun (rasg, instrs, fvar) instr ->
-        let rec aux rasg instr fvar =
-          match instr.instr_desc with
-          | MLocalAssign (i, _) when VSet.mem i rasg ->
-            ( VSet.remove i rasg,
-              {
-                instr with
-                instr_spec =
-                  add_ghost_assign_spec
-                    (ghost_vd i)
-                    (vdecl_to_val i)
-                    instr.instr_spec;
-              },
-              fun v -> if v = i then ghost_vd i else fvar v )
-          | MStep (il, _, _) ->
-            let il = List.filter (fun i -> VSet.mem i rasg) il in
-            let rasg, instr_spec, fvar =
-              List.fold_left
-                (fun (rasg, spec, fvar) i ->
-                  ( VSet.remove i rasg,
-                    add_ghost_assign_spec (ghost_vd i) (vdecl_to_val i) spec,
-                    fun v -> if v = i then ghost_vd i else fvar v ))
-                (rasg, instr.instr_spec, fvar)
-                il
-            in
-            rasg, { instr with instr_spec }, fvar
-          | MBranch (e, hl, b) ->
-            let rasg, fvar, hl =
+  let rec aux n instr fvar =
+    match instr.instr_desc with
+    | MLocalAssign (i, _) ->
+      let instr, fvar =
+        match VMap.find_opt i rasg with
+        | Some n' when n = n' ->
+          ( {
+              instr with
+              instr_spec =
+                add_ghost_assign_spec
+                  (ghost_vd i)
+                  (vdecl_to_val i)
+                  instr.instr_spec;
+            },
+            fun v -> if v = i then ghost_vd i else fvar v )
+        | _ ->
+          instr, fvar
+      in
+      n + 1, instr, fvar
+    | MStep (il, _, _) ->
+      let il =
+        List.filter
+          (fun i ->
+            match VMap.find_opt i rasg with Some n' -> n = n' | _ -> false)
+          il
+      in
+      let instr_spec, fvar =
+        List.fold_left
+          (fun (spec, fvar) i ->
+            ( add_ghost_assign_spec (ghost_vd i) (vdecl_to_val i) spec,
+              fun v -> if v = i then ghost_vd i else fvar v ))
+          (instr.instr_spec, fvar)
+          il
+      in
+      n + 1, { instr with instr_spec }, fvar
+    | MBranch (e, hl, b) ->
+      let n, fvar, hl =
+        List.fold_left
+          (fun (n, fvar, hl) (h, l) ->
+            let n, fvar, l =
               List.fold_left
-                (fun (rasg, fvar, hl) (h, l) ->
-                  let rasg, fvar, l =
-                    List.fold_left
-                      (fun (rasg, fvar, l) i ->
-                        let rasg, i, fvar = aux rasg i fvar in
-                        rasg, fvar, i :: l)
-                      (rasg, fvar, [])
-                      l
-                  in
-                  rasg, fvar, (h, List.rev l) :: hl)
-                (rasg, fvar, [])
-                hl
+                (fun (n, fvar, l) i ->
+                  let n, i, fvar = aux n i fvar in
+                  n, fvar, i :: l)
+                (n, fvar, [])
+                l
             in
-            rasg, { instr with instr_desc = MBranch (e, List.rev hl, b) }, fvar
-          | _ ->
-            rasg, instr, fvar
-        in
-        let rasg, instr, fvar = aux rasg instr fvar in
+            n, fvar, (h, List.rev l) :: hl)
+          (n, fvar, [])
+          hl
+      in
+      n, { instr with instr_desc = MBranch (e, List.rev hl, b) }, fvar
+    | _ ->
+      n + 1, instr, fvar
+  in
+  let _, instrs, _ =
+    List.fold_left
+      (fun (n, instrs, fvar) instr ->
+        let n, instr, fvar = aux n instr fvar in
         let instr_spec =
           List.map (fun (t, b) -> instr_spec_replace fvar t, b) instr.instr_spec
         in
-        rasg, { instr with instr_spec } :: instrs, fvar)
-      (rasg, [], fun v -> v)
+        n, { instr with instr_spec } :: instrs, fvar)
+      (0, [], fun v -> v)
       instrs
   in
   List.rev instrs
 
 module IntS = Set.Make (Int)
 
-let add_assigned k v =
+let add_assigned n k v =
   VMap.update v (function
       | Some (n, ks) as b ->
-        if k > IntS.max_elt ks then Some (n + 1, IntS.add k ks) else b
+        if k > IntS.max_elt ks then Some (n, IntS.add k ks) else b
       | None ->
-        Some (1, IntS.singleton k))
+        Some (n, IntS.singleton k))
 
 let silly_asg i v =
   match v.value_desc with Var w -> w.var_id = i.var_id | _ -> false
@@ -1025,55 +1044,73 @@ let step_replace_var m reuse step =
   let step_checks =
     List.map (fun (l, v) -> l, value_replace_var fvar v) step.step_checks
   in
-  let rec asg_instr k asg instr =
+  let rec asg_instr (n, k, asg) instr =
+    (* k: instruction block index (equation index) n: instruction index
+       (absolute) *)
     match instr.instr_desc with
     | MLocalAssign (i, v) ->
-      if silly_asg i v then asg else add_assigned k i asg
+      n + 1, k + 1, if silly_asg i v then asg else add_assigned n k i asg
     | MStep (il, _, _) ->
-      List.fold_right (add_assigned k) il asg
+      n + 1, k + 1, List.fold_right (add_assigned n k) il asg
     | MBranch (_, hl, _) ->
-      List.fold_left
-        (fun asg' (_, il) ->
-          let asg'' = List.fold_left (asg_instr k) asg il in
-          VMap.union (fun _ n1 n2 -> Some (max n1 n2)) asg' asg'')
-        VMap.empty
-        hl
+      let n, k, asg =
+        List.fold_left
+          (fun (n, _, asg') (_, il) ->
+            let n, _, asg'' = List.fold_left asg_instr (n, k, asg) il in
+            ( n,
+              k,
+              VMap.union
+                (fun _ ((_, ks1) as x1) ((_, ks2) as x2) ->
+                  if IntS.(cardinal ks1 > cardinal ks2) then Some x1
+                  else Some x2)
+                asg'
+                asg'' ))
+          (n, k, VMap.empty)
+          hl
+      in
+      n, k + 1, asg
     | _ ->
-      asg
+      n + 1, k + 1, asg
   in
   let assigned asg instrs =
-    let asg, _ =
-      List.fold_left
-        (fun (asg, k) instr -> asg_instr k asg instr, k + 1)
-        (asg, 0)
-        instrs
-    in
+    let _, _, asg = List.fold_left asg_instr (0, 0, asg) instrs in
+    (* let asg, _ = *)
+    (*   List.fold_left *)
+    (*     (fun (asg, k) instr -> asg_instr k asg instr, k + 1) *)
+    (*     (asg, 0) *)
+    (*     instrs *)
+    (* in *)
     asg
   in
   (* SSA *)
   let step_instrs = add_ghost_assigns fvar step.step_instrs in
   (* register the locations of assignments *)
   let asg = assigned VMap.empty step_instrs in
-  (* let pp fmt (k, s) = *)
-  (* Format.(fprintf fmt "%n{@[%a}@]" k (pp_comma_list pp_print_int)
-     (IntS.elements s)) *)
-  (* in *)
-  (* Format.printf "AVANT %a@." (VMap.pp pp) asg; *)
+  let pp fmt (k, s) =
+    Format.(
+      fprintf fmt "%n{@[%a}@]" k (pp_comma_list pp_print_int) (IntS.elements s))
+  in
+  Format.printf "AVANT %a@." (VMap.pp pp) asg;
   (* SSA *)
   let step_instrs = instrs_replace_var m fvar step_instrs in
   (* update the locations of assignments, consider as reassignments only the
      ones appearing *after* the original one *)
   let asg = assigned asg step_instrs in
-  (* Format.printf "APRES %a@." (VMap.pp pp) asg; *)
   let rasg =
-    VMap.fold
-      (fun v (n, _) rasg -> if n > 1 then VSet.add v rasg else rasg)
+    VMap.filter_map
+      (fun _ (n, ks) -> if IntS.cardinal ks > 1 then Some n else None)
       asg
-      VSet.empty
+    (* VMap.fold *)
+    (* (fun v (_, ks) rasg -> if IntS.cardinal ks > 1 then VSet.add v rasg else
+       rasg) *)
+    (*   asg *)
+    (*   VSet.empty *)
   in
+  Format.printf "APRES %a@." (VMap.pp pp) asg;
   (* not SSA anymore *)
   let step_instrs = add_ghost_assigns_reassigned rasg step_instrs in
   (* not SSA anymore *)
+  let step_instrs = remove_skips_instrs step_instrs in
   { step with step_checks; step_locals; step_instrs }
 
 let machine_replace_variables reuse m =
-- 
GitLab