@ -20,8 +20,8 @@ module rec T : sig
type t =
(* nary: arithmetic, numeric and pointer *)
| Add of { args : qset ; typ : Typ . t }
| Mul of { args : qset ; typ : Typ . t }
| Add of { args : qset }
| Mul of { args : qset }
(* pointer and memory constants and operations *)
| Splat of { byt : t ; siz : t }
| Memory of { siz : t ; arr : t }
@ -62,7 +62,7 @@ module rec T : sig
| Extract of { unsigned : bool ; bits : int }
| Convert of { unsigned : bool ; dst : Typ . t ; src : Typ . t }
(* numeric constants *)
| Integer of { data : Z . t ; typ : Typ . t }
| Integer of { data : Z . t }
| Float of { data : string }
[ @@ deriving compare , equal , hash , sexp ]
@ -82,8 +82,8 @@ and T0 : sig
type qset = Qset . M ( T ) . t [ @@ deriving compare , equal , hash , sexp ]
type t =
| Add of { args : qset ; typ : Typ . t }
| Mul of { args : qset ; typ : Typ . t }
| Add of { args : qset }
| Mul of { args : qset }
| Splat of { byt : t ; siz : t }
| Memory of { siz : t ; arr : t }
| Concat of { args : t vector }
@ -114,15 +114,15 @@ and T0 : sig
| Struct_rec of { elts : t vector }
| Extract of { unsigned : bool ; bits : int }
| Convert of { unsigned : bool ; dst : Typ . t ; src : Typ . t }
| Integer of { data : Z . t ; typ : Typ . t }
| Integer of { data : Z . t }
| Float of { data : string }
[ @@ deriving compare , equal , hash , sexp ]
end = struct
type qset = Qset . M ( T ) . t [ @@ deriving compare , equal , hash , sexp ]
type t =
| Add of { args : qset ; typ : Typ . t }
| Mul of { args : qset ; typ : Typ . t }
| Add of { args : qset }
| Mul of { args : qset }
| Splat of { byt : t ; siz : t }
| Memory of { siz : t ; arr : t }
| Concat of { args : t vector }
@ -153,7 +153,7 @@ end = struct
| Struct_rec of { elts : t vector }
| Extract of { unsigned : bool ; bits : int }
| Convert of { unsigned : bool ; dst : Typ . t ; src : Typ . t }
| Integer of { data : Z . t ; typ : Typ . t }
| Integer of { data : Z . t }
| Float of { data : string }
[ @@ deriving compare , equal , hash , sexp ]
end
@ -207,7 +207,6 @@ let rec pp ?is_x fs term =
Trace . pp_styled ( get_var_style var ) " %%%s_%d " fs name id
| Nondet { msg } -> pf " nondet \" %s \" " msg
| Label { name } -> pf " %s " name
| Integer { data ; typ = Pointer _ } when Z . equal Z . zero data -> pf " null "
| Splat { byt ; siz } -> pf " %a^%a " pp byt pp siz
| Memory { siz ; arr } -> pf " @<1>⟨%a,%a@<1>⟩ " pp siz pp arr
| Concat { args } -> pf " %a " ( Vector . pp " @,^ " pp ) args
@ -308,30 +307,6 @@ let pp = pp_t
(* * Invariant *)
let rec typ_of = function
| Add { typ } | Mul { typ } | Integer { typ } | App { op = Convert { dst = typ } } ->
Some typ
| App { op = App { op = Eq | Dq | Gt | Ge | Lt | Le } } -> Some Typ . bool
| App
{ op = App { op = Div | Rem | And | Or | Xor | Shl | Lshr | Ashr ; arg = x }
; arg = y } -> (
match typ_of x with Some _ as t -> t | None -> typ_of y )
| App { op = App { op = App { op = Conditional } ; arg = thn } ; arg = els } -> (
match typ_of thn with Some _ as t -> t | None -> typ_of els )
| _ -> None
let typ = typ_of
let is_boolean e = Option . exists ~ f : ( Typ . equal Typ . bool ) ( typ_of e )
let type_check e typ =
assert (
Option . for_all ~ f : ( Typ . castable typ ) ( typ_of e )
| | fail " %a@ : %a not <:@ %a " pp e Typ . pp
( Option . value_exn ( typ_of e ) )
Typ . pp typ )
let type_check2 e f typ = type_check e typ ; type_check f typ
(* an indeterminate ( factor of a monomial ) is any non-Add/Mul/Integer term *)
let rec assert_indeterminate = function
| App { op } -> assert_indeterminate op
@ -342,11 +317,9 @@ let rec assert_indeterminate = function
* ∏ ᵢ x ᵢ ^ n ᵢ
* for ( non - constant ) indeterminants x ᵢ and positive integer exponents n ᵢ
* )
let assert_monomial add_typ mono =
let assert_monomial mono =
match mono with
| Mul { typ ; args } ->
assert ( Typ . castable add_typ typ ) ;
assert ( Option . is_some ( Typ . prim_bit_size_of typ ) ) ;
| Mul { args } ->
Qset . iter args ~ f : ( fun factor exponent ->
assert ( Q . sign exponent > 0 ) ;
assert_indeterminate factor | > Fn . id )
@ -355,7 +328,7 @@ let assert_monomial add_typ mono =
(* a polynomial term is a monomial multiplied by a non-zero coefficient
* c × ∏ ᵢ x ᵢ
* )
let assert_poly_term add_typ mono coeff =
let assert_poly_term mono coeff =
assert ( not ( Q . equal Q . zero coeff ) ) ;
match mono with
| Integer { data } -> assert ( Z . equal Z . one data )
@ -364,8 +337,8 @@ let assert_poly_term add_typ mono coeff =
| None | Some ( Integer _ , _ ) -> assert false
| Some ( _ , n ) -> assert ( Qset . length args > 1 | | not ( Q . equal Q . one n ) )
) ;
assert_monomial add_typ mono | > Fn . id
| _ -> assert_monomial add_typ mono | > Fn . id
assert_monomial mono | > Fn . id
| _ -> assert_monomial mono | > Fn . id
(* a polynomial is a linear combination of monomials, e.g.
* ∑ ᵢ c ᵢ × ∏ ⱼ x ᵢ ⱼ
@ -374,13 +347,12 @@ let assert_poly_term add_typ mono coeff =
* )
let assert_polynomial poly =
match poly with
| Add { typ; args} ->
| Add { args} ->
( match Qset . min_elt args with
| None -> assert false
| Some ( Integer _ , _ ) -> assert false
| None | Some ( Integer _ , _ ) -> assert false
| Some ( _ , k ) -> assert ( Qset . length args > 1 | | not ( Q . equal Q . one k ) )
) ;
Qset . iter args ~ f : ( fun m c -> assert_poly_term typ m c | > Fn . id )
Qset . iter args ~ f : ( fun m c -> assert_poly_term m c | > Fn . id )
| _ -> assert false
let invariant ? ( partial = false ) e =
@ -393,41 +365,23 @@ let invariant ?(partial = false) e =
in
match op with
| App _ -> fail " uncurry cannot return App " ()
| Integer { data ; typ = ( Integer _ | Pointer _ ) as typ } -> (
match Typ . prim_bit_size_of typ with
| None -> assert false
| Some bits ->
assert_arity 0 ;
assert ( Z . numbits data < = bits ) )
| Integer _ -> assert false
| Integer _ -> assert_arity 0
| Var _ | Nondet _ | Label _ | Float _ -> assert_arity 0
| Extract _ -> assert_arity 1
| Convert { dst ; src } ->
( match args with
| [ Integer { typ = Integer _ as typ } ] -> assert ( Typ . equal src typ )
| [ arg ] ->
assert ( Option . for_all ~ f : ( Typ . convertible src ) ( typ_of arg ) )
| _ -> assert_arity 1 ) ;
assert_arity 1 ;
assert ( Typ . convertible src dst )
| Add _ -> assert_polynomial e | > Fn . id
| Mul {typ } -> assert_monomial typ e | > Fn . id
| Mul _ -> assert_monomial e | > Fn . id
| Eq | Dq | Gt | Ge | Lt | Le | Div | Rem | And | Or | Xor | Shl | Lshr
| Ashr -> (
match args with
| [ x ; y ] -> (
match ( typ_of x , typ_of y ) with
| Some typ , Some typ' -> assert ( Typ . castable typ typ' )
| _ -> assert true )
| _ -> assert_arity 2 )
| Ashr ->
assert_arity 2
| Concat { args } -> assert ( Vector . length args < > 1 )
| Splat { byt ; siz } -> (
assert ( Option . exists ~ f : ( Typ . convertible Typ . byt ) ( typ_of byt ) ) ;
assert ( Option . exists ~ f : ( Typ . convertible Typ . siz ) ( typ_of siz ) ) ;
match siz with
| Integer { data } -> assert ( not ( Z . equal Z . zero data ) )
| _ -> () )
| Memory { siz } ->
assert ( Option . for_all ~ f : ( Typ . convertible Typ . siz ) ( typ_of siz ) )
| Splat { siz } -> (
match siz with
| Integer { data } -> assert ( not ( Z . equal Z . zero data ) )
| _ -> () )
| Memory _ -> assert true
| Ord | Uno | Select -> assert_arity 2
| Conditional | Update -> assert_arity 3
| Record -> assert ( partial | | not ( List . is_empty args ) )
@ -581,24 +535,19 @@ let fv e = fold_vars e ~f:Set.add ~init:Var.Set.empty
let var x = x
let nondet msg = Nondet { msg } | > check invariant
let label ~ parent ~ name = Label { parent ; name } | > check invariant
let integer data typ = Integer { data ; typ } | > check invariant
let null = integer Z . zero Typ . ptr
let bool b = integer ( Z . of_bool b ) Typ . bool
let integer data = Integer { data } | > check invariant
let null = integer Z . zero
let zero = integer Z . zero
let one = integer Z . one
let minus_one = integer Z . minus_one
let bool b = integer ( Z . of_bool b )
let true _ = bool true
let false _ = bool false
let float data = Float { data } | > check invariant
let zero ( typ : Typ . t ) =
match typ with Float _ -> float " 0 " | _ -> integer Z . zero typ
let one ( typ : Typ . t ) =
match typ with Float _ -> float " 1 " | _ -> integer Z . one typ
let minus_one ( typ : Typ . t ) =
match typ with Float _ -> float " -1 " | _ -> integer Z . minus_one typ
let simp_extract ~ unsigned bits arg =
match arg with
| Integer { data } ->
integer ( Z . extract ~ unsigned bits data ) ( Typ . integer ~ bits )
| Integer { data } -> integer ( Z . extract ~ unsigned bits data )
| _ -> App { op = Extract { unsigned ; bits } ; arg }
let simp_convert ~ unsigned dst src arg =
@ -606,7 +555,7 @@ let simp_convert ~unsigned dst src arg =
else
match ( dst , src , arg ) with
| Integer { bits = m } , Integer { bits = n } , Integer { data } ->
integer ( Z . extract ~ unsigned ( min m n ) data ) dst
integer ( Z . extract ~ unsigned ( min m n ) data )
| _ -> App { op = Convert { unsigned ; dst ; src } ; arg }
let simp_gt x y =
@ -637,37 +586,37 @@ let sum_mul_const const sum =
if Q . equal Q . one const then sum
else Qset . map_counts ~ f : ( fun _ -> Q . mul const ) sum
let rec sum_to_term typ sum =
let rec sum_to_term sum =
match Qset . length sum with
| 0 -> zero typ
| 0 -> zero
| 1 -> (
match Qset . min_elt sum with
| Some ( Integer _ , q ) -> rational q typ
| Some ( Integer _ , q ) -> rational q
| Some ( arg , q ) when Q . equal Q . one q -> arg
| _ -> Add { typ; args= sum } )
| _ -> Add { typ; args= sum }
| _ -> Add { args= sum } )
| _ -> Add { args= sum }
and rational Q . { num ; den } typ = simp_div ( integer num typ ) ( integer den typ )
and rational Q . { num ; den } = simp_div ( integer num ) ( integer den )
and simp_div x y =
match ( x , y ) with
(* i / j *)
| Integer { data = i ; typ }, Integer { data = j } when not ( Z . equal Z . zero j ) ->
integer ( Z . div i j ) typ
| Integer { data = i }, Integer { data = j } when not ( Z . equal Z . zero j ) ->
integer ( Z . div i j )
(* e / 1 ==> e *)
| e , Integer { data } when Z . equal Z . one data -> e
(* ( ∑ᵢ cᵢ × Xᵢ ) / z ==> ∑ᵢ cᵢ/z × Xᵢ *)
| Add { typ; args} , Integer { data } ->
sum_to_term typ ( sum_mul_const Q . ( inv ( of_z data ) ) args )
| Add { args} , Integer { data } ->
sum_to_term ( sum_mul_const Q . ( inv ( of_z data ) ) args )
| _ -> App { op = App { op = Div ; arg = x } ; arg = y }
let simp_rem x y =
match ( x , y ) with
(* i % j *)
| Integer { data = i ; typ }, Integer { data = j } when not ( Z . equal Z . zero j ) ->
integer ( Z . rem i j ) typ
| Integer { data = i }, Integer { data = j } when not ( Z . equal Z . zero j ) ->
integer ( Z . rem i j )
(* e % 1 ==> 0 *)
| _ , Integer { data ; typ } when Z . equal Z . one data -> integer Z . zero typ
| _ , Integer { data } when Z . equal Z . one data -> zero
| _ -> App { op = App { op = Rem ; arg = x } ; arg = y }
(* Sums of polynomial terms represented by multisets. A sum ∑ᵢ cᵢ × Xᵢ of
@ -681,8 +630,7 @@ module Sum = struct
assert ( not ( Q . equal Q . zero coeff ) ) ;
match term with
| Integer { data } when Z . equal Z . zero data -> sum
| Integer { data ; typ } ->
Qset . add sum ( integer Z . one typ ) Q . ( coeff * of_z data )
| Integer { data } -> Qset . add sum one Q . ( coeff * of_z data )
| _ -> Qset . add sum term coeff
let singleton ? ( coeff = Q . one ) term = add coeff term empty
@ -694,7 +642,7 @@ module Sum = struct
let to_term = sum_to_term
end
let rec simp_add_ typ es poly =
let rec simp_add_ es poly =
(* ( coeff × term ) + poly *)
let f term coeff poly =
match ( term , poly ) with
@ -704,18 +652,18 @@ let rec simp_add_ typ es poly =
| Integer { data } , _ when Z . equal Z . zero data -> poly
(* ( c × cᵢ ) + cⱼ ==> c× cᵢ+cⱼ *)
| Integer { data = i } , Integer { data = j } ->
rational Q . ( ( coeff * of_z i ) + of_z j ) typ
rational Q . ( ( coeff * of_z i ) + of_z j )
(* ( c × ∑ᵢ cᵢ × Xᵢ ) + s ==> ( ∑ᵢ ( c × cᵢ ) × Xᵢ ) + s *)
| Add { args } , _ -> simp_add_ typ ( Sum . mul_const coeff args ) poly
| Add { args } , _ -> simp_add_ ( Sum . mul_const coeff args ) poly
(* ( c₀ × X₀ ) + ( ∑ᵢ₌₁ⁿ cᵢ × Xᵢ ) ==> ∑ᵢ₌₀ⁿ cᵢ × Xᵢ *)
| _ , Add { args } -> Sum . to_term typ ( Sum . add coeff term args )
| _ , Add { args } -> Sum . to_term ( Sum . add coeff term args )
(* ( c₁ × X₁ ) + X₂ ==> ∑ᵢ₌₁² cᵢ × Xᵢ for c₂ = 1 *)
| _ -> Sum . to_term typ ( Sum . add coeff term ( Sum . singleton poly ) )
| _ -> Sum . to_term ( Sum . add coeff term ( Sum . singleton poly ) )
in
Qset . fold ~ f es ~ init : poly
let simp_add typ es = simp_add_ typ es ( zero typ )
let simp_add2 typ e f = simp_add_ typ ( Sum . singleton e ) f
let simp_add es = simp_add_ es zero
let simp_add2 e f = simp_add_ ( Sum . singleton e ) f
(* Products of indeterminants represented by multisets. A product ∏ᵢ xᵢ^nᵢ
of indeterminates x ᵢ is represented by a multiset where the elements are
@ -731,58 +679,56 @@ module Prod = struct
let union = Qset . union
end
let rec simp_mul2 typ e f =
let rec simp_mul2 e f =
match ( e , f ) with
(* c₁ × c₂ ==> c₁× c₂ *)
| Integer { data = i } , Integer { data = j } -> integer ( Z . mul i j ) typ
| Integer { data = i } , Integer { data = j } -> integer ( Z . mul i j )
(* 0 × f ==> 0 *)
| Integer { data } , _ when Z . equal Z . zero data -> e
(* e × 0 ==> 0 *)
| _ , Integer { data } when Z . equal Z . zero data -> f
(* c × ( ∑ᵤ cᵤ × ∏ⱼ yᵤⱼ ) ==> ∑ᵤ c × cᵤ × ∏ⱼ yᵤⱼ *)
| Integer { data } , Add { args } | Add { args } , Integer { data } ->
Sum . to_term typ ( Sum . mul_const ( Q . of_z data ) args )
Sum . to_term ( Sum . mul_const ( Q . of_z data ) args )
(* c₁ × x₁ ==> ∑ᵢ₌₁ cᵢ × xᵢ *)
| Integer { data = c } , x | x , Integer { data = c } ->
Sum . to_term typ ( Sum . singleton ~ coeff : ( Q . of_z c ) x )
Sum . to_term ( Sum . singleton ~ coeff : ( Q . of_z c ) x )
(* ( ∏ᵤ₌₀ⁱ xᵤ ) × ( ∏ᵥ₌ᵢ₊₁ⁿ xᵥ ) ==> ∏ⱼ₌₀ⁿ xⱼ *)
| Mul { args = xs1 } , Mul { args = xs2 } -> Mul { typ; args= Prod . union xs1 xs2 }
| Mul { args = xs1 } , Mul { args = xs2 } -> Mul { args= Prod . union xs1 xs2 }
(* ( ∏ᵢ xᵢ ) × ( ∑ᵤ cᵤ × ∏ⱼ yᵤⱼ ) ==> ∑ᵤ cᵤ × ∏ᵢ xᵢ × ∏ⱼ yᵤⱼ *)
| ( Mul { args = prod } as m ) , Add { args = sum }
| Add { args = sum } , ( Mul { args = prod } as m ) ->
Sum . to_term typ
Sum . to_term
( Sum . map sum ~ f : ( function
| Mul { args } -> Mul { typ; args= Prod . union prod args }
| Integer _ as c -> simp_mul2 typ c m
| mono -> Mul { typ; args= Prod . add mono prod } ) )
| Mul { args } -> Mul { args= Prod . union prod args }
| Integer _ as c -> simp_mul2 c m
| mono -> Mul { args= Prod . add mono prod } ) )
(* x₀ × ( ∏ᵢ₌₁ⁿ xᵢ ) ==> ∏ᵢ₌₀ⁿ xᵢ *)
| Mul { args = xs1 } , x | x , Mul { args = xs1 } ->
Mul { typ ; args = Prod . add x xs1 }
| Mul { args = xs1 } , x | x , Mul { args = xs1 } -> Mul { args = Prod . add x xs1 }
(* e × ( ∑ᵤ cᵤ × ∏ⱼ yᵤⱼ ) ==> ∑ᵤ e × cᵤ × ∏ⱼ yᵤⱼ *)
| Add { args } , e | e , Add { args } ->
simp_add typ ( Sum . map ~ f : ( fun m -> simp_mul2 typ e m ) args )
simp_add ( Sum . map ~ f : ( fun m -> simp_mul2 e m ) args )
(* x₁ × x₂ ==> ∏ᵢ₌₁² xᵢ *)
| _ -> Mul { args = Prod . add e ( Prod . singleton f ) ; typ }
| _ -> Mul { args = Prod . add e ( Prod . singleton f ) }
let simp_mul typ es =
let simp_mul es =
(* ( bas ^ pwr ) × term *)
let rec mul_pwr bas pwr term =
if Q . equal Q . zero pwr then term
else mul_pwr bas Q . ( pwr - one ) ( simp_mul2 typ bas term )
else mul_pwr bas Q . ( pwr - one ) ( simp_mul2 bas term )
in
let one = one typ in
Qset . fold es ~ init : one ~ f : ( fun bas pwr term ->
if Q . sign pwr > = 0 then mul_pwr bas pwr term
else simp_div term ( mul_pwr bas ( Q . neg pwr ) one ) )
let simp_negate typ x = simp_mul2 typ ( minus_one typ ) x
let simp_negate x = simp_mul2 minus_one x
let simp_sub typ x y =
let simp_sub x y =
match ( x , y ) with
(* i - j *)
| Integer { data = i } , Integer { data = j } -> integer ( Z . sub i j ) typ
| Integer { data = i } , Integer { data = j } -> integer ( Z . sub i j )
(* x - y ==> x + ( -1 * y ) *)
| _ -> simp_add2 typ x ( simp_negate typ y )
| _ -> simp_add2 x ( simp_negate y )
let simp_cond cnd thn els =
match cnd with
@ -796,7 +742,7 @@ let simp_cond cnd thn els =
let rec simp_and x y =
match ( x , y ) with
(* i && j *)
| Integer { data = i ; typ }, Integer { data = j } -> integer ( Z . logand i j ) typ
| Integer { data = i }, Integer { data = j } -> integer ( Z . logand i j )
(* e && true ==> e *)
| ( Integer { data } , e | e , Integer { data } ) when Z . is_true data -> e
(* e && false ==> 0 *)
@ -814,7 +760,7 @@ let rec simp_and x y =
let rec simp_or x y =
match ( x , y ) with
(* i || j *)
| Integer { data = i ; typ }, Integer { data = j } -> integer ( Z . logor i j ) typ
| Integer { data = i }, Integer { data = j } -> integer ( Z . logor i j )
(* e || true ==> true *)
| ( ( Integer { data } as t ) , _ | _ , ( Integer { data } as t ) )
when Z . is_true data ->
@ -829,7 +775,18 @@ let rec simp_or x y =
| _ when equal x y -> x
| _ -> App { op = App { op = Or ; arg = x } ; arg = y }
let rec simp_not ( typ : Typ . t ) term =
let rec is_boolean = function
| App { op = App { op = Eq | Dq | Gt | Ge | Lt | Le } }
| App { op = Convert { dst = Integer { bits = 1 } } } ->
true
| App
{ op = App { op = Div | Rem | And | Or | Xor | Shl | Lshr | Ashr ; arg = x }
; arg = y }
| App { op = App { op = App { op = Conditional } ; arg = x } ; arg = y } ->
is_boolean x | | is_boolean y
| _ -> false
let rec simp_not term =
match term with
(* ¬ ( x = y ) ==> x ≠ y *)
| App { op = App { op = Eq ; arg = x } ; arg = y } -> simp_dq x y
@ -849,28 +806,26 @@ let rec simp_not (typ : Typ.t) term =
| App { op = App { op = Uno ; arg = x } ; arg = y } -> simp_ord x y
(* ¬ ( a ∧ b ) ==> ¬a ∨ ¬b *)
| App { op = App { op = And ; arg = x } ; arg = y } ->
simp_or ( simp_not typ x) ( simp_not typ y )
simp_or ( simp_not x) ( simp_not y )
(* ¬ ( a ∨ b ) ==> ¬a ∧ ¬b *)
| App { op = App { op = Or ; arg = x } ; arg = y } ->
simp_and ( simp_not typ x) ( simp_not typ y )
simp_and ( simp_not x) ( simp_not y )
(* ¬ ( c ? t : e ) ==> c ? ¬t : ¬e *)
| App { op = App { op = App { op = Conditional ; arg = cnd } ; arg = thn } ; arg = els }
->
simp_cond cnd ( simp_not t yp t hn) ( simp_not typ els )
simp_cond cnd ( simp_not t hn) ( simp_not els )
(* ¬i ==> -i-1 *)
| Integer { data ; typ } -> integer ( Z . lognot data ) typ
| Integer { data } -> integer ( Z . lognot data )
(* ¬e ==> true xor e *)
| e -> App { op = App { op = Xor ; arg = integer ( Z . of_bool true ) typ } ; arg = e }
| e -> App { op = App { op = Xor ; arg = true _ } ; arg = e }
and simp_eq x y =
match ( x , y ) with
(* i = j *)
| Integer { data = i } , Integer { data = j } -> bool ( Z . equal i j )
(* b = false ==> ¬b *)
| b , Integer { data } when Z . is_false data && is_boolean b ->
simp_not Typ . bool b
| Integer { data } , b when Z . is_false data && is_boolean b ->
simp_not Typ . bool b
| b , Integer { data } when Z . is_false data && is_boolean b -> simp_not b
| Integer { data } , b when Z . is_false data && is_boolean b -> simp_not b
(* b = true ==> b *)
| b , Integer { data } when Z . is_true data && is_boolean b -> b
| Integer { data } , b when Z . is_true data && is_boolean b -> b
@ -892,24 +847,22 @@ and simp_dq x y =
match simp_eq x y with
| App { op = App { op = Eq ; arg = x } ; arg = y } ->
App { op = App { op = Dq ; arg = x } ; arg = y }
| b -> simp_not Typ . bool b )
| b -> simp_not b )
let simp_xor x y =
match ( x , y ) with
(* i xor j *)
| Integer { data = i ; typ }, Integer { data = j } -> integer ( Z . logxor i j ) typ
| Integer { data = i }, Integer { data = j } -> integer ( Z . logxor i j )
(* true xor b ==> ¬b *)
| Integer { data } , b when Z . is_true data && is_boolean b ->
simp_not Typ . bool b
| b , Integer { data } when Z . is_true data && is_boolean b ->
simp_not Typ . bool b
| Integer { data } , b when Z . is_true data && is_boolean b -> simp_not b
| b , Integer { data } when Z . is_true data && is_boolean b -> simp_not b
| _ -> App { op = App { op = Xor ; arg = x } ; arg = y }
let simp_shl x y =
match ( x , y ) with
(* i shl j *)
| Integer { data = i ; typ }, Integer { data = j } when Z . sign j > = 0 ->
integer ( Z . shift_left i ( Z . to_int j ) ) typ
| Integer { data = i }, Integer { data = j } when Z . sign j > = 0 ->
integer ( Z . shift_left i ( Z . to_int j ) )
(* e shl 0 ==> e *)
| e , Integer { data } when Z . equal Z . zero data -> e
| _ -> App { op = App { op = Shl ; arg = x } ; arg = y }
@ -917,8 +870,8 @@ let simp_shl x y =
let simp_lshr x y =
match ( x , y ) with
(* i lshr j *)
| Integer { data = i ; typ }, Integer { data = j } when Z . sign j > = 0 ->
integer ( Z . shift_right_trunc i ( Z . to_int j ) ) typ
| Integer { data = i }, Integer { data = j } when Z . sign j > = 0 ->
integer ( Z . shift_right_trunc i ( Z . to_int j ) )
(* e lshr 0 ==> e *)
| e , Integer { data } when Z . equal Z . zero data -> e
| _ -> App { op = App { op = Lshr ; arg = x } ; arg = y }
@ -926,8 +879,8 @@ let simp_lshr x y =
let simp_ashr x y =
match ( x , y ) with
(* i ashr j *)
| Integer { data = i ; typ }, Integer { data = j } when Z . sign j > = 0 ->
integer ( Z . shift_right i ( Z . to_int j ) ) typ
| Integer { data = i }, Integer { data = j } when Z . sign j > = 0 ->
integer ( Z . shift_right i ( Z . to_int j ) )
(* e ashr 0 ==> e *)
| e , Integer { data } when Z . equal Z . zero data -> e
| _ -> App { op = App { op = Ashr ; arg = x } ; arg = y }
@ -1005,22 +958,10 @@ let app1 ?(partial = false) op arg =
let app2 op x y = app1 ( app1 ~ partial : true op x ) y
let app3 op x y z = app1 ( app1 ~ partial : true ( app1 ~ partial : true op x ) y ) z
let addN typ args = simp_add typ args | > check invariant
let mulN typ args = simp_mul typ args | > check invariant
let check1 op typ x =
type_check x typ ;
op typ x | > check invariant
let check2 op typ x y =
type_check2 x y typ ;
op typ x y | > check invariant
let addN args = simp_add args | > check invariant
let mulN args = simp_mul args | > check invariant
let simp_memory siz arr = Memory { siz ; arr }
let memory ~ siz ~ arr =
type_check siz Typ . siz ;
simp_memory siz arr | > check invariant
let memory ~ siz ~ arr = simp_memory siz arr | > check invariant
let simp_concat xs =
if Vector . length xs = 1 then Vector . get xs 0
@ -1044,11 +985,7 @@ let simp_splat byt siz =
| Integer { data } when Z . equal Z . zero data -> concat [| |]
| _ -> Splat { byt ; siz }
let splat ~ byt ~ siz =
type_check byt Typ . byt ;
type_check siz Typ . siz ;
simp_splat byt siz | > check invariant
let splat ~ byt ~ siz = simp_splat byt siz | > check invariant
let eq = app2 Eq
let dq = app2 Dq
let gt = app2 Gt
@ -1057,16 +994,16 @@ let lt = app2 Lt
let le = app2 Le
let ord = app2 Ord
let uno = app2 Uno
let neg = check1 simp_negate
let add = check2 simp_add2
let sub = check2 simp_sub
let mul = check2 simp_mul2
let neg = simp_negate
let add = simp_add2
let sub = simp_sub
let mul = simp_mul2
let div = app2 Div
let rem = app2 Rem
let and_ = app2 And
let or_ = app2 Or
let xor = app2 Xor
let not_ = check1 simp_not
let not_ = simp_not
let shl = app2 Shl
let lshr = app2 Lshr
let ashr = app2 Ashr
@ -1103,6 +1040,10 @@ let extract ?(unsigned = false) ~bits term =
let convert ? ( unsigned = false ) ~ dst ~ src term =
app1 ( Convert { unsigned ; dst ; src } ) term
let size_of t =
Option . bind ( Typ . prim_bit_size_of t ) ~ f : ( fun n ->
if n % 8 = 0 then Some ( integer ( Z . of_int ( n / 8 ) ) ) else None )
let rec of_exp ( e : Exp . t ) =
let unsigned op typ x y =
match Typ . prim_bit_size_of typ with
@ -1116,14 +1057,12 @@ let rec of_exp (e : Exp.t) =
| Reg { name } -> var ( Var { id = 0 ; name } )
| Nondet { msg } -> nondet msg
| Label { parent ; name } -> label ~ parent ~ name
| Integer { data ; typ = Integer { bits } as typ } ->
integer ( Z . signed_extract data 0 bits ) typ
| Integer { data ; typ } -> integer data typ
| Integer { data } -> integer data
| Float { data } -> float data
| Ap1 ( Convert { unsigned ; dst } , src , arg ) ->
convert ~ unsigned ~ dst ~ src ( of_exp arg )
| Ap1 ( Select idx , _ , arg ) ->
select ~ rcd : ( of_exp arg ) ~ idx : ( integer ( Z . of_int idx ) Typ . siz )
select ~ rcd : ( of_exp arg ) ~ idx : ( integer ( Z . of_int idx ) )
| Ap2 ( Eq , _ , x , y ) -> eq ( of_exp x ) ( of_exp y )
| Ap2 ( Dq , _ , x , y ) -> dq ( of_exp x ) ( of_exp y )
| Ap2 ( Gt , _ , x , y ) -> gt ( of_exp x ) ( of_exp y )
@ -1136,9 +1075,9 @@ let rec of_exp (e : Exp.t) =
| Ap2 ( Ule , typ , x , y ) -> unsigned le typ x y
| Ap2 ( Ord , _ , x , y ) -> ord ( of_exp x ) ( of_exp y )
| Ap2 ( Uno , _ , x , y ) -> uno ( of_exp x ) ( of_exp y )
| Ap2 ( Add , typ , x , y ) -> add typ ( of_exp x ) ( of_exp y )
| Ap2 ( Sub , typ , x , y ) -> sub typ ( of_exp x ) ( of_exp y )
| Ap2 ( Mul , typ , x , y ) -> mul typ ( of_exp x ) ( of_exp y )
| Ap2 ( Add , _ , x , y ) -> add ( of_exp x ) ( of_exp y )
| Ap2 ( Sub , _ , x , y ) -> sub ( of_exp x ) ( of_exp y )
| Ap2 ( Mul , _ , x , y ) -> mul ( of_exp x ) ( of_exp y )
| Ap2 ( Div , _ , x , y ) -> div ( of_exp x ) ( of_exp y )
| Ap2 ( Rem , _ , x , y ) -> rem ( of_exp x ) ( of_exp y )
| Ap2 ( Udiv , typ , x , y ) -> unsigned div typ x y
@ -1151,7 +1090,7 @@ let rec of_exp (e : Exp.t) =
| Ap2 ( Ashr , _ , x , y ) -> ashr ( of_exp x ) ( of_exp y )
| Ap2 ( Update idx , _ , rcd , elt ) ->
update ~ rcd : ( of_exp rcd ) ~ elt : ( of_exp elt )
~ idx : ( integer ( Z . of_int idx ) Typ . siz )
~ idx : ( integer ( Z . of_int idx ) )
| Ap3 ( Conditional , _ , cnd , thn , els ) ->
conditional ~ cnd : ( of_exp cnd ) ~ thn : ( of_exp thn ) ~ els : ( of_exp els )
| ApN ( Record , _ , elts ) ->
@ -1162,11 +1101,6 @@ let rec of_exp (e : Exp.t) =
~ id : e
( Vector . map elts ~ f : ( fun e -> lazy ( of_exp e ) ) )
let size_of t =
Option . bind ( Typ . prim_bit_size_of t ) ~ f : ( fun n ->
if n % 8 = 0 then Some ( integer ( Z . of_int ( n / 8 ) ) Typ . siz ) else None
)
(* * Transform *)
let map e ~ f =
@ -1181,14 +1115,14 @@ let map e ~f =
let args' = Vector . map_preserving_phys_equal ~ f args in
if args' = = args then e else mk args'
in
let map_qset mk typ ~ f args =
let map_qset mk ~ f args =
let args' = Qset . map ~ f : ( fun arg q -> ( f arg , q ) ) args in
if args' = = args then e else mk typ args'
if args' = = args then e else mk args'
in
match e with
| App { op ; arg } -> map_bin ( app1 ~ partial : true ) ~ f op arg
| Add { args ; typ } -> map_qset addN typ ~ f args
| Mul { args ; typ } -> map_qset mulN typ ~ f args
| Add { args } -> map_qset addN ~ f args
| Mul { args } -> map_qset mulN ~ f args
| Splat { byt ; siz } -> map_bin simp_splat ~ f byt siz
| Memory { siz ; arr } -> map_bin simp_memory ~ f siz arr
| Concat { args } -> map_vector simp_concat ~ f args
@ -1246,23 +1180,21 @@ let solve e f =
Some ( Map . add_exn s ~ key ~ data )
in
let concat_size args =
Vector . fold_until args ~ init : ( integer Z . zero Typ . siz )
~ f : ( fun sum -> function
| Memory { siz } -> Continue ( add Typ . siz siz sum ) | _ -> Stop None
)
Vector . fold_until args ~ init : zero
~ f : ( fun sum -> function Memory { siz } -> Continue ( add siz sum )
| _ -> Stop None )
~ finish : ( fun _ -> None )
in
match ( e , f ) with
| ( Add { typ } | Mul { typ } | Integer { typ } ) , _
| _ , ( Add { typ } | Mul { typ } | Integer { typ } ) -> (
match sub typ e f with
| ( Add _ | Mul _ | Integer _ ) , _ | _ , ( Add _ | Mul _ | Integer _ ) -> (
match sub e f with
| Add { args } ->
let c , q = Qset . min_elt_exn args in
let n = Sum . to_term typ ( Qset . remove args c ) in
let d = rational ( Q . neg q ) typ in
let n = Sum . to_term ( Qset . remove args c ) in
let d = rational ( Q . neg q ) in
let r = div n d in
Some ( Map . add_exn s ~ key : c ~ data : r )
| e_f -> solve_uninterp e_f ( zero typ ) )
| e_f -> solve_uninterp e_f zero )
| Concat { args = ms } , Concat { args = ns } -> (
match ( concat_size ms , concat_size ns ) with
| Some p , Some q -> solve_uninterp e f > > = solve_ p q