You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
6.8 KiB
213 lines
6.8 KiB
(*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*)
|
|
|
|
(** Expressions
|
|
|
|
Pure (heap-independent) expressions are complex arithmetic,
|
|
bitwise-logical, etc. operations over literal values and registers. *)
|
|
|
|
type op1 =
|
|
| Signed of {bits: int}
|
|
(** [Ap1 (Signed {bits= n}, dst, arg)] is [arg] interpreted as an
|
|
[n]-bit signed integer and injected into the [dst] type. That is,
|
|
it two's-complement--decodes the low [n] bits of the infinite
|
|
two's-complement encoding of [arg]. The injection into [dst] is a
|
|
no-op, so [dst] must be an integer type with bitwidth at least
|
|
[n]. *)
|
|
| Unsigned of {bits: int}
|
|
(** [Ap1 (Unsigned {bits= n}, dst, arg)] is [arg] interpreted as an
|
|
[n]-bit unsigned integer and injected into the [dst] type. That
|
|
is, it unsigned-binary--decodes the low [n] bits of the infinite
|
|
two's-complement encoding of [arg]. The injection into [dst] is a
|
|
no-op, so [dst] must be an integer type with bitwidth greater than
|
|
[n]. *)
|
|
| Convert of {src: Typ.t}
|
|
(** [Ap1 (Convert {src}, dst, arg)] is [arg] converted from type [src]
|
|
to type [dst], possibly with loss of information. The [src] and
|
|
[dst] types must be [Typ.convertible] and must not both be
|
|
[Integer] types. *)
|
|
| Splat (** Iterated concatenation of a single byte *)
|
|
| Select of int (** Select an index from a record *)
|
|
[@@deriving compare, equal, hash, sexp]
|
|
|
|
type op2 =
|
|
| Eq (** Equal test *)
|
|
| Dq (** Disequal test *)
|
|
| Gt (** Greater-than test *)
|
|
| Ge (** Greater-than-or-equal test *)
|
|
| Lt (** Less-than test *)
|
|
| Le (** Less-than-or-equal test *)
|
|
| Ugt (** Unsigned greater-than test *)
|
|
| Uge (** Unsigned greater-than-or-equal test *)
|
|
| Ult (** Unsigned less-than test *)
|
|
| Ule (** Unsigned less-than-or-equal test *)
|
|
| Ord (** Ordered test (neither arg is nan) *)
|
|
| Uno (** Unordered test (some arg is nan) *)
|
|
| Add (** Addition *)
|
|
| Sub (** Subtraction *)
|
|
| Mul (** Multiplication *)
|
|
| Div (** Division *)
|
|
| Rem (** Remainder of division *)
|
|
| Udiv (** Unsigned division *)
|
|
| Urem (** Remainder of unsigned division *)
|
|
| And (** Conjunction, boolean or bitwise *)
|
|
| Or (** Disjunction, boolean or bitwise *)
|
|
| Xor (** Exclusive-or, bitwise *)
|
|
| Shl (** Shift left, bitwise *)
|
|
| Lshr (** Logical shift right, bitwise *)
|
|
| Ashr (** Arithmetic shift right, bitwise *)
|
|
| Update of int (** Constant record with updated index *)
|
|
[@@deriving compare, equal, hash, sexp]
|
|
|
|
type op3 = Conditional (** If-then-else *)
|
|
[@@deriving compare, equal, hash, sexp]
|
|
|
|
type opN =
|
|
| Record (** Record (array / struct) constant *)
|
|
| Struct_rec
|
|
(** Struct constant that may recursively refer to itself
|
|
(transitively) from [elts]. NOTE: represented by cyclic values. *)
|
|
[@@deriving compare, equal, hash, sexp]
|
|
|
|
type t = private {desc: desc; term: Term.t}
|
|
|
|
and desc = private
|
|
| Reg of {name: string; typ: Typ.t} (** Virtual register *)
|
|
| Nondet of {msg: string; typ: Typ.t}
|
|
(** Anonymous register with arbitrary value, representing
|
|
non-deterministic approximation of value described by [msg] *)
|
|
| Label of {parent: string; name: string}
|
|
(** Address of named code block within parent function *)
|
|
| Integer of {data: Z.t; typ: Typ.t} (** Integer constant *)
|
|
| Float of {data: string; typ: Typ.t} (** Floating-point constant *)
|
|
| Ap1 of op1 * Typ.t * t
|
|
| Ap2 of op2 * Typ.t * t * t
|
|
| Ap3 of op3 * Typ.t * t * t * t
|
|
| ApN of opN * Typ.t * t iarray
|
|
[@@deriving compare, equal, hash, sexp]
|
|
|
|
val pp : t pp
|
|
|
|
include Invariant.S with type t := t
|
|
|
|
(** Exp.Reg is re-exported as Reg *)
|
|
module Reg : sig
|
|
type exp := t
|
|
type t = private exp [@@deriving compare, equal, hash, sexp]
|
|
|
|
module Set : sig
|
|
include Set.S with type elt := t
|
|
|
|
val sexp_of_t : t -> Sexp.t
|
|
val t_of_sexp : Sexp.t -> t
|
|
val pp : t pp
|
|
val vars : t -> Var.Set.t
|
|
end
|
|
|
|
module Map : Map.S with type key := t
|
|
|
|
val demangle : (string -> string option) ref
|
|
val pp : t pp
|
|
val pp_demangled : t pp
|
|
|
|
include Invariant.S with type t := t
|
|
|
|
val of_exp : exp -> t option
|
|
val program : ?global:unit -> Typ.t -> string -> t
|
|
val var : t -> Var.t
|
|
val name : t -> string
|
|
val typ : t -> Typ.t
|
|
end
|
|
|
|
(** Construct *)
|
|
|
|
(* registers *)
|
|
val reg : Reg.t -> t
|
|
|
|
(* constants *)
|
|
val nondet : Typ.t -> string -> t
|
|
val label : parent:string -> name:string -> t
|
|
val null : t
|
|
val bool : bool -> t
|
|
val true_ : t
|
|
val false_ : t
|
|
val integer : Typ.t -> Z.t -> t
|
|
val float : Typ.t -> string -> t
|
|
|
|
(* type conversions *)
|
|
val signed : int -> t -> to_:Typ.t -> t
|
|
val unsigned : int -> t -> to_:Typ.t -> t
|
|
val convert : Typ.t -> to_:Typ.t -> t -> t
|
|
|
|
(* comparisons *)
|
|
val eq : ?typ:Typ.t -> t -> t -> t
|
|
val dq : ?typ:Typ.t -> t -> t -> t
|
|
val gt : ?typ:Typ.t -> t -> t -> t
|
|
val ge : ?typ:Typ.t -> t -> t -> t
|
|
val lt : ?typ:Typ.t -> t -> t -> t
|
|
val le : ?typ:Typ.t -> t -> t -> t
|
|
val ugt : ?typ:Typ.t -> t -> t -> t
|
|
val uge : ?typ:Typ.t -> t -> t -> t
|
|
val ult : ?typ:Typ.t -> t -> t -> t
|
|
val ule : ?typ:Typ.t -> t -> t -> t
|
|
val ord : ?typ:Typ.t -> t -> t -> t
|
|
val uno : ?typ:Typ.t -> t -> t -> t
|
|
|
|
(* arithmetic *)
|
|
val add : ?typ:Typ.t -> t -> t -> t
|
|
val sub : ?typ:Typ.t -> t -> t -> t
|
|
val mul : ?typ:Typ.t -> t -> t -> t
|
|
val div : ?typ:Typ.t -> t -> t -> t
|
|
val rem : ?typ:Typ.t -> t -> t -> t
|
|
val udiv : ?typ:Typ.t -> t -> t -> t
|
|
val urem : ?typ:Typ.t -> t -> t -> t
|
|
|
|
(* boolean / bitwise *)
|
|
val and_ : ?typ:Typ.t -> t -> t -> t
|
|
val or_ : ?typ:Typ.t -> t -> t -> t
|
|
|
|
(* bitwise *)
|
|
val xor : ?typ:Typ.t -> t -> t -> t
|
|
val shl : ?typ:Typ.t -> t -> t -> t
|
|
val lshr : ?typ:Typ.t -> t -> t -> t
|
|
val ashr : ?typ:Typ.t -> t -> t -> t
|
|
|
|
(* if-then-else *)
|
|
val conditional : ?typ:Typ.t -> cnd:t -> thn:t -> els:t -> t
|
|
|
|
(* memory *)
|
|
val splat : Typ.t -> t -> t
|
|
|
|
(* records (struct / array values) *)
|
|
val record : Typ.t -> t iarray -> t
|
|
val select : Typ.t -> t -> int -> t
|
|
val update : Typ.t -> rcd:t -> int -> elt:t -> t
|
|
|
|
val struct_rec :
|
|
(module Hashtbl.Key_plain with type t = 'id)
|
|
-> (id:'id -> Typ.t -> t lazy_t iarray -> t) Staged.t
|
|
(** [struct_rec Id id element_thunks] constructs a possibly-cyclic [Struct]
|
|
value. Cycles are detected using [Id]. The caller of [struct_rec Id]
|
|
must ensure that a single unstaging of [struct_rec Id] is used for each
|
|
complete cyclic value. Also, the caller must ensure that recursive calls
|
|
to [struct_rec Id] provide [id] values that uniquely identify at least
|
|
one point on each cycle. Failure to obey these requirements will lead to
|
|
stack overflow. *)
|
|
|
|
val size_of : t -> t
|
|
|
|
(** Traverse *)
|
|
|
|
val fold_regs : t -> init:'a -> f:('a -> Reg.t -> 'a) -> 'a
|
|
|
|
(** Query *)
|
|
|
|
val term : t -> Term.t
|
|
val typ : t -> Typ.t
|
|
val is_true : t -> bool
|
|
val is_false : t -> bool
|