Skip to content

Commit d5b7edb

Browse files
authored
Merge pull request #1745 from arkocal/demand_constr
Refactor `goblint.constraint` dune library
2 parents 167e326 + da9c42e commit d5b7edb

38 files changed

+288
-270
lines changed

scripts/goblint-lib-modules.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
goblint_lib_paths = [
1010
src_root_path / "goblint_lib.ml",
11+
src_root_path / "constraint" / "goblint_constraint.ml",
1112
src_root_path / "solver" / "goblint_solver.ml",
1213
src_root_path / "util" / "std" / "goblint_std.ml",
1314
]
@@ -34,6 +35,7 @@
3435

3536
# libraries
3637
"Goblint_std",
38+
"Goblint_constraint",
3739
"Goblint_solver",
3840
"Goblint_timing",
3941
"Goblint_backtrace",

src/analyses/apron/relationPriv.apron.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ module Q = Queries
1212

1313
module RelationComponents = RelationDomain.RelComponents
1414

15+
module VarQuery = Goblint_constraint.VarQuery
16+
1517
open CommonPriv
1618

1719

src/analyses/basePriv.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ module VD = BaseDomain.VD
1111
module CPA = BaseDomain.CPA
1212
module BaseComponents = BaseDomain.BaseComponents
1313

14+
module VarQuery = Goblint_constraint.VarQuery
15+
1416
open CommonPriv
1517

1618

src/analyses/basePriv.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ open GoblintCil
66
(* Cannot use local module substitutions because ppx_import is still stuck at 4.07 AST: https://github.com/ocaml-ppx/ppx_import/issues/50#issuecomment-775817579. *)
77
(* TODO: try again, because ppx_import is now removed *)
88

9+
module VarQuery = Goblint_constraint.VarQuery
10+
911
module type S =
1012
sig
1113
module D: Lattice.S

src/analyses/commonPriv.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ struct
130130

131131
let iter_sys_vars getg vq vf =
132132
match vq with
133-
| VarQuery.Global g -> vf (V.global g)
133+
| Goblint_constraint.VarQuery.Global g -> vf (V.global g)
134134
| _ -> ()
135135
end
136136

src/constraint/constrSys.ml

Lines changed: 36 additions & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
(** {{!MonSystem} constraint system} signatures. *)
1+
(** {{!EqConstrSys} constraint system} signatures. *)
22

33
open Batteries
44

@@ -21,115 +21,6 @@ sig
2121
val relift : t -> t (* needed only for incremental+hashcons to re-hashcons contexts after loading *)
2222
end
2323

24-
(** Abstract incremental change to constraint system.
25-
@param 'v constrain system variable type *)
26-
type 'v sys_change_info = {
27-
obsolete: 'v list; (** Variables to destabilize. *)
28-
delete: 'v list; (** Variables to delete. *)
29-
reluctant: 'v list; (** Variables to solve reluctantly. *)
30-
restart: 'v list; (** Variables to restart. *)
31-
}
32-
33-
(** A side-effecting system. *)
34-
module type MonSystem =
35-
sig
36-
type v (* variables *)
37-
type d (* values *)
38-
type 'a m (* basically a monad carrier *)
39-
40-
(** Variables must be hashable, comparable, etc. *)
41-
module Var : VarType with type t = v
42-
43-
(** Values must form a lattice. *)
44-
module Dom : Lattice.S with type t = d
45-
46-
(** The system in functional form. *)
47-
val system : v -> ((v -> d) -> (v -> d -> unit) -> d) m
48-
49-
(** Compute incremental constraint system change from old solution. *)
50-
val sys_change: (v -> d) -> v sys_change_info
51-
52-
(** List of unknowns that should be queried again when the argument unknown has shrunk to bot, to eagerly trigger (analysis-time!) abstract garbage collection idependently of reach-based pruning at the end.
53-
@see <https://arxiv.org/abs/2504.06026> Stemmler, F., Schwarz, M., Erhard, J., Tilscher, S., Seidl, H. Taking out the Toxic Trash: Recovering Precision in Mixed Flow-Sensitive Static Analyses *)
54-
val postmortem: v -> v list
55-
end
56-
57-
(** Any system of side-effecting equations over lattices. *)
58-
module type EqConstrSys = MonSystem with type 'a m := 'a option
59-
60-
(** A side-effecting system with globals. *)
61-
module type GlobConstrSys =
62-
sig
63-
module LVar : VarType
64-
module GVar : VarType
65-
66-
module D : Lattice.S
67-
module G : Lattice.S
68-
val system : LVar.t -> ((LVar.t -> D.t) -> (LVar.t -> D.t -> unit) -> (GVar.t -> G.t) -> (GVar.t -> G.t -> unit) -> D.t) option
69-
val iter_vars: (LVar.t -> D.t) -> (GVar.t -> G.t) -> VarQuery.t -> LVar.t VarQuery.f -> GVar.t VarQuery.f -> unit
70-
val sys_change: (LVar.t -> D.t) -> (GVar.t -> G.t) -> [`L of LVar.t | `G of GVar.t] sys_change_info
71-
val postmortem: LVar.t -> LVar.t list
72-
end
73-
74-
(** A solver is something that can translate a system into a solution (hash-table).
75-
Incremental solver has data to be marshaled. *)
76-
module type GenericEqIncrSolverBase =
77-
functor (S:EqConstrSys) ->
78-
functor (H:Hashtbl.S with type key=S.v) ->
79-
sig
80-
type marshal
81-
82-
val copy_marshal: marshal -> marshal
83-
val relift_marshal: marshal -> marshal
84-
85-
(** The hash-map that is the first component of [solve xs vs] is a local solution for interesting variables [vs],
86-
reached from starting values [xs].
87-
As a second component the solver returns data structures for incremental serialization. *)
88-
val solve : (S.v*S.d) list -> S.v list -> marshal option -> S.d H.t * marshal
89-
end
90-
91-
(** (Incremental) solver argument, indicating which postsolving should be performed by the solver. *)
92-
module type IncrSolverArg =
93-
sig
94-
val should_prune: bool
95-
val should_verify: bool
96-
val should_warn: bool
97-
val should_save_run: bool
98-
end
99-
100-
(** An incremental solver takes the argument about postsolving. *)
101-
module type GenericEqIncrSolver =
102-
functor (Arg: IncrSolverArg) ->
103-
GenericEqIncrSolverBase
104-
105-
(** A solver is something that can translate a system into a solution (hash-table) *)
106-
module type GenericEqSolver =
107-
functor (S:EqConstrSys) ->
108-
functor (H:Hashtbl.S with type key=S.v) ->
109-
sig
110-
(** The hash-map that is the first component of [solve xs vs] is a local solution for interesting variables [vs],
111-
reached from starting values [xs]. *)
112-
val solve : (S.v*S.d) list -> S.v list -> S.d H.t
113-
end
114-
115-
(** A solver is something that can translate a system into a solution (hash-table) *)
116-
module type GenericGlobSolver =
117-
functor (S:GlobConstrSys) ->
118-
functor (LH:Hashtbl.S with type key=S.LVar.t) ->
119-
functor (GH:Hashtbl.S with type key=S.GVar.t) ->
120-
sig
121-
type marshal
122-
123-
val copy_marshal: marshal -> marshal
124-
val relift_marshal: marshal -> marshal
125-
126-
(** The hash-map that is the first component of [solve xs vs] is a local solution for interesting variables [vs],
127-
reached from starting values [xs].
128-
As a second component the solver returns data structures for incremental serialization. *)
129-
val solve : (S.LVar.t*S.D.t) list -> (S.GVar.t*S.G.t) list -> S.LVar.t list -> marshal option -> (S.D.t LH.t * S.G.t GH.t) * marshal
130-
end
131-
132-
13324
(** Combined variables so that we can also use the more common [EqConstrSys]
13425
that uses only one kind of a variable. *)
13526
module Var2 (LV:VarType) (GV:VarType)
@@ -163,124 +54,52 @@ struct
16354
| `G a -> GV.is_write_only a
16455
end
16556

57+
(** Abstract incremental change to constraint system.
58+
@param 'v constrain system variable type *)
59+
type 'v sys_change_info = {
60+
obsolete: 'v list; (** Variables to destabilize. *)
61+
delete: 'v list; (** Variables to delete. *)
62+
reluctant: 'v list; (** Variables to solve reluctantly. *)
63+
restart: 'v list; (** Variables to restart. *)
64+
}
16665

167-
(** Translate a [GlobConstrSys] into a [EqConstrSys] *)
168-
module EqConstrSysFromGlobConstrSys (S:GlobConstrSys)
169-
: EqConstrSys with type v = Var2(S.LVar)(S.GVar).t
170-
and type d = Lattice.Lift2(S.G)(S.D).t
171-
and module Var = Var2(S.LVar)(S.GVar)
172-
and module Dom = Lattice.Lift2(S.G)(S.D)
173-
=
174-
struct
175-
module Var = Var2(S.LVar)(S.GVar)
176-
module Dom =
177-
struct
178-
include Lattice.Lift2 (S.G) (S.D)
179-
let printXml f = function
180-
| `Lifted1 a -> S.G.printXml f a
181-
| `Lifted2 a -> S.D.printXml f a
182-
| (`Bot | `Top) as x -> printXml f x
183-
end
184-
type v = Var.t
185-
type d = Dom.t
186-
187-
let getG = function
188-
| `Lifted1 x -> x
189-
| `Bot -> S.G.bot ()
190-
| `Top -> failwith "EqConstrSysFromGlobConstrSys.getG: global variable has top value"
191-
| `Lifted2 _ -> failwith "EqConstrSysFromGlobConstrSys.getG: global variable has local value"
192-
193-
let getL = function
194-
| `Lifted2 x -> x
195-
| `Bot -> S.D.bot ()
196-
| `Top -> failwith "EqConstrSysFromGlobConstrSys.getL: local variable has top value"
197-
| `Lifted1 _ -> failwith "EqConstrSysFromGlobConstrSys.getL: local variable has global value"
198-
199-
let l, g = (fun x -> `L x), (fun x -> `G x)
200-
let lD, gD = (fun x -> `Lifted2 x), (fun x -> `Lifted1 x)
66+
(** A side-effecting system. *)
67+
module type EqConstrSys =
68+
sig
69+
type v (* variables *)
70+
type d (* values *)
20171

202-
let conv f get set =
203-
f (getL % get % l) (fun x v -> set (l x) (lD v))
204-
(getG % get % g) (fun x v -> set (g x) (gD v))
205-
|> lD
72+
(** Variables must be hashable, comparable, etc. *)
73+
module Var : VarType with type t = v
20674

207-
let system = function
208-
| `G _ -> None
209-
| `L x -> Option.map conv (S.system x)
75+
(** Values must form a lattice. *)
76+
module Dom : Lattice.S with type t = d
21077

211-
let sys_change get =
212-
S.sys_change (getL % get % l) (getG % get % g)
78+
(** The system in functional form. *)
79+
val system : v -> ((v -> d) -> (v -> d -> unit) -> d) option
21380

214-
let postmortem = function
215-
| `L g -> List.map (fun x -> `L x) @@ S.postmortem g
216-
| _ -> []
217-
end
81+
(** Compute incremental constraint system change from old solution. *)
82+
val sys_change: (v -> d) -> v sys_change_info
21883

219-
(** Splits a [EqConstrSys] solution into a [GlobConstrSys] solution with given [Hashtbl.S] for the [EqConstrSys]. *)
220-
module GlobConstrSolFromEqConstrSolBase (S: GlobConstrSys) (LH: Hashtbl.S with type key = S.LVar.t) (GH: Hashtbl.S with type key = S.GVar.t) (VH: Hashtbl.S with type key = Var2 (S.LVar) (S.GVar).t) =
221-
struct
222-
let split_solution hm =
223-
let l' = LH.create 113 in
224-
let g' = GH.create 113 in
225-
let split_vars x d = match x with
226-
| `L x ->
227-
begin match d with
228-
| `Lifted2 d -> LH.replace l' x d
229-
(* | `Bot -> () *)
230-
(* Since Verify2 is broken and only checks existing keys, add it with local bottom value.
231-
This works around some cases, where Verify2 would not detect a problem due to completely missing variable. *)
232-
| `Bot -> LH.replace l' x (S.D.bot ())
233-
| `Top -> failwith "GlobConstrSolFromEqConstrSolBase.split_vars: local variable has top value"
234-
| `Lifted1 _ -> failwith "GlobConstrSolFromEqConstrSolBase.split_vars: local variable has global value"
235-
end
236-
| `G x ->
237-
begin match d with
238-
| `Lifted1 d -> GH.replace g' x d
239-
| `Bot -> ()
240-
| `Top -> failwith "GlobConstrSolFromEqConstrSolBase.split_vars: global variable has top value"
241-
| `Lifted2 _ -> failwith "GlobConstrSolFromEqConstrSolBase.split_vars: global variable has local value"
242-
end
243-
in
244-
VH.iter split_vars hm;
245-
(l', g')
84+
(** List of unknowns that should be queried again when the argument unknown has shrunk to bot, to eagerly trigger (analysis-time!) abstract garbage collection idependently of reach-based pruning at the end.
85+
@see <https://arxiv.org/abs/2504.06026> Stemmler, F., Schwarz, M., Erhard, J., Tilscher, S., Seidl, H. Taking out the Toxic Trash: Recovering Precision in Mixed Flow-Sensitive Static Analyses *)
86+
val postmortem: v -> v list
24687
end
24788

248-
(** Splits a [EqConstrSys] solution into a [GlobConstrSys] solution. *)
249-
module GlobConstrSolFromEqConstrSol (S: GlobConstrSys) (LH: Hashtbl.S with type key = S.LVar.t) (GH: Hashtbl.S with type key = S.GVar.t) =
250-
struct
251-
module S2 = EqConstrSysFromGlobConstrSys (S)
252-
module VH = Hashtbl.Make (S2.Var)
89+
(** A side-effecting system with globals. *)
90+
module type GlobConstrSys =
91+
sig
92+
module LVar : VarType
93+
module GVar : VarType
25394

254-
include GlobConstrSolFromEqConstrSolBase (S) (LH) (GH) (VH)
95+
module D : Lattice.S
96+
module G : Lattice.S
97+
val system : LVar.t -> ((LVar.t -> D.t) -> (LVar.t -> D.t -> unit) -> (GVar.t -> G.t) -> (GVar.t -> G.t -> unit) -> D.t) option
98+
val iter_vars: (LVar.t -> D.t) -> (GVar.t -> G.t) -> VarQuery.t -> LVar.t VarQuery.f -> GVar.t VarQuery.f -> unit
99+
val sys_change: (LVar.t -> D.t) -> (GVar.t -> G.t) -> [`L of LVar.t | `G of GVar.t] sys_change_info
100+
val postmortem: LVar.t -> LVar.t list
255101
end
256102

257-
(** Transforms a [GenericEqIncrSolver] into a [GenericGlobSolver]. *)
258-
module GlobSolverFromEqSolver (Sol:GenericEqIncrSolverBase)
259-
= functor (S:GlobConstrSys) ->
260-
functor (LH:Hashtbl.S with type key=S.LVar.t) ->
261-
functor (GH:Hashtbl.S with type key=S.GVar.t) ->
262-
struct
263-
module EqSys = EqConstrSysFromGlobConstrSys (S)
264-
265-
module VH : Hashtbl.S with type key=EqSys.v = Hashtbl.Make(EqSys.Var)
266-
module Sol' = Sol (EqSys) (VH)
267-
268-
module Splitter = GlobConstrSolFromEqConstrSolBase (S) (LH) (GH) (VH) (* reuse EqSys and VH *)
269-
270-
type marshal = Sol'.marshal
271-
272-
let copy_marshal = Sol'.copy_marshal
273-
let relift_marshal = Sol'.relift_marshal
274-
275-
let solve ls gs l old_data =
276-
let vs = List.map (fun (x,v) -> `L x, `Lifted2 v) ls
277-
@ List.map (fun (x,v) -> `G x, `Lifted1 v) gs in
278-
let sv = List.map (fun x -> `L x) l in
279-
let hm, solver_data = Sol'.solve vs sv old_data in
280-
Splitter.split_solution hm, solver_data
281-
end
282-
283-
284103
(** [EqConstrSys] where [current_var] indicates the variable whose right-hand side is currently being evaluated. *)
285104
module CurrentVarEqConstrSys (S: EqConstrSys) =
286105
struct

src/constraint/constraint.mld

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/constraint/dune

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
(library
44
(name goblint_constraint)
55
(public_name goblint.constraint)
6-
(wrapped false) ; TODO: wrap
76
(libraries
87
batteries.unthreaded
98
goblint_std
@@ -17,5 +16,3 @@
1716
ppx_deriving_hash
1817
ppx_deriving_yojson))
1918
(instrumentation (backend bisect_ppx)))
20-
21-
(documentation)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
(** (Side-effecting) constraint systems. *)
2+
3+
(** {1 Specification} *)
4+
5+
module ConstrSys = ConstrSys
6+
module SolverTypes = SolverTypes
7+
8+
(** {2 Utilities} *)
9+
10+
module Translators = Translators
11+
12+
13+
(** {1 Results} *)
14+
15+
module VarQuery = VarQuery

0 commit comments

Comments
 (0)