Skip to content

Commit 82a3b43

Browse files
authored
Merge pull request #1668 from goblint/invariant-mli
Add abstract interface to `Invariant`
2 parents 0109577 + 245ab07 commit 82a3b43

File tree

5 files changed

+85
-56
lines changed

5 files changed

+85
-56
lines changed

src/cdomain/value/domains/invariant.ml

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
(** Invariants for witnesses. *)
2-
31
open GoblintCil
42

53
(** Symbolic (and fully syntactic) expression "lattice". *)
6-
module ExpLat =
4+
module Exp =
75
struct
86
include CilType.Exp
7+
(* This type is abstract in the interface because invariant expressions may be optimized for readability but lack implicit casts, etc, which are required to normally use CIL exp-s in Goblint. *)
98

109
let bot () = zero (* false *)
1110
let top () = one (* true *)
@@ -22,8 +21,52 @@ struct
2221
let meet x y = BinOp (LAnd, x, y, intType)
2322
let widen x y = y
2423
let narrow = meet
24+
25+
let to_cil = Fun.id
26+
27+
28+
module ES = SetDomain.Make (CilType.Exp)
29+
30+
(* Turns an expression into alist of conjuncts, pulling out common conjuncts from top-level disjunctions *)
31+
let rec pullOutCommonConjuncts e =
32+
let rec to_conjunct_set = function
33+
| Cil.BinOp(LAnd,e1,e2,_) -> ES.join (to_conjunct_set e1) (to_conjunct_set e2)
34+
| e -> ES.singleton e
35+
in
36+
let combine_conjuncts es = ES.fold (fun e acc -> match acc with | None -> Some e | Some acce -> Some (BinOp(LAnd,acce,e,Cil.intType))) es None in
37+
match e with
38+
| Cil.BinOp(LOr, e1, e2,t) ->
39+
let e1s = pullOutCommonConjuncts e1 in
40+
let e2s = pullOutCommonConjuncts e2 in
41+
let common = ES.inter e1s e2s in
42+
let e1s' = ES.diff e1s e2s in
43+
let e2s' = ES.diff e2s e1s in
44+
(match combine_conjuncts e1s', combine_conjuncts e2s' with
45+
| Some e1e, Some e2e -> ES.add (BinOp(LOr,e1e,e2e,Cil.intType)) common
46+
| _ -> common (* if one of the disjuncts is empty, it is equivalent to true here *)
47+
)
48+
| e -> to_conjunct_set e
49+
50+
let process inv =
51+
let exp_deep_unroll_types =
52+
if GobConfig.get_bool "witness.invariant.typedefs" then
53+
Fun.id
54+
else
55+
InvariantCil.exp_deep_unroll_types
56+
in
57+
let inv' =
58+
inv
59+
|> exp_deep_unroll_types
60+
|> InvariantCil.exp_replace_original_name
61+
in
62+
if GobConfig.get_bool "witness.invariant.split-conjunction" then
63+
ES.elements (pullOutCommonConjuncts inv')
64+
|> List.filter (Fun.negate InvariantCil.exp_contains_anon_type)
65+
else
66+
[inv']
2567
end
2668

69+
2770
(** Lift {!ExpLat} such that join/meet folds don't introduce excessive [|| 0|] or [&& 1] expressions. *)
2871

2972
module N =
@@ -33,7 +76,7 @@ struct
3376
let top_name = "true"
3477
end
3578

36-
include Lattice.LiftConf (N) (ExpLat)
79+
include Lattice.LiftConf (N) (Exp)
3780

3881
let none = top ()
3982
let of_exp = lift
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
(** Invariants for witnesses. *)
2+
3+
module Exp:
4+
sig
5+
include Printable.S
6+
7+
val process: t -> t list
8+
9+
val to_cil: t -> GoblintCil.exp
10+
(** Breaks abstraction, only for use in {!EvalAssert}! *)
11+
end
12+
13+
14+
include Lattice.S with type t = [ `Bot | `Lifted of Exp.t | `Top ]
15+
16+
val none: t
17+
val of_exp: GoblintCil.exp -> t
18+
19+
val (&&): t -> t -> t
20+
val (||): t -> t -> t
21+
22+
23+
type context = {
24+
path: int option;
25+
lvals: Lval.Set.t;
26+
}
27+
28+
val default_context : context

src/transform/evalAssert.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ struct
6060
let context = {Invariant.default_context with lvals} in
6161
match (ask ~node loc).f (Queries.Invariant context) with
6262
| `Lifted e ->
63-
let es = WitnessUtil.InvariantExp.process_exp e in
64-
let asserts = List.map (fun e -> cInstr ("%v:assert (%e:exp);") loc [("assert", Fv assert_function); ("exp", Fe e)]) es in
63+
let es = Invariant.Exp.process e in
64+
let asserts = List.map (fun e -> cInstr ("%v:assert (%e:exp);") loc [("assert", Fv assert_function); ("exp", Fe (Invariant.Exp.to_cil e))]) es in
6565
if surroundByAtomic then
6666
let abegin = (cInstr ("%v:__VERIFIER_atomic_begin();") loc [("__VERIFIER_atomic_begin", Fv atomicBegin)]) in
6767
let aend = (cInstr ("%v:__VERIFIER_atomic_end();") loc [("__VERIFIER_atomic_end", Fv atomicEnd)]) in

src/witness/witnessUtil.ml

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -139,48 +139,6 @@ struct
139139
end
140140
[@@deprecated]
141141

142-
module InvariantExp =
143-
struct
144-
module ES = SetDomain.Make (CilType.Exp)
145-
146-
(* Turns an expression into alist of conjuncts, pulling out common conjuncts from top-level disjunctions *)
147-
let rec pullOutCommonConjuncts e =
148-
let rec to_conjunct_set = function
149-
| Cil.BinOp(LAnd,e1,e2,_) -> ES.join (to_conjunct_set e1) (to_conjunct_set e2)
150-
| e -> ES.singleton e
151-
in
152-
let combine_conjuncts es = ES.fold (fun e acc -> match acc with | None -> Some e | Some acce -> Some (BinOp(LAnd,acce,e,Cil.intType))) es None in
153-
match e with
154-
| Cil.BinOp(LOr, e1, e2,t) ->
155-
let e1s = pullOutCommonConjuncts e1 in
156-
let e2s = pullOutCommonConjuncts e2 in
157-
let common = ES.inter e1s e2s in
158-
let e1s' = ES.diff e1s e2s in
159-
let e2s' = ES.diff e2s e1s in
160-
(match combine_conjuncts e1s', combine_conjuncts e2s' with
161-
| Some e1e, Some e2e -> ES.add (BinOp(LOr,e1e,e2e,Cil.intType)) common
162-
| _ -> common (* if one of the disjuncts is empty, it is equivalent to true here *)
163-
)
164-
| e -> to_conjunct_set e
165-
166-
let process_exp inv =
167-
let exp_deep_unroll_types =
168-
if GobConfig.get_bool "witness.invariant.typedefs" then
169-
Fun.id
170-
else
171-
InvariantCil.exp_deep_unroll_types
172-
in
173-
let inv' =
174-
inv
175-
|> exp_deep_unroll_types
176-
|> InvariantCil.exp_replace_original_name
177-
in
178-
if GobConfig.get_bool "witness.invariant.split-conjunction" then
179-
ES.elements (pullOutCommonConjuncts inv')
180-
|> List.filter (Fun.negate InvariantCil.exp_contains_anon_type)
181-
else
182-
[inv']
183-
end
184142

185143
module InvariantParser =
186144
struct

src/witness/yamlWitness.ml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ struct
232232
(* Currently same invariants (from InvariantGlobal query) for all nodes (from InvariantGlobalNodes query).
233233
The alternative would be querying InvariantGlobal per local unknown when looping over them to generate location invariants.
234234
See: https://github.com/goblint/analyzer/pull/1394#discussion_r1698149514. *)
235-
let invs = WitnessUtil.InvariantExp.process_exp inv in
235+
let invs = Invariant.Exp.process inv in
236236
Queries.NS.fold (fun n acc ->
237237
let fundec = Node.find_fundec n in
238238
match WitnessInvariant.location_location n with (* Not just using Node.location because it returns expression location which may be invalid for location invariant (e.g. inside conditional). *)
@@ -293,9 +293,9 @@ struct
293293
let fundec = Node.find_fundec (List.hd ns) in (* TODO: fix location hack *)
294294
let location_function = fundec.svar.vname in
295295
let location = Entry.location ~location:loc ~location_function in
296-
let invs = WitnessUtil.InvariantExp.process_exp inv in
296+
let invs = Invariant.Exp.process inv in
297297
List.fold_left (fun acc inv ->
298-
let invariant = CilType.Exp.show inv in
298+
let invariant = Invariant.Exp.show inv in
299299
let invariant = Entry.location_invariant ~location ~invariant in
300300
incr cnt_location_invariant;
301301
invariant :: acc
@@ -323,9 +323,9 @@ struct
323323
let fundec = Node.find_fundec (List.hd ns) in (* TODO: fix location hack *)
324324
let location_function = fundec.svar.vname in
325325
let location = Entry.location ~location:loc ~location_function in
326-
let invs = WitnessUtil.InvariantExp.process_exp inv in
326+
let invs = Invariant.Exp.process inv in
327327
List.fold_left (fun acc inv ->
328-
let invariant = CilType.Exp.show inv in
328+
let invariant = Invariant.Exp.show inv in
329329
let invariant = Entry.loop_invariant ~location ~invariant in
330330
incr cnt_loop_invariant;
331331
invariant :: acc
@@ -349,17 +349,17 @@ struct
349349
| `Left g -> (* global unknown from analysis Spec *)
350350
begin match R.ask_global (InvariantGlobal (Obj.repr g)), GobConfig.get_string "witness.invariant.flow_insensitive-as" with
351351
| `Lifted inv, "invariant_set-flow_insensitive_invariant" ->
352-
let invs = WitnessUtil.InvariantExp.process_exp inv in
352+
let invs = Invariant.Exp.process inv in
353353
List.fold_left (fun acc inv ->
354-
let invariant = CilType.Exp.show inv in
354+
let invariant = Invariant.Exp.show inv in
355355
let invariant = Entry.flow_insensitive_invariant ~invariant in
356356
incr cnt_flow_insensitive_invariant;
357357
invariant :: acc
358358
) acc invs
359359
| `Lifted inv, "invariant_set-location_invariant" ->
360360
(* TODO: fold_flow_insensitive_as_location is now only used here, inline/move? *)
361361
fold_flow_insensitive_as_location ~inv (fun ~location ~inv acc ->
362-
let invariant = CilType.Exp.show inv in
362+
let invariant = Invariant.Exp.show inv in
363363
let invariant = Entry.location_invariant ~location ~invariant in
364364
incr cnt_location_invariant;
365365
invariant :: acc

0 commit comments

Comments
 (0)