You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2231 lines
78 KiB
2231 lines
78 KiB
10 years ago
|
(*
|
||
10 years ago
|
* Copyright (c) 2009 - 2013 Monoidics ltd.
|
||
|
* Copyright (c) 2013 - present Facebook, Inc.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* This source code is licensed under the BSD style license found in the
|
||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||
|
*)
|
||
10 years ago
|
|
||
8 years ago
|
open! IStd
|
||
8 years ago
|
module Hashtbl = Caml.Hashtbl
|
||
9 years ago
|
|
||
10 years ago
|
(** Operators for the abstract domain. In particular, join and meet. *)
|
||
|
|
||
|
module L = Logging
|
||
|
module F = Format
|
||
|
|
||
8 years ago
|
let ( ++ ) = IntLit.add
|
||
|
|
||
|
let ( -- ) = IntLit.sub
|
||
10 years ago
|
|
||
|
(** {2 Utility functions for ids} *)
|
||
|
|
||
8 years ago
|
let can_rename id = Ident.is_primed id || Ident.is_footprint id
|
||
10 years ago
|
|
||
|
(** {2 Utility functions for sigma} *)
|
||
|
|
||
8 years ago
|
let equal_sigma sigma1 sigma2 =
|
||
10 years ago
|
let rec f sigma1_rest sigma2_rest =
|
||
|
match (sigma1_rest, sigma2_rest) with
|
||
7 years ago
|
| [], [] ->
|
||
|
()
|
||
|
| [], _ :: _ | _ :: _, [] ->
|
||
|
L.d_strln "failure reason 1" ; raise Sil.JoinFail
|
||
|
| hpred1 :: sigma1_rest', hpred2 :: sigma2_rest' ->
|
||
|
if Sil.equal_hpred hpred1 hpred2 then f sigma1_rest' sigma2_rest'
|
||
8 years ago
|
else ( L.d_strln "failure reason 2" ; raise Sil.JoinFail )
|
||
|
in
|
||
8 years ago
|
let sigma1_sorted = List.sort ~cmp:Sil.compare_hpred sigma1 in
|
||
|
let sigma2_sorted = List.sort ~cmp:Sil.compare_hpred sigma2 in
|
||
10 years ago
|
f sigma1_sorted sigma2_sorted
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
let sigma_get_start_lexps_sort sigma =
|
||
8 years ago
|
let exp_compare_neg e1 e2 = -Exp.compare e1 e2 in
|
||
7 years ago
|
let filter e = Exp.free_vars e |> Sequence.for_all ~f:Ident.is_normal in
|
||
10 years ago
|
let lexps = Sil.hpred_list_get_lexps filter sigma in
|
||
8 years ago
|
List.sort ~cmp:exp_compare_neg lexps
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
(** {2 Utility functions for side} *)
|
||
|
|
||
|
type side = Lhs | Rhs
|
||
|
|
||
8 years ago
|
let select side e1 e2 = match side with Lhs -> e1 | Rhs -> e2
|
||
10 years ago
|
|
||
8 years ago
|
let opposite side = match side with Lhs -> Rhs | Rhs -> Lhs
|
||
10 years ago
|
|
||
8 years ago
|
let do_side side f e1 e2 = match side with Lhs -> f e1 e2 | Rhs -> f e2 e1
|
||
10 years ago
|
|
||
|
(** {2 Sets for expression pairs} *)
|
||
|
|
||
8 years ago
|
module EPset = Caml.Set.Make (struct
|
||
|
type t = Exp.t * Exp.t [@@deriving compare]
|
||
|
end)
|
||
10 years ago
|
|
||
|
(** {2 Module for maintaining information about noninjectivity during join} *)
|
||
|
|
||
|
module NonInj : sig
|
||
|
val init : unit -> unit
|
||
8 years ago
|
|
||
10 years ago
|
val final : unit -> unit
|
||
8 years ago
|
|
||
9 years ago
|
val add : side -> Exp.t -> Exp.t -> unit
|
||
10 years ago
|
|
||
8 years ago
|
val check : side -> Exp.t list -> bool
|
||
10 years ago
|
end = struct
|
||
|
(* mappings from primed or footprint var exps to primed or footprint var exps *)
|
||
|
let equiv_tbl1 = Hashtbl.create 32
|
||
8 years ago
|
|
||
10 years ago
|
let equiv_tbl2 = Hashtbl.create 32
|
||
|
|
||
|
(* mappings from primed or footprint var exps to normal var, lvar or const exps *)
|
||
|
let const_tbl1 = Hashtbl.create 32
|
||
8 years ago
|
|
||
10 years ago
|
let const_tbl2 = Hashtbl.create 32
|
||
|
|
||
|
let reset () =
|
||
8 years ago
|
Hashtbl.clear equiv_tbl1 ;
|
||
|
Hashtbl.clear equiv_tbl2 ;
|
||
|
Hashtbl.clear const_tbl1 ;
|
||
10 years ago
|
Hashtbl.clear const_tbl2
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
let init () = reset ()
|
||
8 years ago
|
|
||
10 years ago
|
let final () = reset ()
|
||
|
|
||
|
let lookup' tbl e default =
|
||
|
match e with
|
||
8 years ago
|
| Exp.Var _ -> (
|
||
7 years ago
|
try Hashtbl.find tbl e with Not_found -> Hashtbl.replace tbl e default ; default )
|
||
7 years ago
|
| _ ->
|
||
|
assert false
|
||
|
|
||
8 years ago
|
|
||
|
let lookup_equiv' tbl e = lookup' tbl e e
|
||
|
|
||
|
let lookup_const' tbl e = lookup' tbl e Exp.Set.empty
|
||
10 years ago
|
|
||
|
let rec find' tbl e =
|
||
|
let e' = lookup_equiv' tbl e in
|
||
|
match e' with
|
||
7 years ago
|
| Exp.Var _ ->
|
||
|
if Exp.equal e e' then e
|
||
10 years ago
|
else
|
||
8 years ago
|
let root = find' tbl e' in
|
||
|
Hashtbl.replace tbl e root ; root
|
||
7 years ago
|
| _ ->
|
||
|
assert false
|
||
|
|
||
10 years ago
|
|
||
|
let union' tbl const_tbl e1 e2 =
|
||
|
let r1 = find' tbl e1 in
|
||
|
let r2 = find' tbl e2 in
|
||
8 years ago
|
let new_r, old_r = match Exp.compare r1 r2 with i when i <= 0 -> (r1, r2) | _ -> (r2, r1) in
|
||
10 years ago
|
let new_c = lookup_const' const_tbl new_r in
|
||
|
let old_c = lookup_const' const_tbl old_r in
|
||
9 years ago
|
let res_c = Exp.Set.union new_c old_c in
|
||
8 years ago
|
if Exp.Set.cardinal res_c > 1 then ( L.d_strln "failure reason 3" ; raise Sil.JoinFail ) ;
|
||
|
Hashtbl.replace tbl old_r new_r ;
|
||
10 years ago
|
Hashtbl.replace const_tbl new_r res_c
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
let replace_const' tbl const_tbl e c =
|
||
|
let r = find' tbl e in
|
||
9 years ago
|
let set = Exp.Set.add c (lookup_const' const_tbl r) in
|
||
8 years ago
|
if Exp.Set.cardinal set > 1 then ( L.d_strln "failure reason 4" ; raise Sil.JoinFail ) ;
|
||
10 years ago
|
Hashtbl.replace const_tbl r set
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
let add side e e' =
|
||
|
let tbl, const_tbl =
|
||
8 years ago
|
match side with Lhs -> (equiv_tbl1, const_tbl1) | Rhs -> (equiv_tbl2, const_tbl2)
|
||
10 years ago
|
in
|
||
8 years ago
|
match (e, e') with
|
||
|
| Exp.Var id, Exp.Var id' -> (
|
||
|
match (can_rename id, can_rename id') with
|
||
7 years ago
|
| true, true ->
|
||
|
union' tbl const_tbl e e'
|
||
|
| true, false ->
|
||
|
replace_const' tbl const_tbl e e'
|
||
|
| false, true ->
|
||
|
replace_const' tbl const_tbl e' e
|
||
|
| _ ->
|
||
|
L.d_strln "failure reason 5" ; raise Sil.JoinFail )
|
||
|
| Exp.Var id, Exp.Const _ | Exp.Var id, Exp.Lvar _ ->
|
||
|
if can_rename id then replace_const' tbl const_tbl e e'
|
||
8 years ago
|
else ( L.d_strln "failure reason 6" ; raise Sil.JoinFail )
|
||
7 years ago
|
| Exp.Const _, Exp.Var id' | Exp.Lvar _, Exp.Var id' ->
|
||
|
if can_rename id' then replace_const' tbl const_tbl e' e
|
||
8 years ago
|
else ( L.d_strln "failure reason 7" ; raise Sil.JoinFail )
|
||
7 years ago
|
| _ ->
|
||
|
if not (Exp.equal e e') then ( L.d_strln "failure reason 8" ; raise Sil.JoinFail ) else ()
|
||
|
|
||
10 years ago
|
|
||
|
let check side es =
|
||
9 years ago
|
let f = function Exp.Var id -> can_rename id | _ -> false in
|
||
8 years ago
|
let vars, nonvars = List.partition_tf ~f es in
|
||
10 years ago
|
let tbl, const_tbl =
|
||
8 years ago
|
match side with Lhs -> (equiv_tbl1, const_tbl1) | Rhs -> (equiv_tbl2, const_tbl2)
|
||
10 years ago
|
in
|
||
8 years ago
|
if List.length nonvars > 1 then false
|
||
10 years ago
|
else
|
||
8 years ago
|
match (vars, nonvars) with
|
||
7 years ago
|
| [], _ | [_], [] ->
|
||
|
true
|
||
|
| v :: vars', _ ->
|
||
|
let r = find' tbl v in
|
||
10 years ago
|
let set = lookup_const' const_tbl r in
|
||
8 years ago
|
List.for_all ~f:(fun v' -> Exp.equal (find' tbl v') r) vars'
|
||
|
&& List.for_all ~f:(fun c -> Exp.Set.mem c set) nonvars
|
||
10 years ago
|
end
|
||
|
|
||
|
(** {2 Modules for checking whether join or meet loses too much info} *)
|
||
|
|
||
8 years ago
|
module type InfoLossCheckerSig = sig
|
||
9 years ago
|
val init : Prop.sigma -> Prop.sigma -> unit
|
||
8 years ago
|
|
||
10 years ago
|
val final : unit -> unit
|
||
8 years ago
|
|
||
9 years ago
|
val lost_little : side -> Exp.t -> Exp.t list -> bool
|
||
8 years ago
|
|
||
9 years ago
|
val add : side -> Exp.t -> Exp.t -> unit
|
||
10 years ago
|
end
|
||
|
|
||
|
module Dangling : sig
|
||
9 years ago
|
val init : Prop.sigma -> Prop.sigma -> unit
|
||
8 years ago
|
|
||
10 years ago
|
val final : unit -> unit
|
||
|
|
||
8 years ago
|
val check : side -> Exp.t -> bool
|
||
10 years ago
|
end = struct
|
||
9 years ago
|
let lexps1 = ref Exp.Set.empty
|
||
8 years ago
|
|
||
9 years ago
|
let lexps2 = ref Exp.Set.empty
|
||
10 years ago
|
|
||
|
let get_lexp_set' sigma =
|
||
|
let lexp_lst = Sil.hpred_list_get_lexps (fun _ -> true) sigma in
|
||
8 years ago
|
List.fold ~f:(fun set e -> Exp.Set.add e set) ~init:Exp.Set.empty lexp_lst
|
||
8 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let init sigma1 sigma2 =
|
||
8 years ago
|
lexps1 := get_lexp_set' sigma1 ;
|
||
10 years ago
|
lexps2 := get_lexp_set' sigma2
|
||
8 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let final () =
|
||
8 years ago
|
lexps1 := Exp.Set.empty ;
|
||
9 years ago
|
lexps2 := Exp.Set.empty
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
(* conservatively checks whether e is dangling *)
|
||
|
let check side e =
|
||
8 years ago
|
let lexps = match side with Lhs -> !lexps1 | Rhs -> !lexps2 in
|
||
10 years ago
|
match e with
|
||
7 years ago
|
| Exp.Var id ->
|
||
|
can_rename id && not (Exp.Set.mem e lexps)
|
||
|
| Exp.Const _ ->
|
||
|
not (Exp.Set.mem e lexps)
|
||
|
| Exp.BinOp _ ->
|
||
|
not (Exp.Set.mem e lexps)
|
||
|
| _ ->
|
||
|
false
|
||
10 years ago
|
end
|
||
|
|
||
|
module CheckJoinPre : InfoLossCheckerSig = struct
|
||
8 years ago
|
let init sigma1 sigma2 = NonInj.init () ; Dangling.init sigma1 sigma2
|
||
10 years ago
|
|
||
8 years ago
|
let final () = NonInj.final () ; Dangling.final ()
|
||
10 years ago
|
|
||
|
let fail_case side e es =
|
||
|
let side_op = opposite side in
|
||
|
match e with
|
||
7 years ago
|
| Exp.Lvar _ ->
|
||
|
false
|
||
|
| Exp.Var id when Ident.is_normal id ->
|
||
|
List.length es >= 1
|
||
|
| Exp.Var _ ->
|
||
|
if Int.equal Config.join_cond 0 then List.exists ~f:(Exp.equal Exp.zero) es
|
||
7 years ago
|
else if Dangling.check side e then (
|
||
8 years ago
|
let r = List.exists ~f:(fun e' -> not (Dangling.check side_op e')) es in
|
||
|
if r then (
|
||
|
L.d_str ".... Dangling Check (dang e:" ;
|
||
|
Sil.d_exp e ;
|
||
|
L.d_str ") (? es:" ;
|
||
|
Sil.d_exp_list es ;
|
||
|
L.d_strln ") ...." ;
|
||
|
L.d_ln () ) ;
|
||
7 years ago
|
r )
|
||
10 years ago
|
else
|
||
8 years ago
|
let r = List.exists ~f:(Dangling.check side_op) es in
|
||
|
if r then (
|
||
|
L.d_str ".... Dangling Check (notdang e:" ;
|
||
|
Sil.d_exp e ;
|
||
|
L.d_str ") (? es:" ;
|
||
|
Sil.d_exp_list es ;
|
||
|
L.d_strln ") ...." ;
|
||
|
L.d_ln () ) ;
|
||
|
r
|
||
7 years ago
|
| _ ->
|
||
|
false
|
||
|
|
||
10 years ago
|
|
||
|
let lost_little side e es =
|
||
|
let side_op = opposite side in
|
||
9 years ago
|
let es = match e with Exp.Const _ -> [] | _ -> es in
|
||
8 years ago
|
if fail_case side e es then false
|
||
|
else match es with [] | [_] -> true | _ -> NonInj.check side_op es
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let add = NonInj.add
|
||
|
end
|
||
|
|
||
|
module CheckJoinPost : InfoLossCheckerSig = struct
|
||
8 years ago
|
let init _ _ = NonInj.init ()
|
||
10 years ago
|
|
||
8 years ago
|
let final () = NonInj.final ()
|
||
10 years ago
|
|
||
9 years ago
|
let fail_case _ e es =
|
||
10 years ago
|
match e with
|
||
7 years ago
|
| Exp.Lvar _ ->
|
||
|
false
|
||
|
| Exp.Var id when Ident.is_normal id ->
|
||
|
List.length es >= 1
|
||
|
| Exp.Var _ ->
|
||
|
false
|
||
|
| _ ->
|
||
|
false
|
||
|
|
||
10 years ago
|
|
||
|
let lost_little side e es =
|
||
|
let side_op = opposite side in
|
||
9 years ago
|
let es = match e with Exp.Const _ -> [] | _ -> es in
|
||
8 years ago
|
if fail_case side e es then false
|
||
|
else match es with [] | [_] -> true | _ -> NonInj.check side_op es
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let add = NonInj.add
|
||
|
end
|
||
|
|
||
|
module CheckJoin : sig
|
||
9 years ago
|
val init : JoinState.mode -> Prop.sigma -> Prop.sigma -> unit
|
||
8 years ago
|
|
||
10 years ago
|
val final : unit -> unit
|
||
8 years ago
|
|
||
9 years ago
|
val lost_little : side -> Exp.t -> Exp.t list -> bool
|
||
10 years ago
|
|
||
8 years ago
|
val add : side -> Exp.t -> Exp.t -> unit
|
||
10 years ago
|
end = struct
|
||
|
let mode_ref : JoinState.mode ref = ref JoinState.Post
|
||
|
|
||
|
let init mode sigma1 sigma2 =
|
||
8 years ago
|
mode_ref := mode ;
|
||
10 years ago
|
match mode with
|
||
7 years ago
|
| JoinState.Pre ->
|
||
|
CheckJoinPre.init sigma1 sigma2
|
||
|
| JoinState.Post ->
|
||
|
CheckJoinPost.init sigma1 sigma2
|
||
|
|
||
10 years ago
|
|
||
|
let final () =
|
||
|
match !mode_ref with
|
||
7 years ago
|
| JoinState.Pre ->
|
||
|
CheckJoinPre.final () ;
|
||
8 years ago
|
mode_ref := JoinState.Post
|
||
7 years ago
|
| JoinState.Post ->
|
||
|
CheckJoinPost.final () ;
|
||
8 years ago
|
mode_ref := JoinState.Post
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let lost_little side e es =
|
||
|
match !mode_ref with
|
||
7 years ago
|
| JoinState.Pre ->
|
||
|
CheckJoinPre.lost_little side e es
|
||
|
| JoinState.Post ->
|
||
|
CheckJoinPost.lost_little side e es
|
||
|
|
||
10 years ago
|
|
||
|
let add side e1 e2 =
|
||
|
match !mode_ref with
|
||
7 years ago
|
| JoinState.Pre ->
|
||
|
CheckJoinPre.add side e1 e2
|
||
|
| JoinState.Post ->
|
||
|
CheckJoinPost.add side e1 e2
|
||
10 years ago
|
end
|
||
|
|
||
|
module CheckMeet : InfoLossCheckerSig = struct
|
||
9 years ago
|
let lexps1 = ref Exp.Set.empty
|
||
8 years ago
|
|
||
9 years ago
|
let lexps2 = ref Exp.Set.empty
|
||
10 years ago
|
|
||
|
let init sigma1 sigma2 =
|
||
|
let lexps1_lst = Sil.hpred_list_get_lexps (fun _ -> true) sigma1 in
|
||
|
let lexps2_lst = Sil.hpred_list_get_lexps (fun _ -> true) sigma2 in
|
||
8 years ago
|
lexps1 := Sil.elist_to_eset lexps1_lst ;
|
||
10 years ago
|
lexps2 := Sil.elist_to_eset lexps2_lst
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
let final () =
|
||
8 years ago
|
lexps1 := Exp.Set.empty ;
|
||
9 years ago
|
lexps2 := Exp.Set.empty
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let lost_little side e es =
|
||
8 years ago
|
let lexps = match side with Lhs -> !lexps1 | Rhs -> !lexps2 in
|
||
|
match (es, e) with
|
||
7 years ago
|
| [], _ ->
|
||
|
true
|
||
|
| [(Exp.Const _)], Exp.Lvar _ ->
|
||
|
false
|
||
|
| [(Exp.Const _)], Exp.Var _ ->
|
||
|
not (Exp.Set.mem e lexps)
|
||
|
| [(Exp.Const _)], _ ->
|
||
|
assert false
|
||
|
| [_], Exp.Lvar _ | [_], Exp.Var _ ->
|
||
|
true
|
||
|
| [_], _ ->
|
||
|
assert false
|
||
|
| _, Exp.Lvar _ | _, Exp.Var _ ->
|
||
|
false
|
||
|
| _, Exp.Const _ ->
|
||
|
assert false
|
||
|
| _ ->
|
||
|
assert false
|
||
|
|
||
10 years ago
|
|
||
|
let add = NonInj.add
|
||
|
end
|
||
|
|
||
|
(** {2 Module for worklist} *)
|
||
|
|
||
|
module Todo : sig
|
||
|
exception Empty
|
||
8 years ago
|
|
||
10 years ago
|
type t
|
||
8 years ago
|
|
||
10 years ago
|
val init : unit -> unit
|
||
8 years ago
|
|
||
10 years ago
|
val final : unit -> unit
|
||
8 years ago
|
|
||
9 years ago
|
val reset : (Exp.t * Exp.t * Exp.t) list -> unit
|
||
8 years ago
|
|
||
|
val push : Exp.t * Exp.t * Exp.t -> unit
|
||
|
|
||
|
val pop : unit -> Exp.t * Exp.t * Exp.t
|
||
|
|
||
10 years ago
|
val set : t -> unit
|
||
|
|
||
8 years ago
|
val take : unit -> t
|
||
10 years ago
|
end = struct
|
||
|
exception Empty
|
||
8 years ago
|
|
||
9 years ago
|
type t = (Exp.t * Exp.t * Exp.t) list
|
||
10 years ago
|
|
||
|
let tbl = ref []
|
||
|
|
||
|
let init () = tbl := []
|
||
8 years ago
|
|
||
10 years ago
|
let final () = tbl := []
|
||
8 years ago
|
|
||
10 years ago
|
let reset todo = tbl := todo
|
||
|
|
||
8 years ago
|
let push e = tbl := e :: !tbl
|
||
|
|
||
10 years ago
|
let pop () =
|
||
|
match !tbl with
|
||
7 years ago
|
| h :: t ->
|
||
|
tbl := t ;
|
||
8 years ago
|
h
|
||
7 years ago
|
| _ ->
|
||
|
raise Empty
|
||
|
|
||
10 years ago
|
|
||
|
let set todo = tbl := todo
|
||
|
|
||
8 years ago
|
let take () =
|
||
|
let res = !tbl in
|
||
|
tbl := [] ;
|
||
|
res
|
||
10 years ago
|
end
|
||
|
|
||
|
(** {2 Module for introducing fresh variables} *)
|
||
|
|
||
|
module FreshVarExp : sig
|
||
|
val init : unit -> unit
|
||
8 years ago
|
|
||
9 years ago
|
val get_fresh_exp : Exp.t -> Exp.t -> Exp.t
|
||
8 years ago
|
|
||
9 years ago
|
val get_induced_pi : Tenv.t -> unit -> Prop.pi
|
||
10 years ago
|
|
||
8 years ago
|
val final : unit -> unit
|
||
|
(*
|
||
9 years ago
|
val lookup : side -> Exp.t -> (Exp.t * Exp.t) option
|
||
9 years ago
|
*)
|
||
10 years ago
|
end = struct
|
||
|
let t = ref []
|
||
|
|
||
|
let init () = t := []
|
||
8 years ago
|
|
||
10 years ago
|
let final () = t := []
|
||
|
|
||
9 years ago
|
let entry_compare (e1, e2, _) (_, e2', _) =
|
||
9 years ago
|
let n1 = Exp.compare e1 e2 in
|
||
|
if n1 <> 0 then n1 else Exp.compare e2 e2'
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let get_fresh_exp e1 e2 =
|
||
8 years ago
|
match
|
||
8 years ago
|
List.find ~f:(fun (e1', e2', _) -> Exp.equal e1 e1' && Exp.equal e2 e2') !t
|
||
|
|> Option.map ~f:trd3
|
||
8 years ago
|
with
|
||
7 years ago
|
| Some res ->
|
||
|
res
|
||
|
| None ->
|
||
|
let e = Exp.get_undefined (JoinState.get_footprint ()) in
|
||
8 years ago
|
t := (e1, e2, e) :: !t ;
|
||
8 years ago
|
e
|
||
10 years ago
|
|
||
7 years ago
|
|
||
9 years ago
|
let get_induced_atom tenv acc strict_lower upper e =
|
||
8 years ago
|
let ineq_lower = Prop.mk_inequality tenv (Exp.BinOp (Binop.Lt, strict_lower, e)) in
|
||
|
let ineq_upper = Prop.mk_inequality tenv (Exp.BinOp (Binop.Le, e, upper)) in
|
||
|
ineq_lower :: ineq_upper :: acc
|
||
10 years ago
|
|
||
7 years ago
|
|
||
8 years ago
|
let minus2_to_2 = List.map ~f:IntLit.of_int [-2; -1; 0; 1; 2]
|
||
10 years ago
|
|
||
9 years ago
|
let get_induced_pi tenv () =
|
||
8 years ago
|
let t_sorted = List.sort ~cmp:entry_compare !t in
|
||
10 years ago
|
let add_and_chk_eq e1 e1' n =
|
||
8 years ago
|
match (e1, e1') with
|
||
7 years ago
|
| Exp.Const Const.Cint n1, Exp.Const Const.Cint n1' ->
|
||
|
IntLit.eq (n1 ++ n) n1'
|
||
|
| _ ->
|
||
|
false
|
||
8 years ago
|
in
|
||
10 years ago
|
let add_and_gen_eq e e' n =
|
||
8 years ago
|
let e_plus_n = Exp.BinOp (Binop.PlusA, e, Exp.int n) in
|
||
|
Prop.mk_eq tenv e_plus_n e'
|
||
|
in
|
||
7 years ago
|
let rec f_eqs_entry ((e1, e2, e) as entry) eqs_acc t_seen = function
|
||
|
| [] ->
|
||
|
(eqs_acc, t_seen)
|
||
|
| ((e1', e2', e') as entry') :: t_rest' ->
|
||
8 years ago
|
match
|
||
|
List.find ~f:(fun n -> add_and_chk_eq e1 e1' n && add_and_chk_eq e2 e2' n) minus2_to_2
|
||
|
|> Option.map ~f:(fun n ->
|
||
8 years ago
|
let eq = add_and_gen_eq e e' n in
|
||
8 years ago
|
let eqs_acc' = eq :: eqs_acc in
|
||
|
f_eqs_entry entry eqs_acc' t_seen t_rest' )
|
||
|
with
|
||
7 years ago
|
| Some res ->
|
||
|
res
|
||
|
| None ->
|
||
|
let t_seen' = entry' :: t_seen in
|
||
8 years ago
|
f_eqs_entry entry eqs_acc t_seen' t_rest'
|
||
|
in
|
||
10 years ago
|
let rec f_eqs eqs_acc t_acc = function
|
||
7 years ago
|
| [] ->
|
||
|
(eqs_acc, t_acc)
|
||
|
| entry :: t_rest ->
|
||
|
let eqs_acc', t_rest' = f_eqs_entry entry eqs_acc [] t_rest in
|
||
8 years ago
|
let t_acc' = entry :: t_acc in
|
||
|
f_eqs eqs_acc' t_acc' t_rest'
|
||
|
in
|
||
10 years ago
|
let eqs, t_minimal = f_eqs [] [] t_sorted in
|
||
|
let f_ineqs acc (e1, e2, e) =
|
||
8 years ago
|
match (e1, e2) with
|
||
7 years ago
|
| Exp.Const Const.Cint n1, Exp.Const Const.Cint n2 ->
|
||
|
let strict_lower1, upper1 =
|
||
8 years ago
|
if IntLit.leq n1 n2 then (n1 -- IntLit.one, n2) else (n2 -- IntLit.one, n1)
|
||
|
in
|
||
9 years ago
|
let e_strict_lower1 = Exp.int strict_lower1 in
|
||
|
let e_upper1 = Exp.int upper1 in
|
||
9 years ago
|
get_induced_atom tenv acc e_strict_lower1 e_upper1 e
|
||
7 years ago
|
| _ ->
|
||
|
acc
|
||
8 years ago
|
in
|
||
8 years ago
|
List.fold ~f:f_ineqs ~init:eqs t_minimal
|
||
10 years ago
|
end
|
||
|
|
||
|
(** {2 Modules for renaming} *)
|
||
|
|
||
|
module Rename : sig
|
||
9 years ago
|
type data_opt = ExtFresh | ExtDefault of Exp.t
|
||
10 years ago
|
|
||
|
val init : unit -> unit
|
||
8 years ago
|
|
||
10 years ago
|
val final : unit -> unit
|
||
8 years ago
|
|
||
9 years ago
|
val reset : unit -> (Exp.t * Exp.t * Exp.t) list
|
||
10 years ago
|
|
||
9 years ago
|
val extend : Exp.t -> Exp.t -> data_opt -> Exp.t
|
||
8 years ago
|
|
||
9 years ago
|
val check : (side -> Exp.t -> Exp.t list -> bool) -> bool
|
||
10 years ago
|
|
||
9 years ago
|
val get_others : side -> Exp.t -> (Exp.t * Exp.t) option
|
||
8 years ago
|
|
||
9 years ago
|
val get_other_atoms : Tenv.t -> side -> Sil.atom -> (Sil.atom * Sil.atom) option
|
||
10 years ago
|
|
||
9 years ago
|
val lookup : side -> Exp.t -> Exp.t
|
||
8 years ago
|
|
||
9 years ago
|
val lookup_list : side -> Exp.t list -> Exp.t list
|
||
8 years ago
|
|
||
9 years ago
|
val lookup_list_todo : side -> Exp.t list -> Exp.t list
|
||
10 years ago
|
|
||
7 years ago
|
val to_subst_proj : side -> unit Ident.HashQueue.t -> Sil.exp_subst
|
||
8 years ago
|
|
||
8 years ago
|
val to_subst_emb : side -> Sil.exp_subst
|
||
8 years ago
|
(*
|
||
9 years ago
|
val get : Exp.t -> Exp.t -> Exp.t option
|
||
|
val pp : printenv -> Format.formatter -> (Exp.t * Exp.t * Exp.t) list -> unit
|
||
9 years ago
|
*)
|
||
10 years ago
|
end = struct
|
||
9 years ago
|
type t = (Exp.t * Exp.t * Exp.t) list
|
||
9 years ago
|
|
||
|
let tbl : t ref = ref []
|
||
10 years ago
|
|
||
|
let init () = tbl := []
|
||
8 years ago
|
|
||
10 years ago
|
let final () = tbl := []
|
||
8 years ago
|
|
||
10 years ago
|
let reset () =
|
||
|
let f = function
|
||
7 years ago
|
| Exp.Var id, e, _ | e, Exp.Var id, _ ->
|
||
|
Ident.is_footprint id
|
||
7 years ago
|
&& Exp.free_vars e |> Sequence.for_all ~f:(fun id -> not (Ident.is_primed id))
|
||
7 years ago
|
| _ ->
|
||
|
false
|
||
8 years ago
|
in
|
||
8 years ago
|
let t' = List.filter ~f !tbl in
|
||
8 years ago
|
tbl := t' ;
|
||
10 years ago
|
t'
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
let push v = tbl := v :: !tbl
|
||
|
|
||
|
let check lost_little =
|
||
|
let f side e =
|
||
|
let side_op = opposite side in
|
||
|
let assoc_es =
|
||
|
match e with
|
||
7 years ago
|
| Exp.Const _ ->
|
||
|
[]
|
||
|
| Exp.Lvar _ | Exp.Var _ | Exp.BinOp (Binop.PlusA, Exp.Var _, _) ->
|
||
|
let is_same_e (e1, e2, _) = Exp.equal e (select side e1 e2) in
|
||
8 years ago
|
let assoc = List.filter ~f:is_same_e !tbl in
|
||
8 years ago
|
List.map ~f:(fun (e1, e2, _) -> select side_op e1 e2) assoc
|
||
7 years ago
|
| _ ->
|
||
|
L.d_str "no pattern match in check lost_little e: " ;
|
||
8 years ago
|
Sil.d_exp e ;
|
||
|
L.d_ln () ;
|
||
|
raise Sil.JoinFail
|
||
|
in
|
||
|
lost_little side e assoc_es
|
||
|
in
|
||
8 years ago
|
let lhs_es = List.map ~f:(fun (e1, _, _) -> e1) !tbl in
|
||
|
let rhs_es = List.map ~f:(fun (_, e2, _) -> e2) !tbl in
|
||
8 years ago
|
List.for_all ~f:(f Rhs) rhs_es && List.for_all ~f:(f Lhs) lhs_es
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let lookup_side' side e =
|
||
9 years ago
|
let f (e1, e2, _) = Exp.equal e (select side e1 e2) in
|
||
8 years ago
|
List.filter ~f !tbl
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let lookup_side_induced' side e =
|
||
|
let res = ref [] in
|
||
8 years ago
|
let f v =
|
||
|
match (v, side) with
|
||
7 years ago
|
| (Exp.BinOp (Binop.PlusA, e1', Exp.Const Const.Cint i), e2, e'), Lhs when Exp.equal e e1' ->
|
||
|
let c' = Exp.int (IntLit.neg i) in
|
||
8 years ago
|
let v' = (e1', Exp.BinOp (Binop.PlusA, e2, c'), Exp.BinOp (Binop.PlusA, e', c')) in
|
||
|
res := v' :: !res
|
||
7 years ago
|
| (e1, Exp.BinOp (Binop.PlusA, e2', Exp.Const Const.Cint i), e'), Rhs when Exp.equal e e2' ->
|
||
|
let c' = Exp.int (IntLit.neg i) in
|
||
8 years ago
|
let v' = (Exp.BinOp (Binop.PlusA, e1, c'), e2', Exp.BinOp (Binop.PlusA, e', c')) in
|
||
|
res := v' :: !res
|
||
7 years ago
|
| _ ->
|
||
|
()
|
||
8 years ago
|
in
|
||
|
List.iter ~f !tbl ;
|
||
|
List.rev !res
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
(* Return the triple whose side is [e], if it exists unique *)
|
||
9 years ago
|
let lookup' todo side e : Exp.t =
|
||
10 years ago
|
match e with
|
||
8 years ago
|
| Exp.Var id when can_rename id
|
||
7 years ago
|
-> (
|
||
8 years ago
|
let r = lookup_side' side e in
|
||
|
match r with
|
||
7 years ago
|
| [((_, _, id) as t)] ->
|
||
|
if todo then Todo.push t ;
|
||
8 years ago
|
id
|
||
7 years ago
|
| _ ->
|
||
|
L.d_strln "failure reason 9" ; raise Sil.JoinFail )
|
||
|
| Exp.Var _ | Exp.Const _ | Exp.Lvar _ ->
|
||
|
if todo then Todo.push (e, e, e) ;
|
||
8 years ago
|
e
|
||
7 years ago
|
| _ ->
|
||
|
L.d_strln "failure reason 10" ; raise Sil.JoinFail
|
||
|
|
||
10 years ago
|
|
||
|
let lookup side e = lookup' false side e
|
||
8 years ago
|
|
||
10 years ago
|
let lookup_todo side e = lookup' true side e
|
||
8 years ago
|
|
||
8 years ago
|
let lookup_list side l = List.map ~f:(lookup side) l
|
||
8 years ago
|
|
||
8 years ago
|
let lookup_list_todo side l = List.map ~f:(lookup_todo side) l
|
||
10 years ago
|
|
||
|
let to_subst_proj (side: side) vars =
|
||
|
let renaming_restricted =
|
||
7 years ago
|
List.filter
|
||
|
~f:(function _, _, Exp.Var i -> Ident.HashQueue.mem vars i | _ -> assert false)
|
||
|
!tbl
|
||
8 years ago
|
in
|
||
10 years ago
|
let sub_list_side =
|
||
8 years ago
|
List.map
|
||
8 years ago
|
~f:(function e1, e2, Exp.Var i -> (i, select side e1 e2) | _ -> assert false)
|
||
|
renaming_restricted
|
||
|
in
|
||
10 years ago
|
let sub_list_side_sorted =
|
||
8 years ago
|
List.sort ~cmp:(fun (_, e) (_, e') -> Exp.compare e e') sub_list_side
|
||
|
in
|
||
|
let rec find_duplicates = function
|
||
7 years ago
|
| (_, e) :: ((_, e') :: _ as t) ->
|
||
|
Exp.equal e e' || find_duplicates t
|
||
|
| _ ->
|
||
|
false
|
||
8 years ago
|
in
|
||
|
if find_duplicates sub_list_side_sorted then (
|
||
|
L.d_strln "failure reason 11" ; raise Sil.JoinFail )
|
||
8 years ago
|
else Sil.exp_subst_of_list sub_list_side
|
||
10 years ago
|
|
||
7 years ago
|
|
||
8 years ago
|
let to_subst_emb (side: side) =
|
||
10 years ago
|
let renaming_restricted =
|
||
9 years ago
|
let pick_id_case (e1, e2, _) =
|
||
8 years ago
|
match select side e1 e2 with Exp.Var i -> can_rename i | _ -> false
|
||
|
in
|
||
|
List.filter ~f:pick_id_case !tbl
|
||
|
in
|
||
10 years ago
|
let sub_list =
|
||
|
let project (e1, e2, e) =
|
||
8 years ago
|
match select side e1 e2 with Exp.Var i -> (i, e) | _ -> assert false
|
||
|
in
|
||
|
List.map ~f:project renaming_restricted
|
||
|
in
|
||
10 years ago
|
let sub_list_sorted =
|
||
|
let compare (i, _) (i', _) = Ident.compare i i' in
|
||
8 years ago
|
List.sort ~cmp:compare sub_list
|
||
|
in
|
||
10 years ago
|
let rec find_duplicates = function
|
||
7 years ago
|
| (i, _) :: ((i', _) :: _ as t) ->
|
||
|
Ident.equal i i' || find_duplicates t
|
||
|
| _ ->
|
||
|
false
|
||
8 years ago
|
in
|
||
|
if find_duplicates sub_list_sorted then ( L.d_strln "failure reason 12" ; raise Sil.JoinFail )
|
||
8 years ago
|
else Sil.exp_subst_of_list sub_list_sorted
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let get_others' f_lookup side e =
|
||
|
let side_op = opposite side in
|
||
|
let r = f_lookup side e in
|
||
8 years ago
|
match r with [] -> None | [(e1, e2, e')] -> Some (e', select side_op e1 e2) | _ -> None
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
let get_others = get_others' lookup_side'
|
||
8 years ago
|
|
||
10 years ago
|
let get_others_direct_or_induced side e =
|
||
|
let others = get_others side e in
|
||
8 years ago
|
match others with None -> get_others' lookup_side_induced' side e | Some _ -> others
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
let get_others_deep side = function
|
||
8 years ago
|
| Exp.BinOp (op, e, e')
|
||
7 years ago
|
-> (
|
||
10 years ago
|
let others = get_others_direct_or_induced side e in
|
||
|
let others' = get_others_direct_or_induced side e' in
|
||
8 years ago
|
match (others, others') with
|
||
7 years ago
|
| None, _ | _, None ->
|
||
|
None
|
||
|
| Some (e_res, e_op), Some (e_res', e_op') ->
|
||
|
let e_res'' = Exp.BinOp (op, e_res, e_res') in
|
||
8 years ago
|
let e_op'' = Exp.BinOp (op, e_op, e_op') in
|
||
|
Some (e_res'', e_op'') )
|
||
7 years ago
|
| _ ->
|
||
|
None
|
||
|
|
||
10 years ago
|
|
||
9 years ago
|
let get_other_atoms tenv side atom_in =
|
||
10 years ago
|
let build_other_atoms construct side e =
|
||
8 years ago
|
if Config.trace_join then ( L.d_str "build_other_atoms: " ; Sil.d_exp e ; L.d_ln () ) ;
|
||
10 years ago
|
let others1 = get_others_direct_or_induced side e in
|
||
|
let others2 = match others1 with None -> get_others_deep side e | Some _ -> others1 in
|
||
|
match others2 with
|
||
7 years ago
|
| None ->
|
||
|
None
|
||
|
| Some (e_res, e_op) ->
|
||
|
let a_res = construct e_res in
|
||
10 years ago
|
let a_op = construct e_op in
|
||
8 years ago
|
if Config.trace_join then (
|
||
|
L.d_str "build_other_atoms (successful) " ;
|
||
|
Sil.d_atom a_res ;
|
||
|
L.d_str ", " ;
|
||
|
Sil.d_atom a_op ;
|
||
|
L.d_ln () ) ;
|
||
|
Some (a_res, a_op)
|
||
|
in
|
||
7 years ago
|
let exp_contains_only_normal_ids e = Exp.free_vars e |> Sequence.for_all ~f:Ident.is_normal in
|
||
10 years ago
|
let atom_contains_only_normal_ids a =
|
||
7 years ago
|
Sil.atom_free_vars a |> Sequence.for_all ~f:Ident.is_normal
|
||
8 years ago
|
in
|
||
10 years ago
|
let normal_ids_only = atom_contains_only_normal_ids atom_in in
|
||
|
if normal_ids_only then Some (atom_in, atom_in)
|
||
|
else
|
||
8 years ago
|
match atom_in with
|
||
|
| Sil.Aneq ((Exp.Var id as e), e')
|
||
7 years ago
|
when exp_contains_only_normal_ids e' && not (Ident.is_normal id) ->
|
||
|
(* e' cannot also be a normal id according to the guard so we can consider the two cases
|
||
8 years ago
|
separately (this case and the next) *)
|
||
8 years ago
|
build_other_atoms (fun e0 -> Prop.mk_neq tenv e0 e') side e
|
||
|
| Sil.Aneq (e', (Exp.Var id as e))
|
||
7 years ago
|
when exp_contains_only_normal_ids e' && not (Ident.is_normal id) ->
|
||
|
build_other_atoms (fun e0 -> Prop.mk_neq tenv e0 e') side e
|
||
8 years ago
|
| Sil.Apred (a, (Var id as e) :: es)
|
||
7 years ago
|
when not (Ident.is_normal id) && List.for_all ~f:exp_contains_only_normal_ids es ->
|
||
|
build_other_atoms (fun e0 -> Prop.mk_pred tenv a (e0 :: es)) side e
|
||
8 years ago
|
| Sil.Anpred (a, (Var id as e) :: es)
|
||
7 years ago
|
when not (Ident.is_normal id) && List.for_all ~f:exp_contains_only_normal_ids es ->
|
||
|
build_other_atoms (fun e0 -> Prop.mk_npred tenv a (e0 :: es)) side e
|
||
8 years ago
|
| Sil.Aeq ((Exp.Var id as e), e')
|
||
7 years ago
|
when exp_contains_only_normal_ids e' && not (Ident.is_normal id) ->
|
||
|
(* e' cannot also be a normal id according to the guard so we can consider the two cases
|
||
8 years ago
|
separately (this case and the next) *)
|
||
8 years ago
|
build_other_atoms (fun e0 -> Prop.mk_eq tenv e0 e') side e
|
||
|
| Sil.Aeq (e', (Exp.Var id as e))
|
||
7 years ago
|
when exp_contains_only_normal_ids e' && not (Ident.is_normal id) ->
|
||
|
build_other_atoms (fun e0 -> Prop.mk_eq tenv e0 e') side e
|
||
8 years ago
|
| Sil.Aeq (Exp.BinOp (Binop.Le, e, e'), Exp.Const Const.Cint i)
|
||
|
| Sil.Aeq (Exp.Const Const.Cint i, Exp.BinOp (Binop.Le, e, e'))
|
||
7 years ago
|
when IntLit.isone i && exp_contains_only_normal_ids e' ->
|
||
|
let construct e0 = Prop.mk_inequality tenv (Exp.BinOp (Binop.Le, e0, e')) in
|
||
8 years ago
|
build_other_atoms construct side e
|
||
|
| Sil.Aeq (Exp.BinOp (Binop.Lt, e', e), Exp.Const Const.Cint i)
|
||
|
| Sil.Aeq (Exp.Const Const.Cint i, Exp.BinOp (Binop.Lt, e', e))
|
||
7 years ago
|
when IntLit.isone i && exp_contains_only_normal_ids e' ->
|
||
|
let construct e0 = Prop.mk_inequality tenv (Exp.BinOp (Binop.Lt, e', e0)) in
|
||
8 years ago
|
build_other_atoms construct side e
|
||
7 years ago
|
| Sil.Aeq _ | Aneq _ | Apred _ | Anpred _ ->
|
||
|
None
|
||
|
|
||
10 years ago
|
|
||
9 years ago
|
type data_opt = ExtFresh | ExtDefault of Exp.t
|
||
10 years ago
|
|
||
|
(* Extend the renaming relation. At least one of e1 and e2
|
||
10 years ago
|
* should be a primed or footprint variable *)
|
||
10 years ago
|
let extend e1 e2 default_op =
|
||
8 years ago
|
match
|
||
8 years ago
|
List.find ~f:(fun (f1, f2, _) -> Exp.equal e1 f1 && Exp.equal e2 f2) !tbl
|
||
|
|> Option.map ~f:trd3
|
||
8 years ago
|
with
|
||
7 years ago
|
| Some res ->
|
||
|
res
|
||
|
| None ->
|
||
8 years ago
|
let some_primed () =
|
||
7 years ago
|
Exp.free_vars e1 |> Sequence.exists ~f:Ident.is_primed
|
||
|
|| Exp.free_vars e2 |> Sequence.exists ~f:Ident.is_primed
|
||
8 years ago
|
in
|
||
8 years ago
|
let e =
|
||
7 years ago
|
if not (Exp.free_vars e1 |> Sequence.exists ~f:can_rename)
|
||
|
&& not (Exp.free_vars e2 |> Sequence.exists ~f:can_rename)
|
||
|
then
|
||
8 years ago
|
if Exp.equal e1 e2 then e1 else ( L.d_strln "failure reason 13" ; raise Sil.JoinFail )
|
||
8 years ago
|
else
|
||
|
match default_op with
|
||
7 years ago
|
| ExtDefault e ->
|
||
|
e
|
||
|
| ExtFresh ->
|
||
|
let kind =
|
||
8 years ago
|
if JoinState.get_footprint () && not (some_primed ()) then Ident.kfootprint
|
||
|
else Ident.kprimed
|
||
|
in
|
||
|
Exp.Var (Ident.create_fresh kind)
|
||
|
in
|
||
|
let entry = (e1, e2, e) in
|
||
|
push entry ; Todo.push entry ; e
|
||
10 years ago
|
end
|
||
|
|
||
|
(** {2 Functions for constructing fresh sil data types} *)
|
||
|
|
||
|
let extend_side' kind side e =
|
||
|
match Rename.get_others side e with
|
||
7 years ago
|
| None ->
|
||
|
let e_op = Exp.Var (Ident.create_fresh kind) in
|
||
9 years ago
|
let e_new = Exp.Var (Ident.create_fresh kind) in
|
||
8 years ago
|
let e1, e2 = match side with Lhs -> (e, e_op) | Rhs -> (e_op, e) in
|
||
|
Rename.extend e1 e2 (Rename.ExtDefault e_new)
|
||
7 years ago
|
| Some (e', _) ->
|
||
|
e'
|
||
|
|
||
10 years ago
|
|
||
|
let rec exp_construct_fresh side e =
|
||
|
match e with
|
||
7 years ago
|
| Exp.Var id ->
|
||
|
if Ident.is_normal id then (
|
||
8 years ago
|
Todo.push (e, e, e) ;
|
||
|
e )
|
||
|
else if Ident.is_footprint id then extend_side' Ident.kfootprint side e
|
||
|
else extend_side' Ident.kprimed side e
|
||
7 years ago
|
| Exp.Const _ ->
|
||
|
e
|
||
|
| Exp.Cast (t, e1) ->
|
||
|
let e1' = exp_construct_fresh side e1 in
|
||
9 years ago
|
Exp.Cast (t, e1')
|
||
7 years ago
|
| Exp.UnOp (unop, e1, topt) ->
|
||
|
let e1' = exp_construct_fresh side e1 in
|
||
8 years ago
|
Exp.UnOp (unop, e1', topt)
|
||
7 years ago
|
| Exp.BinOp (binop, e1, e2) ->
|
||
|
let e1' = exp_construct_fresh side e1 in
|
||
10 years ago
|
let e2' = exp_construct_fresh side e2 in
|
||
8 years ago
|
Exp.BinOp (binop, e1', e2')
|
||
7 years ago
|
| Exp.Exn _ ->
|
||
|
e
|
||
|
| Exp.Closure _ ->
|
||
|
e
|
||
|
| Exp.Lvar _ ->
|
||
|
e
|
||
|
| Exp.Lfield (e1, fld, typ) ->
|
||
|
let e1' = exp_construct_fresh side e1 in
|
||
8 years ago
|
Exp.Lfield (e1', fld, typ)
|
||
7 years ago
|
| Exp.Lindex (e1, e2) ->
|
||
|
let e1' = exp_construct_fresh side e1 in
|
||
10 years ago
|
let e2' = exp_construct_fresh side e2 in
|
||
8 years ago
|
Exp.Lindex (e1', e2')
|
||
7 years ago
|
| Exp.Sizeof {dynamic_length= None} ->
|
||
|
e
|
||
|
| Exp.Sizeof ({dynamic_length= Some len} as sizeof) ->
|
||
|
Exp.Sizeof {sizeof with dynamic_length= Some (exp_construct_fresh side len)}
|
||
|
|
||
10 years ago
|
|
||
|
let strexp_construct_fresh side =
|
||
|
let f (e, inst_opt) = (exp_construct_fresh side e, inst_opt) in
|
||
|
Sil.strexp_expmap f
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
let hpred_construct_fresh side =
|
||
|
let f (e, inst_opt) = (exp_construct_fresh side e, inst_opt) in
|
||
|
Sil.hpred_expmap f
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
(** {2 Join and Meet for Ids} *)
|
||
|
|
||
|
let ident_same_kind_primed_footprint id1 id2 =
|
||
8 years ago
|
Ident.is_primed id1 && Ident.is_primed id2 || Ident.is_footprint id1 && Ident.is_footprint id2
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let ident_partial_join (id1: Ident.t) (id2: Ident.t) =
|
||
8 years ago
|
match (Ident.is_normal id1, Ident.is_normal id2) with
|
||
7 years ago
|
| true, true ->
|
||
|
if Ident.equal id1 id2 then Exp.Var id1
|
||
8 years ago
|
else ( L.d_strln "failure reason 14" ; raise Sil.JoinFail )
|
||
7 years ago
|
| true, _ | _, true ->
|
||
|
Rename.extend (Exp.Var id1) (Exp.Var id2) Rename.ExtFresh
|
||
|
| _ ->
|
||
|
if not (ident_same_kind_primed_footprint id1 id2) then (
|
||
8 years ago
|
L.d_strln "failure reason 15" ; raise Sil.JoinFail )
|
||
|
else
|
||
|
let e1 = Exp.Var id1 in
|
||
|
let e2 = Exp.Var id2 in
|
||
|
Rename.extend e1 e2 Rename.ExtFresh
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let ident_partial_meet (id1: Ident.t) (id2: Ident.t) =
|
||
8 years ago
|
match (Ident.is_normal id1, Ident.is_normal id2) with
|
||
7 years ago
|
| true, true ->
|
||
|
if Ident.equal id1 id2 then Exp.Var id1
|
||
8 years ago
|
else ( L.d_strln "failure reason 16" ; raise Sil.JoinFail )
|
||
7 years ago
|
| true, _ ->
|
||
|
let e1, e2 = (Exp.Var id1, Exp.Var id2) in
|
||
8 years ago
|
Rename.extend e1 e2 (Rename.ExtDefault e1)
|
||
7 years ago
|
| _, true ->
|
||
|
let e1, e2 = (Exp.Var id1, Exp.Var id2) in
|
||
8 years ago
|
Rename.extend e1 e2 (Rename.ExtDefault e2)
|
||
7 years ago
|
| _ ->
|
||
|
if Ident.is_primed id1 && Ident.is_primed id2 then
|
||
9 years ago
|
Rename.extend (Exp.Var id1) (Exp.Var id2) Rename.ExtFresh
|
||
10 years ago
|
else if Ident.is_footprint id1 && Ident.equal id1 id2 then
|
||
8 years ago
|
let e = Exp.Var id1 in
|
||
|
Rename.extend e e (Rename.ExtDefault e)
|
||
|
else ( L.d_strln "failure reason 17" ; raise Sil.JoinFail )
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
(** {2 Join and Meet for Exps} *)
|
||
|
|
||
9 years ago
|
let option_partial_join partial_join o1 o2 =
|
||
8 years ago
|
match (o1, o2) with None, _ -> o2 | _, None -> o1 | Some x1, Some x2 -> partial_join x1 x2
|
||
9 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let const_partial_join c1 c2 =
|
||
9 years ago
|
let is_int = function Const.Cint _ -> true | _ -> false in
|
||
9 years ago
|
if Const.equal c1 c2 then Exp.Const c1
|
||
8 years ago
|
else if Const.kind_equal c1 c2 && not (is_int c1) then (
|
||
|
L.d_strln "failure reason 18" ; raise Sil.JoinFail )
|
||
|
else if !Config.abs_val >= 2 then FreshVarExp.get_fresh_exp (Exp.Const c1) (Exp.Const c2)
|
||
|
else ( L.d_strln "failure reason 19" ; raise Sil.JoinFail )
|
||
10 years ago
|
|
||
7 years ago
|
|
||
9 years ago
|
let rec exp_partial_join (e1: Exp.t) (e2: Exp.t) : Exp.t =
|
||
10 years ago
|
(* L.d_str "exp_partial_join "; Sil.d_exp e1; L.d_str " "; Sil.d_exp e2; L.d_ln (); *)
|
||
8 years ago
|
match (e1, e2) with
|
||
7 years ago
|
| Exp.Var id1, Exp.Var id2 ->
|
||
|
ident_partial_join id1 id2
|
||
|
| Exp.Var id, Exp.Const _ | Exp.Const _, Exp.Var id ->
|
||
|
if Ident.is_normal id then ( L.d_strln "failure reason 20" ; raise Sil.JoinFail )
|
||
10 years ago
|
else Rename.extend e1 e2 Rename.ExtFresh
|
||
7 years ago
|
| Exp.Const c1, Exp.Const c2 ->
|
||
|
const_partial_join c1 c2
|
||
|
| Exp.Var id, Exp.Lvar _ | Exp.Lvar _, Exp.Var id ->
|
||
|
if Ident.is_normal id then ( L.d_strln "failure reason 21" ; raise Sil.JoinFail )
|
||
8 years ago
|
else Rename.extend e1 e2 Rename.ExtFresh
|
||
|
| Exp.BinOp (Binop.PlusA, Exp.Var id1, Exp.Const _), Exp.Var id2
|
||
|
| Exp.Var id1, Exp.BinOp (Binop.PlusA, Exp.Var id2, Exp.Const _)
|
||
7 years ago
|
when ident_same_kind_primed_footprint id1 id2 ->
|
||
|
Rename.extend e1 e2 Rename.ExtFresh
|
||
8 years ago
|
| Exp.BinOp (Binop.PlusA, Exp.Var id1, Exp.Const Const.Cint c1), Exp.Const Const.Cint c2
|
||
7 years ago
|
when can_rename id1 ->
|
||
|
let c2' = c2 -- c1 in
|
||
9 years ago
|
let e_res = Rename.extend (Exp.Var id1) (Exp.int c2') Rename.ExtFresh in
|
||
8 years ago
|
Exp.BinOp (Binop.PlusA, e_res, Exp.int c1)
|
||
|
| Exp.Const Const.Cint c1, Exp.BinOp (Binop.PlusA, Exp.Var id2, Exp.Const Const.Cint c2)
|
||
7 years ago
|
when can_rename id2 ->
|
||
|
let c1' = c1 -- c2 in
|
||
9 years ago
|
let e_res = Rename.extend (Exp.int c1') (Exp.Var id2) Rename.ExtFresh in
|
||
8 years ago
|
Exp.BinOp (Binop.PlusA, e_res, Exp.int c2)
|
||
7 years ago
|
| Exp.Cast (t1, e1), Exp.Cast (t2, e2) ->
|
||
|
if not (Typ.equal t1 t2) then ( L.d_strln "failure reason 22" ; raise Sil.JoinFail )
|
||
10 years ago
|
else
|
||
|
let e1'' = exp_partial_join e1 e2 in
|
||
9 years ago
|
Exp.Cast (t1, e1'')
|
||
7 years ago
|
| Exp.UnOp (unop1, e1, topt1), Exp.UnOp (unop2, e2, _) ->
|
||
|
if not (Unop.equal unop1 unop2) then ( L.d_strln "failure reason 23" ; raise Sil.JoinFail )
|
||
8 years ago
|
else Exp.UnOp (unop1, exp_partial_join e1 e2, topt1)
|
||
|
(* should be topt1 = topt2 *)
|
||
7 years ago
|
| Exp.BinOp (Binop.PlusPI, e1, e1'), Exp.BinOp (Binop.PlusPI, e2, e2') ->
|
||
|
let e1'' = exp_partial_join e1 e2 in
|
||
8 years ago
|
let e2'' =
|
||
|
match (e1', e2') with
|
||
7 years ago
|
| Exp.Const _, Exp.Const _ ->
|
||
|
exp_partial_join e1' e2'
|
||
|
| _ ->
|
||
|
FreshVarExp.get_fresh_exp e1 e2
|
||
8 years ago
|
in
|
||
|
Exp.BinOp (Binop.PlusPI, e1'', e2'')
|
||
7 years ago
|
| Exp.BinOp (binop1, e1, e1'), Exp.BinOp (binop2, e2, e2') ->
|
||
|
if not (Binop.equal binop1 binop2) then ( L.d_strln "failure reason 24" ; raise Sil.JoinFail )
|
||
10 years ago
|
else
|
||
|
let e1'' = exp_partial_join e1 e2 in
|
||
|
let e2'' = exp_partial_join e1' e2' in
|
||
8 years ago
|
Exp.BinOp (binop1, e1'', e2'')
|
||
7 years ago
|
| Exp.Lvar pvar1, Exp.Lvar pvar2 ->
|
||
|
if not (Pvar.equal pvar1 pvar2) then ( L.d_strln "failure reason 25" ; raise Sil.JoinFail )
|
||
10 years ago
|
else e1
|
||
7 years ago
|
| Exp.Lfield (e1, f1, t1), Exp.Lfield (e2, f2, _) ->
|
||
|
if not (Typ.Fieldname.equal f1 f2) then ( L.d_strln "failure reason 26" ; raise Sil.JoinFail )
|
||
8 years ago
|
else Exp.Lfield (exp_partial_join e1 e2, f1, t1)
|
||
|
(* should be t1 = t2 *)
|
||
7 years ago
|
| Exp.Lindex (e1, e1'), Exp.Lindex (e2, e2') ->
|
||
|
let e1'' = exp_partial_join e1 e2 in
|
||
10 years ago
|
let e2'' = exp_partial_join e1' e2' in
|
||
8 years ago
|
Exp.Lindex (e1'', e2'')
|
||
|
| ( Exp.Sizeof {typ= t1; nbytes= nbytes1; dynamic_length= len1; subtype= st1}
|
||
7 years ago
|
, Exp.Sizeof {typ= t2; nbytes= nbytes2; dynamic_length= len2; subtype= st2} ) ->
|
||
|
(* forget the static sizes if they differ *)
|
||
8 years ago
|
let nbytes_join i1 i2 = if Int.equal i1 i2 then Some i1 else None in
|
||
8 years ago
|
Exp.Sizeof
|
||
|
{ typ= typ_partial_join t1 t2
|
||
|
; nbytes= option_partial_join nbytes_join nbytes1 nbytes2
|
||
|
; dynamic_length= dynamic_length_partial_join len1 len2
|
||
|
; subtype= Subtype.join st1 st2 }
|
||
7 years ago
|
| _ ->
|
||
|
L.d_str "exp_partial_join no match " ;
|
||
8 years ago
|
Sil.d_exp e1 ;
|
||
|
L.d_str " " ;
|
||
|
Sil.d_exp e2 ;
|
||
|
L.d_ln () ;
|
||
8 years ago
|
raise Sil.JoinFail
|
||
10 years ago
|
|
||
7 years ago
|
|
||
8 years ago
|
and length_partial_join len1 len2 =
|
||
|
match (len1, len2) with
|
||
7 years ago
|
| Exp.BinOp (Binop.PlusA, e1, Exp.Const c1), Exp.BinOp (Binop.PlusA, e2, Exp.Const c2) ->
|
||
|
let e' = exp_partial_join e1 e2 in
|
||
9 years ago
|
let c' = exp_partial_join (Exp.Const c1) (Exp.Const c2) in
|
||
|
Exp.BinOp (Binop.PlusA, e', c')
|
||
7 years ago
|
| Exp.BinOp (Binop.PlusA, _, _), Exp.BinOp (Binop.PlusA, _, _) ->
|
||
|
Rename.extend len1 len2 Rename.ExtFresh
|
||
|
| Exp.Var id1, Exp.Var id2 when Ident.equal id1 id2 ->
|
||
|
len1
|
||
|
| _ ->
|
||
|
exp_partial_join len1 len2
|
||
|
|
||
9 years ago
|
|
||
|
and static_length_partial_join l1 l2 =
|
||
9 years ago
|
option_partial_join (fun len1 len2 -> if IntLit.eq len1 len2 then Some len1 else None) l1 l2
|
||
9 years ago
|
|
||
7 years ago
|
|
||
9 years ago
|
and dynamic_length_partial_join l1 l2 =
|
||
|
option_partial_join (fun len1 len2 -> Some (length_partial_join len1 len2)) l1 l2
|
||
10 years ago
|
|
||
7 years ago
|
|
||
8 years ago
|
and typ_partial_join (t1: Typ.t) (t2: Typ.t) =
|
||
|
match (t1.desc, t2.desc) with
|
||
8 years ago
|
| Typ.Tptr (t1, pk1), Typ.Tptr (t2, pk2)
|
||
7 years ago
|
when Typ.equal_ptr_kind pk1 pk2 && Typ.equal_quals t1.quals t2.quals ->
|
||
|
Typ.mk ~default:t1 (Tptr (typ_partial_join t1 t2, pk1))
|
||
8 years ago
|
(* quals are the same for t1 and t2 *)
|
||
7 years ago
|
| ( Typ.Tarray {elt= typ1; length= len1; stride= stride1}
|
||
|
, Typ.Tarray {elt= typ2; length= len2; stride= stride2} )
|
||
7 years ago
|
when Typ.equal_quals typ1.quals typ2.quals ->
|
||
7 years ago
|
let elt = typ_partial_join typ1 typ2 in
|
||
|
let length = static_length_partial_join len1 len2 in
|
||
8 years ago
|
let stride = static_length_partial_join stride1 stride2 in
|
||
7 years ago
|
Typ.mk_array ~default:t1 elt ?length ?stride
|
||
8 years ago
|
(* quals are the same for t1 and t2 *)
|
||
7 years ago
|
| _ when Typ.equal t1 t2 ->
|
||
|
t1 (* common case *)
|
||
|
| _ ->
|
||
|
L.d_str "typ_partial_join no match " ;
|
||
8 years ago
|
Typ.d_full t1 ;
|
||
|
L.d_str " " ;
|
||
|
Typ.d_full t2 ;
|
||
|
L.d_ln () ;
|
||
8 years ago
|
raise Sil.JoinFail
|
||
10 years ago
|
|
||
7 years ago
|
|
||
9 years ago
|
let rec exp_partial_meet (e1: Exp.t) (e2: Exp.t) : Exp.t =
|
||
8 years ago
|
match (e1, e2) with
|
||
7 years ago
|
| Exp.Var id1, Exp.Var id2 ->
|
||
|
ident_partial_meet id1 id2
|
||
|
| Exp.Var id, Exp.Const _ ->
|
||
|
if not (Ident.is_normal id) then Rename.extend e1 e2 (Rename.ExtDefault e2)
|
||
8 years ago
|
else ( L.d_strln "failure reason 27" ; raise Sil.JoinFail )
|
||
7 years ago
|
| Exp.Const _, Exp.Var id ->
|
||
|
if not (Ident.is_normal id) then Rename.extend e1 e2 (Rename.ExtDefault e1)
|
||
8 years ago
|
else ( L.d_strln "failure reason 28" ; raise Sil.JoinFail )
|
||
7 years ago
|
| Exp.Const c1, Exp.Const c2 ->
|
||
|
if Const.equal c1 c2 then e1 else ( L.d_strln "failure reason 29" ; raise Sil.JoinFail )
|
||
|
| Exp.Cast (t1, e1), Exp.Cast (t2, e2) ->
|
||
|
if not (Typ.equal t1 t2) then ( L.d_strln "failure reason 30" ; raise Sil.JoinFail )
|
||
10 years ago
|
else
|
||
|
let e1'' = exp_partial_meet e1 e2 in
|
||
9 years ago
|
Exp.Cast (t1, e1'')
|
||
7 years ago
|
| Exp.UnOp (unop1, e1, topt1), Exp.UnOp (unop2, e2, _) ->
|
||
|
if not (Unop.equal unop1 unop2) then ( L.d_strln "failure reason 31" ; raise Sil.JoinFail )
|
||
8 years ago
|
else Exp.UnOp (unop1, exp_partial_meet e1 e2, topt1)
|
||
|
(* should be topt1 = topt2 *)
|
||
7 years ago
|
| Exp.BinOp (binop1, e1, e1'), Exp.BinOp (binop2, e2, e2') ->
|
||
|
if not (Binop.equal binop1 binop2) then ( L.d_strln "failure reason 32" ; raise Sil.JoinFail )
|
||
10 years ago
|
else
|
||
|
let e1'' = exp_partial_meet e1 e2 in
|
||
|
let e2'' = exp_partial_meet e1' e2' in
|
||
8 years ago
|
Exp.BinOp (binop1, e1'', e2'')
|
||
7 years ago
|
| Exp.Var id, Exp.Lvar _ ->
|
||
|
if not (Ident.is_normal id) then Rename.extend e1 e2 (Rename.ExtDefault e2)
|
||
8 years ago
|
else ( L.d_strln "failure reason 33" ; raise Sil.JoinFail )
|
||
7 years ago
|
| Exp.Lvar _, Exp.Var id ->
|
||
|
if not (Ident.is_normal id) then Rename.extend e1 e2 (Rename.ExtDefault e1)
|
||
8 years ago
|
else ( L.d_strln "failure reason 34" ; raise Sil.JoinFail )
|
||
7 years ago
|
| Exp.Lvar pvar1, Exp.Lvar pvar2 ->
|
||
|
if not (Pvar.equal pvar1 pvar2) then ( L.d_strln "failure reason 35" ; raise Sil.JoinFail )
|
||
10 years ago
|
else e1
|
||
7 years ago
|
| Exp.Lfield (e1, f1, t1), Exp.Lfield (e2, f2, _) ->
|
||
|
if not (Typ.Fieldname.equal f1 f2) then ( L.d_strln "failure reason 36" ; raise Sil.JoinFail )
|
||
8 years ago
|
else Exp.Lfield (exp_partial_meet e1 e2, f1, t1)
|
||
|
(* should be t1 = t2 *)
|
||
7 years ago
|
| Exp.Lindex (e1, e1'), Exp.Lindex (e2, e2') ->
|
||
|
let e1'' = exp_partial_meet e1 e2 in
|
||
10 years ago
|
let e2'' = exp_partial_meet e1' e2' in
|
||
8 years ago
|
Exp.Lindex (e1'', e2'')
|
||
7 years ago
|
| _ ->
|
||
|
L.d_strln "failure reason 37" ; raise Sil.JoinFail
|
||
|
|
||
10 years ago
|
|
||
8 years ago
|
let exp_list_partial_join = List.map2_exn ~f:exp_partial_join
|
||
10 years ago
|
|
||
8 years ago
|
let exp_list_partial_meet = List.map2_exn ~f:exp_partial_meet
|
||
10 years ago
|
|
||
|
(** {2 Join and Meet for Strexp} *)
|
||
|
|
||
|
let rec strexp_partial_join mode (strexp1: Sil.strexp) (strexp2: Sil.strexp) : Sil.strexp =
|
||
|
let rec f_fld_se_list inst mode acc fld_se_list1 fld_se_list2 =
|
||
8 years ago
|
match (fld_se_list1, fld_se_list2) with
|
||
7 years ago
|
| [], [] ->
|
||
|
Sil.Estruct (List.rev acc, inst)
|
||
8 years ago
|
| [], _ | _, [] -> (
|
||
|
match mode with
|
||
7 years ago
|
| JoinState.Pre ->
|
||
|
L.d_strln "failure reason 42" ; raise Sil.JoinFail
|
||
|
| JoinState.Post ->
|
||
|
Sil.Estruct (List.rev acc, inst) )
|
||
|
| (fld1, se1) :: fld_se_list1', (fld2, se2) :: fld_se_list2' ->
|
||
|
let comparison = Typ.Fieldname.compare fld1 fld2 in
|
||
8 years ago
|
if Int.equal comparison 0 then
|
||
10 years ago
|
let strexp' = strexp_partial_join mode se1 se2 in
|
||
|
let fld_se_list_new = (fld1, strexp') :: acc in
|
||
|
f_fld_se_list inst mode fld_se_list_new fld_se_list1' fld_se_list2'
|
||
8 years ago
|
else
|
||
10 years ago
|
match mode with
|
||
7 years ago
|
| JoinState.Pre ->
|
||
|
L.d_strln "failure reason 43" ; raise Sil.JoinFail
|
||
|
| JoinState.Post ->
|
||
|
if comparison < 0 then f_fld_se_list inst mode acc fld_se_list1' fld_se_list2
|
||
8 years ago
|
else if comparison > 0 then f_fld_se_list inst mode acc fld_se_list1 fld_se_list2'
|
||
|
else assert false
|
||
|
(* This case should not happen. *)
|
||
|
in
|
||
9 years ago
|
let rec f_idx_se_list inst len idx_se_list_acc idx_se_list1 idx_se_list2 =
|
||
8 years ago
|
match (idx_se_list1, idx_se_list2) with
|
||
7 years ago
|
| [], [] ->
|
||
|
Sil.Earray (len, List.rev idx_se_list_acc, inst)
|
||
8 years ago
|
| [], _ | _, [] -> (
|
||
|
match mode with
|
||
7 years ago
|
| JoinState.Pre ->
|
||
|
L.d_strln "failure reason 44" ; raise Sil.JoinFail
|
||
|
| JoinState.Post ->
|
||
|
Sil.Earray (len, List.rev idx_se_list_acc, inst) )
|
||
|
| (idx1, se1) :: idx_se_list1', (idx2, se2) :: idx_se_list2' ->
|
||
|
let idx = exp_partial_join idx1 idx2 in
|
||
10 years ago
|
let strexp' = strexp_partial_join mode se1 se2 in
|
||
|
let idx_se_list_new = (idx, strexp') :: idx_se_list_acc in
|
||
8 years ago
|
f_idx_se_list inst len idx_se_list_new idx_se_list1' idx_se_list2'
|
||
|
in
|
||
|
match (strexp1, strexp2) with
|
||
7 years ago
|
| Sil.Eexp (e1, inst1), Sil.Eexp (e2, inst2) ->
|
||
|
Sil.Eexp (exp_partial_join e1 e2, Sil.inst_partial_join inst1 inst2)
|
||
|
| Sil.Estruct (fld_se_list1, inst1), Sil.Estruct (fld_se_list2, inst2) ->
|
||
|
let inst = Sil.inst_partial_join inst1 inst2 in
|
||
10 years ago
|
f_fld_se_list inst mode [] fld_se_list1 fld_se_list2
|
||
7 years ago
|
| Sil.Earray (len1, idx_se_list1, inst1), Sil.Earray (len2, idx_se_list2, inst2) ->
|
||
|
let len = length_partial_join len1 len2 in
|
||
10 years ago
|
let inst = Sil.inst_partial_join inst1 inst2 in
|
||
9 years ago
|
f_idx_se_list inst len [] idx_se_list1 idx_se_list2
|
||
7 years ago
|
| _ ->
|
||
|
L.d_strln "no match in strexp_partial_join" ;
|
||
|
raise Sil.JoinFail
|
||
|
|
||
10 years ago
|
|
||
|
let rec strexp_partial_meet (strexp1: Sil.strexp) (strexp2: Sil.strexp) : Sil.strexp =
|
||
|
let construct side rev_list ref_list =
|
||
|
let construct_offset_se (off, se) = (off, strexp_construct_fresh side se) in
|
||
8 years ago
|
let acc = List.map ~f:construct_offset_se ref_list in
|
||
8 years ago
|
List.rev_append rev_list acc
|
||
|
in
|
||
10 years ago
|
let rec f_fld_se_list inst acc fld_se_list1 fld_se_list2 =
|
||
8 years ago
|
match (fld_se_list1, fld_se_list2) with
|
||
7 years ago
|
| [], [] ->
|
||
|
Sil.Estruct (List.rev acc, inst)
|
||
|
| [], _ ->
|
||
|
Sil.Estruct (construct Rhs acc fld_se_list2, inst)
|
||
|
| _, [] ->
|
||
|
Sil.Estruct (construct Lhs acc fld_se_list1, inst)
|
||
|
| (fld1, se1) :: fld_se_list1', (fld2, se2) :: fld_se_list2' ->
|
||
|
let comparison = Typ.Fieldname.compare fld1 fld2 in
|
||
10 years ago
|
if comparison < 0 then
|
||
|
let se' = strexp_construct_fresh Lhs se1 in
|
||
8 years ago
|
let acc_new = (fld1, se') :: acc in
|
||
10 years ago
|
f_fld_se_list inst acc_new fld_se_list1' fld_se_list2
|
||
|
else if comparison > 0 then
|
||
|
let se' = strexp_construct_fresh Rhs se2 in
|
||
8 years ago
|
let acc_new = (fld2, se') :: acc in
|
||
10 years ago
|
f_fld_se_list inst acc_new fld_se_list1 fld_se_list2'
|
||
|
else
|
||
|
let strexp' = strexp_partial_meet se1 se2 in
|
||
|
let acc_new = (fld1, strexp') :: acc in
|
||
8 years ago
|
f_fld_se_list inst acc_new fld_se_list1' fld_se_list2'
|
||
|
in
|
||
9 years ago
|
let rec f_idx_se_list inst len acc idx_se_list1 idx_se_list2 =
|
||
8 years ago
|
match (idx_se_list1, idx_se_list2) with
|
||
7 years ago
|
| [], [] ->
|
||
|
Sil.Earray (len, List.rev acc, inst)
|
||
|
| [], _ ->
|
||
|
Sil.Earray (len, construct Rhs acc idx_se_list2, inst)
|
||
|
| _, [] ->
|
||
|
Sil.Earray (len, construct Lhs acc idx_se_list1, inst)
|
||
|
| (idx1, se1) :: idx_se_list1', (idx2, se2) :: idx_se_list2' ->
|
||
|
let idx = exp_partial_meet idx1 idx2 in
|
||
10 years ago
|
let se' = strexp_partial_meet se1 se2 in
|
||
|
let acc_new = (idx, se') :: acc in
|
||
8 years ago
|
f_idx_se_list inst len acc_new idx_se_list1' idx_se_list2'
|
||
|
in
|
||
|
match (strexp1, strexp2) with
|
||
7 years ago
|
| Sil.Eexp (e1, inst1), Sil.Eexp (e2, inst2) ->
|
||
|
Sil.Eexp (exp_partial_meet e1 e2, Sil.inst_partial_meet inst1 inst2)
|
||
|
| Sil.Estruct (fld_se_list1, inst1), Sil.Estruct (fld_se_list2, inst2) ->
|
||
|
let inst = Sil.inst_partial_meet inst1 inst2 in
|
||
10 years ago
|
f_fld_se_list inst [] fld_se_list1 fld_se_list2
|
||
9 years ago
|
| Sil.Earray (len1, idx_se_list1, inst1), Sil.Earray (len2, idx_se_list2, inst2)
|
||
7 years ago
|
when Exp.equal len1 len2 ->
|
||
|
let inst = Sil.inst_partial_meet inst1 inst2 in
|
||
9 years ago
|
f_idx_se_list inst len1 [] idx_se_list1 idx_se_list2
|
||
7 years ago
|
| _ ->
|
||
|
L.d_strln "failure reason 52" ; raise Sil.JoinFail
|
||
|
|
||
10 years ago
|
|
||
|
(** {2 Join and Meet for kind, hpara, hpara_dll} *)
|
||
|
|
||
8 years ago
|
let kind_join k1 k2 =
|
||
|
match (k1, k2) with
|
||
7 years ago
|
| Sil.Lseg_PE, _ ->
|
||
|
Sil.Lseg_PE
|
||
|
| _, Sil.Lseg_PE ->
|
||
|
Sil.Lseg_PE
|
||
|
| Sil.Lseg_NE, Sil.Lseg_NE ->
|
||
|
Sil.Lseg_NE
|
||
|
|
||
8 years ago
|
|
||
|
let kind_meet k1 k2 =
|
||
|
match (k1, k2) with
|
||
7 years ago
|
| Sil.Lseg_NE, _ ->
|
||
|
Sil.Lseg_NE
|
||
|
| _, Sil.Lseg_NE ->
|
||
|
Sil.Lseg_NE
|
||
|
| Sil.Lseg_PE, Sil.Lseg_PE ->
|
||
|
Sil.Lseg_PE
|
||
|
|
||
10 years ago
|
|
||
9 years ago
|
let hpara_partial_join tenv (hpara1: Sil.hpara) (hpara2: Sil.hpara) : Sil.hpara =
|
||
8 years ago
|
if Match.hpara_match_with_impl tenv true hpara2 hpara1 then hpara1
|
||
|
else if Match.hpara_match_with_impl tenv true hpara1 hpara2 then hpara2
|
||
|
else ( L.d_strln "failure reason 53" ; raise Sil.JoinFail )
|
||
10 years ago
|
|
||
7 years ago
|
|
||
9 years ago
|
let hpara_partial_meet tenv (hpara1: Sil.hpara) (hpara2: Sil.hpara) : Sil.hpara =
|
||
8 years ago
|
if Match.hpara_match_with_impl tenv true hpara2 hpara1 then hpara2
|
||
|
else if Match.hpara_match_with_impl tenv true hpara1 hpara2 then hpara1
|
||
|
else ( L.d_strln "failure reason 54" ; raise Sil.JoinFail )
|
||
10 years ago
|
|
||
7 years ago
|
|
||
9 years ago
|
let hpara_dll_partial_join tenv (hpara1: Sil.hpara_dll) (hpara2: Sil.hpara_dll) : Sil.hpara_dll =
|
||
8 years ago
|
if Match.hpara_dll_match_with_impl tenv true hpara2 hpara1 then hpara1
|
||
|
else if Match.hpara_dll_match_with_impl tenv true hpara1 hpara2 then hpara2
|
||
|
else ( L.d_strln "failure reason 55" ; raise Sil.JoinFail )
|
||
10 years ago
|
|
||
7 years ago
|
|
||
9 years ago
|
let hpara_dll_partial_meet tenv (hpara1: Sil.hpara_dll) (hpara2: Sil.hpara_dll) : Sil.hpara_dll =
|
||
8 years ago
|
if Match.hpara_dll_match_with_impl tenv true hpara2 hpara1 then hpara2
|
||
|
else if Match.hpara_dll_match_with_impl tenv true hpara1 hpara2 then hpara1
|
||
|
else ( L.d_strln "failure reason 56" ; raise Sil.JoinFail )
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
(** {2 Join and Meet for hpred} *)
|
||
|
|
||
8 years ago
|
let hpred_partial_join tenv mode (todo: Exp.t * Exp.t * Exp.t) (hpred1: Sil.hpred)
|
||
|
(hpred2: Sil.hpred) : Sil.hpred =
|
||
10 years ago
|
let e1, e2, e = todo in
|
||
8 years ago
|
match (hpred1, hpred2) with
|
||
7 years ago
|
| Sil.Hpointsto (_, se1, te1), Sil.Hpointsto (_, se2, te2) ->
|
||
|
let te = exp_partial_join te1 te2 in
|
||
9 years ago
|
Prop.mk_ptsto tenv e (strexp_partial_join mode se1 se2) te
|
||
7 years ago
|
| Sil.Hlseg (k1, hpara1, _, next1, shared1), Sil.Hlseg (k2, hpara2, _, next2, shared2) ->
|
||
|
let hpara' = hpara_partial_join tenv hpara1 hpara2 in
|
||
10 years ago
|
let next' = exp_partial_join next1 next2 in
|
||
|
let shared' = exp_list_partial_join shared1 shared2 in
|
||
9 years ago
|
Prop.mk_lseg tenv (kind_join k1 k2) hpara' e next' shared'
|
||
8 years ago
|
| ( Sil.Hdllseg (k1, para1, iF1, oB1, oF1, iB1, shared1)
|
||
7 years ago
|
, Sil.Hdllseg (k2, para2, iF2, oB2, oF2, iB2, shared2) ) ->
|
||
|
let fwd1 = Exp.equal e1 iF1 in
|
||
9 years ago
|
let fwd2 = Exp.equal e2 iF2 in
|
||
9 years ago
|
let hpara' = hpara_dll_partial_join tenv para1 para2 in
|
||
10 years ago
|
let iF', iB' =
|
||
8 years ago
|
if fwd1 && fwd2 then (e, exp_partial_join iB1 iB2)
|
||
|
else if not fwd1 && not fwd2 then (exp_partial_join iF1 iF2, e)
|
||
|
else ( L.d_strln "failure reason 57" ; raise Sil.JoinFail )
|
||
|
in
|
||
10 years ago
|
let oF' = exp_partial_join oF1 oF2 in
|
||
|
let oB' = exp_partial_join oB1 oB2 in
|
||
|
let shared' = exp_list_partial_join shared1 shared2 in
|
||
9 years ago
|
Prop.mk_dllseg tenv (kind_join k1 k2) hpara' iF' oB' oF' iB' shared'
|
||
7 years ago
|
| _ ->
|
||
|
assert false
|
||
|
|
||
10 years ago
|
|
||
9 years ago
|
let hpred_partial_meet tenv (todo: Exp.t * Exp.t * Exp.t) (hpred1: Sil.hpred) (hpred2: Sil.hpred)
|
||
8 years ago
|
: Sil.hpred =
|
||
10 years ago
|
let e1, e2, e = todo in
|
||
8 years ago
|
match (hpred1, hpred2) with
|
||
7 years ago
|
| Sil.Hpointsto (_, se1, te1), Sil.Hpointsto (_, se2, te2) when Exp.equal te1 te2 ->
|
||
|
Prop.mk_ptsto tenv e (strexp_partial_meet se1 se2) te1
|
||
|
| Sil.Hpointsto _, _ | _, Sil.Hpointsto _ ->
|
||
|
L.d_strln "failure reason 58" ; raise Sil.JoinFail
|
||
|
| Sil.Hlseg (k1, hpara1, _, next1, shared1), Sil.Hlseg (k2, hpara2, _, next2, shared2) ->
|
||
|
let hpara' = hpara_partial_meet tenv hpara1 hpara2 in
|
||
10 years ago
|
let next' = exp_partial_meet next1 next2 in
|
||
|
let shared' = exp_list_partial_meet shared1 shared2 in
|
||
9 years ago
|
Prop.mk_lseg tenv (kind_meet k1 k2) hpara' e next' shared'
|
||
8 years ago
|
| ( Sil.Hdllseg (k1, para1, iF1, oB1, oF1, iB1, shared1)
|
||
7 years ago
|
, Sil.Hdllseg (k2, para2, iF2, oB2, oF2, iB2, shared2) ) ->
|
||
|
let fwd1 = Exp.equal e1 iF1 in
|
||
9 years ago
|
let fwd2 = Exp.equal e2 iF2 in
|
||
9 years ago
|
let hpara' = hpara_dll_partial_meet tenv para1 para2 in
|
||
10 years ago
|
let iF', iB' =
|
||
8 years ago
|
if fwd1 && fwd2 then (e, exp_partial_meet iB1 iB2)
|
||
|
else if not fwd1 && not fwd2 then (exp_partial_meet iF1 iF2, e)
|
||
|
else ( L.d_strln "failure reason 59" ; raise Sil.JoinFail )
|
||
|
in
|
||
10 years ago
|
let oF' = exp_partial_meet oF1 oF2 in
|
||
|
let oB' = exp_partial_meet oB1 oB2 in
|
||
|
let shared' = exp_list_partial_meet shared1 shared2 in
|
||
9 years ago
|
Prop.mk_dllseg tenv (kind_meet k1 k2) hpara' iF' oB' oF' iB' shared'
|
||
7 years ago
|
| _ ->
|
||
|
assert false
|
||
|
|
||
10 years ago
|
|
||
|
(** {2 Join and Meet for Sigma} *)
|
||
|
|
||
9 years ago
|
let find_hpred_by_address tenv (e: Exp.t) (sigma: Prop.sigma) : Sil.hpred option * Prop.sigma =
|
||
10 years ago
|
let is_root_for_e e' =
|
||
8 years ago
|
match Prover.is_root tenv Prop.prop_emp e' e with None -> false | Some _ -> true
|
||
|
in
|
||
10 years ago
|
let contains_e = function
|
||
7 years ago
|
| Sil.Hpointsto (e', _, _) ->
|
||
|
is_root_for_e e'
|
||
|
| Sil.Hlseg (_, _, e', _, _) ->
|
||
|
is_root_for_e e'
|
||
|
| Sil.Hdllseg (_, _, iF, _, _, iB, _) ->
|
||
|
is_root_for_e iF || is_root_for_e iB
|
||
8 years ago
|
in
|
||
10 years ago
|
let rec f sigma_acc = function
|
||
7 years ago
|
| [] ->
|
||
|
(None, sigma)
|
||
|
| hpred :: sigma ->
|
||
|
if contains_e hpred then (Some hpred, List.rev_append sigma_acc sigma)
|
||
8 years ago
|
else f (hpred :: sigma_acc) sigma
|
||
|
in
|
||
10 years ago
|
f [] sigma
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
let same_pred (hpred1: Sil.hpred) (hpred2: Sil.hpred) : bool =
|
||
8 years ago
|
match (hpred1, hpred2) with
|
||
7 years ago
|
| Sil.Hpointsto _, Sil.Hpointsto _ ->
|
||
|
true
|
||
|
| Sil.Hlseg _, Sil.Hlseg _ ->
|
||
|
true
|
||
|
| Sil.Hdllseg _, Sil.Hdllseg _ ->
|
||
|
true
|
||
|
| _ ->
|
||
|
false
|
||
|
|
||
10 years ago
|
|
||
|
(* check that applying renaming to the lhs / rhs of [sigma_new]
|
||
10 years ago
|
* gives [sigma] and that the renaming is injective *)
|
||
10 years ago
|
|
||
9 years ago
|
let sigma_renaming_check (lhs: side) (sigma: Prop.sigma) (sigma_new: Prop.sigma) =
|
||
10 years ago
|
(* apply the lhs / rhs of the renaming to sigma,
|
||
10 years ago
|
* and check that the renaming of primed vars is injective *)
|
||
7 years ago
|
let fav_sigma = Prop.sigma_free_vars sigma_new |> Ident.hashqueue_of_sequence in
|
||
10 years ago
|
let sub = Rename.to_subst_proj lhs fav_sigma in
|
||
8 years ago
|
let sigma' = Prop.sigma_sub (`Exp sub) sigma_new in
|
||
8 years ago
|
equal_sigma sigma sigma'
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let sigma_renaming_check_lhs = sigma_renaming_check Lhs
|
||
|
|
||
8 years ago
|
let sigma_renaming_check_rhs = sigma_renaming_check Rhs
|
||
10 years ago
|
|
||
8 years ago
|
let rec sigma_partial_join' tenv mode (sigma_acc: Prop.sigma) (sigma1_in: Prop.sigma)
|
||
|
(sigma2_in: Prop.sigma) : Prop.sigma * Prop.sigma * Prop.sigma =
|
||
10 years ago
|
let lookup_and_expand side e e' =
|
||
|
match (Rename.get_others side e, side) with
|
||
7 years ago
|
| None, _ ->
|
||
|
L.d_strln "failure reason 60" ; raise Sil.JoinFail
|
||
|
| Some (e_res, e_op), Lhs ->
|
||
|
(e_res, exp_partial_join e' e_op)
|
||
|
| Some (e_res, e_op), Rhs ->
|
||
|
(e_res, exp_partial_join e_op e')
|
||
8 years ago
|
in
|
||
10 years ago
|
let join_list_and_non side root' hlseg e opposite =
|
||
|
match hlseg with
|
||
7 years ago
|
| Sil.Hlseg (_, hpara, root, next, shared) ->
|
||
|
let next' = do_side side exp_partial_join next opposite in
|
||
10 years ago
|
let shared' = Rename.lookup_list side shared in
|
||
8 years ago
|
CheckJoin.add side root next ; Sil.Hlseg (Sil.Lseg_PE, hpara, root', next', shared')
|
||
7 years ago
|
| Sil.Hdllseg (_, hpara, iF, oB, oF, iB, shared) when Exp.equal iF e ->
|
||
|
let oF' = do_side side exp_partial_join oF opposite in
|
||
10 years ago
|
let shared' = Rename.lookup_list side shared in
|
||
|
let oB', iB' = lookup_and_expand side oB iB in
|
||
|
(*
|
||
|
let oB' = Rename.lookup side oB in
|
||
|
let iB' = Rename.lookup side iB in
|
||
|
*)
|
||
8 years ago
|
CheckJoin.add side iF oF ;
|
||
|
CheckJoin.add side oB iB ;
|
||
10 years ago
|
Sil.Hdllseg (Sil.Lseg_PE, hpara, root', oB', oF', iB', shared')
|
||
7 years ago
|
| Sil.Hdllseg (_, hpara, iF, oB, oF, iB, shared) when Exp.equal iB e ->
|
||
|
let oB' = do_side side exp_partial_join oB opposite in
|
||
10 years ago
|
let shared' = Rename.lookup_list side shared in
|
||
|
let oF', iF' = lookup_and_expand side oF iF in
|
||
|
(*
|
||
|
let oF' = Rename.lookup side oF in
|
||
|
let iF' = Rename.lookup side iF in
|
||
|
*)
|
||
8 years ago
|
CheckJoin.add side iF oF ;
|
||
|
CheckJoin.add side oB iB ;
|
||
10 years ago
|
Sil.Hdllseg (Sil.Lseg_PE, hpara, iF', oB', oF', root', shared')
|
||
7 years ago
|
| _ ->
|
||
|
assert false
|
||
8 years ago
|
in
|
||
10 years ago
|
let update_list side lseg root' =
|
||
|
match lseg with
|
||
7 years ago
|
| Sil.Hlseg (k, hpara, _, next, shared) ->
|
||
|
let next' = Rename.lookup side next and shared' = Rename.lookup_list_todo side shared in
|
||
10 years ago
|
Sil.Hlseg (k, hpara, root', next', shared')
|
||
7 years ago
|
| _ ->
|
||
|
assert false
|
||
8 years ago
|
in
|
||
10 years ago
|
let update_dllseg side dllseg iF iB =
|
||
|
match dllseg with
|
||
7 years ago
|
| Sil.Hdllseg (k, hpara, _, oB, oF, _, shared) ->
|
||
|
let oB' = Rename.lookup side oB
|
||
10 years ago
|
and oF' = Rename.lookup side oF
|
||
|
and shared' = Rename.lookup_list_todo side shared in
|
||
|
Sil.Hdllseg (k, hpara, iF, oB', oF', iB, shared')
|
||
7 years ago
|
| _ ->
|
||
|
assert false
|
||
8 years ago
|
in
|
||
10 years ago
|
(* Drop the part of 'other' sigma corresponding to 'target' sigma if possible.
|
||
10 years ago
|
'side' describes that target is Lhs or Rhs.
|
||
|
'todo' describes the start point. *)
|
||
9 years ago
|
let cut_sigma side todo (target: Prop.sigma) (other: Prop.sigma) =
|
||
8 years ago
|
let list_is_empty l = if l <> [] then ( L.d_strln "failure reason 61" ; raise Sil.JoinFail ) in
|
||
10 years ago
|
let x = Todo.take () in
|
||
8 years ago
|
Todo.push todo ;
|
||
10 years ago
|
let res =
|
||
|
match side with
|
||
7 years ago
|
| Lhs ->
|
||
|
let res, target', other' = sigma_partial_join' tenv mode [] target other in
|
||
|
list_is_empty target' ;
|
||
|
sigma_renaming_check_lhs target res ;
|
||
|
other'
|
||
|
| Rhs ->
|
||
|
let res, other', target' = sigma_partial_join' tenv mode [] other target in
|
||
|
list_is_empty target' ;
|
||
|
sigma_renaming_check_rhs target res ;
|
||
|
other'
|
||
8 years ago
|
in
|
||
|
Todo.set x ; res
|
||
|
in
|
||
10 years ago
|
let cut_lseg side todo lseg sigma =
|
||
|
match lseg with
|
||
7 years ago
|
| Sil.Hlseg (_, hpara, root, next, shared) ->
|
||
|
let _, sigma_lseg = Sil.hpara_instantiate hpara root next shared in
|
||
10 years ago
|
cut_sigma side todo sigma_lseg sigma
|
||
7 years ago
|
| _ ->
|
||
|
assert false
|
||
8 years ago
|
in
|
||
10 years ago
|
let cut_dllseg side todo root lseg sigma =
|
||
|
match lseg with
|
||
7 years ago
|
| Sil.Hdllseg (_, hpara, _, oB, oF, _, shared) ->
|
||
|
let _, sigma_dllseg = Sil.hpara_dll_instantiate hpara root oB oF shared in
|
||
10 years ago
|
cut_sigma side todo sigma_dllseg sigma
|
||
7 years ago
|
| _ ->
|
||
|
assert false
|
||
8 years ago
|
in
|
||
10 years ago
|
try
|
||
|
let todo_curr = Todo.pop () in
|
||
|
let e1, e2, e = todo_curr in
|
||
8 years ago
|
if Config.trace_join then (
|
||
|
L.d_strln ".... sigma_partial_join' ...." ;
|
||
|
L.d_str "TODO: " ;
|
||
|
Sil.d_exp e1 ;
|
||
|
L.d_str "," ;
|
||
|
Sil.d_exp e2 ;
|
||
|
L.d_str "," ;
|
||
|
Sil.d_exp e ;
|
||
|
L.d_ln () ;
|
||
|
L.d_strln "SIGMA1 =" ;
|
||
|
Prop.d_sigma sigma1_in ;
|
||
|
L.d_ln () ;
|
||
|
L.d_strln "SIGMA2 =" ;
|
||
|
Prop.d_sigma sigma2_in ;
|
||
|
L.d_ln () ;
|
||
|
L.d_ln () ) ;
|
||
9 years ago
|
let hpred_opt1, sigma1 = find_hpred_by_address tenv e1 sigma1_in in
|
||
|
let hpred_opt2, sigma2 = find_hpred_by_address tenv e2 sigma2_in in
|
||
8 years ago
|
match (hpred_opt1, hpred_opt2) with
|
||
7 years ago
|
| None, None ->
|
||
|
sigma_partial_join' tenv mode sigma_acc sigma1 sigma2
|
||
10 years ago
|
| Some (Sil.Hlseg (k, _, _, _, _) as lseg), None
|
||
7 years ago
|
| Some (Sil.Hdllseg (k, _, _, _, _, _, _) as lseg), None ->
|
||
|
if not Config.nelseg || Sil.equal_lseg_kind k Sil.Lseg_PE then
|
||
10 years ago
|
let sigma_acc' = join_list_and_non Lhs e lseg e1 e2 :: sigma_acc in
|
||
9 years ago
|
sigma_partial_join' tenv mode sigma_acc' sigma1 sigma2
|
||
8 years ago
|
else ( L.d_strln "failure reason 62" ; raise Sil.JoinFail )
|
||
10 years ago
|
| None, Some (Sil.Hlseg (k, _, _, _, _) as lseg)
|
||
7 years ago
|
| None, Some (Sil.Hdllseg (k, _, _, _, _, _, _) as lseg) ->
|
||
|
if not Config.nelseg || Sil.equal_lseg_kind k Sil.Lseg_PE then
|
||
10 years ago
|
let sigma_acc' = join_list_and_non Rhs e lseg e2 e1 :: sigma_acc in
|
||
9 years ago
|
sigma_partial_join' tenv mode sigma_acc' sigma1 sigma2
|
||
8 years ago
|
else ( L.d_strln "failure reason 63" ; raise Sil.JoinFail )
|
||
7 years ago
|
| None, _ | _, None ->
|
||
|
L.d_strln "failure reason 64" ; raise Sil.JoinFail
|
||
|
| Some hpred1, Some hpred2 when same_pred hpred1 hpred2 ->
|
||
|
let hpred_res1 = hpred_partial_join tenv mode todo_curr hpred1 hpred2 in
|
||
8 years ago
|
sigma_partial_join' tenv mode (hpred_res1 :: sigma_acc) sigma1 sigma2
|
||
7 years ago
|
| Some (Sil.Hlseg _ as lseg), Some hpred2 ->
|
||
|
let sigma2' = cut_lseg Lhs todo_curr lseg (hpred2 :: sigma2) in
|
||
10 years ago
|
let sigma_acc' = update_list Lhs lseg e :: sigma_acc in
|
||
9 years ago
|
sigma_partial_join' tenv mode sigma_acc' sigma1 sigma2'
|
||
7 years ago
|
| Some hpred1, Some (Sil.Hlseg _ as lseg) ->
|
||
|
let sigma1' = cut_lseg Rhs todo_curr lseg (hpred1 :: sigma1) in
|
||
10 years ago
|
let sigma_acc' = update_list Rhs lseg e :: sigma_acc in
|
||
9 years ago
|
sigma_partial_join' tenv mode sigma_acc' sigma1' sigma2
|
||
7 years ago
|
| Some (Sil.Hdllseg (_, _, iF1, _, _, iB1, _) as dllseg), Some hpred2 when Exp.equal e1 iF1 ->
|
||
|
let iB_res = exp_partial_join iB1 e2 in
|
||
8 years ago
|
let sigma2' = cut_dllseg Lhs todo_curr iF1 dllseg (hpred2 :: sigma2) in
|
||
10 years ago
|
let sigma_acc' = update_dllseg Lhs dllseg e iB_res :: sigma_acc in
|
||
8 years ago
|
CheckJoin.add Lhs iF1 iB1 ;
|
||
|
(* add equality iF1=iB1 *)
|
||
9 years ago
|
sigma_partial_join' tenv mode sigma_acc' sigma1 sigma2'
|
||
8 years ago
|
| Some (Sil.Hdllseg (_, _, iF1, _, _, iB1, _) as dllseg), Some hpred2
|
||
7 years ago
|
(* when Exp.equal e1 iB1 *) ->
|
||
|
let iF_res = exp_partial_join iF1 e2 in
|
||
8 years ago
|
let sigma2' = cut_dllseg Lhs todo_curr iB1 dllseg (hpred2 :: sigma2) in
|
||
10 years ago
|
let sigma_acc' = update_dllseg Lhs dllseg iF_res e :: sigma_acc in
|
||
8 years ago
|
CheckJoin.add Lhs iF1 iB1 ;
|
||
|
(* add equality iF1=iB1 *)
|
||
9 years ago
|
sigma_partial_join' tenv mode sigma_acc' sigma1 sigma2'
|
||
7 years ago
|
| Some hpred1, Some (Sil.Hdllseg (_, _, iF2, _, _, iB2, _) as dllseg) when Exp.equal e2 iF2 ->
|
||
|
let iB_res = exp_partial_join e1 iB2 in
|
||
8 years ago
|
let sigma1' = cut_dllseg Rhs todo_curr iF2 dllseg (hpred1 :: sigma1) in
|
||
10 years ago
|
let sigma_acc' = update_dllseg Rhs dllseg e iB_res :: sigma_acc in
|
||
8 years ago
|
CheckJoin.add Rhs iF2 iB2 ;
|
||
|
(* add equality iF2=iB2 *)
|
||
9 years ago
|
sigma_partial_join' tenv mode sigma_acc' sigma1' sigma2
|
||
7 years ago
|
| Some hpred1, Some (Sil.Hdllseg (_, _, iF2, _, _, iB2, _) as dllseg) ->
|
||
|
let iF_res = exp_partial_join e1 iF2 in
|
||
8 years ago
|
let sigma1' = cut_dllseg Rhs todo_curr iB2 dllseg (hpred1 :: sigma1) in
|
||
10 years ago
|
let sigma_acc' = update_dllseg Rhs dllseg iF_res e :: sigma_acc in
|
||
8 years ago
|
CheckJoin.add Rhs iF2 iB2 ;
|
||
|
(* add equality iF2=iB2 *)
|
||
9 years ago
|
sigma_partial_join' tenv mode sigma_acc' sigma1' sigma2
|
||
7 years ago
|
| Some Sil.Hpointsto _, Some Sil.Hpointsto _ ->
|
||
|
assert false
|
||
8 years ago
|
(* Should be handled by a guarded case *)
|
||
10 years ago
|
with Todo.Empty ->
|
||
8 years ago
|
match (sigma1_in, sigma2_in) with
|
||
7 years ago
|
| _ :: _, _ :: _ ->
|
||
|
L.d_strln "todo is empty, but the sigmas are not" ;
|
||
|
raise Sil.JoinFail
|
||
|
| _ ->
|
||
|
(sigma_acc, sigma1_in, sigma2_in)
|
||
|
|
||
10 years ago
|
|
||
9 years ago
|
let sigma_partial_join tenv mode (sigma1: Prop.sigma) (sigma2: Prop.sigma)
|
||
8 years ago
|
: Prop.sigma * Prop.sigma * Prop.sigma =
|
||
|
CheckJoin.init mode sigma1 sigma2 ;
|
||
10 years ago
|
let lost_little = CheckJoin.lost_little in
|
||
9 years ago
|
let s1, s2, s3 = sigma_partial_join' tenv mode [] sigma1 sigma2 in
|
||
8 years ago
|
SymOp.try_finally
|
||
8 years ago
|
~f:(fun () ->
|
||
|
if Rename.check lost_little then (s1, s2, s3)
|
||
7 years ago
|
else ( L.d_strln "failed Rename.check" ; raise Sil.JoinFail ) )
|
||
8 years ago
|
~finally:CheckJoin.final
|
||
10 years ago
|
|
||
7 years ago
|
|
||
8 years ago
|
let rec sigma_partial_meet' tenv (sigma_acc: Prop.sigma) (sigma1_in: Prop.sigma)
|
||
|
(sigma2_in: Prop.sigma) : Prop.sigma =
|
||
10 years ago
|
try
|
||
|
let todo_curr = Todo.pop () in
|
||
|
let e1, e2, e = todo_curr in
|
||
8 years ago
|
L.d_strln ".... sigma_partial_meet' ...." ;
|
||
|
L.d_str "TODO: " ;
|
||
|
Sil.d_exp e1 ;
|
||
|
L.d_str "," ;
|
||
|
Sil.d_exp e2 ;
|
||
|
L.d_str "," ;
|
||
|
Sil.d_exp e ;
|
||
|
L.d_ln () ;
|
||
|
L.d_str "PROP1=" ;
|
||
|
Prop.d_sigma sigma1_in ;
|
||
|
L.d_ln () ;
|
||
|
L.d_str "PROP2=" ;
|
||
|
Prop.d_sigma sigma2_in ;
|
||
|
L.d_ln () ;
|
||
|
L.d_ln () ;
|
||
9 years ago
|
let hpred_opt1, sigma1 = find_hpred_by_address tenv e1 sigma1_in in
|
||
|
let hpred_opt2, sigma2 = find_hpred_by_address tenv e2 sigma2_in in
|
||
8 years ago
|
match (hpred_opt1, hpred_opt2) with
|
||
7 years ago
|
| None, None ->
|
||
|
sigma_partial_meet' tenv sigma_acc sigma1 sigma2
|
||
|
| Some hpred, None ->
|
||
|
let hpred' = hpred_construct_fresh Lhs hpred in
|
||
10 years ago
|
let sigma_acc' = hpred' :: sigma_acc in
|
||
9 years ago
|
sigma_partial_meet' tenv sigma_acc' sigma1 sigma2
|
||
7 years ago
|
| None, Some hpred ->
|
||
|
let hpred' = hpred_construct_fresh Rhs hpred in
|
||
10 years ago
|
let sigma_acc' = hpred' :: sigma_acc in
|
||
9 years ago
|
sigma_partial_meet' tenv sigma_acc' sigma1 sigma2
|
||
7 years ago
|
| Some hpred1, Some hpred2 when same_pred hpred1 hpred2 ->
|
||
|
let hpred' = hpred_partial_meet tenv todo_curr hpred1 hpred2 in
|
||
8 years ago
|
sigma_partial_meet' tenv (hpred' :: sigma_acc) sigma1 sigma2
|
||
7 years ago
|
| Some _, Some _ ->
|
||
|
L.d_strln "failure reason 65" ; raise Sil.JoinFail
|
||
10 years ago
|
with Todo.Empty ->
|
||
8 years ago
|
match (sigma1_in, sigma2_in) with
|
||
7 years ago
|
| [], [] ->
|
||
|
sigma_acc
|
||
|
| _, _ ->
|
||
|
L.d_strln "todo is empty, but the sigmas are not" ;
|
||
|
raise Sil.JoinFail
|
||
|
|
||
10 years ago
|
|
||
9 years ago
|
let sigma_partial_meet tenv (sigma1: Prop.sigma) (sigma2: Prop.sigma) : Prop.sigma =
|
||
|
sigma_partial_meet' tenv [] sigma1 sigma2
|
||
10 years ago
|
|
||
7 years ago
|
|
||
9 years ago
|
let widening_top =
|
||
|
(* nearly max_int but not so close to overflow *)
|
||
8 years ago
|
IntLit.of_int64 Int64.max_value -- IntLit.of_int 1000
|
||
8 years ago
|
|
||
7 years ago
|
|
||
9 years ago
|
let widening_bottom =
|
||
|
(* nearly min_int but not so close to underflow *)
|
||
8 years ago
|
IntLit.of_int64 Int64.min_value ++ IntLit.of_int 1000
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
(** {2 Join and Meet for Pi} *)
|
||
8 years ago
|
let pi_partial_join tenv mode (ep1: Prop.exposed Prop.t) (ep2: Prop.exposed Prop.t) (pi1: Prop.pi)
|
||
|
(pi2: Prop.pi) : Prop.pi =
|
||
9 years ago
|
let get_array_len prop =
|
||
|
(* find some array length in the prop, to be used as heuritic for upper bound in widening *)
|
||
|
let len_list = ref [] in
|
||
10 years ago
|
let do_hpred = function
|
||
7 years ago
|
| Sil.Hpointsto (_, Sil.Earray (Exp.Const Const.Cint n, _, _), _) ->
|
||
|
if IntLit.geq n IntLit.one then len_list := n :: !len_list
|
||
|
| _ ->
|
||
|
()
|
||
8 years ago
|
in
|
||
7 years ago
|
List.iter ~f:do_hpred prop.Prop.sigma ;
|
||
|
!len_list
|
||
8 years ago
|
in
|
||
10 years ago
|
let bounds =
|
||
9 years ago
|
let bounds1 = get_array_len ep1 in
|
||
|
let bounds2 = get_array_len ep2 in
|
||
8 years ago
|
let bounds_sorted = List.sort ~cmp:IntLit.compare_value (bounds1 @ bounds2) in
|
||
|
List.rev (List.remove_consecutive_duplicates ~equal:IntLit.eq bounds_sorted)
|
||
|
in
|
||
10 years ago
|
let widening_atom a =
|
||
9 years ago
|
(* widening heuristic for upper bound: take the length of some array, -2 and -1 *)
|
||
8 years ago
|
match (Prop.atom_exp_le_const a, bounds) with
|
||
7 years ago
|
| Some (e, n), len :: _ ->
|
||
|
let first_try = IntLit.sub len IntLit.one in
|
||
9 years ago
|
let second_try = IntLit.sub len IntLit.two in
|
||
10 years ago
|
let bound =
|
||
8 years ago
|
if IntLit.leq n first_try then if IntLit.leq n second_try then second_try else first_try
|
||
|
else widening_top
|
||
|
in
|
||
|
let a' = Prop.mk_inequality tenv (Exp.BinOp (Binop.Le, e, Exp.int bound)) in
|
||
10 years ago
|
Some a'
|
||
7 years ago
|
| Some (e, _), [] ->
|
||
|
let bound = widening_top in
|
||
8 years ago
|
let a' = Prop.mk_inequality tenv (Exp.BinOp (Binop.Le, e, Exp.int bound)) in
|
||
10 years ago
|
Some a'
|
||
|
| _ ->
|
||
8 years ago
|
match Prop.atom_const_lt_exp a with
|
||
7 years ago
|
| None ->
|
||
|
None
|
||
|
| Some (n, e) ->
|
||
|
let bound =
|
||
8 years ago
|
if IntLit.leq IntLit.minus_one n then IntLit.minus_one else widening_bottom
|
||
|
in
|
||
|
let a' = Prop.mk_inequality tenv (Exp.BinOp (Binop.Lt, Exp.int bound, e)) in
|
||
|
Some a'
|
||
|
in
|
||
10 years ago
|
let is_stronger_le e n a =
|
||
|
match Prop.atom_exp_le_const a with
|
||
7 years ago
|
| None ->
|
||
|
false
|
||
|
| Some (e', n') ->
|
||
|
Exp.equal e e' && IntLit.lt n' n
|
||
8 years ago
|
in
|
||
10 years ago
|
let is_stronger_lt n e a =
|
||
|
match Prop.atom_const_lt_exp a with
|
||
7 years ago
|
| None ->
|
||
|
false
|
||
|
| Some (n', e') ->
|
||
|
Exp.equal e e' && IntLit.lt n n'
|
||
8 years ago
|
in
|
||
10 years ago
|
let join_atom_check_pre p a =
|
||
|
(* check for atoms in pre mode: fail if the negation is implied by the other side *)
|
||
9 years ago
|
let not_a = Prover.atom_negate tenv a in
|
||
8 years ago
|
if Prover.check_atom tenv p not_a then (
|
||
7 years ago
|
L.d_str "join_atom_check failed on " ;
|
||
|
Sil.d_atom a ;
|
||
|
L.d_ln () ;
|
||
|
raise Sil.JoinFail )
|
||
8 years ago
|
in
|
||
10 years ago
|
let join_atom_check_attribute p a =
|
||
|
(* check for attribute: fail if the attribute is not in the other side *)
|
||
8 years ago
|
if not (Prover.check_atom tenv p a) then (
|
||
|
L.d_str "join_atom_check_attribute failed on " ;
|
||
|
Sil.d_atom a ;
|
||
|
L.d_ln () ;
|
||
|
raise Sil.JoinFail )
|
||
|
in
|
||
10 years ago
|
let join_atom side p_op pi_op a =
|
||
|
(* try to find the atom corresponding to a on the other side, and check if it is implied *)
|
||
9 years ago
|
match Rename.get_other_atoms tenv side a with
|
||
7 years ago
|
| None ->
|
||
|
None
|
||
|
| Some (a_res, a_op) ->
|
||
|
if JoinState.equal_mode mode JoinState.Pre then join_atom_check_pre p_op a_op ;
|
||
8 years ago
|
if Attribute.is_pred a then join_atom_check_attribute p_op a_op ;
|
||
9 years ago
|
if not (Prover.check_atom tenv p_op a_op) then None
|
||
8 years ago
|
else
|
||
10 years ago
|
match Prop.atom_exp_le_const a_op with
|
||
8 years ago
|
| None -> (
|
||
|
match Prop.atom_const_lt_exp a_op with
|
||
7 years ago
|
| None ->
|
||
|
Some a_res
|
||
|
| Some (n, e) ->
|
||
|
if List.exists ~f:(is_stronger_lt n e) pi_op then widening_atom a_res
|
||
8 years ago
|
else Some a_res )
|
||
7 years ago
|
| Some (e, n) ->
|
||
|
if List.exists ~f:(is_stronger_le e n) pi_op then widening_atom a_res else Some a_res
|
||
8 years ago
|
in
|
||
9 years ago
|
let handle_atom_with_widening len p_op pi_op atom_list a =
|
||
10 years ago
|
(* find a join for the atom, if it fails apply widening heuristing and try again *)
|
||
9 years ago
|
match join_atom len p_op pi_op a with
|
||
8 years ago
|
| None -> (
|
||
|
match widening_atom a with
|
||
7 years ago
|
| None ->
|
||
|
atom_list
|
||
8 years ago
|
| Some a' ->
|
||
|
match join_atom len p_op pi_op a' with None -> atom_list | Some a' -> a' :: atom_list )
|
||
7 years ago
|
| Some a' ->
|
||
|
a' :: atom_list
|
||
8 years ago
|
in
|
||
|
if Config.trace_join then (
|
||
|
L.d_str "pi1: " ; Prop.d_pi pi1 ; L.d_ln () ; L.d_str "pi2: " ; Prop.d_pi pi2 ; L.d_ln () ) ;
|
||
|
let atom_list1 =
|
||
|
let p2 = Prop.normalize tenv ep2 in
|
||
|
List.fold ~f:(handle_atom_with_widening Lhs p2 pi2) ~init:[] pi1
|
||
|
in
|
||
|
if Config.trace_join then ( L.d_str "atom_list1: " ; Prop.d_pi atom_list1 ; L.d_ln () ) ;
|
||
|
let atom_list2 =
|
||
|
let p1 = Prop.normalize tenv ep1 in
|
||
|
List.fold ~f:(handle_atom_with_widening Rhs p1 pi1) ~init:[] pi2
|
||
|
in
|
||
|
if Config.trace_join then ( L.d_str "atom_list2: " ; Prop.d_pi atom_list2 ; L.d_ln () ) ;
|
||
7 years ago
|
let atom_list_combined = IList.inter ~cmp:Sil.compare_atom atom_list1 atom_list2 in
|
||
8 years ago
|
if Config.trace_join then (
|
||
|
L.d_str "atom_list_combined: " ; Prop.d_pi atom_list_combined ; L.d_ln () ) ;
|
||
|
atom_list_combined
|
||
|
|
||
7 years ago
|
|
||
8 years ago
|
let pi_partial_meet tenv (p: Prop.normal Prop.t) (ep1: 'a Prop.t) (ep2: 'b Prop.t)
|
||
|
: Prop.normal Prop.t =
|
||
10 years ago
|
let sub1 = Rename.to_subst_emb Lhs in
|
||
|
let sub2 = Rename.to_subst_emb Rhs in
|
||
|
let dom1 = Ident.idlist_to_idset (Sil.sub_domain sub1) in
|
||
|
let dom2 = Ident.idlist_to_idset (Sil.sub_domain sub2) in
|
||
|
let handle_atom sub dom atom =
|
||
7 years ago
|
if Sil.atom_free_vars atom |> Sequence.for_all ~f:(fun id -> Ident.Set.mem id dom) then
|
||
|
Sil.atom_sub (`Exp sub) atom
|
||
8 years ago
|
else ( L.d_str "handle_atom failed on " ; Sil.d_atom atom ; L.d_ln () ; raise Sil.JoinFail )
|
||
|
in
|
||
|
let f1 p' atom = Prop.prop_atom_and tenv p' (handle_atom sub1 dom1 atom) in
|
||
|
let f2 p' atom = Prop.prop_atom_and tenv p' (handle_atom sub2 dom2 atom) in
|
||
9 years ago
|
let pi1 = ep1.Prop.pi in
|
||
|
let pi2 = ep2.Prop.pi in
|
||
8 years ago
|
let p_pi1 = List.fold ~f:f1 ~init:p pi1 in
|
||
|
let p_pi2 = List.fold ~f:f2 ~init:p_pi1 pi2 in
|
||
8 years ago
|
if Prover.check_inconsistency_base tenv p_pi2 then (
|
||
7 years ago
|
L.d_strln "check_inconsistency_base failed" ;
|
||
|
raise Sil.JoinFail )
|
||
10 years ago
|
else p_pi2
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
(** {2 Join and Meet for Prop} *)
|
||
|
|
||
9 years ago
|
let eprop_partial_meet tenv (ep1: 'a Prop.t) (ep2: 'b Prop.t) : 'c Prop.t =
|
||
8 years ago
|
SymOp.pay () ;
|
||
|
(* pay one symop *)
|
||
9 years ago
|
let sigma1 = ep1.Prop.sigma in
|
||
|
let sigma2 = ep2.Prop.sigma in
|
||
10 years ago
|
let es1 = sigma_get_start_lexps_sort sigma1 in
|
||
|
let es2 = sigma_get_start_lexps_sort sigma2 in
|
||
7 years ago
|
let es = IList.merge_sorted_nodup ~cmp:Exp.compare ~res:[] es1 es2 in
|
||
10 years ago
|
let sub_check _ =
|
||
9 years ago
|
let sub1 = ep1.Prop.sub in
|
||
|
let sub2 = ep2.Prop.sub in
|
||
10 years ago
|
let range1 = Sil.sub_range sub1 in
|
||
7 years ago
|
let f e = Exp.free_vars e |> Sequence.for_all ~f:Ident.is_normal in
|
||
8 years ago
|
Sil.equal_exp_subst sub1 sub2 && List.for_all ~f range1
|
||
|
in
|
||
|
if not (sub_check ()) then ( L.d_strln "sub_check() failed" ; raise Sil.JoinFail )
|
||
|
else
|
||
8 years ago
|
let todos = List.map ~f:(fun x -> (x, x, x)) es in
|
||
8 years ago
|
List.iter ~f:Todo.push todos ;
|
||
9 years ago
|
let sigma_new = sigma_partial_meet tenv sigma1 sigma2 in
|
||
9 years ago
|
let ep = Prop.set ep1 ~sigma:sigma_new in
|
||
|
let ep' = Prop.set ep ~pi:[] in
|
||
9 years ago
|
let p' = Prop.normalize tenv ep' in
|
||
|
let p'' = pi_partial_meet tenv p' ep1 ep2 in
|
||
|
let res = Prop.prop_rename_primed_footprint_vars tenv p'' in
|
||
10 years ago
|
res
|
||
|
|
||
7 years ago
|
|
||
9 years ago
|
let prop_partial_meet tenv p1 p2 =
|
||
8 years ago
|
Rename.init () ;
|
||
|
FreshVarExp.init () ;
|
||
|
Todo.init () ;
|
||
10 years ago
|
try
|
||
7 years ago
|
SymOp.try_finally
|
||
|
~f:(fun () -> Some (eprop_partial_meet tenv p1 p2))
|
||
|
~finally:(fun () -> Rename.final () ; FreshVarExp.final () ; Todo.final ())
|
||
8 years ago
|
with Sil.JoinFail -> None
|
||
8 years ago
|
|
||
7 years ago
|
|
||
8 years ago
|
let eprop_partial_join' tenv mode (ep1: Prop.exposed Prop.t) (ep2: Prop.exposed Prop.t)
|
||
|
: Prop.normal Prop.t =
|
||
|
SymOp.pay () ;
|
||
|
(* pay one symop *)
|
||
9 years ago
|
let sigma1 = ep1.Prop.sigma in
|
||
|
let sigma2 = ep2.Prop.sigma in
|
||
10 years ago
|
let es1 = sigma_get_start_lexps_sort sigma1 in
|
||
|
let es2 = sigma_get_start_lexps_sort sigma2 in
|
||
8 years ago
|
let simple_check = Int.equal (List.length es1) (List.length es2) in
|
||
10 years ago
|
let rec expensive_check es1' es2' =
|
||
|
match (es1', es2') with
|
||
7 years ago
|
| [], [] ->
|
||
|
true
|
||
|
| [], _ :: _ | _ :: _, [] ->
|
||
|
false
|
||
|
| e1 :: es1'', e2 :: es2'' ->
|
||
|
Exp.equal e1 e2 && expensive_check es1'' es2''
|
||
8 years ago
|
in
|
||
10 years ago
|
let sub_common, eqs_from_sub1, eqs_from_sub2 =
|
||
9 years ago
|
let sub1 = ep1.Prop.sub in
|
||
|
let sub2 = ep2.Prop.sub in
|
||
10 years ago
|
let sub_common, sub1_only, sub2_only = Sil.sub_symmetric_difference sub1 sub2 in
|
||
|
let sub_common_normal, sub_common_other =
|
||
7 years ago
|
let f e = Exp.free_vars e |> Sequence.for_all ~f:Ident.is_normal in
|
||
8 years ago
|
Sil.sub_range_partition f sub_common
|
||
|
in
|
||
10 years ago
|
let eqs1, eqs2 =
|
||
9 years ago
|
let sub_to_eqs sub =
|
||
8 years ago
|
List.map ~f:(fun (id, e) -> Sil.Aeq (Exp.Var id, e)) (Sil.sub_to_list sub)
|
||
|
in
|
||
10 years ago
|
let eqs1 = sub_to_eqs sub1_only @ sub_to_eqs sub_common_other in
|
||
|
let eqs2 = sub_to_eqs sub2_only in
|
||
8 years ago
|
(eqs1, eqs2)
|
||
|
in
|
||
|
(sub_common_normal, eqs1, eqs2)
|
||
|
in
|
||
|
if not (simple_check && expensive_check es1 es2) then (
|
||
|
if not simple_check then L.d_strln "simple_check failed"
|
||
|
else L.d_strln "expensive_check failed" ;
|
||
|
raise Sil.JoinFail ) ;
|
||
8 years ago
|
let todos = List.map ~f:(fun x -> (x, x, x)) es1 in
|
||
8 years ago
|
List.iter ~f:Todo.push todos ;
|
||
9 years ago
|
match sigma_partial_join tenv mode sigma1 sigma2 with
|
||
7 years ago
|
| sigma_new, [], [] ->
|
||
|
L.d_strln "sigma_partial_join succeeded" ;
|
||
10 years ago
|
let ep_sub =
|
||
9 years ago
|
let ep = Prop.set ep1 ~pi:[] in
|
||
8 years ago
|
Prop.set ep ~sub:sub_common
|
||
|
in
|
||
|
let p_sub_sigma = Prop.normalize tenv (Prop.set ep_sub ~sigma:sigma_new) in
|
||
10 years ago
|
let p_sub_sigma_pi =
|
||
9 years ago
|
let pi1 = ep1.Prop.pi @ eqs_from_sub1 in
|
||
|
let pi2 = ep2.Prop.pi @ eqs_from_sub2 in
|
||
9 years ago
|
let pi' = pi_partial_join tenv mode ep1 ep2 pi1 pi2 in
|
||
8 years ago
|
L.d_strln "pi_partial_join succeeded" ;
|
||
9 years ago
|
let pi_from_fresh_vars = FreshVarExp.get_induced_pi tenv () in
|
||
10 years ago
|
let pi_all = pi' @ pi_from_fresh_vars in
|
||
8 years ago
|
List.fold ~f:(Prop.prop_atom_and tenv) ~init:p_sub_sigma pi_all
|
||
|
in
|
||
10 years ago
|
p_sub_sigma_pi
|
||
7 years ago
|
| _ ->
|
||
|
L.d_strln "leftovers not empty" ; raise Sil.JoinFail
|
||
|
|
||
10 years ago
|
|
||
8 years ago
|
let footprint_partial_join' tenv (p1: Prop.normal Prop.t) (p2: Prop.normal Prop.t)
|
||
|
: Prop.normal Prop.t * Prop.normal Prop.t =
|
||
|
if not !Config.footprint then (p1, p2)
|
||
|
else
|
||
10 years ago
|
let fp1 = Prop.extract_footprint p1 in
|
||
|
let fp2 = Prop.extract_footprint p2 in
|
||
9 years ago
|
let efp = eprop_partial_join' tenv JoinState.Pre fp1 fp2 in
|
||
9 years ago
|
let pi_fp =
|
||
|
let pi_fp0 = Prop.get_pure efp in
|
||
7 years ago
|
let f a = Sil.atom_free_vars a |> Sequence.for_all ~f:Ident.is_footprint in
|
||
8 years ago
|
List.filter ~f pi_fp0
|
||
|
in
|
||
9 years ago
|
let sigma_fp =
|
||
|
let sigma_fp0 = efp.Prop.sigma in
|
||
7 years ago
|
let f a =
|
||
|
Sil.hpred_free_vars a |> Sequence.exists ~f:(fun a -> not (Ident.is_footprint a))
|
||
|
in
|
||
8 years ago
|
if List.exists ~f sigma_fp0 then ( L.d_strln "failure reason 66" ; raise Sil.JoinFail ) ;
|
||
|
sigma_fp0
|
||
|
in
|
||
9 years ago
|
let ep1' = Prop.set p1 ~pi_fp ~sigma_fp in
|
||
|
let ep2' = Prop.set p2 ~pi_fp ~sigma_fp in
|
||
8 years ago
|
(Prop.normalize tenv ep1', Prop.normalize tenv ep2')
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let prop_partial_join pname tenv mode p1 p2 =
|
||
|
let res_by_implication_only =
|
||
|
if !Config.footprint then None
|
||
|
else if Prover.check_implication pname tenv p1 (Prop.expose p2) then Some p2
|
||
|
else if Prover.check_implication pname tenv p2 (Prop.expose p1) then Some p1
|
||
8 years ago
|
else None
|
||
|
in
|
||
10 years ago
|
match res_by_implication_only with
|
||
8 years ago
|
| None
|
||
7 years ago
|
-> (
|
||
8 years ago
|
if !Config.footprint then JoinState.set_footprint true ;
|
||
|
Rename.init () ;
|
||
|
FreshVarExp.init () ;
|
||
|
Todo.init () ;
|
||
|
try
|
||
8 years ago
|
SymOp.try_finally
|
||
8 years ago
|
~f:(fun () ->
|
||
|
let p1', p2' = footprint_partial_join' tenv p1 p2 in
|
||
|
let rename_footprint = Rename.reset () in
|
||
|
Todo.reset rename_footprint ;
|
||
|
let res = eprop_partial_join' tenv mode (Prop.expose p1') (Prop.expose p2') in
|
||
|
if !Config.footprint then JoinState.set_footprint false ;
|
||
7 years ago
|
Some res )
|
||
|
~finally:(fun () -> Rename.final () ; FreshVarExp.final () ; Todo.final ())
|
||
8 years ago
|
with Sil.JoinFail -> None )
|
||
7 years ago
|
| Some _ ->
|
||
|
res_by_implication_only
|
||
|
|
||
8 years ago
|
|
||
|
let eprop_partial_join tenv mode (ep1: Prop.exposed Prop.t) (ep2: Prop.exposed Prop.t)
|
||
|
: Prop.normal Prop.t =
|
||
|
Rename.init () ;
|
||
|
FreshVarExp.init () ;
|
||
|
Todo.init () ;
|
||
7 years ago
|
SymOp.try_finally
|
||
|
~f:(fun () -> eprop_partial_join' tenv mode ep1 ep2)
|
||
|
~finally:(fun () -> Rename.final () ; FreshVarExp.final () ; Todo.final ())
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
(** {2 Join and Meet for Propset} *)
|
||
|
|
||
|
let list_reduce name dd f list =
|
||
|
let rec element_list_reduce acc (x, p1) = function
|
||
7 years ago
|
| [] ->
|
||
|
((x, p1), List.rev acc)
|
||
|
| (y, p2) :: ys ->
|
||
|
L.d_strln ("COMBINE[" ^ name ^ "] ....") ;
|
||
8 years ago
|
L.d_str "ENTRY1: " ;
|
||
|
L.d_ln () ;
|
||
|
dd x ;
|
||
|
L.d_ln () ;
|
||
|
L.d_str "ENTRY2: " ;
|
||
|
L.d_ln () ;
|
||
|
dd y ;
|
||
|
L.d_ln () ;
|
||
|
L.d_ln () ;
|
||
10 years ago
|
match f x y with
|
||
7 years ago
|
| None ->
|
||
|
L.d_strln_color Red (".... COMBINE[" ^ name ^ "] FAILED ...") ;
|
||
8 years ago
|
element_list_reduce ((y, p2) :: acc) (x, p1) ys
|
||
7 years ago
|
| Some x' ->
|
||
|
L.d_strln_color Green (".... COMBINE[" ^ name ^ "] SUCCEEDED ....") ;
|
||
8 years ago
|
L.d_strln "RESULT:" ;
|
||
|
dd x' ;
|
||
|
L.d_ln () ;
|
||
10 years ago
|
element_list_reduce acc (x', p1) ys
|
||
8 years ago
|
in
|
||
10 years ago
|
let rec reduce acc = function
|
||
7 years ago
|
| [] ->
|
||
|
List.rev acc
|
||
|
| x :: xs ->
|
||
|
let x', xs' = element_list_reduce [] x xs in
|
||
8 years ago
|
reduce (x' :: acc) xs'
|
||
|
in
|
||
10 years ago
|
reduce [] list
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
let pathset_collapse_impl pname tenv pset =
|
||
|
let f x y =
|
||
|
if Prover.check_implication pname tenv x (Prop.expose y) then Some y
|
||
|
else if Prover.check_implication pname tenv y (Prop.expose x) then Some x
|
||
8 years ago
|
else None
|
||
|
in
|
||
10 years ago
|
let plist = Paths.PathSet.elements pset in
|
||
|
let plist' = list_reduce "JOIN_IMPL" Prop.d_prop f plist in
|
||
|
Paths.PathSet.from_renamed_list plist'
|
||
|
|
||
7 years ago
|
|
||
9 years ago
|
let jprop_partial_join tenv mode jp1 jp2 =
|
||
8 years ago
|
let p1, p2 = (Prop.expose (Specs.Jprop.to_prop jp1), Prop.expose (Specs.Jprop.to_prop jp2)) in
|
||
10 years ago
|
try
|
||
9 years ago
|
let p = eprop_partial_join tenv mode p1 p2 in
|
||
|
let p_renamed = Prop.prop_rename_primed_footprint_vars tenv p in
|
||
10 years ago
|
Some (Specs.Jprop.Joined (0, p_renamed, jp1, jp2))
|
||
8 years ago
|
with Sil.JoinFail -> None
|
||
10 years ago
|
|
||
7 years ago
|
|
||
9 years ago
|
let jplist_collapse tenv mode jplist =
|
||
|
let f = jprop_partial_join tenv mode in
|
||
10 years ago
|
list_reduce "JOIN" Specs.Jprop.d_shallow f jplist
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
(** Add identifiers to a list of jprops *)
|
||
|
let jprop_list_add_ids jplist =
|
||
|
let seq_number = ref 0 in
|
||
|
let rec do_jprop = function
|
||
7 years ago
|
| Specs.Jprop.Prop (_, p) ->
|
||
|
incr seq_number ; Specs.Jprop.Prop (!seq_number, p)
|
||
|
| Specs.Jprop.Joined (_, p, jp1, jp2) ->
|
||
|
let jp1' = do_jprop jp1 in
|
||
10 years ago
|
let jp2' = do_jprop jp2 in
|
||
8 years ago
|
incr seq_number ; Specs.Jprop.Joined (!seq_number, p, jp1', jp2')
|
||
|
in
|
||
8 years ago
|
List.map ~f:(fun (p, path) -> (do_jprop p, path)) jplist
|
||
10 years ago
|
|
||
7 years ago
|
|
||
9 years ago
|
let proplist_collapse tenv mode plist =
|
||
8 years ago
|
let jplist = List.map ~f:(fun (p, path) -> (Specs.Jprop.Prop (0, p), path)) plist in
|
||
9 years ago
|
let jplist_joined = jplist_collapse tenv mode (jplist_collapse tenv mode jplist) in
|
||
10 years ago
|
jprop_list_add_ids jplist_joined
|
||
|
|
||
7 years ago
|
|
||
9 years ago
|
let proplist_collapse_pre tenv plist =
|
||
8 years ago
|
let plist' = List.map ~f:(fun p -> (p, ())) plist in
|
||
|
List.map ~f:fst (proplist_collapse tenv JoinState.Pre plist')
|
||
10 years ago
|
|
||
7 years ago
|
|
||
9 years ago
|
let pathset_collapse tenv pset =
|
||
10 years ago
|
let plist = Paths.PathSet.elements pset in
|
||
9 years ago
|
let plist' = proplist_collapse tenv JoinState.Post plist in
|
||
8 years ago
|
Paths.PathSet.from_renamed_list
|
||
|
(List.map ~f:(fun (p, path) -> (Specs.Jprop.to_prop p, path)) plist')
|
||
10 years ago
|
|
||
7 years ago
|
|
||
8 years ago
|
let pathset_join pname tenv (pset1: Paths.PathSet.t) (pset2: Paths.PathSet.t)
|
||
|
: Paths.PathSet.t * Paths.PathSet.t =
|
||
10 years ago
|
let mode = JoinState.Post in
|
||
|
let pset_to_plist pset =
|
||
|
let f_list p pa acc = (p, pa) :: acc in
|
||
8 years ago
|
Paths.PathSet.fold f_list pset []
|
||
|
in
|
||
10 years ago
|
let ppalist1 = pset_to_plist pset1 in
|
||
|
let ppalist2 = pset_to_plist pset2 in
|
||
7 years ago
|
let rec join_proppath_plist ppalist2_acc ((p2, pa2) as ppa2) = function
|
||
|
| [] ->
|
||
|
(ppa2, List.rev ppalist2_acc)
|
||
|
| ((p2', pa2') as ppa2') :: ppalist2_rest ->
|
||
|
L.d_strln ".... JOIN ...." ;
|
||
8 years ago
|
L.d_strln "JOIN SYM HEAP1: " ;
|
||
|
Prop.d_prop p2 ;
|
||
|
L.d_ln () ;
|
||
|
L.d_strln "JOIN SYM HEAP2: " ;
|
||
|
Prop.d_prop p2' ;
|
||
|
L.d_ln () ;
|
||
|
L.d_ln () ;
|
||
10 years ago
|
match prop_partial_join pname tenv mode p2 p2' with
|
||
7 years ago
|
| None ->
|
||
|
L.d_strln_color Red ".... JOIN FAILED ...." ;
|
||
8 years ago
|
L.d_ln () ;
|
||
|
join_proppath_plist (ppa2' :: ppalist2_acc) ppa2 ppalist2_rest
|
||
7 years ago
|
| Some p2'' ->
|
||
|
L.d_strln_color Green ".... JOIN SUCCEEDED ...." ;
|
||
8 years ago
|
L.d_strln "RESULT SYM HEAP:" ;
|
||
|
Prop.d_prop p2'' ;
|
||
|
L.d_ln () ;
|
||
|
L.d_ln () ;
|
||
10 years ago
|
join_proppath_plist ppalist2_acc (p2'', Paths.Path.join pa2 pa2') ppalist2_rest
|
||
8 years ago
|
in
|
||
10 years ago
|
let rec join ppalist1_cur ppalist2_acc = function
|
||
7 years ago
|
| [] ->
|
||
|
(ppalist1_cur, ppalist2_acc)
|
||
|
| ppa2 :: ppalist2_rest ->
|
||
|
let ppa2', ppalist2_acc' = join_proppath_plist [] ppa2 ppalist2_acc in
|
||
8 years ago
|
let ppa2'', ppalist2_rest' = join_proppath_plist [] ppa2' ppalist2_rest in
|
||
|
let ppa2_new, ppalist1_cur' = join_proppath_plist [] ppa2'' ppalist1_cur in
|
||
|
join ppalist1_cur' (ppa2_new :: ppalist2_acc') ppalist2_rest'
|
||
|
in
|
||
7 years ago
|
let ppalist1_res_, ppalist2_res_ = join ppalist1 [] ppalist2 in
|
||
8 years ago
|
let ren l = List.map ~f:(fun (p, x) -> (Prop.prop_rename_primed_footprint_vars tenv p, x)) l in
|
||
7 years ago
|
let ppalist1_res, ppalist2_res = (ren ppalist1_res_, ren ppalist2_res_) in
|
||
8 years ago
|
let res =
|
||
|
(Paths.PathSet.from_renamed_list ppalist1_res, Paths.PathSet.from_renamed_list ppalist2_res)
|
||
|
in
|
||
10 years ago
|
res
|
||
|
|
||
7 years ago
|
|
||
10 years ago
|
(**
|
||
10 years ago
|
The meet operator does two things:
|
||
|
1) makes the result logically stronger (just like additive conjunction)
|
||
|
2) makes the result spatially larger (just like multiplicative conjunction).
|
||
|
Assuming that the meet operator forms a partial commutative monoid (soft assumption: it means
|
||
|
that the results are more predictable), try to combine every element of plist with any other element.
|
||
|
Return a list of the same lenght, with each element maximally combined. The algorithm is quadratic.
|
||
|
The operation is dependent on the order in which elements are combined; there is a straightforward
|
||
|
order - independent algorithm but it is exponential.
|
||
10 years ago
|
*)
|
||
9 years ago
|
let proplist_meet_generate tenv plist =
|
||
10 years ago
|
let props_done = ref Propset.empty in
|
||
|
let combine p (porig, pcombined) =
|
||
8 years ago
|
SymOp.pay () ;
|
||
|
(* pay one symop *)
|
||
|
L.d_strln ".... MEET ...." ;
|
||
|
L.d_strln "MEET SYM HEAP1: " ;
|
||
|
Prop.d_prop p ;
|
||
|
L.d_ln () ;
|
||
|
L.d_strln "MEET SYM HEAP2: " ;
|
||
|
Prop.d_prop pcombined ;
|
||
|
L.d_ln () ;
|
||
9 years ago
|
match prop_partial_meet tenv p pcombined with
|
||
7 years ago
|
| None ->
|
||
|
L.d_strln_color Red ".... MEET FAILED ...." ;
|
||
|
L.d_ln () ;
|
||
|
(porig, pcombined)
|
||
|
| Some pcombined' ->
|
||
|
L.d_strln_color Green ".... MEET SUCCEEDED ...." ;
|
||
8 years ago
|
L.d_strln "RESULT SYM HEAP:" ;
|
||
|
Prop.d_prop pcombined' ;
|
||
|
L.d_ln () ;
|
||
|
L.d_ln () ;
|
||
|
(porig, pcombined')
|
||
|
in
|
||
10 years ago
|
let rec proplist_meet = function
|
||
7 years ago
|
| [] ->
|
||
|
()
|
||
|
| (porig, pcombined) :: pplist ->
|
||
|
(* use porig instead of pcombined because it might be combinable with more othe props *)
|
||
10 years ago
|
(* e.g. porig might contain a global var to add to the ture branch of a conditional *)
|
||
|
(* but pcombined might have been combined with the false branch already *)
|
||
8 years ago
|
let pplist' = List.map ~f:(combine porig) pplist in
|
||
8 years ago
|
props_done := Propset.add tenv pcombined !props_done ;
|
||
|
proplist_meet pplist'
|
||
|
in
|
||
|
proplist_meet (List.map ~f:(fun p -> (p, p)) plist) ;
|
||
10 years ago
|
!props_done
|
||
|
|
||
7 years ago
|
|
||
9 years ago
|
let propset_meet_generate_pre tenv pset =
|
||
10 years ago
|
let plist = Propset.to_proplist pset in
|
||
8 years ago
|
if Int.equal Config.meet_level 0 then plist
|
||
10 years ago
|
else
|
||
9 years ago
|
let pset1 = proplist_meet_generate tenv plist in
|
||
10 years ago
|
let pset_new = Propset.diff pset1 pset in
|
||
|
let plist_old = Propset.to_proplist pset in
|
||
|
let plist_new = Propset.to_proplist pset_new in
|
||
|
plist_new @ plist_old
|