Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file sideWPointSelect.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222(** Strategies for widening leaf unknowns *)openBatteriesopenGoblint_constraint.ConstrSysopenMessagesmoduletypeS=functor(S:EqConstrSys)->functor(HM:Hashtbl.Swithtypekey=S.v)->functor(VS:Set.Swithtypeelt=S.v)->sigtypedata(** Create data required by this widening point selection strategy.
The parameters are not necessarily used by all strategies.
@param is_stable This callback should return whether an unknown is stable.
@param add_infl Allows the strategy to record additional influences.
This is mainly intended for strategies like unstable-self,
which records the influence of a side-effecting unknown x to the leaf y.
*)valcreate_data:(S.v->bool)->(S.v->S.v->unit)->data(** Notifies this strategy that a side-effect has occurred.
This allows the strategy to adapt its internal data structure.
@param data The internal state of this strategy
@param x The optional source of the side-effect
@param y The leaf receiving the side-effect
*)valnotify_side:data->S.voption->S.v->unit(** Whether the destabilization of the side-effected var should record the destabilization
of called variables and start variables. This information should be passed to [should_mark_wpoint]
by the solver.
*)valrecord_destabilized_vs:bool(** This strategy can decide to prevent widening.
Note that, if this strategy does not veto, this does not mean that widening
will necessarily be performed. Nor does a call to this function imply that
the value of the leaf has grown.
@param data The internal state of this strategy
@param called Set of called unknowns
@param old_sides Prior side-effects to leaf y
@param x Optional source of the side-effect
@param y Side-effected leaf y
@return [true]: widening will not be applied; [false]: widening might be applied
*)valveto_widen:data->unitHM.t->VS.t->S.voption->S.v->bool(** The value of the leaf has grown. Should it be marked a widening point?
Widening points are widened when their value grows, unless vetoed.
Even if this function is called, leaf y might already be a widening point
from an earlier side-effect.
@param data The internal state of this strategy
@param called Set of called unknowns
@param old_sides Prior side-effects to leaf y
@param x Optional source of the side-effect
@param y Side-effected leaf y
@param destabilized_vs Optional destabilization info, described in [record_destabilized_vs]
@return [true]: mark as widening point; [false]: do not mark as widening point
*)valshould_mark_wpoint:data->unitHM.t->VS.t->S.voption->S.v->booloption->boolend(** Any side-effect after the first one will be widened which will unnecessarily lose precision. *)moduleAlways:S=functor(S:EqConstrSys)->functor(HM:Hashtbl.Swithtypekey=S.v)->functor(VS:Set.Swithtypeelt=S.v)->structtypedata=unitletcreate_data__=()letnotify_side___=()letrecord_destabilized_vs=falseletveto_widen_____=falseletshould_mark_wpoint______=trueend(* On side-effect cycles, this should terminate via the outer `solver` loop. TODO check. *)(** Never widen side-effects. *)moduleNever:S=functor(S:EqConstrSys)->functor(HM:Hashtbl.Swithtypekey=S.v)->functor(VS:Set.Swithtypeelt=S.v)->structtypedata=unitletcreate_data__=()letnotify_side___=()letrecord_destabilized_vs=falseletveto_widen_____=falseletshould_mark_wpoint______=falseend(** Widening check happens by checking sides.
Only widen if value increases and there has already been a side-effect from the same source *)moduleSidesLocal:S=functor(S:EqConstrSys)->functor(HM:Hashtbl.Swithtypekey=S.v)->functor(VS:Set.Swithtypeelt=S.v)->structtypedata=unitletcreate_data__=()letnotify_side___=()letrecord_destabilized_vs=falseletveto_widenstatecalledold_sidesxy=matchxwith|None->false|SomexwhenVS.memxold_sides->false|_->trueletshould_mark_wpoint______=trueend(** If there was already a `side x y d` from the same program point and now again, make y a widening point.
Different from `Sides` in that it will not distinguish between side-effects from different contexts,
only the program point matters. *)moduleSidesPP:S=functor(S:EqConstrSys)->functor(HM:Hashtbl.Swithtypekey=S.v)->functor(VS:Set.Swithtypeelt=S.v)->structtypedata=unitletcreate_data__=()letnotify_side___=()letrecord_destabilized_vs=falseletveto_widenstatecalledold_sidesxy=falseletshould_mark_wpointstatecalledold_sidesxy_=matchxwith|Somex->letn=S.Var.nodexinVS.exists(funv->Node.equal(S.Var.nodev)n)old_sides|None->false(* TODO: This is consistent with the previous implementation, but if multiple side-effects come in with x = None,
the leaf will never be widened. This is different from SidesLocal *)end(** If there already was a `side x y d` that changed rho[y] and now again, we make y a wpoint.
x caused more than one update to y. >=3 partial context calls will be precise since sides come from different x. TODO this has 8 instead of 5 phases of `solver` for side_cycle.c *)moduleSides:S=functor(S:EqConstrSys)->functor(HM:Hashtbl.Swithtypekey=S.v)->functor(VS:Set.Swithtypeelt=S.v)->structtypedata=unitletcreate_data__=()letnotify_side___=()letrecord_destabilized_vs=falseletveto_widenstatecalledold_sidesxy=falseletshould_mark_wpointstatecalledold_sidesxy_=matchxwith|Some(x)->VS.memxold_sides|None->trueend(* TODO: The following two don't check if a vs got destabilized which may be a problem. *)(* TODO test/remove. Check for which examples this is problematic! *)(** Side to y destabilized itself via some infl-cycle. Records influences from unknowns to globals *)moduleUnstableSelf:S=functor(S:EqConstrSys)->functor(HM:Hashtbl.Swithtypekey=S.v)->functor(VS:Set.Swithtypeelt=S.v)->structtypedata={is_stable:S.v->bool;add_infl:S.v->S.v->unit}letcreate_datais_stableadd_infl={is_stable;add_infl}letnotify_sidedataxy=(matchxwithNone->()|Somex->data.add_inflxy)letrecord_destabilized_vs=falseletveto_widen_____=falseletshould_mark_wpointstatecalledold_sidesxy_=not(state.is_stabley)end(* TODO test/remove. *)(** Widen if any called var (not just y) is no longer stable. Expensive! *)moduleUnstableCalled:S=functor(S:EqConstrSys)->functor(HM:Hashtbl.Swithtypekey=S.v)->functor(VS:Set.Swithtypeelt=S.v)->structtypedata={is_stable:S.v->bool}letcreate_datais_stable_={is_stable}letnotify_side___=()letrecord_destabilized_vs=falseletveto_widenstatecalledold_sidesyx=falseletshould_mark_wpointstatecalledold_sidesyx_=HM.exists(funk_->not(state.is_stablek))called(* this is very expensive since it iterates over called! see https://github.com/goblint/analyzer/issues/265#issuecomment-880748636 *)end(** Destabilized a called or start var. Problem: two partial context calls will be precise, but third call will widen the state.
If this side destabilized some of the initial unknowns vs, there may be a side-cycle between vs and we should make y a wpoint *)moduleCycle:S=functor(S:EqConstrSys)->functor(HM:Hashtbl.Swithtypekey=S.v)->functor(VS:Set.Swithtypeelt=S.v)->structtypedata=unitletcreate_data__=()letnotify_side___=()letrecord_destabilized_vs=trueletveto_widenstatecalledold_sidesxy=falseletshould_mark_wpointstatecalledold_sidesxycycle=matchcyclewith|Somecycle->iftracing&&cyclethentrace"side_widen""cycle: should mark wpoint %a"S.Var.pretty_tracey;cycle|None->failwith"destabilize_vs information not provided to side_widen cycle strategy";endletchoose_impl:unit->(moduleS)=fun()->letconf=GobConfig.get_string"solvers.td3.side_widen"inmatchconfwith|"always"->(moduleAlways)|"never"->(moduleNever)|"sides-local"->(moduleSidesLocal)|"sides"->(moduleSides)|"sides-pp"->(moduleSidesPP)|"unstable-self"->(moduleUnstableSelf)|"unstable-called"->(moduleUnstableCalled)|"cycle"->(moduleCycle)|_->failwith("Unknown value '"^conf^"' for option solvers.td3.side_widen!")