|
|
|
@ -29,7 +29,8 @@ type if_kind =
|
|
|
|
|
| Ik_if
|
|
|
|
|
| Ik_land_lor /* obtained from translation of && or || */
|
|
|
|
|
| Ik_while
|
|
|
|
|
| Ik_switch;
|
|
|
|
|
| Ik_switch
|
|
|
|
|
[@@deriving compare];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** An instruction. */
|
|
|
|
@ -57,7 +58,8 @@ type instr =
|
|
|
|
|
| Nullify Pvar.t Location.t
|
|
|
|
|
| Abstract Location.t /** apply abstraction */
|
|
|
|
|
| Remove_temps (list Ident.t) Location.t /** remove temporaries */
|
|
|
|
|
| Declare_locals (list (Pvar.t, Typ.t)) Location.t /** declare local variables */;
|
|
|
|
|
| Declare_locals (list (Pvar.t, Typ.t)) Location.t /** declare local variables */
|
|
|
|
|
[@@deriving compare];
|
|
|
|
|
|
|
|
|
|
let skip_instr = Remove_temps [] Location.dummy;
|
|
|
|
|
|
|
|
|
@ -88,21 +90,27 @@ type atom =
|
|
|
|
|
| Aeq Exp.t Exp.t /** equality */
|
|
|
|
|
| Aneq Exp.t Exp.t /** disequality */
|
|
|
|
|
| Apred PredSymb.t (list Exp.t) /** predicate symbol applied to exps */
|
|
|
|
|
| Anpred PredSymb.t (list Exp.t) /** negated predicate symbol applied to exps */;
|
|
|
|
|
| Anpred PredSymb.t (list Exp.t) /** negated predicate symbol applied to exps */
|
|
|
|
|
[@@deriving compare];
|
|
|
|
|
|
|
|
|
|
let equal_atom x y => compare_atom x y == 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** kind of lseg or dllseg predicates */
|
|
|
|
|
type lseg_kind =
|
|
|
|
|
| Lseg_NE /** nonempty (possibly circular) listseg */
|
|
|
|
|
| Lseg_PE /** possibly empty (possibly circular) listseg */;
|
|
|
|
|
| Lseg_PE /** possibly empty (possibly circular) listseg */
|
|
|
|
|
[@@deriving compare];
|
|
|
|
|
|
|
|
|
|
let equal_lseg_kind k1 k2 => compare_lseg_kind k1 k2 == 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** The boolean is true when the pointer was dereferenced without testing for zero. */
|
|
|
|
|
type zero_flag = option bool;
|
|
|
|
|
type zero_flag = option bool [@@deriving compare];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** True when the value was obtained by doing case analysis on null in a procedure call. */
|
|
|
|
|
type null_case_flag = bool;
|
|
|
|
|
type null_case_flag = bool [@@deriving compare];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** instrumentation of heap values */
|
|
|
|
@ -118,13 +126,19 @@ type inst =
|
|
|
|
|
| Irearrange zero_flag null_case_flag int PredSymb.path_pos
|
|
|
|
|
| Itaint
|
|
|
|
|
| Iupdate zero_flag null_case_flag int PredSymb.path_pos
|
|
|
|
|
| Ireturn_from_call int;
|
|
|
|
|
| Ireturn_from_call int
|
|
|
|
|
[@@deriving compare];
|
|
|
|
|
|
|
|
|
|
/* some occurrences of inst are always ignored by compare */
|
|
|
|
|
type _inst = inst;
|
|
|
|
|
|
|
|
|
|
let compare__inst _ _ => 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** structured expressions represent a value of structured type, such as an array or a struct. */
|
|
|
|
|
type strexp =
|
|
|
|
|
| Eexp Exp.t inst /** Base case: expression with instrumentation */
|
|
|
|
|
| Estruct (list (Ident.fieldname, strexp)) inst /** C structure */
|
|
|
|
|
type strexp0 'inst =
|
|
|
|
|
| Eexp Exp.t 'inst /** Base case: expression with instrumentation */
|
|
|
|
|
| Estruct (list (Ident.fieldname, strexp0 _inst)) 'inst /** C structure */
|
|
|
|
|
/** Array of given length
|
|
|
|
|
There are two conditions imposed / used in the array case.
|
|
|
|
|
First, if some index and value pair appears inside an array
|
|
|
|
@ -132,45 +146,102 @@ type strexp =
|
|
|
|
|
For instance, x |->[10 | e1: v1] implies that e1 <= 9.
|
|
|
|
|
Second, if two indices appear in an array, they should be different.
|
|
|
|
|
For instance, x |->[10 | e1: v1, e2: v2] implies that e1 != e2. */
|
|
|
|
|
| Earray Exp.t (list (Exp.t, strexp)) inst;
|
|
|
|
|
| Earray Exp.t (list (Exp.t, strexp0 _inst)) 'inst
|
|
|
|
|
[@@deriving compare];
|
|
|
|
|
|
|
|
|
|
type strexp = strexp0 inst;
|
|
|
|
|
|
|
|
|
|
let compare_strexp inst::inst=false se1 se2 =>
|
|
|
|
|
compare_strexp0 (inst ? compare_inst : compare__inst) se1 se2;
|
|
|
|
|
|
|
|
|
|
let equal_strexp inst::inst=false se1 se2 => compare_strexp inst::inst se1 se2 == 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** an atomic heap predicate */
|
|
|
|
|
type hpred =
|
|
|
|
|
| Hpointsto Exp.t strexp Exp.t
|
|
|
|
|
type hpred0 'inst =
|
|
|
|
|
| Hpointsto Exp.t (strexp0 'inst) Exp.t
|
|
|
|
|
/** represents [exp|->strexp:typexp] where [typexp]
|
|
|
|
|
is an expression representing a type, e.h. [sizeof(t)]. */
|
|
|
|
|
| Hlseg lseg_kind hpara Exp.t Exp.t (list Exp.t)
|
|
|
|
|
| Hlseg lseg_kind (hpara0 'inst) Exp.t Exp.t (list Exp.t)
|
|
|
|
|
/** higher - order predicate for singly - linked lists.
|
|
|
|
|
Should ensure that exp1!= exp2 implies that exp1 is allocated.
|
|
|
|
|
This assumption is used in the rearrangement. The last [exp list] parameter
|
|
|
|
|
is used to denote the shared links by all the nodes in the list. */
|
|
|
|
|
| Hdllseg lseg_kind hpara_dll Exp.t Exp.t Exp.t Exp.t (list Exp.t)
|
|
|
|
|
/** higher-order predicate for doubly-linked lists. */
|
|
|
|
|
/** parameter for the higher-order singly-linked list predicate.
|
|
|
|
|
Means "lambda (root,next,svars). Exists evars. body".
|
|
|
|
|
Assume that root, next, svars, evars are disjoint sets of
|
|
|
|
|
primed identifiers, and include all the free primed identifiers in body.
|
|
|
|
|
body should not contain any non - primed identifiers or program
|
|
|
|
|
variables (i.e. pvars). */
|
|
|
|
|
and hpara = {
|
|
|
|
|
| Hdllseg lseg_kind (hpara_dll0 'inst) Exp.t Exp.t Exp.t Exp.t (list Exp.t)
|
|
|
|
|
/** higher-order predicate for doubly-linked lists.
|
|
|
|
|
Parameter for the higher-order singly-linked list predicate.
|
|
|
|
|
Means "lambda (root,next,svars). Exists evars. body".
|
|
|
|
|
Assume that root, next, svars, evars are disjoint sets of
|
|
|
|
|
primed identifiers, and include all the free primed identifiers in body.
|
|
|
|
|
body should not contain any non - primed identifiers or program
|
|
|
|
|
variables (i.e. pvars). */
|
|
|
|
|
[@@deriving compare]
|
|
|
|
|
and hpara0 'inst = {
|
|
|
|
|
root: Ident.t,
|
|
|
|
|
next: Ident.t,
|
|
|
|
|
svars: list Ident.t,
|
|
|
|
|
evars: list Ident.t,
|
|
|
|
|
body: list hpred
|
|
|
|
|
body: list (hpred0 'inst)
|
|
|
|
|
}
|
|
|
|
|
[@@deriving compare]
|
|
|
|
|
/** parameter for the higher-order doubly-linked list predicates.
|
|
|
|
|
Assume that all the free identifiers in body_dll should belong to
|
|
|
|
|
cell, blink, flink, svars_dll, evars_dll. */
|
|
|
|
|
and hpara_dll = {
|
|
|
|
|
and hpara_dll0 'inst = {
|
|
|
|
|
cell: Ident.t, /** address cell */
|
|
|
|
|
blink: Ident.t, /** backward link */
|
|
|
|
|
flink: Ident.t, /** forward link */
|
|
|
|
|
svars_dll: list Ident.t,
|
|
|
|
|
evars_dll: list Ident.t,
|
|
|
|
|
body_dll: list hpred
|
|
|
|
|
};
|
|
|
|
|
body_dll: list (hpred0 'inst)
|
|
|
|
|
}
|
|
|
|
|
[@@deriving compare];
|
|
|
|
|
|
|
|
|
|
type hpred = hpred0 inst;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Comparsion between heap predicates. Reverse natural order, and order first by anchor exp. */
|
|
|
|
|
let compare_hpred inst::inst=false hpred1 hpred2 =>
|
|
|
|
|
if (hpred1 === hpred2) {
|
|
|
|
|
0
|
|
|
|
|
} else {
|
|
|
|
|
switch (hpred1, hpred2) {
|
|
|
|
|
| (
|
|
|
|
|
Hpointsto e1 _ _ | Hlseg _ _ e1 _ _ | Hdllseg _ _ e1 _ _ _ _,
|
|
|
|
|
Hpointsto e2 _ _ | Hlseg _ _ e2 _ _ | Hdllseg _ _ e2 _ _ _ _
|
|
|
|
|
)
|
|
|
|
|
when Exp.compare e2 e1 != 0 =>
|
|
|
|
|
Exp.compare e2 e1
|
|
|
|
|
| (Hpointsto _, Hpointsto _)
|
|
|
|
|
| (Hlseg _, Hlseg _)
|
|
|
|
|
| (Hdllseg _, Hdllseg _) =>
|
|
|
|
|
if inst {
|
|
|
|
|
compare_hpred0 compare_inst hpred2 hpred1
|
|
|
|
|
} else {
|
|
|
|
|
compare_hpred0 (fun _ _ => 0) hpred2 hpred1
|
|
|
|
|
}
|
|
|
|
|
| _ =>
|
|
|
|
|
if inst {
|
|
|
|
|
compare_hpred0 compare_inst hpred1 hpred2
|
|
|
|
|
} else {
|
|
|
|
|
compare_hpred0 (fun _ _ => 0) hpred1 hpred2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let equal_hpred inst::inst=false hpred1 hpred2 => compare_hpred inst::inst hpred1 hpred2 == 0;
|
|
|
|
|
|
|
|
|
|
type hpara = hpara0 inst;
|
|
|
|
|
|
|
|
|
|
let compare_hpara = compare_hpara0 (fun _ _ => 0);
|
|
|
|
|
|
|
|
|
|
let equal_hpara hpara1 hpara2 => compare_hpara hpara1 hpara2 == 0;
|
|
|
|
|
|
|
|
|
|
type hpara_dll = hpara_dll0 inst;
|
|
|
|
|
|
|
|
|
|
let compare_hpara_dll = compare_hpara_dll0 (fun _ _ => 0);
|
|
|
|
|
|
|
|
|
|
let equal_hpara_dll hpara1 hpara2 => compare_hpara_dll hpara1 hpara2 == 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Return the lhs expression of a hpred */
|
|
|
|
@ -222,343 +293,6 @@ let is_static_local_name pname pvar => {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let ident_exp_compare = pair_compare Ident.compare Exp.compare;
|
|
|
|
|
|
|
|
|
|
let ident_exp_equal ide1 ide2 => ident_exp_compare ide1 ide2 == 0;
|
|
|
|
|
|
|
|
|
|
let exp_list_compare = IList.compare Exp.compare;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Compare atoms. Equalities come before disequalities */
|
|
|
|
|
let atom_compare a b =>
|
|
|
|
|
if (a === b) {
|
|
|
|
|
0
|
|
|
|
|
} else {
|
|
|
|
|
switch (a, b) {
|
|
|
|
|
| (Aeq e1 e2, Aeq f1 f2) =>
|
|
|
|
|
let n = Exp.compare e1 f1;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
Exp.compare e2 f2
|
|
|
|
|
}
|
|
|
|
|
| (Aeq _, _) => (-1)
|
|
|
|
|
| (_, Aeq _) => 1
|
|
|
|
|
| (Aneq e1 e2, Aneq f1 f2) =>
|
|
|
|
|
let n = Exp.compare e1 f1;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
Exp.compare e2 f2
|
|
|
|
|
}
|
|
|
|
|
| (Aneq _, _) => (-1)
|
|
|
|
|
| (_, Aneq _) => 1
|
|
|
|
|
| (Apred a1 es1, Apred a2 es2) =>
|
|
|
|
|
let n = PredSymb.compare a1 a2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
IList.compare Exp.compare es1 es2
|
|
|
|
|
}
|
|
|
|
|
| (Apred _, _) => (-1)
|
|
|
|
|
| (_, Apred _) => 1
|
|
|
|
|
| (Anpred a1 es1, Anpred a2 es2) =>
|
|
|
|
|
let n = PredSymb.compare a1 a2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
IList.compare Exp.compare es1 es2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let atom_equal x y => atom_compare x y == 0;
|
|
|
|
|
|
|
|
|
|
let lseg_kind_compare k1 k2 =>
|
|
|
|
|
switch (k1, k2) {
|
|
|
|
|
| (Lseg_NE, Lseg_NE) => 0
|
|
|
|
|
| (Lseg_NE, Lseg_PE) => (-1)
|
|
|
|
|
| (Lseg_PE, Lseg_NE) => 1
|
|
|
|
|
| (Lseg_PE, Lseg_PE) => 0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let lseg_kind_equal k1 k2 => lseg_kind_compare k1 k2 == 0;
|
|
|
|
|
|
|
|
|
|
let zero_flag_compare = opt_compare bool_compare;
|
|
|
|
|
|
|
|
|
|
let inst_compare_base inst1 inst2 =>
|
|
|
|
|
switch (inst1, inst2) {
|
|
|
|
|
| (Iabstraction, Iabstraction) => 0
|
|
|
|
|
| (Iabstraction, _) => (-1)
|
|
|
|
|
| (_, Iabstraction) => 1
|
|
|
|
|
| (Iactual_precondition, Iactual_precondition) => 0
|
|
|
|
|
| (Iactual_precondition, _) => (-1)
|
|
|
|
|
| (_, Iactual_precondition) => 1
|
|
|
|
|
| (Ialloc, Ialloc) => 0
|
|
|
|
|
| (Ialloc, _) => (-1)
|
|
|
|
|
| (_, Ialloc) => 1
|
|
|
|
|
| (Iformal zero_flag1 null_case_flag1, Iformal zero_flag2 null_case_flag2) =>
|
|
|
|
|
let n = zero_flag_compare zero_flag1 zero_flag2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
bool_compare null_case_flag1 null_case_flag2
|
|
|
|
|
}
|
|
|
|
|
| (Iformal _, _) => (-1)
|
|
|
|
|
| (_, Iformal _) => 1
|
|
|
|
|
| (Iinitial, Iinitial) => 0
|
|
|
|
|
| (Iinitial, _) => (-1)
|
|
|
|
|
| (_, Iinitial) => 1
|
|
|
|
|
| (Ilookup, Ilookup) => 0
|
|
|
|
|
| (Ilookup, _) => (-1)
|
|
|
|
|
| (_, Ilookup) => 1
|
|
|
|
|
| (Inone, Inone) => 0
|
|
|
|
|
| (Inone, _) => (-1)
|
|
|
|
|
| (_, Inone) => 1
|
|
|
|
|
| (Inullify, Inullify) => 0
|
|
|
|
|
| (Inullify, _) => (-1)
|
|
|
|
|
| (_, Inullify) => 1
|
|
|
|
|
| (
|
|
|
|
|
Irearrange zero_flag1 null_case_flag1 i1 path_pos1,
|
|
|
|
|
Irearrange zero_flag2 null_case_flag2 i2 path_pos2
|
|
|
|
|
) =>
|
|
|
|
|
let n = zero_flag_compare zero_flag1 zero_flag2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = bool_compare null_case_flag1 null_case_flag2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = int_compare i1 i2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
PredSymb.compare_path_pos path_pos1 path_pos2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
| (Irearrange _, _) => (-1)
|
|
|
|
|
| (_, Irearrange _) => 1
|
|
|
|
|
| (Itaint, Itaint) => 0
|
|
|
|
|
| (Itaint, _) => (-1)
|
|
|
|
|
| (_, Itaint) => 1
|
|
|
|
|
| (
|
|
|
|
|
Iupdate zero_flag1 null_case_flag1 i1 path_pos1,
|
|
|
|
|
Iupdate zero_flag2 null_case_flag2 i2 path_pos2
|
|
|
|
|
) =>
|
|
|
|
|
let n = zero_flag_compare zero_flag1 zero_flag2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = bool_compare null_case_flag1 null_case_flag2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = int_compare i1 i2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
PredSymb.compare_path_pos path_pos1 path_pos2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
| (Iupdate _, _) => (-1)
|
|
|
|
|
| (_, Iupdate _) => 1
|
|
|
|
|
| (Ireturn_from_call i1, Ireturn_from_call i2) => int_compare i1 i2
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let inst_compare inst::inst inst1 inst2 => inst ? inst_compare_base inst1 inst2 : 0;
|
|
|
|
|
|
|
|
|
|
/* Comparison for strexps */
|
|
|
|
|
let rec strexp_compare inst::inst=false se1 se2 =>
|
|
|
|
|
if (se1 === se2) {
|
|
|
|
|
0
|
|
|
|
|
} else {
|
|
|
|
|
switch (se1, se2) {
|
|
|
|
|
| (Eexp e1 i1, Eexp e2 i2) =>
|
|
|
|
|
let n = Exp.compare e1 e2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
inst_compare inst::inst i1 i2
|
|
|
|
|
}
|
|
|
|
|
| (Eexp _, _) => (-1)
|
|
|
|
|
| (_, Eexp _) => 1
|
|
|
|
|
| (Estruct fel1 i1, Estruct fel2 i2) =>
|
|
|
|
|
let n = fld_strexp_list_compare fel1 fel2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
inst_compare inst::inst i1 i2
|
|
|
|
|
}
|
|
|
|
|
| (Estruct _, _) => (-1)
|
|
|
|
|
| (_, Estruct _) => 1
|
|
|
|
|
| (Earray e1 esel1 i1, Earray e2 esel2 i2) =>
|
|
|
|
|
let n = Exp.compare e1 e2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = exp_strexp_list_compare esel1 esel2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
inst_compare inst::inst i1 i2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
and fld_strexp_compare fse1 fse2 => pair_compare Ident.compare_fieldname strexp_compare fse1 fse2
|
|
|
|
|
and fld_strexp_list_compare fsel1 fsel2 => IList.compare fld_strexp_compare fsel1 fsel2
|
|
|
|
|
and exp_strexp_compare ese1 ese2 => pair_compare Exp.compare strexp_compare ese1 ese2
|
|
|
|
|
and exp_strexp_list_compare esel1 esel2 => IList.compare exp_strexp_compare esel1 esel2;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Comparsion between heap predicates. Hpointsto comes before others. */
|
|
|
|
|
let rec hpred_compare inst::inst=false hpred1 hpred2 =>
|
|
|
|
|
if (hpred1 === hpred2) {
|
|
|
|
|
0
|
|
|
|
|
} else {
|
|
|
|
|
switch (hpred1, hpred2) {
|
|
|
|
|
| (Hpointsto e1 _ _, Hlseg _ _ e2 _ _) when Exp.compare e2 e1 != 0 => Exp.compare e2 e1
|
|
|
|
|
| (Hpointsto e1 _ _, Hdllseg _ _ e2 _ _ _ _) when Exp.compare e2 e1 != 0 => Exp.compare e2 e1
|
|
|
|
|
| (Hlseg _ _ e1 _ _, Hpointsto e2 _ _) when Exp.compare e2 e1 != 0 => Exp.compare e2 e1
|
|
|
|
|
| (Hlseg _ _ e1 _ _, Hdllseg _ _ e2 _ _ _ _) when Exp.compare e2 e1 != 0 => Exp.compare e2 e1
|
|
|
|
|
| (Hdllseg _ _ e1 _ _ _ _, Hpointsto e2 _ _) when Exp.compare e2 e1 != 0 => Exp.compare e2 e1
|
|
|
|
|
| (Hdllseg _ _ e1 _ _ _ _, Hlseg _ _ e2 _ _) when Exp.compare e2 e1 != 0 => Exp.compare e2 e1
|
|
|
|
|
| (Hpointsto e1 se1 te1, Hpointsto e2 se2 te2) =>
|
|
|
|
|
let n = Exp.compare e2 e1;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = strexp_compare inst::inst se2 se1;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
Exp.compare te2 te1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
| (Hpointsto _, _) => (-1)
|
|
|
|
|
| (_, Hpointsto _) => 1
|
|
|
|
|
| (Hlseg k1 hpar1 e1 f1 el1, Hlseg k2 hpar2 e2 f2 el2) =>
|
|
|
|
|
let n = Exp.compare e2 e1;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = lseg_kind_compare k2 k1;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = hpara_compare hpar2 hpar1;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Exp.compare f2 f1;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
exp_list_compare el2 el1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
| (Hlseg _, Hdllseg _) => (-1)
|
|
|
|
|
| (Hdllseg _, Hlseg _) => 1
|
|
|
|
|
| (Hdllseg k1 hpar1 e1 f1 g1 h1 el1, Hdllseg k2 hpar2 e2 f2 g2 h2 el2) =>
|
|
|
|
|
let n = Exp.compare e2 e1;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = lseg_kind_compare k2 k1;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = hpara_dll_compare hpar2 hpar1;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Exp.compare f2 f1;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Exp.compare g2 g1;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Exp.compare h2 h1;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
exp_list_compare el2 el1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
and hpred_list_compare l1 l2 => IList.compare hpred_compare l1 l2
|
|
|
|
|
and hpara_compare hp1 hp2 => {
|
|
|
|
|
let n = Ident.compare hp1.root hp2.root;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Ident.compare hp1.next hp2.next;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = IList.compare Ident.compare hp1.svars hp2.svars;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = IList.compare Ident.compare hp1.evars hp2.evars;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
hpred_list_compare hp1.body hp2.body
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
and hpara_dll_compare hp1 hp2 => {
|
|
|
|
|
let n = Ident.compare hp1.cell hp2.cell;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Ident.compare hp1.blink hp2.blink;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Ident.compare hp1.flink hp2.flink;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = IList.compare Ident.compare hp1.svars_dll hp2.svars_dll;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = IList.compare Ident.compare hp1.evars_dll hp2.evars_dll;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
hpred_list_compare hp1.body_dll hp2.body_dll
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let strexp_equal inst::inst=false se1 se2 => strexp_compare inst::inst se1 se2 == 0;
|
|
|
|
|
|
|
|
|
|
let hpred_equal inst::inst=false hpred1 hpred2 => hpred_compare inst::inst hpred1 hpred2 == 0;
|
|
|
|
|
|
|
|
|
|
let hpara_equal hpara1 hpara2 => hpara_compare hpara1 hpara2 == 0;
|
|
|
|
|
|
|
|
|
|
let hpara_dll_equal hpara1 hpara2 => hpara_dll_compare hpara1 hpara2 == 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** {2 Sets of expressions} */
|
|
|
|
|
let elist_to_eset es => IList.fold_left (fun set e => Exp.Set.add e set) Exp.Set.empty es;
|
|
|
|
@ -567,7 +301,7 @@ let elist_to_eset es => IList.fold_left (fun set e => Exp.Set.add e set) Exp.Set
|
|
|
|
|
/** {2 Sets of heap predicates} */
|
|
|
|
|
let module HpredSet = Set.Make {
|
|
|
|
|
type t = hpred;
|
|
|
|
|
let compare = hpred_compare inst::false;
|
|
|
|
|
let compare = compare_hpred inst::false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -891,14 +625,14 @@ let module Predicates: {
|
|
|
|
|
/** hash tables for hpara */
|
|
|
|
|
let module HparaHash = Hashtbl.Make {
|
|
|
|
|
type t = hpara;
|
|
|
|
|
let equal = hpara_equal;
|
|
|
|
|
let equal = equal_hpara;
|
|
|
|
|
let hash = Hashtbl.hash;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** hash tables for hpara_dll */
|
|
|
|
|
let module HparaDllHash = Hashtbl.Make {
|
|
|
|
|
type t = hpara_dll;
|
|
|
|
|
let equal = hpara_dll_equal;
|
|
|
|
|
let equal = equal_hpara_dll;
|
|
|
|
|
let hash = Hashtbl.hash;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -1915,36 +1649,15 @@ let rec sorted_list_check_consecutives f =>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** substitution */
|
|
|
|
|
type subst = list (Ident.t, Exp.t);
|
|
|
|
|
type ident_exp = (Ident.t, Exp.t) [@@deriving compare];
|
|
|
|
|
|
|
|
|
|
let equal_ident_exp ide1 ide2 => compare_ident_exp ide1 ide2 == 0;
|
|
|
|
|
|
|
|
|
|
/** Comparison between substitutions. */
|
|
|
|
|
let rec sub_compare (sub1: subst) (sub2: subst) =>
|
|
|
|
|
if (sub1 === sub2) {
|
|
|
|
|
0
|
|
|
|
|
} else {
|
|
|
|
|
switch (sub1, sub2) {
|
|
|
|
|
| ([], []) => 0
|
|
|
|
|
| ([], [_, ..._]) => (-1)
|
|
|
|
|
| ([(i1, e1), ...sub1'], [(i2, e2), ...sub2']) =>
|
|
|
|
|
let n = Ident.compare i1 i2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Exp.compare e1 e2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
sub_compare sub1' sub2'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
| ([_, ..._], []) => 1
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
type subst = list ident_exp [@@deriving compare];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Equality for substitutions. */
|
|
|
|
|
let sub_equal sub1 sub2 => sub_compare sub1 sub2 == 0;
|
|
|
|
|
let equal_subst sub1 sub2 => compare_subst sub1 sub2 == 0;
|
|
|
|
|
|
|
|
|
|
let sub_check_duplicated_ids sub => {
|
|
|
|
|
let f (id1, _) (id2, _) => Ident.equal id1 id2;
|
|
|
|
@ -1956,8 +1669,8 @@ let sub_check_duplicated_ids sub => {
|
|
|
|
|
For all (id1, e1), (id2, e2) in the input list,
|
|
|
|
|
if id1 = id2, then e1 = e2. */
|
|
|
|
|
let sub_of_list sub => {
|
|
|
|
|
let sub' = IList.sort ident_exp_compare sub;
|
|
|
|
|
let sub'' = remove_duplicates_from_sorted ident_exp_equal sub';
|
|
|
|
|
let sub' = IList.sort compare_ident_exp sub;
|
|
|
|
|
let sub'' = remove_duplicates_from_sorted equal_ident_exp sub';
|
|
|
|
|
if (sub_check_duplicated_ids sub'') {
|
|
|
|
|
assert false
|
|
|
|
|
};
|
|
|
|
@ -1967,7 +1680,7 @@ let sub_of_list sub => {
|
|
|
|
|
|
|
|
|
|
/** like sub_of_list, but allow duplicate ids and only keep the first occurrence */
|
|
|
|
|
let sub_of_list_duplicates sub => {
|
|
|
|
|
let sub' = IList.sort ident_exp_compare sub;
|
|
|
|
|
let sub' = IList.sort compare_ident_exp sub;
|
|
|
|
|
let rec remove_duplicate_ids =
|
|
|
|
|
fun
|
|
|
|
|
| [(id1, e1), (id2, e2), ...l] =>
|
|
|
|
@ -1992,8 +1705,8 @@ let sub_empty = sub_of_list [];
|
|
|
|
|
/** Join two substitutions into one.
|
|
|
|
|
For all id in dom(sub1) cap dom(sub2), sub1(id) = sub2(id). */
|
|
|
|
|
let sub_join sub1 sub2 => {
|
|
|
|
|
let sub = sorted_list_merge ident_exp_compare sub1 sub2;
|
|
|
|
|
let sub' = remove_duplicates_from_sorted ident_exp_equal sub;
|
|
|
|
|
let sub = sorted_list_merge compare_ident_exp sub1 sub2;
|
|
|
|
|
let sub' = remove_duplicates_from_sorted equal_ident_exp sub;
|
|
|
|
|
if (sub_check_duplicated_ids sub') {
|
|
|
|
|
assert false
|
|
|
|
|
};
|
|
|
|
@ -2015,7 +1728,7 @@ let sub_symmetric_difference sub1_in sub2_in => {
|
|
|
|
|
let sub_common = reverse_with_base [] sub_common;
|
|
|
|
|
(sub_common, sub1_only', sub2_only')
|
|
|
|
|
| ([id_e1, ...sub1'], [id_e2, ...sub2']) =>
|
|
|
|
|
let n = ident_exp_compare id_e1 id_e2;
|
|
|
|
|
let n = compare_ident_exp id_e1 id_e2;
|
|
|
|
|
if (n == 0) {
|
|
|
|
|
diff [id_e1, ...sub_common] sub1_only sub2_only sub1' sub2'
|
|
|
|
|
} else if (n < 0) {
|
|
|
|
@ -2280,145 +1993,6 @@ let instr_sub_ids sub_id_binders::sub_id_binders (f: Ident.t => Exp.t) instr =>
|
|
|
|
|
/** apply [subst] to all id's in [instr], including binder id's */
|
|
|
|
|
let instr_sub (subst: subst) instr => instr_sub_ids sub_id_binders::true (apply_sub subst) instr;
|
|
|
|
|
|
|
|
|
|
let id_typ_compare (id1, typ1) (id2, typ2) => {
|
|
|
|
|
let n = Ident.compare id1 id2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
Typ.compare typ1 typ2
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let exp_typ_compare (exp1, typ1) (exp2, typ2) => {
|
|
|
|
|
let n = Exp.compare exp1 exp2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
Typ.compare typ1 typ2
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let instr_compare instr1 instr2 =>
|
|
|
|
|
switch (instr1, instr2) {
|
|
|
|
|
| (Load id1 e1 t1 loc1, Load id2 e2 t2 loc2) =>
|
|
|
|
|
let n = Ident.compare id1 id2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Exp.compare e1 e2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Typ.compare t1 t2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
Location.compare loc1 loc2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
| (Load _, _) => (-1)
|
|
|
|
|
| (_, Load _) => 1
|
|
|
|
|
| (Store e11 t1 e21 loc1, Store e12 t2 e22 loc2) =>
|
|
|
|
|
let n = Exp.compare e11 e12;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Typ.compare t1 t2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Exp.compare e21 e22;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
Location.compare loc1 loc2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
| (Store _, _) => (-1)
|
|
|
|
|
| (_, Store _) => 1
|
|
|
|
|
| (Prune cond1 loc1 true_branch1 ik1, Prune cond2 loc2 true_branch2 ik2) =>
|
|
|
|
|
let n = Exp.compare cond1 cond2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Location.compare loc1 loc2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = bool_compare true_branch1 true_branch2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
Pervasives.compare ik1 ik2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
| (Prune _, _) => (-1)
|
|
|
|
|
| (_, Prune _) => 1
|
|
|
|
|
| (Call ret_id1 e1 arg_ts1 loc1 cf1, Call ret_id2 e2 arg_ts2 loc2 cf2) =>
|
|
|
|
|
let n = opt_compare id_typ_compare ret_id1 ret_id2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Exp.compare e1 e2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = IList.compare exp_typ_compare arg_ts1 arg_ts2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
let n = Location.compare loc1 loc2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
CallFlags.compare cf1 cf2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
| (Call _, _) => (-1)
|
|
|
|
|
| (_, Call _) => 1
|
|
|
|
|
| (Nullify pvar1 loc1, Nullify pvar2 loc2) =>
|
|
|
|
|
let n = Pvar.compare pvar1 pvar2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
Location.compare loc1 loc2
|
|
|
|
|
}
|
|
|
|
|
| (Nullify _, _) => (-1)
|
|
|
|
|
| (_, Nullify _) => 1
|
|
|
|
|
| (Abstract loc1, Abstract loc2) => Location.compare loc1 loc2
|
|
|
|
|
| (Abstract _, _) => (-1)
|
|
|
|
|
| (_, Abstract _) => 1
|
|
|
|
|
| (Remove_temps temps1 loc1, Remove_temps temps2 loc2) =>
|
|
|
|
|
let n = IList.compare Ident.compare temps1 temps2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
Location.compare loc1 loc2
|
|
|
|
|
}
|
|
|
|
|
| (Remove_temps _, _) => (-1)
|
|
|
|
|
| (_, Remove_temps _) => 1
|
|
|
|
|
| (Declare_locals ptl1 loc1, Declare_locals ptl2 loc2) =>
|
|
|
|
|
let pt_compare (pv1, t1) (pv2, t2) => {
|
|
|
|
|
let n = Pvar.compare pv1 pv2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
Typ.compare t1 t2
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
let n = IList.compare pt_compare ptl1 ptl2;
|
|
|
|
|
if (n != 0) {
|
|
|
|
|
n
|
|
|
|
|
} else {
|
|
|
|
|
Location.compare loc1 loc2
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** compare expressions from different procedures without considering loc's, ident's, and pvar's.
|
|
|
|
|
the [exp_map] param gives a mapping of names used in the procedure of [e1] to names used in the
|
|
|
|
@ -2515,7 +2089,7 @@ let exp_typ_compare_structural (e1, t1) (e2, t2) exp_map => {
|
|
|
|
|
/** compare instructions from different procedures without considering loc's, ident's, and pvar's.
|
|
|
|
|
the [exp_map] param gives a mapping of names used in the procedure of [instr1] to identifiers
|
|
|
|
|
used in the procedure of [instr2] */
|
|
|
|
|
let instr_compare_structural instr1 instr2 exp_map => {
|
|
|
|
|
let compare_structural_instr instr1 instr2 exp_map => {
|
|
|
|
|
let id_typ_opt_compare_structural id_typ1 id_typ2 exp_map => {
|
|
|
|
|
let id_typ_compare_structural (id1, typ1) (id2, typ2) => {
|
|
|
|
|
let (n, exp_map) = exp_compare_structural (Var id1) (Var id2) exp_map;
|
|
|
|
@ -2660,7 +2234,7 @@ let instr_compare_structural instr1 instr2 exp_map => {
|
|
|
|
|
ptl1
|
|
|
|
|
ptl2
|
|
|
|
|
}
|
|
|
|
|
| _ => (instr_compare instr1 instr2, exp_map)
|
|
|
|
|
| _ => (compare_instr instr1 instr2, exp_map)
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -2726,7 +2300,7 @@ let hpred_replace_exp epairs =>
|
|
|
|
|
/** {2 Compaction} */
|
|
|
|
|
let module HpredInstHash = Hashtbl.Make {
|
|
|
|
|
type t = hpred;
|
|
|
|
|
let equal = hpred_equal inst::true;
|
|
|
|
|
let equal = equal_hpred inst::true;
|
|
|
|
|
let hash = Hashtbl.hash;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|