|
|
|
@ -61,9 +61,7 @@ module T = struct
|
|
|
|
|
| Record
|
|
|
|
|
[@@deriving compare, equal, hash, sexp]
|
|
|
|
|
|
|
|
|
|
type t = {desc: desc; term: Term.t}
|
|
|
|
|
|
|
|
|
|
and desc =
|
|
|
|
|
type t =
|
|
|
|
|
| Reg of {name: string; global: bool; typ: Typ.t}
|
|
|
|
|
| Nondet of {msg: string; typ: Typ.t}
|
|
|
|
|
| Label of {parent: string; name: string}
|
|
|
|
@ -81,7 +79,57 @@ include T
|
|
|
|
|
module Set = struct include Set.Make (T) include Provide_of_sexp (T) end
|
|
|
|
|
module Map = Map.Make (T)
|
|
|
|
|
|
|
|
|
|
let term e = e.term
|
|
|
|
|
let unsigned typ = Term.unsigned (Typ.bit_size_of typ)
|
|
|
|
|
|
|
|
|
|
let rec term = function
|
|
|
|
|
| Reg {name; global; typ= _} ->
|
|
|
|
|
Term.var (Var.program ?global:(Option.some_if global ()) name)
|
|
|
|
|
| Nondet {msg; typ= _} -> Term.nondet msg
|
|
|
|
|
| Label {parent; name} -> Term.label ~parent ~name
|
|
|
|
|
| Integer {data; typ= _} -> Term.integer data
|
|
|
|
|
| Float {data; typ= _} -> Term.float data
|
|
|
|
|
| Ap1 (Signed {bits}, _, x) -> Term.signed bits (term x)
|
|
|
|
|
| Ap1 (Unsigned {bits}, _, x) -> Term.unsigned bits (term x)
|
|
|
|
|
| Ap1 (Convert {src}, dst, exp) -> Term.convert src ~to_:dst (term exp)
|
|
|
|
|
| Ap2 (Eq, _, x, y) -> Term.eq (term x) (term y)
|
|
|
|
|
| Ap2 (Dq, _, x, y) -> Term.dq (term x) (term y)
|
|
|
|
|
| Ap2 (Gt, _, x, y) -> Term.lt (term y) (term x)
|
|
|
|
|
| Ap2 (Ge, _, x, y) -> Term.le (term y) (term x)
|
|
|
|
|
| Ap2 (Lt, _, x, y) -> Term.lt (term x) (term y)
|
|
|
|
|
| Ap2 (Le, _, x, y) -> Term.le (term x) (term y)
|
|
|
|
|
| Ap2 (Ugt, typ, x, y) ->
|
|
|
|
|
Term.lt (unsigned typ (term y)) (unsigned typ (term x))
|
|
|
|
|
| Ap2 (Uge, typ, x, y) ->
|
|
|
|
|
Term.le (unsigned typ (term y)) (unsigned typ (term x))
|
|
|
|
|
| Ap2 (Ult, typ, x, y) ->
|
|
|
|
|
Term.lt (unsigned typ (term x)) (unsigned typ (term y))
|
|
|
|
|
| Ap2 (Ule, typ, x, y) ->
|
|
|
|
|
Term.le (unsigned typ (term x)) (unsigned typ (term y))
|
|
|
|
|
| Ap2 (Ord, _, x, y) -> Term.ord (term x) (term y)
|
|
|
|
|
| Ap2 (Uno, _, x, y) -> Term.uno (term x) (term y)
|
|
|
|
|
| Ap2 (Add, _, x, y) -> Term.add (term x) (term y)
|
|
|
|
|
| Ap2 (Sub, _, x, y) -> Term.sub (term x) (term y)
|
|
|
|
|
| Ap2 (Mul, _, x, y) -> Term.mul (term x) (term y)
|
|
|
|
|
| Ap2 (Div, _, x, y) -> Term.div (term x) (term y)
|
|
|
|
|
| Ap2 (Rem, _, x, y) -> Term.rem (term x) (term y)
|
|
|
|
|
| Ap2 (Udiv, typ, x, y) ->
|
|
|
|
|
Term.div (unsigned typ (term x)) (unsigned typ (term y))
|
|
|
|
|
| Ap2 (Urem, typ, x, y) ->
|
|
|
|
|
Term.rem (unsigned typ (term x)) (unsigned typ (term y))
|
|
|
|
|
| Ap2 (And, _, x, y) -> Term.and_ (term x) (term y)
|
|
|
|
|
| Ap2 (Or, _, x, y) -> Term.or_ (term x) (term y)
|
|
|
|
|
| Ap2 (Xor, _, x, y) -> Term.xor (term x) (term y)
|
|
|
|
|
| Ap2 (Shl, _, x, y) -> Term.shl (term x) (term y)
|
|
|
|
|
| Ap2 (Lshr, _, x, y) -> Term.lshr (term x) (term y)
|
|
|
|
|
| Ap2 (Ashr, _, x, y) -> Term.ashr (term x) (term y)
|
|
|
|
|
| Ap3 (Conditional, _, cnd, thn, els) ->
|
|
|
|
|
Term.conditional ~cnd:(term cnd) ~thn:(term thn) ~els:(term els)
|
|
|
|
|
| Ap1 (Splat, _, byt) -> Term.splat (term byt)
|
|
|
|
|
| ApN (Record, _, elts) -> Term.record (IArray.map ~f:term elts)
|
|
|
|
|
| Ap1 (Select idx, _, rcd) -> Term.select ~rcd:(term rcd) ~idx
|
|
|
|
|
| Ap2 (Update idx, _, rcd, elt) ->
|
|
|
|
|
Term.update ~rcd:(term rcd) ~idx ~elt:(term elt)
|
|
|
|
|
| RecRecord (i, _) -> Term.rec_record i
|
|
|
|
|
|
|
|
|
|
let pp_op2 fs op =
|
|
|
|
|
let pf fmt = Format.fprintf fs fmt in
|
|
|
|
@ -118,9 +166,9 @@ let rec pp fs exp =
|
|
|
|
|
Format.pp_open_box fs 2 ;
|
|
|
|
|
Format.kfprintf (fun fs -> Format.pp_close_box fs ()) fs fmt
|
|
|
|
|
in
|
|
|
|
|
match exp.desc with
|
|
|
|
|
match exp with
|
|
|
|
|
| Reg {name} -> (
|
|
|
|
|
match Var.of_term exp.term with
|
|
|
|
|
match Var.of_term (term exp) with
|
|
|
|
|
| Some v when Var.is_global v -> pf "%@%s" name
|
|
|
|
|
| _ -> pf "%%%s" name )
|
|
|
|
|
| Nondet {msg} -> pf "nondet \"%s\"" msg
|
|
|
|
@ -138,11 +186,9 @@ let rec pp fs exp =
|
|
|
|
|
| Ap1 (Select idx, _, rcd) -> pf "%a[%i]" pp rcd idx
|
|
|
|
|
| Ap2 (Update idx, _, rcd, elt) ->
|
|
|
|
|
pf "[%a@ @[| %i → %a@]]" pp rcd idx pp elt
|
|
|
|
|
| Ap2 (Xor, Integer {bits= 1}, {desc= Integer {data}}, x)
|
|
|
|
|
when Z.is_true data ->
|
|
|
|
|
| Ap2 (Xor, Integer {bits= 1}, Integer {data}, x) when Z.is_true data ->
|
|
|
|
|
pf "¬%a" pp x
|
|
|
|
|
| Ap2 (Xor, Integer {bits= 1}, x, {desc= Integer {data}})
|
|
|
|
|
when Z.is_true data ->
|
|
|
|
|
| Ap2 (Xor, Integer {bits= 1}, x, Integer {data}) when Z.is_true data ->
|
|
|
|
|
pf "¬%a" pp x
|
|
|
|
|
| Ap2 (op, _, x, y) -> pf "(%a@ %a %a)" pp x pp_op2 op pp y
|
|
|
|
|
| Ap3 (Conditional, _, cnd, thn, els) ->
|
|
|
|
@ -157,7 +203,7 @@ and pp_record fs elts =
|
|
|
|
|
(fun fs elts ->
|
|
|
|
|
match
|
|
|
|
|
String.init (IArray.length elts) ~f:(fun i ->
|
|
|
|
|
match (IArray.get elts i).desc with
|
|
|
|
|
match IArray.get elts i with
|
|
|
|
|
| Integer {data} -> Char.of_int_exn (Z.to_int data)
|
|
|
|
|
| _ -> raise (Invalid_argument "not a string") )
|
|
|
|
|
with
|
|
|
|
@ -173,7 +219,7 @@ let valid_idx idx elts = 0 <= idx && idx < IArray.length elts
|
|
|
|
|
|
|
|
|
|
let rec invariant exp =
|
|
|
|
|
let@ () = Invariant.invariant [%here] exp [%sexp_of: t] in
|
|
|
|
|
match exp.desc with
|
|
|
|
|
match exp with
|
|
|
|
|
| Reg {typ} | Nondet {typ} -> assert (Typ.is_sized typ)
|
|
|
|
|
| Integer {data; typ} -> (
|
|
|
|
|
match typ with
|
|
|
|
@ -251,7 +297,7 @@ let rec invariant exp =
|
|
|
|
|
(** Type query *)
|
|
|
|
|
|
|
|
|
|
and typ_of exp =
|
|
|
|
|
match exp.desc with
|
|
|
|
|
match exp with
|
|
|
|
|
| Reg {typ} | Nondet {typ} | Integer {typ} | Float {typ} -> typ
|
|
|
|
|
| Label _ -> Typ.ptr
|
|
|
|
|
| Ap1 ((Signed _ | Unsigned _ | Convert _ | Splat), dst, _) -> dst
|
|
|
|
@ -287,7 +333,9 @@ module Reg = struct
|
|
|
|
|
let pp = pp
|
|
|
|
|
|
|
|
|
|
let var r =
|
|
|
|
|
match Var.of_term r.term with Some v -> v | _ -> violates invariant r
|
|
|
|
|
match Var.of_term (term r) with
|
|
|
|
|
| Some v -> v
|
|
|
|
|
| _ -> violates invariant r
|
|
|
|
|
|
|
|
|
|
module Set = struct
|
|
|
|
|
include Set
|
|
|
|
@ -302,8 +350,7 @@ module Reg = struct
|
|
|
|
|
|
|
|
|
|
let demangle = ref (fun _ -> None)
|
|
|
|
|
|
|
|
|
|
let pp_demangled fs e =
|
|
|
|
|
match e.desc with
|
|
|
|
|
let pp_demangled fs = function
|
|
|
|
|
| Reg {name} -> (
|
|
|
|
|
match !demangle name with
|
|
|
|
|
| Some demangled when not (String.equal name demangled) ->
|
|
|
|
@ -314,20 +361,17 @@ module Reg = struct
|
|
|
|
|
|
|
|
|
|
let invariant x =
|
|
|
|
|
let@ () = Invariant.invariant [%here] x [%sexp_of: t] in
|
|
|
|
|
match x.desc with Reg _ -> invariant x | _ -> assert false
|
|
|
|
|
match x with Reg _ -> invariant x | _ -> assert false
|
|
|
|
|
|
|
|
|
|
let name r =
|
|
|
|
|
match r.desc with Reg x -> x.name | _ -> violates invariant r
|
|
|
|
|
let name = function Reg x -> x.name | r -> violates invariant r
|
|
|
|
|
let typ r = match r with Reg x -> x.typ | _ -> violates invariant r
|
|
|
|
|
|
|
|
|
|
let typ r = match r.desc with Reg x -> x.typ | _ -> violates invariant r
|
|
|
|
|
|
|
|
|
|
let of_exp e =
|
|
|
|
|
match e.desc with Reg _ -> Some (e |> check invariant) | _ -> None
|
|
|
|
|
let of_exp = function
|
|
|
|
|
| Reg _ as e -> Some (e |> check invariant)
|
|
|
|
|
| _ -> None
|
|
|
|
|
|
|
|
|
|
let program ?global typ name =
|
|
|
|
|
{ desc= Reg {name; global= Option.is_some global; typ}
|
|
|
|
|
; term= Term.var (Var.program ?global name) }
|
|
|
|
|
|> check invariant
|
|
|
|
|
Reg {name; global= Option.is_some global; typ} |> check invariant
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
(** Construct *)
|
|
|
|
@ -338,126 +382,96 @@ let reg x = x
|
|
|
|
|
|
|
|
|
|
(* constants *)
|
|
|
|
|
|
|
|
|
|
let nondet typ msg =
|
|
|
|
|
{desc= Nondet {msg; typ}; term= Term.nondet msg} |> check invariant
|
|
|
|
|
|
|
|
|
|
let label ~parent ~name =
|
|
|
|
|
{desc= Label {parent; name}; term= Term.label ~parent ~name}
|
|
|
|
|
|> check invariant
|
|
|
|
|
|
|
|
|
|
let integer typ data =
|
|
|
|
|
{desc= Integer {data; typ}; term= Term.integer data} |> check invariant
|
|
|
|
|
|
|
|
|
|
let nondet typ msg = Nondet {msg; typ} |> check invariant
|
|
|
|
|
let label ~parent ~name = Label {parent; name} |> check invariant
|
|
|
|
|
let integer typ data = Integer {data; typ} |> check invariant
|
|
|
|
|
let null = integer Typ.ptr Z.zero
|
|
|
|
|
let bool b = integer Typ.bool (Z.of_bool b)
|
|
|
|
|
let true_ = bool true
|
|
|
|
|
let false_ = bool false
|
|
|
|
|
|
|
|
|
|
let float typ data =
|
|
|
|
|
{desc= Float {data; typ}; term= Term.float data} |> check invariant
|
|
|
|
|
let float typ data = Float {data; typ} |> check invariant
|
|
|
|
|
|
|
|
|
|
(* type conversions *)
|
|
|
|
|
|
|
|
|
|
let signed bits x ~to_:typ =
|
|
|
|
|
{desc= Ap1 (Signed {bits}, typ, x); term= Term.signed bits x.term}
|
|
|
|
|
|> check invariant
|
|
|
|
|
let signed bits x ~to_:typ = Ap1 (Signed {bits}, typ, x) |> check invariant
|
|
|
|
|
|
|
|
|
|
let unsigned bits x ~to_:typ =
|
|
|
|
|
{desc= Ap1 (Unsigned {bits}, typ, x); term= Term.unsigned bits x.term}
|
|
|
|
|
|> check invariant
|
|
|
|
|
Ap1 (Unsigned {bits}, typ, x) |> check invariant
|
|
|
|
|
|
|
|
|
|
let convert src ~to_:dst exp =
|
|
|
|
|
{ desc= Ap1 (Convert {src}, dst, exp)
|
|
|
|
|
; term= Term.convert src ~to_:dst exp.term }
|
|
|
|
|
|> check invariant
|
|
|
|
|
Ap1 (Convert {src}, dst, exp) |> check invariant
|
|
|
|
|
|
|
|
|
|
(* comparisons *)
|
|
|
|
|
|
|
|
|
|
let binary op mk ?typ x y =
|
|
|
|
|
let binary op ?typ x y =
|
|
|
|
|
let typ = match typ with Some typ -> typ | None -> typ_of x in
|
|
|
|
|
{desc= Ap2 (op, typ, x, y); term= mk x.term y.term} |> check invariant
|
|
|
|
|
Ap2 (op, typ, x, y) |> check invariant
|
|
|
|
|
|
|
|
|
|
let ubinary op mk ?typ x y =
|
|
|
|
|
let ubinary op ?typ x y =
|
|
|
|
|
let typ = match typ with Some typ -> typ | None -> typ_of x in
|
|
|
|
|
let umk x y =
|
|
|
|
|
let unsigned = Term.unsigned (Typ.bit_size_of typ) in
|
|
|
|
|
mk (unsigned x) (unsigned y)
|
|
|
|
|
in
|
|
|
|
|
binary op umk ~typ x y
|
|
|
|
|
|
|
|
|
|
let eq = binary Eq Term.eq
|
|
|
|
|
let dq = binary Dq Term.dq
|
|
|
|
|
let gt = binary Gt (fun x y -> Term.lt y x)
|
|
|
|
|
let ge = binary Ge (fun x y -> Term.le y x)
|
|
|
|
|
let lt = binary Lt Term.lt
|
|
|
|
|
let le = binary Le Term.le
|
|
|
|
|
let ugt = ubinary Ugt (fun x y -> Term.lt y x)
|
|
|
|
|
let uge = ubinary Uge (fun x y -> Term.le y x)
|
|
|
|
|
let ult = ubinary Ult Term.lt
|
|
|
|
|
let ule = ubinary Ule Term.le
|
|
|
|
|
let ord = binary Ord Term.ord
|
|
|
|
|
let uno = binary Uno Term.uno
|
|
|
|
|
binary op ~typ x y
|
|
|
|
|
|
|
|
|
|
let eq = binary Eq
|
|
|
|
|
let dq = binary Dq
|
|
|
|
|
let gt = binary Gt
|
|
|
|
|
let ge = binary Ge
|
|
|
|
|
let lt = binary Lt
|
|
|
|
|
let le = binary Le
|
|
|
|
|
let ugt = ubinary Ugt
|
|
|
|
|
let uge = ubinary Uge
|
|
|
|
|
let ult = ubinary Ult
|
|
|
|
|
let ule = ubinary Ule
|
|
|
|
|
let ord = binary Ord
|
|
|
|
|
let uno = binary Uno
|
|
|
|
|
|
|
|
|
|
(* arithmetic *)
|
|
|
|
|
|
|
|
|
|
let add = binary Add Term.add
|
|
|
|
|
let sub = binary Sub Term.sub
|
|
|
|
|
let mul = binary Mul Term.mul
|
|
|
|
|
let div = binary Div Term.div
|
|
|
|
|
let rem = binary Rem Term.rem
|
|
|
|
|
let udiv = ubinary Udiv Term.div
|
|
|
|
|
let urem = ubinary Urem Term.rem
|
|
|
|
|
let add = binary Add
|
|
|
|
|
let sub = binary Sub
|
|
|
|
|
let mul = binary Mul
|
|
|
|
|
let div = binary Div
|
|
|
|
|
let rem = binary Rem
|
|
|
|
|
let udiv = ubinary Udiv
|
|
|
|
|
let urem = ubinary Urem
|
|
|
|
|
|
|
|
|
|
(* boolean / bitwise *)
|
|
|
|
|
|
|
|
|
|
let and_ = binary And Term.and_
|
|
|
|
|
let or_ = binary Or Term.or_
|
|
|
|
|
let and_ = binary And
|
|
|
|
|
let or_ = binary Or
|
|
|
|
|
|
|
|
|
|
(* bitwise *)
|
|
|
|
|
|
|
|
|
|
let xor = binary Xor Term.xor
|
|
|
|
|
let shl = binary Shl Term.shl
|
|
|
|
|
let lshr = binary Lshr Term.lshr
|
|
|
|
|
let ashr = binary Ashr Term.ashr
|
|
|
|
|
let xor = binary Xor
|
|
|
|
|
let shl = binary Shl
|
|
|
|
|
let lshr = binary Lshr
|
|
|
|
|
let ashr = binary Ashr
|
|
|
|
|
|
|
|
|
|
(* if-then-else *)
|
|
|
|
|
|
|
|
|
|
let conditional ?typ ~cnd ~thn ~els =
|
|
|
|
|
let typ = match typ with Some typ -> typ | None -> typ_of thn in
|
|
|
|
|
{ desc= Ap3 (Conditional, typ, cnd, thn, els)
|
|
|
|
|
; term= Term.conditional ~cnd:cnd.term ~thn:thn.term ~els:els.term }
|
|
|
|
|
|> check invariant
|
|
|
|
|
Ap3 (Conditional, typ, cnd, thn, els) |> check invariant
|
|
|
|
|
|
|
|
|
|
(* memory *)
|
|
|
|
|
|
|
|
|
|
let splat typ byt =
|
|
|
|
|
{desc= Ap1 (Splat, typ, byt); term= Term.splat byt.term}
|
|
|
|
|
|> check invariant
|
|
|
|
|
let splat typ byt = Ap1 (Splat, typ, byt) |> check invariant
|
|
|
|
|
|
|
|
|
|
(* records (struct / array values) *)
|
|
|
|
|
|
|
|
|
|
let record typ elts =
|
|
|
|
|
{ desc= ApN (Record, typ, elts)
|
|
|
|
|
; term= Term.record (IArray.map ~f:(fun elt -> elt.term) elts) }
|
|
|
|
|
|> check invariant
|
|
|
|
|
|
|
|
|
|
let select typ rcd idx =
|
|
|
|
|
{desc= Ap1 (Select idx, typ, rcd); term= Term.select ~rcd:rcd.term ~idx}
|
|
|
|
|
|> check invariant
|
|
|
|
|
let record typ elts = ApN (Record, typ, elts) |> check invariant
|
|
|
|
|
let select typ rcd idx = Ap1 (Select idx, typ, rcd) |> check invariant
|
|
|
|
|
|
|
|
|
|
let update typ ~rcd idx ~elt =
|
|
|
|
|
{ desc= Ap2 (Update idx, typ, rcd, elt)
|
|
|
|
|
; term= Term.update ~rcd:rcd.term ~idx ~elt:elt.term }
|
|
|
|
|
|> check invariant
|
|
|
|
|
Ap2 (Update idx, typ, rcd, elt) |> check invariant
|
|
|
|
|
|
|
|
|
|
let rec_record i typ = {desc= RecRecord (i, typ); term= Term.rec_record i}
|
|
|
|
|
let rec_record i typ = RecRecord (i, typ)
|
|
|
|
|
|
|
|
|
|
(** Traverse *)
|
|
|
|
|
|
|
|
|
|
let fold_exps e ~init ~f =
|
|
|
|
|
let rec fold_exps_ e z =
|
|
|
|
|
let z =
|
|
|
|
|
match e.desc with
|
|
|
|
|
match e with
|
|
|
|
|
| Ap1 (_, _, x) -> fold_exps_ x z
|
|
|
|
|
| Ap2 (_, _, x, y) -> fold_exps_ y (fold_exps_ x z)
|
|
|
|
|
| Ap3 (_, _, w, x, y) -> fold_exps_ w (fold_exps_ y (fold_exps_ x z))
|
|
|
|
@ -471,16 +485,16 @@ let fold_exps e ~init ~f =
|
|
|
|
|
|
|
|
|
|
let fold_regs e ~init ~f =
|
|
|
|
|
fold_exps e ~init ~f:(fun z x ->
|
|
|
|
|
match x.desc with Reg _ -> f z (x :> Reg.t) | _ -> z )
|
|
|
|
|
match x with Reg _ -> f z (x :> Reg.t) | _ -> z )
|
|
|
|
|
|
|
|
|
|
(** Query *)
|
|
|
|
|
|
|
|
|
|
let is_true e =
|
|
|
|
|
match e.desc with
|
|
|
|
|
match e with
|
|
|
|
|
| Integer {data; typ= Integer {bits= 1; _}} -> Z.is_true data
|
|
|
|
|
| _ -> false
|
|
|
|
|
|
|
|
|
|
let is_false e =
|
|
|
|
|
match e.desc with
|
|
|
|
|
match e with
|
|
|
|
|
| Integer {data; typ= Integer {bits= 1; _}} -> Z.is_false data
|
|
|
|
|
| _ -> false
|
|
|
|
|