diff --git a/CHANGES.md b/CHANGES.md index a886e37d..fb3f17a8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,13 +1,26 @@ ## Unreleased ### Added -### Fixed + +- Add Bitvector library +- optimize Expr.equal, cache Expr.simplify (@zapashcanon) +- Add floating-point operator `Copysign` (Closes #185) +- Add sign extension to operators with unsigned counter parts (Closes #207) + ### Changed +- Use bitvector library for bitvectors instead of `Num (IXX _)` + +### Fixed + +- Bring back forall and exists quantifiers (Closes #200) +- Fixes `Value.compare` (Closes #210) + ## v0.5.0 ### Changed +- Bump `prelude` 0.3 -> 0.5 - Removes `satisfiability` type ## v0.4.1 diff --git a/bin/dune b/bin/dune index 26d20101..15504bb4 100644 --- a/bin/dune +++ b/bin/dune @@ -1,4 +1,5 @@ (executable + (package smtml) (name main) (public_name smtml) (libraries cmdliner smtml) diff --git a/bitvector.opam b/bitvector.opam new file mode 100644 index 00000000..3b4941e7 --- /dev/null +++ b/bitvector.opam @@ -0,0 +1,39 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: "Another Arbitrary-Width Bitvectors using the Zarith Library" +description: "Arbitrary-Width Bitvectors using the Zarith Library" +maintainer: ["Filipe Marques "] +authors: [ + "João Pereira " + "Filipe Marques " + "Hichem Rami Ait El Hara " + "Léo Andrès " + "Arthur Carcano " + "Pierre Chambart " + "José Fragoso Santos " +] +license: "MIT" +homepage: "https://github.com/formalsec/smtml" +doc: "https://formalsec.github.io/smtml/smtml/index.html" +bug-reports: "https://github.com/formalsec/smtml/issues" +depends: [ + "dune" {>= "3.10"} + "ocaml" {>= "4.14.0"} + "zarith" + "odoc" {with-doc} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +dev-repo: "git+https://github.com/formalsec/smtml.git" diff --git a/dune-project b/dune-project index 89ad5c2f..d359ca23 100644 --- a/dune-project +++ b/dune-project @@ -26,6 +26,15 @@ (license "MIT") +(package + (name bitvector) + (synopsis "Another Arbitrary-Width Bitvectors using the Zarith Library") + (description "Arbitrary-Width Bitvectors using the Zarith Library") + (depends + (ocaml + (>= "4.14.0")) + zarith)) + (package (name smtml) (synopsis "An SMT solver frontend for OCaml") diff --git a/smtml.opam b/smtml.opam index 3d0c1fad..4103bf49 100644 --- a/smtml.opam +++ b/smtml.opam @@ -71,8 +71,8 @@ build: [ dev-repo: "git+https://github.com/formalsec/smtml.git" available: arch != "arm32" & arch != "x86_32" pin-depends: [ - ["colibri2.0.4.0" "git+https://git.frama-c.com/pub/colibrics.git#1feba887bbb7980f27bbcec8137eb908caa8f0ce"] - ["colibrilib.0.4.0" "git+https://git.frama-c.com/pub/colibrics.git#1feba887bbb7980f27bbcec8137eb908caa8f0ce"] + ["colibri2.0.4.0" "git+https://git.frama-c.com/pub/colibrics.git#e15e6fc52b1f4e9a015b630a1f377d203ed9ec5b"] + ["colibrilib.0.4.0" "git+https://git.frama-c.com/pub/colibrics.git#e15e6fc52b1f4e9a015b630a1f377d203ed9ec5b"] ["alt-ergo-lib.2.6.0" "git+https://github.com/OCamlPro/alt-ergo.git#7ee96296a5de9588a4d585b3b8abec35f4755425"] ["cvc5.dev" "git+https://github.com/formalsec/ocaml-cvc5.git#b7aade52d49a19d646036d7e6aac09039c3e95cf"] ["benchpress.dev" "git+https://github.com/sneeuwballen/benchpress.git#7f44cdd9f0511afcce2c9ad3c04cc9b72919bcff"] diff --git a/smtml.opam.template b/smtml.opam.template index c539b812..ecf6b54d 100644 --- a/smtml.opam.template +++ b/smtml.opam.template @@ -1,7 +1,7 @@ available: arch != "arm32" & arch != "x86_32" pin-depends: [ - ["colibri2.0.4.0" "git+https://git.frama-c.com/pub/colibrics.git#1feba887bbb7980f27bbcec8137eb908caa8f0ce"] - ["colibrilib.0.4.0" "git+https://git.frama-c.com/pub/colibrics.git#1feba887bbb7980f27bbcec8137eb908caa8f0ce"] + ["colibri2.0.4.0" "git+https://git.frama-c.com/pub/colibrics.git#e15e6fc52b1f4e9a015b630a1f377d203ed9ec5b"] + ["colibrilib.0.4.0" "git+https://git.frama-c.com/pub/colibrics.git#e15e6fc52b1f4e9a015b630a1f377d203ed9ec5b"] ["alt-ergo-lib.2.6.0" "git+https://github.com/OCamlPro/alt-ergo.git#7ee96296a5de9588a4d585b3b8abec35f4755425"] ["cvc5.dev" "git+https://github.com/formalsec/ocaml-cvc5.git#b7aade52d49a19d646036d7e6aac09039c3e95cf"] ["benchpress.dev" "git+https://github.com/sneeuwballen/benchpress.git#7f44cdd9f0511afcce2c9ad3c04cc9b72919bcff"] diff --git a/src/bisect.exclude b/src/bisect.exclude index 154c460e..1ab5cd59 100644 --- a/src/bisect.exclude +++ b/src/bisect.exclude @@ -1,3 +1,3 @@ -file "src/colibri2_mappings.ml" -file "src/bitwuzla_mappings.ml" -file "src/cvc5_mappings.ml" +file "src/smtml/colibri2_mappings.ml" +file "src/smtml/bitwuzla_mappings.ml" +file "src/smtml/cvc5_mappings.ml" diff --git a/src/bitvector/bitvector.ml b/src/bitvector/bitvector.ml new file mode 100644 index 00000000..4ed62ca1 --- /dev/null +++ b/src/bitvector/bitvector.ml @@ -0,0 +1,166 @@ +type t = + { value : Z.t + ; width : int + } + +let mask width = Z.pred (Z.shift_left Z.one width) + +let make v m = + let masked_value = Z.logand v (mask m) in + { value = masked_value; width = m } + +let view { value; _ } = value + +let numbits { width; _ } = width + +let equal a b = Z.equal a.value b.value && a.width = b.width + +let compare a b = Z.compare a.value b.value + +let msb bv = Z.testbit bv.value (bv.width - 1) + +let to_signed bv = + let msb = msb bv in + if msb then Z.sub bv.value (Z.shift_left Z.one bv.width) else bv.value + +let pp fmt bv = Z.pp_print fmt bv.value + +(* Unop *) +let neg bv = make (Z.neg bv.value) bv.width + +let lognot a = make (Z.lognot a.value) a.width + +let clz bv = + let rec count_zeros i = + if i >= bv.width || Z.testbit bv.value (bv.width - 1 - i) then i + else count_zeros (i + 1) + in + make (Z.of_int @@ count_zeros 0) bv.width + +let ctz bv = + let rec count_zeros i = + if i >= bv.width || Z.testbit bv.value i then i else count_zeros (i + 1) + in + make (Z.of_int @@ count_zeros 0) bv.width + +let popcnt bv = make (Z.of_int @@ Z.popcount bv.value) bv.width + +(* Binop *) +let add a b = + assert (a.width = b.width); + make (Z.add a.value b.value) a.width + +let sub a b = + assert (a.width = b.width); + make (Z.sub a.value b.value) a.width + +let mul a b = + assert (a.width = b.width); + make (Z.mul a.value b.value) a.width + +let div a b = + assert (a.width = b.width); + if Z.equal b.value Z.zero then invalid_arg "division by zero"; + make (Z.div (to_signed a) (to_signed b)) a.width + +let div_u a b = + assert (a.width = b.width); + if Z.equal b.value Z.zero then invalid_arg "division by zero"; + make (Z.div a.value b.value) a.width + +let logand a b = + assert (a.width = b.width); + make (Z.logand a.value b.value) a.width + +let logor a b = + assert (a.width = b.width); + make (Z.logor a.value b.value) a.width + +let logxor a b = + assert (a.width = b.width); + make (Z.logxor a.value b.value) a.width + +let shl a n = + let n = Z.to_int n.value in + make (Z.shift_left a.value n) a.width + +let ashr a n = + let n = Z.to_int n.value in + let signed_value = to_signed a in + make (Z.shift_right signed_value n) a.width + +let lshr a n = + let n = Z.to_int n.value in + make (Z.shift_right_trunc a.value n) a.width + +let rem a b = + assert (a.width = b.width); + if Z.equal b.value Z.zero then invalid_arg "division by zero"; + make (Z.rem (to_signed a) (to_signed b)) a.width + +let rem_u a b = + assert (a.width = b.width); + if Z.equal b.value Z.zero then invalid_arg "division by zero"; + make (Z.rem a.value b.value) a.width + +let rotate_left bv n = + let n = Z.to_int n.value mod bv.width in + let left_part = Z.shift_left bv.value n in + let right_part = Z.shift_right bv.value (bv.width - n) in + let rotated = Z.logor left_part right_part in + make rotated bv.width + +let rotate_right bv n = + let n = Z.to_int n.value mod bv.width in + let right_part = Z.shift_right bv.value n in + let left_part = Z.shift_left bv.value (bv.width - n) in + let rotated = Z.logor left_part right_part in + make rotated bv.width + +(* Relop *) +let lt_u a b = Z.lt a.value b.value + +let gt_u a b = Z.gt a.value b.value + +let le_u a b = Z.leq a.value b.value + +let ge_u a b = Z.geq a.value b.value + +let lt a b = Z.lt (to_signed a) (to_signed b) + +let gt a b = Z.gt (to_signed a) (to_signed b) + +let le a b = Z.leq (to_signed a) (to_signed b) + +let ge a b = Z.geq (to_signed a) (to_signed b) + +(* Extract and concat *) +let concat a b = + let new_width = a.width + b.width in + let shifted = Z.shift_left a.value b.width in + let combined = Z.logor shifted b.value in + make combined new_width + +let extract bv ~high ~low = + assert (high <= bv.width && low >= 0 && low < high); + let width = high - low + 1 in + let shifted = Z.shift_right bv.value low in + let extracted = Z.logand shifted (mask width) in + make extracted width + +(* Cvtop *) +let zero_extend width bv = + let new_width = bv.width + width in + make bv.value new_width + +let sign_extend width bv = + let new_width = bv.width + width in + let msb = msb bv in + let sign_mask = + if msb then + let shift_amount = bv.width in + Z.shift_left (mask width) shift_amount + else Z.zero + in + let extended = Z.logor bv.value sign_mask in + make extended new_width diff --git a/src/bitvector/bitvector.mli b/src/bitvector/bitvector.mli new file mode 100644 index 00000000..b08975d4 --- /dev/null +++ b/src/bitvector/bitvector.mli @@ -0,0 +1,77 @@ +type t + +val make : Z.t -> int -> t + +val view : t -> Z.t + +val numbits : t -> int + +val equal : t -> t -> bool + +val compare : t -> t -> int + +val pp : Format.formatter -> t -> unit + +val neg : t -> t + +val lognot : t -> t + +val clz : t -> t + +val ctz : t -> t + +val popcnt : t -> t + +val add : t -> t -> t + +val sub : t -> t -> t + +val mul : t -> t -> t + +val div : t -> t -> t + +val div_u : t -> t -> t + +val logand : t -> t -> t + +val logor : t -> t -> t + +val logxor : t -> t -> t + +val shl : t -> t -> t + +val ashr : t -> t -> t + +val lshr : t -> t -> t + +val rem : t -> t -> t + +val rem_u : t -> t -> t + +val rotate_left : t -> t -> t + +val rotate_right : t -> t -> t + +val lt : t -> t -> bool + +val lt_u : t -> t -> bool + +val gt : t -> t -> bool + +val gt_u : t -> t -> bool + +val le : t -> t -> bool + +val le_u : t -> t -> bool + +val ge : t -> t -> bool + +val ge_u : t -> t -> bool + +val concat : t -> t -> t + +val extract : t -> high:int -> low:int -> t + +val zero_extend : int -> t -> t + +val sign_extend : int -> t -> t diff --git a/src/bitvector/dune b/src/bitvector/dune new file mode 100644 index 00000000..982ca815 --- /dev/null +++ b/src/bitvector/dune @@ -0,0 +1,6 @@ +(library + (wrapped false) + (name bitvector) + (public_name bitvector) + (modules bitvector) + (libraries zarith)) diff --git a/src/constructors_intf.ml b/src/constructors_intf.ml deleted file mode 100644 index 0542fc8d..00000000 --- a/src/constructors_intf.ml +++ /dev/null @@ -1,27 +0,0 @@ -(* SPDX-License-Identifier: MIT *) -(* Copyright (C) 2023-2024 formalsec *) -(* Written by the Smtml programmers *) - -module type Infix = sig - type t - - type elt - - val v : elt -> t - - val sym : string -> t - - val ( ~- ) : t -> t - - val ( = ) : t -> t -> t - - val ( != ) : t -> t -> t - - val ( > ) : t -> t -> t - - val ( >= ) : t -> t -> t - - val ( < ) : t -> t -> t - - val ( <= ) : t -> t -> t -end diff --git a/src/altergo_mappings.default.ml b/src/smtml/altergo_mappings.default.ml similarity index 96% rename from src/altergo_mappings.default.ml rename to src/smtml/altergo_mappings.default.ml index 1786da1c..41036096 100644 --- a/src/altergo_mappings.default.ml +++ b/src/smtml/altergo_mappings.default.ml @@ -210,9 +210,7 @@ module Fresh = struct | { f = False; _ } -> False | { f = Int z; _ } -> Int (Z.to_int z) | { f = Real q; _ } -> Real (Q.to_float q) - | { f = Bitv (8, z); _ } -> Num (I8 (Z.to_int z)) - | { f = Bitv (32, z); _ } -> Num (I32 (Z.to_int32 z)) - | { f = Bitv (64, z); _ } -> Num (I64 (Z.to_int64 z)) + | { f = Bitv (n, z); _ } -> Bitv (Bitvector.make z n) | _ -> Fmt.failwith "Altergo_mappings: ae_expr_to_value(%a)" AEL.Expr.print e @@ -238,9 +236,7 @@ module Fresh = struct | Some q -> Real (Q.to_float q) | None -> ( match (DM.Value.extract ~ops:DM.Bitv.ops v, ty) with - | Some z, Ty_bitv 8 -> Num (I8 (Z.to_int z)) - | Some z, Ty_bitv 32 -> Num (I32 (Z.to_int32 z)) - | Some z, Ty_bitv 64 -> Num (I64 (Z.to_int64 z)) + | Some z, Ty_bitv n -> Bitv (Bitvector.make z n) | _ -> Fmt.failwith "Altergo_mappings: dvalue_to_value(%a)" DM.Value.print v ) ) ) diff --git a/src/ast.ml b/src/smtml/ast.ml similarity index 100% rename from src/ast.ml rename to src/smtml/ast.ml diff --git a/src/ast.mli b/src/smtml/ast.mli similarity index 100% rename from src/ast.mli rename to src/smtml/ast.mli diff --git a/src/axioms.ml b/src/smtml/axioms.ml similarity index 100% rename from src/axioms.ml rename to src/smtml/axioms.ml diff --git a/src/binder.ml b/src/smtml/binder.ml similarity index 100% rename from src/binder.ml rename to src/smtml/binder.ml diff --git a/src/bitwuzla_mappings.default.ml b/src/smtml/bitwuzla_mappings.default.ml similarity index 100% rename from src/bitwuzla_mappings.default.ml rename to src/smtml/bitwuzla_mappings.default.ml diff --git a/src/bitwuzla_mappings.mli b/src/smtml/bitwuzla_mappings.mli similarity index 100% rename from src/bitwuzla_mappings.mli rename to src/smtml/bitwuzla_mappings.mli diff --git a/src/cache.ml b/src/smtml/cache.ml similarity index 100% rename from src/cache.ml rename to src/smtml/cache.ml diff --git a/src/cache.mli b/src/smtml/cache.mli similarity index 100% rename from src/cache.mli rename to src/smtml/cache.mli diff --git a/src/cache_intf.ml b/src/smtml/cache_intf.ml similarity index 100% rename from src/cache_intf.ml rename to src/smtml/cache_intf.ml diff --git a/src/colibri2_mappings.default.ml b/src/smtml/colibri2_mappings.default.ml similarity index 96% rename from src/colibri2_mappings.default.ml rename to src/smtml/colibri2_mappings.default.ml index eb339b7d..d458ca15 100644 --- a/src/colibri2_mappings.default.ml +++ b/src/smtml/colibri2_mappings.default.ml @@ -274,20 +274,16 @@ module Fresh = struct with | Some a when A.is_integer a -> Some (Value.Int (A.to_int a)) | Some a when A.is_real a -> - Some (Value.Real (Float.of_string (A.to_string a))) + Option.map + (fun f -> Value.Real f) + (Float.of_string_opt (A.to_string a)) | Some _ | None -> None ) | Ty_bitv n -> ( match Colibri2_core.Value.value Colibri2_theories_LRA.RealValue.key v with | Some a when A.is_integer a -> - Some - (Value.Num - ( match n with - | 8 -> I8 (A.to_int a) - | 32 -> I32 (Int32.of_int (A.to_int a)) - | 64 -> I64 (Int64.of_int (A.to_int a)) - | _ -> assert false ) ) + Some (Value.Bitv (Bitvector.make (A.to_z a) n)) | _ -> assert false ) | Ty_fp n -> ( match Colibri2_core.Value.value Colibri2_theories_fp.Fp_value.key v with diff --git a/src/colibri2_mappings.mli b/src/smtml/colibri2_mappings.mli similarity index 100% rename from src/colibri2_mappings.mli rename to src/smtml/colibri2_mappings.mli diff --git a/src/compile.ml b/src/smtml/compile.ml similarity index 100% rename from src/compile.ml rename to src/smtml/compile.ml diff --git a/src/cvc5_mappings.default.ml b/src/smtml/cvc5_mappings.default.ml similarity index 100% rename from src/cvc5_mappings.default.ml rename to src/smtml/cvc5_mappings.default.ml diff --git a/src/cvc5_mappings.mli b/src/smtml/cvc5_mappings.mli similarity index 100% rename from src/cvc5_mappings.mli rename to src/smtml/cvc5_mappings.mli diff --git a/src/dolmenexpr_to_expr.ml b/src/smtml/dolmenexpr_to_expr.ml similarity index 91% rename from src/dolmenexpr_to_expr.ml rename to src/smtml/dolmenexpr_to_expr.ml index bea35437..4622b1a0 100644 --- a/src/dolmenexpr_to_expr.ml +++ b/src/smtml/dolmenexpr_to_expr.ml @@ -328,34 +328,37 @@ end module Bv = struct open Ty - let encode_val (type a) (cast : a Ty.cast) (i : a) = - match cast with - | C8 -> - let n = if i >= 0 then i else i land ((1 lsl 8) - 1) in - (* necessary to have the same behaviour as Z3 *) - DTerm.Bitv.mk - (Dolmen_type.Misc.Bitv.parse_decimal - (String.cat "bv" (Int.to_string n)) - 8 ) - | C32 -> - let iint = Int32.to_int i in - let n = if iint >= 0 then iint else iint land ((1 lsl 32) - 1) in - (* necessary to have the same behaviour as Z3 *) - DTerm.Bitv.mk - (Dolmen_type.Misc.Bitv.parse_decimal - (String.cat "bv" (Int.to_string n)) - 32 ) - | C64 -> - let n = - if Int64.compare i Int64.zero >= 0 then Z.of_int64 i - else Z.logand (Z.of_int64 i) (Z.sub (Z.( lsl ) Z.one 64) Z.one) - in - - (* necessary to have the same behaviour as Z3 *) - DTerm.Bitv.mk - (Dolmen_type.Misc.Bitv.parse_decimal - (String.cat "bv" (Z.to_string n)) - 64 ) + let encode_val bv = + DTerm.Bitv.mk + (Dolmen_type.Misc.Bitv.parse_decimal + (String.cat "bv" (Z.to_string (Bitvector.view bv))) + (Bitvector.numbits bv) ) + (* match cast with *) + (* | C8 -> *) + (* let n = if i >= 0 then i else i land ((1 lsl 8) - 1) in *) + (* (1* necessary to have the same behaviour as Z3 *1) *) + (* DTerm.Bitv.mk *) + (* (Dolmen_type.Misc.Bitv.parse_decimal *) + (* (String.cat "bv" (Int.to_string n)) *) + (* 8 ) *) + (* | C32 -> *) + (* let iint = Int32.to_int i in *) + (* let n = if iint >= 0 then iint else iint land ((1 lsl 32) - 1) in *) + (* (1* necessary to have the same behaviour as Z3 *1) *) + (* DTerm.Bitv.mk *) + (* (Dolmen_type.Misc.Bitv.parse_decimal *) + (* (String.cat "bv" (Int.to_string n)) *) + (* 32 ) *) + (* | C64 -> *) + (* let n = *) + (* if Int64.compare i Int64.zero >= 0 then Z.of_int64 i *) + (* else Z.logand (Z.of_int64 i) (Z.sub (Z.( lsl ) Z.one 64) Z.one) *) + (* in *) + (* (1* necessary to have the same behaviour as Z3 *1) *) + (* DTerm.Bitv.mk *) + (* (Dolmen_type.Misc.Bitv.parse_decimal *) + (* (String.cat "bv" (Z.to_string n)) *) + (* 64 ) *) let encode_unop op e = let op' = @@ -420,12 +423,13 @@ module Bv = struct DTerm.Float.to_ubv 64 DTerm.Float.roundTowardZero | Reinterpret_float when sz = 32 -> DTerm.Float.ieee_format_to_fp 8 24 | Reinterpret_float when sz = 64 -> DTerm.Float.ieee_format_to_fp 11 53 - | ToBool when sz = 32 -> encode_relop Ne (encode_val C32 0l) - | ToBool when sz = 64 -> encode_relop Ne (encode_val C64 0L) - | OfBool when sz = 32 -> - fun e -> DTerm.ite e (encode_val C32 1l) (encode_val C32 0l) - | OfBool when sz = 64 -> - fun e -> DTerm.ite e (encode_val C64 1L) (encode_val C64 0L) + | ToBool -> + let zero = Bitvector.make Z.zero sz in + encode_relop Ne (encode_val zero) + | OfBool -> + let zero = Bitvector.make Z.zero sz in + let one = Bitvector.make Z.one sz in + fun e -> DTerm.ite e (encode_val one) (encode_val zero) | _ -> Fmt.failwith {|Bv: Unsupported bv(32) operator "%a"|} Cvtop.pp op in op' e @@ -437,8 +441,12 @@ module Fp = struct let encode_val (type a) (sz : a Ty.cast) (f : a) = match sz with | C8 -> Fmt.failwith "Unable to create FP numeral using 8 bits" - | C32 -> DTerm.Float.ieee_format_to_fp 8 24 (Bv.encode_val C32 f) - | C64 -> DTerm.Float.ieee_format_to_fp 11 53 (Bv.encode_val C64 f) + | C32 -> + let bv = Bitvector.make (Z.of_int32 f) 32 in + DTerm.Float.ieee_format_to_fp 8 24 (Bv.encode_val bv) + | C64 -> + let bv = Bitvector.make (Z.of_int64 f) 64 in + DTerm.Float.ieee_format_to_fp 11 53 (Bv.encode_val bv) let encode_unop op e = let op' = @@ -526,9 +534,7 @@ let encode_val : Value.t -> expr = function | Int v -> I.encode_val v | Real v -> Real.encode_val v | Str _ -> assert false - | Num (I8 x) -> Bv.encode_val C8 x - | Num (I32 x) -> Bv.encode_val C32 x - | Num (I64 x) -> Bv.encode_val C64 x + | Bitv bv -> Bv.encode_val bv | Num (F32 x) -> Fp.encode_val C32 x | Num (F64 x) -> Fp.encode_val C64 x | v -> Fmt.failwith {|Unsupported value "%a"|} Value.pp v @@ -593,7 +599,7 @@ let encode_expr_acc ?(record_sym = fun acc _ -> acc) acc e = match Expr.view e with | Val v -> (acc, encode_val v) | Ptr { base; offset } -> - let base' = encode_val (Num (I32 base)) in + let base' = encode_val (Bitv (Bitvector.make (Z.of_int32 base) 32)) in let acc, offset' = aux acc offset in (acc, DTerm.Bitv.add base' offset') | Symbol s -> diff --git a/src/dolmenexpr_to_expr.mli b/src/smtml/dolmenexpr_to_expr.mli similarity index 100% rename from src/dolmenexpr_to_expr.mli rename to src/smtml/dolmenexpr_to_expr.mli diff --git a/src/dune b/src/smtml/dune similarity index 95% rename from src/dune rename to src/smtml/dune index 205bd2ed..b5d062f1 100644 --- a/src/dune +++ b/src/smtml/dune @@ -1,9 +1,3 @@ -(library - (name smtml_prelude) - (public_name smtml.prelude) - (modules smtml_prelude) - (libraries prelude)) - (ocamllex (modules lexer)) @@ -24,7 +18,6 @@ cache_intf colibri2_mappings compile - constructors_intf cvc5_mappings dolmenexpr_to_expr eval @@ -61,6 +54,7 @@ (flags (:standard -open Smtml_prelude)) (libraries + bitvector bos cmdliner dolmen diff --git a/src/eval.ml b/src/smtml/eval.ml similarity index 75% rename from src/eval.ml rename to src/smtml/eval.ml index 4a0a9408..69a4ddfe 100644 --- a/src/eval.ml +++ b/src/smtml/eval.ml @@ -9,6 +9,8 @@ (* TODO: This module should be concrete or a part of the reducer *) +[@@@ocaml.warning "-27-32"] + type op_type = [ `Unop of Ty.Unop.t | `Binop of Ty.Binop.t @@ -439,63 +441,22 @@ module Lst = struct Fmt.failwith {|naryop: Unsupported list operator "%a"|} Ty.Naryop.pp op end -module I32 = struct - let to_value (i : int32) : Value.t = Num (I32 i) [@@inline] +module Bitv = struct + let to_value (bv : Bitvector.t) : Value.t = Bitv bv [@@inline] - let of_value (n : int) (op : op_type) (v : Value.t) : int32 = + let of_value (n : int) (op : op_type) (v : Value.t) = of_arg - (function Num (I32 i) -> i | _ -> raise_notrace (Value (Ty_bitv 32))) + (function Bitv bv -> bv | _ -> raise_notrace (Value (Ty_bitv ~-1))) n v op [@@inline] - let cmp_u x op y = op Int32.(add x min_int) Int32.(add y min_int) [@@inline] - - let lt_u x y = cmp_u x Int32.Infix.( < ) y [@@inline] - - let le_u x y = cmp_u x Int32.Infix.( <= ) y [@@inline] - - let gt_u x y = cmp_u x Int32.Infix.( > ) y [@@inline] - - let ge_u x y = cmp_u x Int32.Infix.( >= ) y [@@inline] - - let shift f x y = f x Int32.(to_int (logand y 31l)) [@@inline] - - let shl x y = shift Int32.shift_left x y [@@inline] - - let shr_s x y = shift Int32.shift_right x y [@@inline] - - let shr_u x y = shift Int32.shift_right_logical x y [@@inline] - - (* Stolen rotl and rotr from: *) - (* https://github.com/OCamlPro/owi/blob/main/src/int32.ml *) - (* We must mask the count to implement rotates via shifts. *) - let clamp_rotate_count n = Int32.(to_int (logand n 31l)) [@@inline] - - let rotl x y = - let n = clamp_rotate_count y in - Int32.logor (shl x (Int32.of_int n)) (shr_u x (Int32.of_int (32 - n))) - [@@inline] - - let rotr x y = - let n = clamp_rotate_count y in - Int32.logor (shr_u x (Int32.of_int n)) (shl x (Int32.of_int (32 - n))) - [@@inline] - - let clz n = - let n = Ocaml_intrinsics.Int32.count_leading_zeros n in - Int32.of_int n - - let ctz n = - let n = Ocaml_intrinsics.Int32.count_trailing_zeros n in - Int32.of_int n - let unop (op : Ty.Unop.t) (v : Value.t) : Value.t = let f = match op with - | Neg -> Int32.neg - | Not -> Int32.lognot - | Clz -> clz - | Ctz -> ctz + | Neg -> Bitvector.neg + | Not -> Bitvector.lognot + | Clz -> Bitvector.clz + | Ctz -> Bitvector.ctz | _ -> Fmt.failwith {|unop: Unsupported i32 operator "%a"|} Ty.Unop.pp op in to_value (f (of_value 1 (`Unop op) v)) @@ -503,21 +464,21 @@ module I32 = struct let binop op v1 v2 = let f = match op with - | Ty.Binop.Add -> Int32.add - | Sub -> Int32.sub - | Mul -> Int32.mul - | Div -> Int32.div - | DivU -> Int32.unsigned_div - | Rem -> Int32.rem - | RemU -> Int32.unsigned_rem - | And -> Int32.logand - | Or -> Int32.logor - | Xor -> Int32.logxor - | Shl -> shl - | ShrL -> shr_u - | ShrA -> shr_s - | Rotl -> rotl - | Rotr -> rotr + | Ty.Binop.Add -> Bitvector.add + | Sub -> Bitvector.sub + | Mul -> Bitvector.mul + | Div -> Bitvector.div + | DivU -> Bitvector.div_u + | Rem -> Bitvector.rem + | RemU -> Bitvector.rem_u + | And -> Bitvector.logand + | Or -> Bitvector.logor + | Xor -> Bitvector.logxor + | Shl -> Bitvector.shl + | ShrL -> Bitvector.lshr + | ShrA -> Bitvector.ashr + | Rotl -> Bitvector.rotate_left + | Rotr -> Bitvector.rotate_right | _ -> Fmt.failwith {|binop: Unsupported i32 operator "%a"|} Ty.Binop.pp op in @@ -526,114 +487,14 @@ module I32 = struct let relop (op : Ty.Relop.t) (v1 : Value.t) (v2 : Value.t) : bool = let f = match op with - | Lt -> Int32.Infix.( < ) - | LtU -> lt_u - | Le -> Int32.Infix.( <= ) - | LeU -> le_u - | Gt -> Int32.Infix.( > ) - | GtU -> gt_u - | Ge -> Int32.Infix.( >= ) - | GeU -> ge_u - | Eq | Ne -> assert false - in - f (of_value 1 (`Relop op) v1) (of_value 2 (`Relop op) v2) -end - -module I64 = struct - let to_value (i : int64) : Value.t = Num (I64 i) [@@inline] - - let of_value (n : int) (op : op_type) (v : Value.t) : int64 = - of_arg - (function Num (I64 i) -> i | _ -> raise_notrace (Value (Ty_bitv 64))) - n v op - [@@inline] - - let cmp_u x op y = op Int64.(add x min_int) Int64.(add y min_int) [@@inline] - - let lt_u x y = cmp_u x Int64.Infix.( < ) y [@@inline] - - let le_u x y = cmp_u x Int64.Infix.( <= ) y [@@inline] - - let gt_u x y = cmp_u x Int64.Infix.( > ) y [@@inline] - - let ge_u x y = cmp_u x Int64.Infix.( >= ) y [@@inline] - - let shift f x y = f x Int64.(to_int (logand y 63L)) [@@inline] - - let shl x y = shift Int64.shift_left x y [@@inline] - - let shr_s x y = shift Int64.shift_right x y [@@inline] - - let shr_u x y = shift Int64.shift_right_logical x y [@@inline] - - (* Stolen rotl and rotr from: *) - (* https://github.com/OCamlPro/owi/blob/main/src/int64.ml *) - (* We must mask the count to implement rotates via shifts. *) - let clamp_rotate_count n = Int64.(to_int (logand n (of_int 63))) [@@inline] - - let rotl x y = - let n = clamp_rotate_count y in - Int64.logor (shl x (Int64.of_int n)) (shr_u x (Int64.of_int (64 - n))) - [@@inline] - - let rotr x y = - let n = clamp_rotate_count y in - Int64.logor (shr_u x (Int64.of_int n)) (shl x (Int64.of_int (64 - n))) - [@@inline] - - let clz n = - let n = Ocaml_intrinsics.Int64.count_leading_zeros n in - Int64.of_int n - - let ctz n = - let n = Ocaml_intrinsics.Int64.count_trailing_zeros n in - Int64.of_int n - - let unop (op : Ty.Unop.t) (v : Value.t) : Value.t = - let f = - match op with - | Neg -> Int64.neg - | Not -> Int64.lognot - | Clz -> clz - | Ctz -> ctz - | _ -> Fmt.failwith {|unop: Unsupported i64 operator "%a"|} Ty.Unop.pp op - in - to_value (f (of_value 1 (`Unop op) v)) - - let binop (op : Ty.Binop.t) (v1 : Value.t) (v2 : Value.t) : Value.t = - let f = - match op with - | Add -> Int64.add - | Sub -> Int64.sub - | Mul -> Int64.mul - | Div -> Int64.div - | DivU -> Int64.unsigned_div - | Rem -> Int64.rem - | RemU -> Int64.unsigned_rem - | And -> Int64.logand - | Or -> Int64.logor - | Xor -> Int64.logxor - | Shl -> shl - | ShrL -> shr_u - | ShrA -> shr_s - | Rotl -> rotl - | Rotr -> rotr - | _ -> - Fmt.failwith {|binop: Unsupported i64 operator "%a"|} Ty.Binop.pp op - in - to_value (f (of_value 1 (`Binop op) v1) (of_value 2 (`Binop op) v2)) - - let relop (op : Ty.Relop.t) (v1 : Value.t) (v2 : Value.t) : bool = - let f = - match op with - | Lt -> Int64.Infix.( < ) - | LtU -> lt_u - | Le -> Int64.Infix.( <= ) - | LeU -> le_u - | Gt -> Int64.Infix.( > ) - | GtU -> gt_u - | Ge -> Int64.Infix.( >= ) - | GeU -> ge_u + | Lt -> Bitvector.lt + | LtU -> Bitvector.lt_u + | Le -> Bitvector.le + | LeU -> Bitvector.le_u + | Gt -> Bitvector.gt + | GtU -> Bitvector.gt_u + | Ge -> Bitvector.ge + | GeU -> Bitvector.ge_u | Eq | Ne -> assert false in f (of_value 1 (`Relop op) v1) (of_value 2 (`Relop op) v2) @@ -806,20 +667,20 @@ module I32CvtOp = struct then raise IntegerOverflow else Int32.of_float xf - let cvtop op v = - let op' = `Cvtop op in - match op with - | Ty.Cvtop.WrapI64 -> I32.to_value (Int64.to_int32 (I64.of_value 1 op' v)) - | TruncSF32 -> I32.to_value (trunc_f32_s (F32.of_value 1 op' v)) - | TruncUF32 -> I32.to_value (trunc_f32_u (F32.of_value 1 op' v)) - | TruncSF64 -> I32.to_value (trunc_f64_s (F64.of_value 1 op' v)) - | TruncUF64 -> I32.to_value (trunc_f64_u (F64.of_value 1 op' v)) - | Reinterpret_float -> I32.to_value (F32.of_value 1 op' v) - | Sign_extend n -> I32.to_value (extend_s n (I32.of_value 1 op' v)) - | Zero_extend _n -> I32.to_value (I32.of_value 1 op' v) - | OfBool -> v (* already a num here *) - | ToBool | _ -> - Fmt.failwith {|cvtop: Unsupported i32 operator "%a"|} Ty.Cvtop.pp op + let cvtop op v = assert false + (* let op' = `Cvtop op in *) + (* match op with *) + (* | Ty.Cvtop.WrapI64 -> I32.to_value (Int64.to_int32 (I64.of_value 1 op' v)) *) + (* | TruncSF32 -> I32.to_value (trunc_f32_s (F32.of_value 1 op' v)) *) + (* | TruncUF32 -> I32.to_value (trunc_f32_u (F32.of_value 1 op' v)) *) + (* | TruncSF64 -> I32.to_value (trunc_f64_s (F64.of_value 1 op' v)) *) + (* | TruncUF64 -> I32.to_value (trunc_f64_u (F64.of_value 1 op' v)) *) + (* | Reinterpret_float -> I32.to_value (F32.of_value 1 op' v) *) + (* | Sign_extend n -> I32.to_value (extend_s n (I32.of_value 1 op' v)) *) + (* | Zero_extend _n -> I32.to_value (I32.of_value 1 op' v) *) + (* | OfBool -> v (1* already a num here *1) *) + (* | ToBool | _ -> *) + (* Fmt.failwith {|cvtop: Unsupported i32 operator "%a"|} Ty.Cvtop.pp op *) end module I64CvtOp = struct @@ -871,21 +732,22 @@ module I64CvtOp = struct else Int64.of_float xf let cvtop (op : Ty.Cvtop.t) (v : Value.t) : Value.t = - let op' = `Cvtop op in - match op with - | Sign_extend 32 -> I64.to_value (Int64.of_int32 (I32.of_value 1 op' v)) - | Zero_extend 32 -> I64.to_value (extend_i32_u (I32.of_value 1 op' v)) - | TruncSF32 -> I64.to_value (trunc_f32_s (F32.of_value 1 op' v)) - | TruncUF32 -> I64.to_value (trunc_f32_u (F32.of_value 1 op' v)) - | TruncSF64 -> I64.to_value (trunc_f64_s (F64.of_value 1 op' v)) - | TruncUF64 -> I64.to_value (trunc_f64_u (F64.of_value 1 op' v)) - | Reinterpret_float -> I64.to_value (F64.of_value 1 op' v) - | WrapI64 -> - raise - (TypeError - { index = 1; value = v; ty = Ty_bitv 64; op = `Cvtop WrapI64 } ) - | ToBool | OfBool | _ -> - Fmt.failwith {|cvtop: Unsupported i64 operator "%a"|} Ty.Cvtop.pp op + (* let op' = `Cvtop op in *) + (* match op with *) + (* | Sign_extend 32 -> I64.to_value (Int64.of_int32 (I32.of_value 1 op' v)) *) + (* | Zero_extend 32 -> I64.to_value (extend_i32_u (I32.of_value 1 op' v)) *) + (* | TruncSF32 -> I64.to_value (trunc_f32_s (F32.of_value 1 op' v)) *) + (* | TruncUF32 -> I64.to_value (trunc_f32_u (F32.of_value 1 op' v)) *) + (* | TruncSF64 -> I64.to_value (trunc_f64_s (F64.of_value 1 op' v)) *) + (* | TruncUF64 -> I64.to_value (trunc_f64_u (F64.of_value 1 op' v)) *) + (* | Reinterpret_float -> I64.to_value (F64.of_value 1 op' v) *) + (* | WrapI64 -> *) + (* raise *) + (* (TypeError *) + (* { index = 1; value = v; ty = Ty_bitv 64; op = `Cvtop WrapI64 } ) *) + (* | ToBool | OfBool | _ -> *) + (* Fmt.failwith {|cvtop: Unsupported i64 operator "%a"|} Ty.Cvtop.pp op *) + assert false end module F32CvtOp = struct @@ -921,24 +783,34 @@ module F32CvtOp = struct let r = if logand x 0xfffL = 0L then 0L else 1L in to_float (logor (shift_right x 12) r) *. 0x1p12 ) ) - let convert_i64_u x = - F32.of_float - Int64.( - Int64.Infix.( - if I64.lt_u x 0x10_0000_0000_0000L then to_float x - else - let r = if logand x 0xfffL = 0L then 0L else 1L in - to_float (logor (shift_right_logical x 12) r) *. 0x1p12 ) ) + let convert_i64_u x = assert false + (* F32.of_float *) + (* Int64.( *) + (* Int64.Infix.( *) + (* if I64.lt_u x 0x10_0000_0000_0000L then to_float x *) + (* else *) + (* let r = if logand x 0xfffL = 0L then 0L else 1L in *) + (* to_float (logor (shift_right_logical x 12) r) *. 0x1p12 ) ) *) let cvtop (op : Ty.Cvtop.t) (v : Value.t) : Value.t = let op' = `Cvtop op in match op with | DemoteF64 -> F32.to_value (demote_f64 (F64.of_value 1 op' v)) - | ConvertSI32 -> F32.to_value (convert_i32_s (I32.of_value 1 op' v)) - | ConvertUI32 -> F32.to_value (convert_i32_u (I32.of_value 1 op' v)) - | ConvertSI64 -> F32.to_value (convert_i64_s (I64.of_value 1 op' v)) - | ConvertUI64 -> F32.to_value (convert_i64_u (I64.of_value 1 op' v)) - | Reinterpret_int -> F32.to_value (I32.of_value 1 op' v) + | ConvertSI32 -> + let i32 = Z.to_int32 @@ Bitvector.view @@ Bitv.of_value 1 op' v in + F32.to_value (convert_i32_s i32) + | ConvertUI32 -> + let i32 = Z.to_int32 @@ Bitvector.view @@ Bitv.of_value 1 op' v in + F32.to_value (convert_i32_u i32) + | ConvertSI64 -> + let i64 = Z.to_int64 @@ Bitvector.view @@ Bitv.of_value 1 op' v in + F32.to_value (convert_i64_s i64) + | ConvertUI64 -> + let i64 = Z.to_int64 @@ Bitvector.view @@ Bitv.of_value 1 op' v in + F32.to_value (convert_i64_u i64) + | Reinterpret_int -> + let i32 = Z.to_int32 @@ Bitvector.view @@ Bitv.of_value 1 op' v in + F32.to_value i32 | PromoteF32 -> raise (TypeError @@ -992,12 +864,30 @@ module F64CvtOp = struct let cvtop (op : Ty.Cvtop.t) v : Value.t = let op' = `Cvtop op in match op with - | PromoteF32 -> F64.to_value (promote_f32 (F32.of_value 1 op' v)) - | ConvertSI32 -> F64.to_value (convert_i32_s (I32.of_value 1 op' v)) - | ConvertUI32 -> F64.to_value (convert_i32_u (I32.of_value 1 op' v)) - | ConvertSI64 -> F64.to_value (convert_i64_s (I64.of_value 1 op' v)) - | ConvertUI64 -> F64.to_value (convert_i64_u (I64.of_value 1 op' v)) - | Reinterpret_int -> F64.to_value (I64.of_value 1 op' v) + | PromoteF32 -> + (* TODO: Invariant here is that bv.width = 32 *) + let i32 = Z.to_int32 @@ Bitvector.view @@ Bitv.of_value 1 op' v in + F64.to_value (promote_f32 i32) + | ConvertSI32 -> + (* TODO: Invariant here is that bv.width = 32 *) + let i32 = Z.to_int32 @@ Bitvector.view @@ Bitv.of_value 1 op' v in + F64.to_value (convert_i32_s i32) + | ConvertUI32 -> + (* TODO: Invariant here is that bv.width = 32 *) + let i32 = Z.to_int32 @@ Bitvector.view @@ Bitv.of_value 1 op' v in + F64.to_value (convert_i32_u i32) + | ConvertSI64 -> + (* TODO: Invariant here is that bv.width = 64 *) + let i64 = Z.to_int64 @@ Bitvector.view @@ Bitv.of_value 1 op' v in + F64.to_value (convert_i64_s i64) + | ConvertUI64 -> + (* TODO: Invariant here is that bv.width = 64 *) + let i64 = Z.to_int64 @@ Bitvector.view @@ Bitv.of_value 1 op' v in + F64.to_value (convert_i64_u i64) + | Reinterpret_int -> + (* TODO: Invariant here is that bv.width = 64 *) + let i64 = Z.to_int64 @@ Bitvector.view @@ Bitv.of_value 1 op' v in + F64.to_value i64 | DemoteF64 -> raise (TypeError @@ -1008,27 +898,25 @@ end (* Dispatch *) -let op int real bool str lst i32 i64 f32 f64 ty op = +let op int real bool str lst bitv f32 f64 ty op = match ty with | Ty.Ty_int -> int op | Ty_real -> real op | Ty_bool -> bool op | Ty_str -> str op | Ty_list -> lst op - | Ty_bitv 32 -> i32 op - | Ty_bitv 64 -> i64 op + | Ty_bitv _n -> bitv op | Ty_fp 32 -> f32 op | Ty_fp 64 -> f64 op - | Ty_bitv _ | Ty_fp _ | Ty_app | Ty_unit | Ty_none | Ty_regexp -> assert false + | Ty_fp _ | Ty_app | Ty_unit | Ty_none | Ty_regexp -> assert false [@@inline] let unop = - op Int.unop Real.unop Bool.unop Str.unop Lst.unop I32.unop I64.unop F32.unop - F64.unop + op Int.unop Real.unop Bool.unop Str.unop Lst.unop Bitv.unop F32.unop F64.unop let binop = - op Int.binop Real.binop Bool.binop Str.binop Lst.binop I32.binop I64.binop - F32.binop F64.binop + op Int.binop Real.binop Bool.binop Str.binop Lst.binop Bitv.binop F32.binop + F64.binop let triop = function | Ty.Ty_bool -> Bool.triop @@ -1041,11 +929,10 @@ let relop = function | Ty_real -> Real.relop | Ty_bool -> Bool.relop | Ty_str -> Str.relop - | Ty_bitv 32 -> I32.relop - | Ty_bitv 64 -> I64.relop + | Ty_bitv _n -> Bitv.relop | Ty_fp 32 -> F32.relop | Ty_fp 64 -> F64.relop - | _ -> assert false + | Ty_app | Ty_none | Ty_unit | Ty_fp _ | Ty_list | Ty_regexp -> assert false let cvtop = function | Ty.Ty_int -> Int.cvtop diff --git a/src/eval.mli b/src/smtml/eval.mli similarity index 100% rename from src/eval.mli rename to src/smtml/eval.mli diff --git a/src/expr.ml b/src/smtml/expr.ml similarity index 78% rename from src/expr.ml rename to src/smtml/expr.ml index aed78879..da1e9fca 100644 --- a/src/expr.ml +++ b/src/smtml/expr.ml @@ -104,7 +104,7 @@ let[@inline] compare (hte1 : t) (hte2 : t) = compare hte1.tag hte2.tag let symbol s = make (Symbol s) -let is_num (e : t) = match view e with Val (Num _) -> true | _ -> false +let is_bv (e : t) = match view e with Val (Bitv _) -> true | _ -> false (** The return type of an expression *) let rec ty (hte : t) : Ty.t = @@ -187,21 +187,21 @@ let get_symbols (hte : t list) = Hashtbl.fold (fun k () acc -> k :: acc) tbl [] let negate_relop (hte : t) : (t, string) Result.t = - let e = - match view hte with - | Relop (ty, Eq, e1, e2) -> Ok (Relop (ty, Ne, e1, e2)) - | Relop (ty, Ne, e1, e2) -> Ok (Relop (ty, Eq, e1, e2)) - | Relop (ty, Lt, e1, e2) -> Ok (Relop (ty, Ge, e1, e2)) - | Relop (ty, LtU, e1, e2) -> Ok (Relop (ty, GeU, e1, e2)) - | Relop (ty, Le, e1, e2) -> Ok (Relop (ty, Gt, e1, e2)) - | Relop (ty, LeU, e1, e2) -> Ok (Relop (ty, GtU, e1, e2)) - | Relop (ty, Gt, e1, e2) -> Ok (Relop (ty, Le, e1, e2)) - | Relop (ty, GtU, e1, e2) -> Ok (Relop (ty, LeU, e1, e2)) - | Relop (ty, Ge, e1, e2) -> Ok (Relop (ty, Lt, e1, e2)) - | Relop (ty, GeU, e1, e2) -> Ok (Relop (ty, LtU, e1, e2)) - | _ -> Error "negate_relop: not a relop." + let negate = function + | Ty.Relop.Eq -> Ty.Relop.Ne + | Ne -> Eq + | Lt -> Ge + | LtU -> GeU + | Le -> Gt + | LeU -> GtU + | Gt -> Le + | GtU -> LeU + | Ge -> Lt + | GeU -> LtU in - Result.map make e + match view hte with + | Relop (ty, op, e1, e2) -> Ok (make (Relop (ty, negate op, e1, e2))) + | _ -> Error "negate_relop: not a relop." module Pp = struct let rec pp fmt (hte : t) = @@ -309,17 +309,21 @@ let rec binop ty op hte1 hte2 = | Sub, Ptr { base; offset }, _ -> ptr base (binop (Ty_bitv 32) Sub offset hte2) | Rem, Ptr { base; offset }, _ -> - let rhs = value (Num (I32 base)) in + let rhs = value (Bitv (Bitvector.make (Z.of_int32 base) 32)) in let addr = binop (Ty_bitv 32) Add rhs offset in binop ty Rem addr hte2 | Add, _, Ptr { base; offset } -> ptr base (binop (Ty_bitv 32) Add offset hte1) | Sub, _, Ptr { base; offset } -> - binop ty Sub hte1 (binop (Ty_bitv 32) Add (value (Num (I32 base))) offset) - | (Add | Or), Val (Num (I32 0l)), _ -> hte2 - | (And | Div | DivU | Mul | Rem | RemU), Val (Num (I32 0l)), _ -> hte1 - | (Add | Or), _, Val (Num (I32 0l)) -> hte1 - | (And | Mul), _, Val (Num (I32 0l)) -> hte2 + let base = value (Bitv (Bitvector.make (Z.of_int32 base) 32)) in + binop ty Sub hte1 (binop (Ty_bitv 32) Add base offset) + | (Add | Or), Val (Bitv bv), _ when Z.equal (Bitvector.view bv) Z.zero -> hte2 + | (And | Div | DivU | Mul | Rem | RemU), Val (Bitv bv), _ + when Z.equal (Bitvector.view bv) Z.zero -> + hte1 + | (Add | Or), _, Val (Bitv bv) when Z.equal (Bitvector.view bv) Z.zero -> hte1 + | (And | Mul), _, Val (Bitv bv) when Z.equal (Bitvector.view bv) Z.zero -> + hte2 | Add, Binop (ty, Add, x, { node = Val v1; _ }), Val v2 -> let v = value (Eval.binop ty Add v1 v2) in binop' ty Add x v @@ -385,15 +389,18 @@ let rec relop ty op hte1 hte2 = , Ptr { base = b2; offset = os2 } ) -> if Int32.equal b1 b2 then relop ty op os1 os2 else - value - (if Eval.relop ty op (Num (I32 b1)) (Num (I32 b2)) then True else False) - | op, Val (Num _ as n), Ptr { base; offset = { node = Val (Num _ as o); _ } } + let b1 = Bitvector.make (Z.of_int32 b1) 32 in + let b2 = Bitvector.make (Z.of_int32 b2) 32 in + value (if Eval.relop ty op (Bitv b1) (Bitv b2) then True else False) + | op, Val (Bitv _ as n), Ptr { base; offset = { node = Val (Bitv _ as o); _ } } -> - let base = Eval.binop (Ty_bitv 32) Add (Num (I32 base)) o in + let base = Bitvector.make (Z.of_int32 base) 32 in + let base = Eval.binop (Ty_bitv 32) Add (Bitv base) o in value (if Eval.relop ty op n base then True else False) - | op, Ptr { base; offset = { node = Val (Num _ as o); _ } }, Val (Num _ as n) + | op, Ptr { base; offset = { node = Val (Bitv _ as o); _ } }, Val (Bitv _ as n) -> - let base = Eval.binop (Ty_bitv 32) Add (Num (I32 base)) o in + let base = Bitvector.make (Z.of_int32 base) 32 in + let base = Eval.binop (Ty_bitv 32) Add (Bitv base) o in value (if Eval.relop ty op base n then True else False) | op, List l1, List l2 -> relop_list op l1 l2 | _, _, _ -> relop' ty op hte1 hte2 @@ -436,69 +443,36 @@ let naryop ty op es = value (Eval.naryop ty op vs) else naryop' ty op es -let nland64 (x : int64) (n : int) = - let rec loop x' n' acc = - if n' = 0 then Int64.logand x' acc - else loop x' (n' - 1) Int64.(logor (shift_left acc 8) 0xffL) - in - loop x n 0L - -let nland32 (x : int32) (n : int) = - let rec loop x' n' acc = - if n' = 0 then Int32.logand x' acc - else loop x' (n' - 1) Int32.(logor (shift_left acc 8) 0xffl) - in - loop x n 0l - let extract' (hte : t) ~(high : int) ~(low : int) : t = make (Extract (hte, high, low)) [@@inline] let extract (hte : t) ~(high : int) ~(low : int) : t = match view hte with - | Val (Num (I64 x)) -> - let x' = nland64 (Int64.shift_right x (low * 8)) (high - low) in - value (Num (I64 x')) + | Val (Bitv bv) -> value (Bitv (Bitvector.extract bv ~high ~low)) + (* Any other value cannot be extracted! *) + (* | Val _ -> assert false *) | _ -> if high - low = Ty.size (ty hte) then hte else extract' hte ~high ~low let concat' (msb : t) (lsb : t) : t = make (Concat (msb, lsb)) [@@inline] let concat (msb : t) (lsb : t) : t = match (view msb, view lsb) with - | ( Extract ({ node = Val (Num (I64 x2)); _ }, h2, l2) - , Extract ({ node = Val (Num (I64 x1)); _ }, h1, l1) ) -> - let d1 = h1 - l1 in - let d2 = h2 - l2 in - let x1' = nland64 (Int64.shift_right x1 (l1 * 8)) d1 in - let x2' = nland64 (Int64.shift_right x2 (l2 * 8)) d2 in - let x = Int64.(logor (shift_left x2' (d1 * 8)) x1') in - extract' (value (Num (I64 x))) ~high:(d1 + d2) ~low:0 - | ( Extract ({ node = Val (Num (I32 x2)); _ }, h2, l2) - , Extract ({ node = Val (Num (I32 x1)); _ }, h1, l1) ) -> - let d1 = h1 - l1 in - let d2 = h2 - l2 in - let x1' = nland32 (Int32.shift_right x1 (l1 * 8)) d1 in - let x2' = nland32 (Int32.shift_right x2 (l2 * 8)) d2 in - let x = Int32.(logor (shift_left x2' (d1 * 8)) x1') in - extract' (value (Num (I32 x))) ~high:(d1 + d2) ~low:0 + | Val (Bitv a), Val (Bitv b) -> value (Bitv (Bitvector.concat a b)) | Extract (s1, h, m1), Extract (s2, m2, l) when equal s1 s2 && m1 = m2 -> extract' s1 ~high:h ~low:l - | ( Extract ({ node = Val (Num (I64 x2)); _ }, h2, l2) - , Concat - ({ node = Extract ({ node = Val (Num (I64 x1)); _ }, h1, l1); _ }, se) ) - when not (is_num se) -> - let d1 = h1 - l1 in - let d2 = h2 - l2 in - let x1' = nland64 (Int64.shift_right x1 (l1 * 8)) d1 in - let x2' = nland64 (Int64.shift_right x2 (l2 * 8)) d2 in - let x = Int64.(logor (shift_left x2' (d1 * 8)) x1') in - concat' (extract' (value (Num (I64 x))) ~high:(d1 + d2) ~low:0) se + | Val (Bitv a), Concat ({ node = Val (Bitv b); _ }, se) when not (is_bv se) -> + let bv = value (Bitv (Bitvector.concat a b)) in + concat' bv se | _ -> concat' msb lsb let rec simplify_expr ?(rm_extract = true) (hte : t) : t = match view hte with | Val _ | Symbol _ -> hte - | Ptr { base; offset } -> ptr base (simplify_expr offset) + | Ptr { base; offset } -> + (* FIXME: *) + let base = Bitvector.make (Z.of_int32 base) 32 in + binop (Ty_bitv 32) Add (value (Bitv base)) offset | List es -> make @@ List (List.map simplify_expr es) | App (x, es) -> make @@ App (x, List.map simplify_expr es) | Unop (ty, op, e) -> @@ -609,94 +583,3 @@ module Bool = struct let ite c r1 r2 = triop Ty_bool Ite c r1 r2 end - -module Make (T : sig - type elt - - val ty : Ty.t - - val num : elt -> Num.t -end) = -struct - open Ty - - let v i = value (Num (T.num i)) - - let sym x = symbol Symbol.(x @: T.ty) - - let ( ~- ) e = unop T.ty Neg e - - let ( = ) e1 e2 = relop Ty_bool Eq e1 e2 - - let ( != ) e1 e2 = relop Ty_bool Ne e1 e2 - - let ( > ) e1 e2 = relop T.ty Gt e1 e2 - - let ( >= ) e1 e2 = relop T.ty Ge e1 e2 - - let ( < ) e1 e2 = relop T.ty Lt e1 e2 - - let ( <= ) e1 e2 = relop T.ty Le e1 e2 -end - -module Bitv = struct - open Ty - - module I8 = Make (struct - type elt = int - - let ty = Ty_bitv 8 - - let num i = Num.I8 i - end) - - module I32 = Make (struct - type elt = int32 - - let ty = Ty_bitv 32 - - let num i = Num.I32 i - end) - - module I64 = Make (struct - type elt = int64 - - let ty = Ty_bitv 64 - - let num i = Num.I64 i - end) -end - -module Fpa = struct - open Ty - - module F32 = struct - include Make (struct - type elt = float - - let ty = Ty_fp 32 - - let num f = Num.F32 (Int32.bits_of_float f) - end) - - (* Redeclare equality due to incorrect theory annotation *) - let ( = ) e1 e2 = relop (Ty_fp 32) Eq e1 e2 - - let ( != ) e1 e2 = relop (Ty_fp 32) Ne e1 e2 - end - - module F64 = struct - include Make (struct - type elt = float - - let ty = Ty_fp 64 - - let num f = Num.F64 (Int64.bits_of_float f) - end) - - (* Redeclare equality due to incorrect theory annotation *) - let ( = ) e1 e2 = relop (Ty_fp 64) Eq e1 e2 - - let ( != ) e1 e2 = relop (Ty_fp 64) Ne e1 e2 - end -end diff --git a/src/expr.mli b/src/smtml/expr.mli similarity index 89% rename from src/expr.mli rename to src/smtml/expr.mli index 7ce0d672..343eb010 100644 --- a/src/expr.mli +++ b/src/smtml/expr.mli @@ -153,17 +153,3 @@ module Set : sig val compare : t -> t -> int end - -module Bitv : sig - module I8 : Constructors_intf.Infix with type elt := int and type t := t - - module I32 : Constructors_intf.Infix with type elt := int32 and type t := t - - module I64 : Constructors_intf.Infix with type elt := int64 and type t := t -end - -module Fpa : sig - module F32 : Constructors_intf.Infix with type elt := float and type t := t - - module F64 : Constructors_intf.Infix with type elt := float and type t := t -end diff --git a/src/interpret.ml b/src/smtml/interpret.ml similarity index 100% rename from src/interpret.ml rename to src/smtml/interpret.ml diff --git a/src/interpret.mli b/src/smtml/interpret.mli similarity index 100% rename from src/interpret.mli rename to src/smtml/interpret.mli diff --git a/src/interpret_intf.ml b/src/smtml/interpret_intf.ml similarity index 100% rename from src/interpret_intf.ml rename to src/smtml/interpret_intf.ml diff --git a/src/lexer.mll b/src/smtml/lexer.mll similarity index 100% rename from src/lexer.mll rename to src/smtml/lexer.mll diff --git a/src/log.ml b/src/smtml/log.ml similarity index 100% rename from src/log.ml rename to src/smtml/log.ml diff --git a/src/logic.ml b/src/smtml/logic.ml similarity index 100% rename from src/logic.ml rename to src/smtml/logic.ml diff --git a/src/mappings.ml b/src/smtml/mappings.ml similarity index 98% rename from src/mappings.ml rename to src/smtml/mappings.ml index edc0b383..9ac92c60 100644 --- a/src/mappings.ml +++ b/src/smtml/mappings.ml @@ -542,9 +542,12 @@ module Make (M_with_make : M_with_make) : S_with_fresh = struct | Int v -> Int_impl.v v | Real v -> Real_impl.v v | Str v -> String_impl.v v - | Num (I8 x) -> I8.v x - | Num (I32 x) -> I32.v x - | Num (I64 x) -> I64.v x + (* | Num (I8 x) -> I8.v x *) + (* | Num (I32 x) -> I32.v x *) + (* | Num (I64 x) -> I64.v x *) + | Bitv bv -> + let m = Bitvector.numbits bv in + M.Bitv.v (Z.to_string (Bitvector.view bv)) m | Num (F32 x) -> Float32_impl.v x | Num (F64 x) -> Float64_impl.v x | List _ | App _ | Unit | Nothing -> assert false @@ -628,7 +631,7 @@ module Make (M_with_make : M_with_make) : S_with_fresh = struct match Expr.view hte with | Val value -> (ctx, v value) | Ptr { base; offset } -> - let base' = v (Num (I32 base)) in + let base' = v (Bitv (Bitvector.make (Z.of_int32 base) 32)) in let ctx, offset' = encode_expr ctx offset in (ctx, I32.binop Add base' offset') | Symbol sym -> make_symbol ctx sym @@ -704,23 +707,16 @@ module Make (M_with_make : M_with_make) : S_with_fresh = struct else ( assert (Int64.equal b 0L); Value.False ) - | Ty_bitv 8 -> - let i8 = M.Interp.to_bitv v 8 in - Value.Num (I8 (Int64.to_int i8)) - | Ty_bitv 32 -> - let i32 = M.Interp.to_bitv v 32 in - Value.Num (I32 (Int64.to_int32 i32)) - | Ty_bitv 64 -> - let i64 = M.Interp.to_bitv v 64 in - Value.Num (I64 i64) + | Ty_bitv n -> + let i = M.Interp.to_bitv v n in + Value.Bitv (Bitvector.make (Z.of_int64 i) n) | Ty_fp 32 -> let float = M.Interp.to_float v 8 24 in Value.Num (F32 (Int32.bits_of_float float)) | Ty_fp 64 -> let float = M.Interp.to_float v 11 53 in Value.Num (F64 (Int64.bits_of_float float)) - | Ty_bitv _ | Ty_fp _ | Ty_list | Ty_app | Ty_unit | Ty_none | Ty_regexp - -> + | Ty_fp _ | Ty_list | Ty_app | Ty_unit | Ty_none | Ty_regexp -> assert false let value ({ model = m; ctx } : model) (c : Expr.t) : Value.t = diff --git a/src/mappings.nop.ml b/src/smtml/mappings.nop.ml similarity index 100% rename from src/mappings.nop.ml rename to src/smtml/mappings.nop.ml diff --git a/src/mappings_intf.ml b/src/smtml/mappings_intf.ml similarity index 100% rename from src/mappings_intf.ml rename to src/smtml/mappings_intf.ml diff --git a/src/model.ml b/src/smtml/model.ml similarity index 100% rename from src/model.ml rename to src/smtml/model.ml diff --git a/src/model.mli b/src/smtml/model.mli similarity index 100% rename from src/model.mli rename to src/smtml/model.mli diff --git a/src/num.ml b/src/smtml/num.ml similarity index 60% rename from src/num.ml rename to src/smtml/num.ml index 8613767d..c93a25fa 100644 --- a/src/num.ml +++ b/src/smtml/num.ml @@ -3,9 +3,9 @@ (* Written by the Smtml programmers *) type t = - | I8 of int - | I32 of int32 - | I64 of int64 + (* | I8 of int *) + (* | I32 of int32 *) + (* | I64 of int64 *) | F32 of int32 | F64 of int64 @@ -16,54 +16,52 @@ type printer = let type_of (n : t) = match n with - | I8 _ -> Ty.(Ty_bitv 8) - | I32 _ -> Ty.(Ty_bitv 32) - | I64 _ -> Ty.(Ty_bitv 64) + (* | I8 _ -> Ty.(Ty_bitv 8) *) + (* | I32 _ -> Ty.(Ty_bitv 32) *) + (* | I64 _ -> Ty.(Ty_bitv 64) *) | F32 _ -> Ty.(Ty_fp 32) | F64 _ -> Ty.(Ty_fp 64) let compare n1 n2 = match (n1, n2) with - | I8 i1, I8 i2 -> Int.compare i1 i2 - | I32 i1, I32 i2 -> Int32.compare i1 i2 - | I64 i1, I64 i2 -> Int64.compare i1 i2 + (* | I8 i1, I8 i2 -> Int.compare i1 i2 *) + (* | I32 i1, I32 i2 -> Int32.compare i1 i2 *) + (* | I64 i1, I64 i2 -> Int64.compare i1 i2 *) | F32 i1, F32 i2 -> Float.compare (Int32.float_of_bits i1) (Int32.float_of_bits i2) | F64 i1, F64 i2 -> Float.compare (Int64.float_of_bits i1) (Int64.float_of_bits i2) - | I8 _, _ -> -1 - | I32 _, I8 _ -> 1 - | I32 _, _ -> -1 - | I64 _, (I8 _ | I32 _) -> 1 - | I64 _, _ -> -1 - | F32 _, (I8 _ | I32 _ | I64 _) -> 1 + (* | I8 _, _ -> -1 *) + (* | I32 _, I8 _ -> 1 *) + (* | I32 _, _ -> -1 *) + (* | I64 _, (I8 _ | I32 _) -> 1 *) + (* | I64 _, _ -> -1 *) + (* | F32 _, (I8 _ | I32 _ | I64 _) -> 1 *) | F32 _, F64 _ -> -1 | F64 _, _ -> 1 let equal (n1 : t) (n2 : t) : bool = compare n1 n2 = 0 -let num_of_bool (b : bool) : t = I32 (if b then 1l else 0l) - let pp_num fmt (n : t) = match n with - | I8 i -> Fmt.pf fmt "(i8 %d)" i - | I32 i -> Fmt.pf fmt "(i32 %ld)" i - | I64 i -> Fmt.pf fmt "(i64 %Ld)" i + (* | I8 i -> Fmt.pf fmt "(i8 %d)" i *) + (* | I32 i -> Fmt.pf fmt "(i32 %ld)" i *) + (* | I64 i -> Fmt.pf fmt "(i64 %Ld)" i *) | F32 f -> Fmt.pf fmt "(f32 %F)" (Int32.float_of_bits f) | F64 f -> Fmt.pf fmt "(f64 %F)" (Int64.float_of_bits f) let pp_hex fmt (n : t) = match n with - | I8 i -> Fmt.pf fmt "0x%02x" (i land 0xff) - | I32 i -> Fmt.pf fmt "0x%08lx" i - | I64 i -> Fmt.pf fmt "0x%016Lx" i + (* | I8 i -> Fmt.pf fmt "0x%02x" (i land 0xff) *) + (* | I32 i -> Fmt.pf fmt "0x%08lx" i *) + (* | I64 i -> Fmt.pf fmt "0x%016Lx" i *) | F32 f -> Fmt.pf fmt "(fp 0x%08lx)" f | F64 f -> Fmt.pf fmt "(fp 0x%016Lx)" f let pp_no_type fmt = function - | I8 i -> Fmt.pf fmt "%d" i - | I32 i -> Fmt.pf fmt "%ld" i - | I64 i -> Fmt.pf fmt "%Ld" i + (* | I8 i -> Fmt.pf fmt "%d" i *) + (* | I32 i -> Fmt.pf fmt "%ld" i *) + (* | I64 i -> Fmt.pf fmt "%Ld" i *) | F32 f -> Fmt.pf fmt "%F" (Int32.float_of_bits f) | F64 f -> Fmt.pf fmt "%F" (Int64.float_of_bits f) @@ -79,12 +77,12 @@ let to_string (n : t) : string = Fmt.str "%a" pp n let of_string (cast : Ty.t) value = match cast with - | Ty_bitv 8 -> ( - match int_of_string_opt value with - | None -> Fmt.error_msg "invalid value %s, expected 8-bit bitv" value - | Some n -> Ok (I8 n) ) - | Ty_bitv 32 -> Ok (I32 (Int32.of_string value)) - | Ty_bitv 64 -> Ok (I64 (Int64.of_string value)) + (* | Ty_bitv 8 -> ( *) + (* match int_of_string_opt value with *) + (* | None -> Fmt.error_msg "invalid value %s, expected 8-bit bitv" value *) + (* | Some n -> Ok (I8 n) ) *) + (* | Ty_bitv 32 -> Ok (I32 (Int32.of_string value)) *) + (* | Ty_bitv 64 -> Ok (I64 (Int64.of_string value)) *) | Ty_fp 32 -> ( match float_of_string_opt value with | None -> Fmt.error_msg "invalid value %s, expected float" value diff --git a/src/num.mli b/src/smtml/num.mli similarity index 86% rename from src/num.mli rename to src/smtml/num.mli index cdaae9b4..56271b4a 100644 --- a/src/num.mli +++ b/src/smtml/num.mli @@ -3,9 +3,9 @@ (* Written by the Smtml programmers *) type t = - | I8 of int - | I32 of int32 - | I64 of int64 + (* | I8 of int *) + (* | I32 of int32 *) + (* | I64 of int64 *) | F32 of int32 | F64 of int64 @@ -20,8 +20,6 @@ val compare : t -> t -> int val equal : t -> t -> bool -val num_of_bool : bool -> t - val set_default_printer : printer -> unit val pp : t Fmt.t diff --git a/src/op_intf.ml b/src/smtml/op_intf.ml similarity index 100% rename from src/op_intf.ml rename to src/smtml/op_intf.ml diff --git a/src/optimizer.ml b/src/smtml/optimizer.ml similarity index 100% rename from src/optimizer.ml rename to src/smtml/optimizer.ml diff --git a/src/optimizer.mli b/src/smtml/optimizer.mli similarity index 100% rename from src/optimizer.mli rename to src/smtml/optimizer.mli diff --git a/src/optimizer_intf.ml b/src/smtml/optimizer_intf.ml similarity index 100% rename from src/optimizer_intf.ml rename to src/smtml/optimizer_intf.ml diff --git a/src/params.ml b/src/smtml/params.ml similarity index 100% rename from src/params.ml rename to src/smtml/params.ml diff --git a/src/params.mli b/src/smtml/params.mli similarity index 100% rename from src/params.mli rename to src/smtml/params.mli diff --git a/src/parse.ml b/src/smtml/parse.ml similarity index 100% rename from src/parse.ml rename to src/smtml/parse.ml diff --git a/src/parse.mli b/src/smtml/parse.mli similarity index 100% rename from src/parse.mli rename to src/smtml/parse.mli diff --git a/src/parser.mly b/src/smtml/parser.mly similarity index 96% rename from src/parser.mly rename to src/smtml/parser.mly index 32a5df84..a3b9d4d5 100644 --- a/src/parser.mly +++ b/src/smtml/parser.mly @@ -85,8 +85,7 @@ let spec_constant := | LPAREN; ty = TYPE; x = NUM; RPAREN; { match ty with - | Ty_bitv 32 -> Num (I32 (Int32.of_int x)) - | Ty_bitv 64 -> Num (I64 (Int64.of_int x)) + | Ty_bitv n -> Bitv (Bitvector.make (Z.of_int x) n) | _ -> Fmt.failwith "invalid bitv type" } | LPAREN; ty = TYPE; x = DEC; RPAREN; diff --git a/src/rewrite.ml b/src/smtml/rewrite.ml similarity index 100% rename from src/rewrite.ml rename to src/smtml/rewrite.ml diff --git a/src/smtlib.ml b/src/smtml/smtlib.ml similarity index 97% rename from src/smtlib.ml rename to src/smtml/smtlib.ml index 86dab0af..ce950a5a 100644 --- a/src/smtlib.ml +++ b/src/smtml/smtlib.ml @@ -52,17 +52,11 @@ module Term = struct | _ -> Expr.symbol id ) | Term, Indexed { basename = base; indices } -> ( match String.(sub base 0 2, sub base 2 (length base - 2), indices) with - | "bv", str, [ "8" ] -> begin - match int_of_string_opt str with - | None -> assert false - | Some n -> Expr.value (Num (I8 n)) + | "bv", str, [ n ] -> begin + match (int_of_string_opt str, int_of_string_opt n) with + | Some v, Some n -> Expr.value (Bitv (Bitvector.make (Z.of_int v) n)) + | (None | Some _), _ -> assert false end - | "bv", str, [ "32" ] -> begin - match int_of_string_opt str with - | None -> assert false - | Some n -> Expr.value (Num (I32 (Int32.of_int (n land 0xffffffff)))) - end - | "bv", str, [ "64" ] -> Expr.value (Num (I64 (Int64.of_string str))) | _ -> Expr.symbol id ) | Attr, Simple _ -> Expr.symbol id | Attr, Indexed _ -> assert false diff --git a/src/altergo_mappings.mli b/src/smtml/smtmlaltergo_mappings.mli similarity index 100% rename from src/altergo_mappings.mli rename to src/smtml/smtmlaltergo_mappings.mli diff --git a/src/solver.ml b/src/smtml/solver.ml similarity index 100% rename from src/solver.ml rename to src/smtml/solver.ml diff --git a/src/solver.mli b/src/smtml/solver.mli similarity index 100% rename from src/solver.mli rename to src/smtml/solver.mli diff --git a/src/solver_dispatcher.ml b/src/smtml/solver_dispatcher.ml similarity index 100% rename from src/solver_dispatcher.ml rename to src/smtml/solver_dispatcher.ml diff --git a/src/solver_dispatcher.mli b/src/smtml/solver_dispatcher.mli similarity index 100% rename from src/solver_dispatcher.mli rename to src/smtml/solver_dispatcher.mli diff --git a/src/solver_intf.ml b/src/smtml/solver_intf.ml similarity index 100% rename from src/solver_intf.ml rename to src/smtml/solver_intf.ml diff --git a/src/solver_mode.ml b/src/smtml/solver_mode.ml similarity index 100% rename from src/solver_mode.ml rename to src/smtml/solver_mode.ml diff --git a/src/solver_mode.mli b/src/smtml/solver_mode.mli similarity index 100% rename from src/solver_mode.mli rename to src/smtml/solver_mode.mli diff --git a/src/solver_type.ml b/src/smtml/solver_type.ml similarity index 100% rename from src/solver_type.ml rename to src/smtml/solver_type.ml diff --git a/src/solver_type.mli b/src/smtml/solver_type.mli similarity index 100% rename from src/solver_type.mli rename to src/smtml/solver_type.mli diff --git a/src/statistics.ml b/src/smtml/statistics.ml similarity index 100% rename from src/statistics.ml rename to src/smtml/statistics.ml diff --git a/src/statistics.mli b/src/smtml/statistics.mli similarity index 100% rename from src/statistics.mli rename to src/smtml/statistics.mli diff --git a/src/symbol.ml b/src/smtml/symbol.ml similarity index 100% rename from src/symbol.ml rename to src/smtml/symbol.ml diff --git a/src/symbol.mli b/src/smtml/symbol.mli similarity index 100% rename from src/symbol.mli rename to src/smtml/symbol.mli diff --git a/src/ty.ml b/src/smtml/ty.ml similarity index 100% rename from src/ty.ml rename to src/smtml/ty.ml diff --git a/src/ty.mli b/src/smtml/ty.mli similarity index 100% rename from src/ty.mli rename to src/smtml/ty.mli diff --git a/src/utils.ml b/src/smtml/utils.ml similarity index 100% rename from src/utils.ml rename to src/smtml/utils.ml diff --git a/src/value.ml b/src/smtml/value.ml similarity index 83% rename from src/value.ml rename to src/smtml/value.ml index 2464981c..ab934f2c 100644 --- a/src/value.ml +++ b/src/smtml/value.ml @@ -12,6 +12,7 @@ type t = | Real of float | Str of string | Num of Num.t + | Bitv of Bitvector.t | List of t list | App : [> `Op of string ] * t list -> t | Nothing @@ -24,6 +25,7 @@ let type_of (v : t) : Ty.t = | Real _ -> Ty_real | Str _ -> Ty_str | Num n -> Num.type_of n + | Bitv bv -> Ty_bitv (Bitvector.numbits bv) | List _ -> Ty_list | App _ -> Ty_app | Nothing -> Ty_none @@ -36,9 +38,10 @@ let discr = function | Real _ -> 4 | Str _ -> 5 | Num _ -> 6 - | List _ -> 7 - | App _ -> 8 - | Nothing -> 9 + | Bitv _ -> 7 + | List _ -> 8 + | App _ -> 9 + | Nothing -> 10 let rec compare (a : t) (b : t) : int = match (a, b) with @@ -49,12 +52,13 @@ let rec compare (a : t) (b : t) : int = | Real a, Real b -> Float.compare a b | Str a, Str b -> String.compare a b | Num a, Num b -> Num.compare a b + | Bitv a, Bitv b -> Bitvector.compare a b | List a, List b -> List.compare compare a b | App (`Op op1, vs1), App (`Op op2, vs2) -> let c = String.compare op1 op2 in if c = 0 then List.compare compare vs1 vs2 else c - | ( ( True | False | Unit | Int _ | Real _ | Str _ | Num _ | List _ | App _ - | Nothing ) + | ( ( True | False | Unit | Int _ | Real _ | Str _ | Num _ | Bitv _ | List _ + | App _ | Nothing ) , _ ) -> (* TODO: I don't know if this is always semantically correct *) Int.compare (discr a) (discr b) @@ -62,15 +66,16 @@ let rec compare (a : t) (b : t) : int = let rec equal (v1 : t) (v2 : t) : bool = match (v1, v2) with | True, True | False, False | Unit, Unit | Nothing, Nothing -> true - | Int x1, Int x2 -> Int.equal x1 x2 - | Real x1, Real x2 -> Float.equal x1 x2 - | Str x1, Str x2 -> String.equal x1 x2 - | Num x1, Num x2 -> Num.equal x1 x2 + | Int a, Int b -> Int.equal a b + | Real a, Real b -> Float.equal a b + | Str a, Str b -> String.equal a b + | Num a, Num b -> Num.equal a b + | Bitv a, Bitv b -> Bitvector.equal a b | List l1, List l2 -> List.equal equal l1 l2 | App (`Op op1, vs1), App (`Op op2, vs2) -> String.equal op1 op2 && List.equal equal vs1 vs2 - | ( ( True | False | Unit | Int _ | Real _ | Str _ | Num _ | List _ | App _ - | Nothing ) + | ( ( True | False | Unit | Int _ | Real _ | Str _ | Num _ | Bitv _ | List _ + | App _ | Nothing ) , _ ) -> false @@ -85,6 +90,7 @@ let rec pp fmt = function | Int x -> Fmt.int fmt x | Real x -> Fmt.pf fmt "%F" x | Num x -> Num.pp_no_type fmt x + | Bitv x -> Bitvector.pp fmt x | Str x -> Fmt.pf fmt "%S" x | List l -> (Fmt.hovbox ~indent:1 (Fmt.list ~sep:Fmt.comma pp)) fmt l | App (`Op op, vs) -> @@ -126,6 +132,7 @@ let rec to_json (v : t) : Yojson.Basic.t = | Real real -> `Float real | Str str -> `String str | Num n -> Num.to_json n + | Bitv bv -> `String (Fmt.str "%a" Bitvector.pp bv) | List l -> `List (List.map to_json l) | Nothing -> `Null | App _ -> assert false diff --git a/src/value.mli b/src/smtml/value.mli similarity index 96% rename from src/value.mli rename to src/smtml/value.mli index 604a33c3..f43f1922 100644 --- a/src/value.mli +++ b/src/smtml/value.mli @@ -10,6 +10,7 @@ type t = | Real of float | Str of string | Num of Num.t + | Bitv of Bitvector.t | List of t list | App : [> `Op of string ] * t list -> t | Nothing diff --git a/src/z3_mappings.default.ml b/src/smtml/z3_mappings.default.ml similarity index 100% rename from src/z3_mappings.default.ml rename to src/smtml/z3_mappings.default.ml diff --git a/src/z3_mappings.mli b/src/smtml/z3_mappings.mli similarity index 100% rename from src/z3_mappings.mli rename to src/smtml/z3_mappings.mli diff --git a/src/smtml_prelude/dune b/src/smtml_prelude/dune new file mode 100644 index 00000000..00464e21 --- /dev/null +++ b/src/smtml_prelude/dune @@ -0,0 +1,5 @@ +(library + (name smtml_prelude) + (public_name smtml.prelude) + (modules smtml_prelude) + (libraries prelude)) diff --git a/src/smtml_prelude.ml b/src/smtml_prelude/smtml_prelude.ml similarity index 100% rename from src/smtml_prelude.ml rename to src/smtml_prelude/smtml_prelude.ml diff --git a/test/bitvector/dune b/test/bitvector/dune new file mode 100644 index 00000000..1013affa --- /dev/null +++ b/test/bitvector/dune @@ -0,0 +1,3 @@ +(test + (name test_bitvector) + (libraries bitvector)) diff --git a/test/bitvector/test_bitvector.ml b/test/bitvector/test_bitvector.ml new file mode 100644 index 00000000..02acad19 --- /dev/null +++ b/test/bitvector/test_bitvector.ml @@ -0,0 +1,85 @@ +open Bitvector + +let z n = Z.of_int n (* Helper to create Z.t values *) + +let test_make () = + let bv = make (z 5) 8 in + assert (view bv = z 5); + assert (numbits bv = 8) + +let test_neg () = + let bv = make (z 5) 8 in + assert (equal (neg bv) (make (z (-5)) 8)) + +let test_add () = + let bv1 = make (z 3) 8 in + let bv2 = make (z 5) 8 in + assert (view (add bv1 bv2) = z 8) + +let test_sub () = + let bv1 = make (z 10) 8 in + let bv2 = make (z 3) 8 in + assert (view (sub bv1 bv2) = z 7) + +let test_mul () = + let bv1 = make (z 4) 8 in + let bv2 = make (z 3) 8 in + assert (view (mul bv1 bv2) = z 12) + +let test_div () = + let bv1 = make (z 10) 8 in + let bv2 = make (z 2) 8 in + assert (view (div bv1 bv2) = z 5) + +let test_div_u () = + let bv1 = make (z 10) 8 in + let bv2 = make (z 3) 8 in + assert (view (div_u bv1 bv2) = z (10 / 3)) + +let test_logical_ops () = + let bv1 = make (z 0b1100) 4 in + let bv2 = make (z 0b1010) 4 in + assert (view (logand bv1 bv2) = z 0b1000); + assert (view (logor bv1 bv2) = z 0b1110); + assert (view (logxor bv1 bv2) = z 0b0110) + +let test_shifts () = + let bv = make (z 0b0011) 4 in + assert (view (shl bv (make (z 1) 4)) = z 0b0110); + assert (view (lshr bv (make (z 1) 4)) = z 0b0001); + assert (view (ashr bv (make (z 1) 4)) = z 0b0001) + +let test_comparisons () = + let bv1 = make (z 3) 4 in + let bv2 = make (z 5) 4 in + assert (lt bv1 bv2); + assert (le bv1 bv2); + assert (gt bv2 bv1); + assert (ge bv2 bv1); + assert (lt_u bv1 bv2); + assert (gt_u bv2 bv1) + +let test_rotate () = + let bv = make (z 0b1101) 4 in + let one = make (z 1) 4 in + assert (view (rotate_left bv one) = z 0b1011); + assert (view (rotate_right bv one) = z 0b1110) + +let test_extensions () = + let bv = make (z 0b1010) 4 in + assert (numbits (zero_extend 4 bv) = 8); + assert (numbits (sign_extend 4 bv) = 8) + +let () = + test_make (); + test_neg (); + test_add (); + test_sub (); + test_mul (); + test_div (); + test_div_u (); + test_logical_ops (); + test_shifts (); + test_comparisons (); + test_rotate (); + test_extensions () diff --git a/test/dune b/test/dune new file mode 100644 index 00000000..bfbb6fe5 --- /dev/null +++ b/test/dune @@ -0,0 +1,4 @@ +(library + (name smtml_test) + (modules test_harness) + (libraries smtml)) diff --git a/test/regression/dune b/test/regression/dune index a3d1e4bf..640b9765 100644 --- a/test/regression/dune +++ b/test/regression/dune @@ -6,7 +6,3 @@ (applies_to test_issue_183) (enabled_if (not %{lib-available:colibri2.core}))) - -(tests - (names test_pr_77) - (libraries smtml)) diff --git a/test/regression/test_pr_77.ml b/test/regression/test_pr_77.ml deleted file mode 100644 index 67b51fef..00000000 --- a/test/regression/test_pr_77.ml +++ /dev/null @@ -1,28 +0,0 @@ -open Smtml - -let () = - let open Num in - let nan0 = F32 (Int32.bits_of_float Float.nan) in - let nan1 = F32 (Int32.bits_of_float Float.nan) in - (* Library functions ensure total order of floats. *) - assert (Num.equal nan0 nan1) - -let () = - let open Expr.Fpa in - let nan0 = F32.v Float.nan in - let nan1 = F32.v Float.nan in - (* Library functions ensure total order of floats. *) - assert (Expr.equal nan0 nan1); - let assert_ = Expr.relop (Ty_fp 32) Eq nan0 nan1 in - (* Evaluation functions do not. *) - assert (Expr.equal assert_ (Expr.value False)) - -let () = - let open Expr in - let nan0 = value (Real Float.nan) in - let nan1 = value (Real Float.nan) in - (* Library functions ensure total order of floats. *) - assert (Expr.equal nan0 nan1); - let assert_ = Expr.relop Ty_real Eq nan0 nan1 in - (* Evaluation functions do not. *) - assert (Expr.equal assert_ (Expr.value False)) diff --git a/test/solver/dune b/test/solver/dune index daa3e810..677eb998 100644 --- a/test/solver/dune +++ b/test/solver/dune @@ -1,43 +1,37 @@ (library - (name smtml_tests) + (name smtml_test_solver) (modules - test_bv - test_fp - test_harness - test_solver_params test_solver - test_lia - test_lra test_optimizer) - (libraries smtml)) + (libraries smtml smtml_test)) (test - (name test_z3) - (modules test_z3) - (libraries smtml smtml_tests) + (name test_solver_z3) + (modules test_solver_z3) + (libraries smtml smtml_test_solver) (build_if %{lib-available:z3})) (test - (name test_colibri2) - (modules test_colibri2) - (libraries smtml_tests) + (name test_solver_colibri2) + (modules test_solver_colibri2) + (libraries smtml_test smtml_test_solver) (build_if %{lib-available:colibri2.core})) (test - (name test_bitwuzla) - (modules test_bitwuzla) - (libraries smtml_tests) + (name test_solver_bitwuzla) + (modules test_solver_bitwuzla) + (libraries smtml_test smtml_test_solver) (build_if %{lib-available:bitwuzla-cxx})) (test - (name test_cvc5) - (modules test_cvc5) - (libraries smtml_tests) + (name test_solver_cvc5) + (modules test_solver_cvc5) + (libraries smtml_test smtml_test_solver) (build_if %{lib-available:cvc5})) (test - (name test_altergo) - (modules test_altergo) - (libraries smtml_tests) + (name test_solver_altergo) + (modules test_solver_altergo) + (libraries smtml_test smtml_test_solver) (build_if (and %{lib-available:alt-ergo-lib} %{lib-available:dolmen_model}))) diff --git a/test/solver/test_altergo.ml b/test/solver/test_altergo.ml deleted file mode 100644 index a54dfd0a..00000000 --- a/test/solver/test_altergo.ml +++ /dev/null @@ -1,16 +0,0 @@ -open Smtml -open Smtml_tests - -let () = - Printexc.record_backtrace true; - assert Altergo_mappings.is_available; - let module Test_solver_params = - Test_solver_params.Make (Altergo_mappings.Fresh.Make ()) in - let module Test_solver = Test_solver.Make (Altergo_mappings.Fresh.Make ()) in - (* let module Test_optimizer = - Test_optimizer.Make (Altergo_mappings.Fresh.Make ()) in *) - let module Test_bv = Test_bv.Make (Altergo_mappings.Fresh.Make ()) in - (* let module Test_fp = Test_fp.Make (Altergo_mappings.Fresh.Make ()) in *) - let module Test_lia = Test_lia.Make (Altergo_mappings.Fresh.Make ()) in - (* let module Test_lra = Test_lra.Make (Altergo_mappings.Fresh.Make ()) in *) - () diff --git a/test/solver/test_bitwuzla.ml b/test/solver/test_bitwuzla.ml deleted file mode 100644 index 7b01fecb..00000000 --- a/test/solver/test_bitwuzla.ml +++ /dev/null @@ -1,10 +0,0 @@ -open Smtml -open Smtml_tests - -let () = - assert Bitwuzla_mappings.is_available; - let module Test_solver_params = - Test_solver_params.Make (Bitwuzla_mappings.Fresh.Make ()) in - let module Test_bv = Test_bv.Make (Bitwuzla_mappings) in - let module Test_fp = Test_fp.Make (Bitwuzla_mappings) in - () diff --git a/test/solver/test_bv.ml b/test/solver/test_bv.ml deleted file mode 100644 index ed098888..00000000 --- a/test/solver/test_bv.ml +++ /dev/null @@ -1,32 +0,0 @@ -open Smtml -open Test_harness - -module Make (M : Mappings_intf.S) = struct - open Test_harness.Infix - module I8 = Expr.Bitv.I8 - module I32 = Expr.Bitv.I32 - module Solver = Solver.Incremental (M) - - let params = Params.default () - - let () = - let solver = Solver.create ~params ~logic:QF_BVFP () in - let x = Expr.symbol @@ Symbol.make (Ty_bitv 8) "h" in - Solver.add solver I8.[ x > v 0; x < v 2 ]; - assert_sat (Solver.check solver []); - let val_x = Solver.get_value solver x in - assert (Expr.equal val_x (I8.v 1)) - - let () = - let solver = Solver.create ~params ~logic:QF_BVFP () in - let x = Expr.symbol @@ Symbol.make (Ty_bitv 32) "x" in - let y = Expr.symbol @@ Symbol.make (Ty_bitv 32) "y" in - let z = Expr.symbol @@ Symbol.make (Ty_bitv 32) "z" in - let w = Expr.symbol @@ Symbol.make (Ty_bitv 32) "w" in - Solver.add solver I32.[ x > v 0l && w < v 5l ]; - Solver.add solver I32.[ x < y && y < z && z < w ]; - assert_sat (Solver.check solver []); - match Solver.model solver with - | None -> assert false - | Some m -> Model.pp Format.std_formatter ~no_values:false m -end diff --git a/test/solver/test_colibri2.ml b/test/solver/test_colibri2.ml deleted file mode 100644 index e55a27c9..00000000 --- a/test/solver/test_colibri2.ml +++ /dev/null @@ -1,14 +0,0 @@ -open Smtml -open Smtml_tests - -let () = - assert Colibri2_mappings.is_available; - let module Test_solver_params = Test_solver_params.Make (Colibri2_mappings) in - let module Test_solver = Test_solver.Make (Colibri2_mappings) in - (* let module Test_optimizer = - Test_optimizer.Make (Altergo_mappings.Fresh.Make ()) in *) - let module Test_bv = Test_bv.Make (Colibri2_mappings) in - let module Test_fp = Test_fp.Make (Colibri2_mappings) in - let module Test_lia = Test_lia.Make (Colibri2_mappings) in - (* let module Test_lra = Test_lra.Make (Altergo_mappings.Fresh.Make ()) in *) - () diff --git a/test/solver/test_cvc5.ml b/test/solver/test_cvc5.ml deleted file mode 100644 index c7284fb4..00000000 --- a/test/solver/test_cvc5.ml +++ /dev/null @@ -1,10 +0,0 @@ -open Smtml -open Smtml_tests - -let () = - assert Cvc5_mappings.is_available; - let module Test_solver_params = - Test_solver_params.Make (Cvc5_mappings.Fresh.Make ()) in - let module Test_bv = Test_bv.Make (Cvc5_mappings) in - (* let module Test_fp = Test_fp.Make (Cvc5_mappings) in *) - () diff --git a/test/solver/test_fp.ml b/test/solver/test_fp.ml deleted file mode 100644 index ab9ff72c..00000000 --- a/test/solver/test_fp.ml +++ /dev/null @@ -1,51 +0,0 @@ -open Smtml -open Test_harness - -module Make (M : Mappings_intf.S) = struct - module Solver = Solver.Incremental (M) - module F32 = Expr.Fpa.F32 - module F64 = Expr.Fpa.F64 - - (* Regression for get value *) - let () = - let solver = Solver.create ~logic:QF_BVFP () in - let x = F32.sym "x" in - let const = F32.v 50.0 in - Solver.add solver F32.[ x = const ]; - assert_sat (Solver.check solver []); - assert (Expr.equal (Solver.get_value solver x) const) - - let () = - let solver = Solver.create ~logic:QF_BVFP () in - let x = F64.sym "x" in - let const = F64.v 50.0 in - Solver.add solver F64.[ x = const ]; - assert_sat (Solver.check solver []); - assert (Expr.equal (Solver.get_value solver x) const) - - (* Sqrt *) - let () = - let solver = Solver.create ~logic:QF_BVFP () in - let x = F32.sym "x" in - Solver.add solver F32.[ x = F32.v 4.0 ]; - Solver.add solver F32.[ Expr.unop (Ty_fp 32) Sqrt x = F32.v 2.0 ]; - assert_sat (Solver.check solver []); - assert (Expr.equal (Solver.get_value solver x) (F32.v 4.0)) - - (* Copysign *) - let () = - let solver = Solver.create ~logic:QF_BVFP () in - let x = F32.sym "x" in - let y = F32.sym "y" in - Solver.add solver F32.[ x > v 0.0; y < v 0.0 ]; - Solver.add solver F32.[ Expr.binop (Ty_fp 32) Copysign x y < v 0.0 ]; - assert_sat (Solver.check solver []) - - let () = - let solver = Solver.create ~logic:QF_BVFP () in - let x = F64.sym "x" in - let y = F64.sym "y" in - Solver.add solver F64.[ x > v 0.0; y < v 0.0 ]; - Solver.add solver F64.[ Expr.binop (Ty_fp 64) Copysign x y < v 0.0 ]; - assert_sat (Solver.check solver []) -end diff --git a/test/solver/test_harness.ml b/test/solver/test_harness.ml deleted file mode 100644 index cab1487f..00000000 --- a/test/solver/test_harness.ml +++ /dev/null @@ -1,53 +0,0 @@ -open Smtml -open Expr - -let assert_sat result = - assert ( - match result with - | `Sat -> true - | `Unsat -> false - | `Unknown -> failwith "Solver returned unknown" ) - -module Infix = struct - let int i = value (Int i) - - let symbol name ty = symbol (Symbol.make ty name) - - let ( = ) i1 i2 = relop Ty_bool Eq i1 i2 - - let ( <> ) i1 i2 = relop Ty_bool Ne i1 i2 - - let ( && ) b1 b2 = binop Ty_bool And b1 b2 - - let ( || ) b1 b2 = binop Ty_bool Or b1 b2 - - let ( => ) b1 b2 = - let left = unop Ty_bool Not b1 in - binop Ty_bool Or left b2 - - module Int = struct - let ( ~- ) i = unop Ty_int Neg i - - let ( + ) i1 i2 = binop Ty_int Add i1 i2 - - let ( - ) i1 i2 = binop Ty_int Sub i1 i2 - - let ( * ) i1 i2 = binop Ty_int Mul i1 i2 - - let ( / ) i1 i2 = binop Ty_int Div i1 i2 - - let ( % ) i1 i2 = binop Ty_int Rem i1 i2 - - let ( ** ) i1 i2 = binop Ty_int Pow i1 i2 - - let ( < ) i1 i2 = relop Ty_int Lt i1 i2 - - let ( > ) i1 i2 = relop Ty_int Gt i1 i2 - - let ( <= ) i1 i2 = relop Ty_int Le i1 i2 - - let ( >= ) i1 i2 = relop Ty_int Ge i1 i2 - - let to_real i = cvtop Ty_real Reinterpret_int i - end -end diff --git a/test/solver/test_lia.ml b/test/solver/test_lia.ml deleted file mode 100644 index 5c035879..00000000 --- a/test/solver/test_lia.ml +++ /dev/null @@ -1,14 +0,0 @@ -open Smtml -open Test_harness -open Infix -open Infix.Int - -module Make (M : Mappings_intf.S) = struct - module Solver = Solver.Incremental (M) - - let () = - let solver = Solver.create ~logic:QF_LIA () in - let a = symbol "a" Ty_int in - Solver.add solver [ a + int 1 = int 2 => ((a * int 2) + int 2 = int 4) ]; - assert_sat (Solver.check solver []) -end diff --git a/test/solver/test_lra.ml b/test/solver/test_lra.ml deleted file mode 100644 index 4ad123f0..00000000 --- a/test/solver/test_lra.ml +++ /dev/null @@ -1,18 +0,0 @@ -open Smtml - -module Make (M : Mappings_intf.S) = struct - module Solver = Solver.Batch (M) - - let () = - let solver = Solver.create () in - assert ( - let x = Expr.symbol Symbol.("x" @: Ty_real) in - let y = Expr.symbol Symbol.("y" @: Ty_real) in - let c0 = Expr.relop Ty_bool Eq x y in - let c1 = - Expr.relop Ty_bool Eq - (Expr.cvtop Ty_real ToString x) - (Expr.cvtop Ty_real ToString y) - in - `Sat = Solver.check solver [ c0; c1 ] ) -end diff --git a/test/solver/test_optimizer.ml b/test/solver/test_optimizer.ml index 31fa63cf..1c08b856 100644 --- a/test/solver/test_optimizer.ml +++ b/test/solver/test_optimizer.ml @@ -1,10 +1,11 @@ open Smtml +(* TODO: Move this some place else? *) module Make (M : Mappings_intf.S) = struct - open Test_harness + open Smtml_test.Test_harness module Optimizer = Optimizer.Make (M) - let () = + let test () = let open Infix in let opt = Optimizer.create () in let x = symbol "x" Ty_int in diff --git a/test/solver/test_solver.ml b/test/solver/test_solver.ml index c134a431..f4ea0c0b 100644 --- a/test/solver/test_solver.ml +++ b/test/solver/test_solver.ml @@ -1,47 +1,62 @@ open Smtml module Make (M : Mappings_intf.S) = struct - open Test_harness + open Smtml_test.Test_harness module Cached = Solver.Cached (M) module Solver = Solver.Incremental (M) - let () = - let open Infix in + let test_default_params () = + assert (Params.default_value Timeout = Int32.(to_int max_int)); + assert (Params.default_value Model = true); + assert (Params.default_value Unsat_core = false); + assert (Params.default_value Ematching = true) + + let test_solver_params () = + let params = + Params.( + default () $ (Timeout, 900) $ (Model, false) $ (Unsat_core, true) + $ (Ematching, false) $ (Parallel, true) $ (Num_threads, 1) ) + in + assert (Params.get params Unsat_core); + let _ : Solver.t = Solver.create ~params () in + () + + let test_params () = + test_default_params (); + test_solver_params () + + let test_cached_solver () = let solver = Cached.create ~logic:LIA () in - let x = symbol "x" Ty_int in - let c = Int.(x >= int 0) in - assert (Stdlib.Int.equal !Cached.solver_count 0); + let x = Infix.symbol "x" Ty_int in + let c = Infix.(Int.(x >= int 0)) in + assert (!Cached.solver_count = 0); assert_sat (Cached.check_set solver @@ Expr.Set.singleton c); assert_sat (Cached.check_set solver @@ Expr.Set.singleton c); assert_sat (Cached.check_set solver @@ Expr.Set.singleton c); - assert (Stdlib.Int.equal !Cached.solver_count 1) + assert (!Cached.solver_count = 1) - let () = + let test () = let open Infix in let solver = Solver.create ~logic:LIA () in let symbol_x = Symbol.("x" @: Ty_int) in let x = Expr.symbol symbol_x in - assert_sat (Solver.check solver []); + assert_sat ~f:"test" (Solver.check solver []); Solver.push solver; Solver.add solver Int.[ x >= int 0 ]; assert_sat (Solver.check solver []); - assert ( - let v = Solver.get_value solver x in - Expr.equal v (int 0) ); + assert_equal (Solver.get_value solver x) (int 0); Solver.pop solver 1; Solver.push solver; Solver.add solver [ x = int 3 ]; - assert_sat (Solver.check solver []); - assert ( - let v = Solver.get_value solver Int.(x * x) in - Expr.equal v (int 9) ); + assert_sat ~f:"test" (Solver.check solver []); + assert_equal (Solver.get_value solver Int.(x * x)) (int 9); Solver.pop solver 1; Solver.push solver; Solver.add solver Int.[ x >= int 0 || x < int 0 ]; - assert_sat (Solver.check solver []); + assert_sat ~f:"test" (Solver.check solver []); (* necessary, otherwise the solver doesn't know x and can't produce a model for it *) let model = Solver.model ~symbols:[ symbol_x ] solver in @@ -53,5 +68,117 @@ module Make (M : Mappings_intf.S) = struct assert_sat (Solver.check solver []); let model = Solver.model solver in let val_x = Option.bind model (fun m -> Model.evaluate m symbol_x) in - assert (Stdlib.(Some (Value.Int 5) = val_x)) + assert (match val_x with Some v -> Value.equal v (Int 5) | None -> false) + + let test_lia () = + let open Infix in + let solver = Solver.create ~logic:QF_LIA () in + let a = symbol "a" Ty_int in + Solver.add solver Int.[ a + int 1 = int 2 => ((a * int 2) + int 2 = int 4) ]; + assert_sat ~f:"test_lia" (Solver.check solver []) + + let test_lra () = + let solver = Solver.create () in + assert_sat ~f:"test_lra" + (let x = Expr.symbol Symbol.("x" @: Ty_real) in + let y = Expr.symbol Symbol.("y" @: Ty_real) in + let c0 = Expr.relop Ty_bool Eq x y in + let c1 = + Expr.relop Ty_bool Eq + (Expr.cvtop Ty_real ToString x) + (Expr.cvtop Ty_real ToString y) + in + Solver.check solver [ c0; c1 ] ) + + let test_bv_8 () = + let open Infix in + let solver = Solver.create ~params:(Params.default ()) ~logic:QF_BVFP () in + let ty = Ty.Ty_bitv 8 in + let x = symbol "h" ty in + Solver.add solver + [ Expr.relop ty Gt x (int8 0); Expr.relop ty Lt x (int8 2) ]; + assert_sat ~f:"test_bv_8" (Solver.check solver []); + assert_equal (Solver.get_value solver x) (int8 1) + + let test_bv_32 () = + let open Infix in + let solver = Solver.create ~params:(Params.default ()) ~logic:QF_BVFP () in + let ty = Ty.Ty_bitv 32 in + let x = symbol "x" ty in + let y = symbol "y" ty in + let z = symbol "z" ty in + let w = symbol "w" ty in + Solver.add solver + [ Expr.relop ty Gt x (int32 0l) && Expr.relop ty Lt w (int32 5l) + ; Expr.relop ty Lt x y && Expr.relop ty Lt y z && Expr.relop ty Lt z w + ]; + assert_sat ~f:"test_bv_32" (Solver.check solver []); + match Solver.model solver with + | None -> assert false + | Some m -> Model.pp Format.std_formatter ~no_values:false m + + let test_bv () = + test_bv_8 (); + test_bv_32 () + + let test_fp_get_value32 () = + let open Infix in + let solver = Solver.create ~logic:QF_BVFP () in + let ty = Ty.Ty_fp 32 in + let x = symbol "x" ty in + let const = float32 50.0 in + Solver.add solver [ Expr.relop ty Eq x const ]; + assert_sat ~f:"test_fp_get_value32" (Solver.check solver []); + assert_equal (Solver.get_value solver x) const + + let test_fp_get_value64 () = + let open Infix in + let solver = Solver.create ~logic:QF_BVFP () in + let ty = Ty.Ty_fp 64 in + let x = symbol "x" ty in + let const = float64 50.0 in + Solver.add solver [ Expr.relop ty Eq x const ]; + assert_sat ~f:"test_fp_get_value64" (Solver.check solver []); + assert_equal (Solver.get_value solver x) const + + let test_fp_sqrt () = + let open Infix in + let solver = Solver.create ~logic:QF_BVFP () in + let ty = Ty.Ty_fp 32 in + let x = symbol "x" ty in + Solver.add solver [ Expr.relop ty Eq x (float32 4.0) ]; + Solver.add solver [ Expr.relop ty Eq (Expr.unop ty Sqrt x) (float32 2.0) ]; + assert_sat ~f:"test_fp_sqrt" (Solver.check solver []); + assert_equal (Solver.get_value solver x) (float32 4.0) + + let test_fp_copysign32 () = + let open Infix in + let solver = Solver.create ~logic:QF_BVFP () in + let ty = Ty.Ty_fp 32 in + let x = symbol "x" ty in + let y = symbol "y" ty in + Solver.add solver + [ Expr.relop ty Gt x (float32 0.0) && Expr.relop ty Lt y (float32 0.0) + ; Expr.relop ty Lt (Expr.binop ty Copysign x y) (float32 0.0) + ]; + assert_sat ~f:"test_copysign32" (Solver.check solver []) + + let test_fp_copysign64 () = + let open Infix in + let solver = Solver.create ~logic:QF_BVFP () in + let ty = Ty.Ty_fp 64 in + let x = symbol "x" ty in + let y = symbol "y" ty in + Solver.add solver + [ Expr.relop ty Gt x (float64 0.0) && Expr.relop ty Lt y (float64 0.0) + ; Expr.relop ty Lt (Expr.binop ty Copysign x y) (float64 0.0) + ]; + assert_sat ~f:"test_copysign64" (Solver.check solver []) + + let test_fp () = + test_fp_get_value32 (); + test_fp_get_value64 (); + test_fp_sqrt (); + test_fp_copysign32 (); + test_fp_copysign64 () end diff --git a/test/solver/test_altergo.expected b/test/solver/test_solver_altergo.expected similarity index 100% rename from test/solver/test_altergo.expected rename to test/solver/test_solver_altergo.expected diff --git a/test/solver/test_solver_altergo.ml b/test/solver/test_solver_altergo.ml new file mode 100644 index 00000000..4d5909a1 --- /dev/null +++ b/test/solver/test_solver_altergo.ml @@ -0,0 +1,12 @@ +open Smtml +open Smtml_test_solver + +let () = + Printexc.record_backtrace true; + assert Altergo_mappings.is_available; + let module Alt_ergo = Test_solver.Make (Altergo_mappings.Fresh.Make ()) in + Alt_ergo.test_params (); + Alt_ergo.test_cached_solver (); + Alt_ergo.test (); + Alt_ergo.test_bv (); + Alt_ergo.test_lia () diff --git a/test/solver/test_bitwuzla.expected b/test/solver/test_solver_bitwuzla.expected similarity index 100% rename from test/solver/test_bitwuzla.expected rename to test/solver/test_solver_bitwuzla.expected diff --git a/test/solver/test_solver_bitwuzla.ml b/test/solver/test_solver_bitwuzla.ml new file mode 100644 index 00000000..04f1ae06 --- /dev/null +++ b/test/solver/test_solver_bitwuzla.ml @@ -0,0 +1,9 @@ +open Smtml +open Smtml_test_solver + +let () = + assert Bitwuzla_mappings.is_available; + let module Bitwuzla = Test_solver.Make (Bitwuzla_mappings.Fresh.Make ()) in + Bitwuzla.test_params (); + Bitwuzla.test_bv (); + Bitwuzla.test_fp () diff --git a/test/solver/test_colibri2.expected b/test/solver/test_solver_colibri2.expected similarity index 100% rename from test/solver/test_colibri2.expected rename to test/solver/test_solver_colibri2.expected diff --git a/test/solver/test_solver_colibri2.ml b/test/solver/test_solver_colibri2.ml new file mode 100644 index 00000000..bf56c119 --- /dev/null +++ b/test/solver/test_solver_colibri2.ml @@ -0,0 +1,12 @@ +open Smtml +open Smtml_test_solver + +let () = + assert Colibri2_mappings.is_available; + let module C2 = Test_solver.Make (Colibri2_mappings) in + C2.test_params (); + C2.test_cached_solver (); + C2.test (); + C2.test_bv (); + C2.test_fp (); + C2.test_lia () diff --git a/test/solver/test_cvc5.expected b/test/solver/test_solver_cvc5.expected similarity index 100% rename from test/solver/test_cvc5.expected rename to test/solver/test_solver_cvc5.expected diff --git a/test/solver/test_solver_cvc5.ml b/test/solver/test_solver_cvc5.ml new file mode 100644 index 00000000..dfe5a803 --- /dev/null +++ b/test/solver/test_solver_cvc5.ml @@ -0,0 +1,10 @@ +open Smtml +open Smtml_test_solver + +let () = + assert Cvc5_mappings.is_available; + let module Cvc5 = Test_solver.Make (Cvc5_mappings.Fresh.Make ()) in + Cvc5.test_params (); + Cvc5.test_cached_solver (); + Cvc5.test (); + Cvc5.test_bv () diff --git a/test/solver/test_solver_params.ml b/test/solver/test_solver_params.ml deleted file mode 100644 index 668de040..00000000 --- a/test/solver/test_solver_params.ml +++ /dev/null @@ -1,21 +0,0 @@ -open Smtml - -module Make (M : Mappings_intf.S) = struct - open Params - module Solver = Solver.Incremental (M) - - let () = - assert (default_value Timeout = Int32.(to_int max_int)); - assert (default_value Model = true); - assert (default_value Unsat_core = false); - assert (default_value Ematching = true) - - let () = - let params = - default () $ (Timeout, 900) $ (Model, false) $ (Unsat_core, true) - $ (Ematching, false) $ (Parallel, true) $ (Num_threads, 1) - in - assert (Params.get params Unsat_core); - let _ : Solver.t = Solver.create ~params () in - () -end diff --git a/test/solver/test_z3.expected b/test/solver/test_solver_z3.expected similarity index 100% rename from test/solver/test_z3.expected rename to test/solver/test_solver_z3.expected diff --git a/test/solver/test_solver_z3.ml b/test/solver/test_solver_z3.ml new file mode 100644 index 00000000..f77f009e --- /dev/null +++ b/test/solver/test_solver_z3.ml @@ -0,0 +1,16 @@ +open Smtml +open Smtml_test_solver + +let () = + assert Z3_mappings.is_available; + let module Z3_mappings = Z3_mappings.Fresh.Make () in + let module Z3_opt = Test_optimizer.Make (Z3_mappings) in + Z3_opt.test (); + let module Z3 = Test_solver.Make (Z3_mappings) in + Z3.test_params (); + Z3.test_cached_solver (); + Z3.test (); + Z3.test_lia (); + Z3.test_lra (); + Z3.test_bv (); + Z3.test_fp () diff --git a/test/solver/test_z3.ml b/test/solver/test_z3.ml deleted file mode 100644 index 8b03ba26..00000000 --- a/test/solver/test_z3.ml +++ /dev/null @@ -1,14 +0,0 @@ -open Smtml -open Smtml_tests - -let () = - assert Z3_mappings.is_available; - let module Test_solver_params = - Test_solver_params.Make (Z3_mappings.Fresh.Make ()) in - let module Test_solver = Test_solver.Make (Z3_mappings.Fresh.Make ()) in - let module Test_optimizer = Test_optimizer.Make (Z3_mappings.Fresh.Make ()) in - let module Test_bv = Test_bv.Make (Z3_mappings.Fresh.Make ()) in - let module Test_fp = Test_fp.Make (Z3_mappings.Fresh.Make ()) in - let module Test_lia = Test_lia.Make (Z3_mappings.Fresh.Make ()) in - let module Test_lra = Test_lra.Make (Z3_mappings.Fresh.Make ()) in - () diff --git a/test/test_harness.ml b/test/test_harness.ml new file mode 100644 index 00000000..9284cedf --- /dev/null +++ b/test/test_harness.ml @@ -0,0 +1,83 @@ +open Smtml +open Expr + +let pp_sat fmt = function + | `Sat -> Fmt.string fmt "sat" + | `Unsat -> Fmt.string fmt "unsat" + | `Unknown -> Fmt.string fmt "unknown" + +let assert_sat ?f result = + if match result with `Sat -> true | `Unsat | `Unknown -> false then () + else + match f with + | None -> Fmt.failwith "expected 'sat' but got '%a'" pp_sat result + | Some func -> + Fmt.failwith "%s: expected 'sat' but got '%a'" func pp_sat result + +let assert_equal a b = assert (Expr.equal a b) + +module Infix = struct + let true_ () = value True + + let false_ () = value False + + let int x = value (Int x) + + let real x = value (Real x) + + let string x = value (Str x) + + let int8 x = value (Bitv (Bitvector.make (Z.of_int x) 8)) + + let int32 x = value (Bitv (Bitvector.make (Z.of_int32 x) 32)) + + let int64 x = value (Bitv (Bitvector.make (Z.of_int64 x) 64)) + + let float32 x = value (Num (F32 (Int32.bits_of_float x))) + + let float64 x = value (Num (F64 (Int64.bits_of_float x))) + + let list x = value (List x) + + let app x = value (App (x, [])) + + let symbol name ty = symbol (Symbol.make ty name) + + let ( = ) i1 i2 = relop Ty_bool Eq i1 i2 + + let ( <> ) i1 i2 = relop Ty_bool Ne i1 i2 + + let ( && ) b1 b2 = binop Ty_bool And b1 b2 + + let ( || ) b1 b2 = binop Ty_bool Or b1 b2 + + let ( => ) b1 b2 = + let left = unop Ty_bool Not b1 in + binop Ty_bool Or left b2 + + module Int = struct + let ( ~- ) i = unop Ty_int Neg i + + let ( + ) i1 i2 = binop Ty_int Add i1 i2 + + let ( - ) i1 i2 = binop Ty_int Sub i1 i2 + + let ( * ) i1 i2 = binop Ty_int Mul i1 i2 + + let ( / ) i1 i2 = binop Ty_int Div i1 i2 + + let ( % ) i1 i2 = binop Ty_int Rem i1 i2 + + let ( ** ) i1 i2 = binop Ty_int Pow i1 i2 + + let ( < ) i1 i2 = relop Ty_int Lt i1 i2 + + let ( > ) i1 i2 = relop Ty_int Gt i1 i2 + + let ( <= ) i1 i2 = relop Ty_int Le i1 i2 + + let ( >= ) i1 i2 = relop Ty_int Ge i1 i2 + + let to_real i = cvtop Ty_real Reinterpret_int i + end +end diff --git a/test/unit/dune b/test/unit/dune index 0ef40dec..d1d4f392 100644 --- a/test/unit/dune +++ b/test/unit/dune @@ -1,14 +1,3 @@ (tests - (names - test_expr_hc - test_simplify - test_unop - test_binop - test_triop - test_ty - test_relop - test_cvtop - test_naryop - test_model - test_statistics) - (libraries smtml yojson)) + (names test_expr test_model test_statistics) + (libraries smtml smtml_test yojson)) diff --git a/test/unit/test_binop.ml b/test/unit/test_binop.ml deleted file mode 100644 index e6a759c2..00000000 --- a/test/unit/test_binop.ml +++ /dev/null @@ -1,149 +0,0 @@ -open Smtml -open Ty -open Expr -open Value - -let ( = ) = Expr.equal - -let true_ = value True - -let false_ = value False - -let int x = value (Int x) - -let real x = value (Real x) - -let string x = value (Str x) - -let int32 x = value (Num (I32 x)) - -let int64 x = value (Num (I64 x)) - -let float32 x = value (Num (F32 (Int32.bits_of_float x))) - -let float64 x = value (Num (F64 (Int64.bits_of_float x))) - -let list x = value (List x) - -(* int *) -let () = - assert (binop Ty_int Add (int 0) (int 42) = int 42); - assert (binop Ty_int Sub (int 0) (int 1) = int (-1)); - assert (binop Ty_int Mul (int 2) (int 21) = int 42); - assert (binop Ty_int Div (int 84) (int 2) = int 42); - assert (binop Ty_int Rem (int 0) (int 1) = int 0); - assert (binop Ty_int Pow (int 2) (int 2) = int 4); - assert (binop Ty_int Min (int 2) (int 4) = int 2); - assert (binop Ty_int Max (int 2) (int 4) = int 4); - assert (binop Ty_int And (int 1) (int 0) = int 0); - assert (binop Ty_int Or (int 0) (int 1) = int 1); - assert (binop Ty_int Xor (int 1) (int 1) = int 0); - assert (binop Ty_int Shl (int 1) (int 2) = int 4); - assert (binop Ty_int ShrA (int 4) (int 2) = int 1); - assert (binop Ty_int ShrA (int (-4)) (int 2) = int (-1)); - assert (binop Ty_int ShrL (int (-4)) (int 2) <> int (-1)) - -(* real *) -let () = - assert (binop Ty_real Add (real 0.0) (real 42.0) = real 42.0); - assert (binop Ty_real Sub (real 0.0) (real 1.0) = real (-1.0)); - assert (binop Ty_real Mul (real 2.0) (real 21.0) = real 42.0); - assert (binop Ty_real Div (real 84.0) (real 2.0) = real 42.0); - assert (binop Ty_real Rem (real 0.0) (real 1.0) = real 0.0); - assert (binop Ty_real Min (real 2.0) (real 4.0) = real 2.0); - assert (binop Ty_real Max (real 2.0) (real 4.0) = real 4.0) - -(* str *) -let () = - assert (binop Ty_str At (string "abc") (int 0) = string "a"); - assert (binop Ty_str String_prefix (string "ab") (string "abcd") = true_); - assert (binop Ty_str String_suffix (string "ab") (string "abcd") = false_); - assert (binop Ty_str String_contains (string "abcd") (string "bc") = true_) - -(* list *) -let () = - let clist = list [ Int 0; Int 1; Int 2 ] in - assert (binop Ty_list At clist (int 0) = int 0); - assert (binop Ty_list List_cons (int 0) (list [ Int 1; Int 2 ]) = clist); - assert ( - binop Ty_list List_append (list [ Int 0; Int 1 ]) (list [ Int 2 ]) = clist ); - let slist2 = make (List [ int 0; int 1 ]) in - let slist3 = make (List [ int 0; int 1; int 2 ]) in - assert (binop Ty_list At slist3 (int 0) = int 0); - assert (binop Ty_list List_append slist2 (list [ Int 2 ]) = slist3); - assert ( - binop Ty_list List_cons (int 0) (make (List [ int 1; int 2 ])) = slist3 ) - -(* i32 *) -let () = - assert ( - let ptr = ptr 8390670l (int32 2l) in - binop (Ty_bitv 32) Rem ptr (int32 1l) = int32 0l ); - assert (binop (Ty_bitv 32) Add (int32 0l) (int32 1l) = int32 1l); - assert (binop (Ty_bitv 32) Sub (int32 1l) (int32 0l) = int32 1l); - assert ( - let x = binop (Ty_bitv 32) Mul (int32 2l) (int32 2l) in - binop (Ty_bitv 32) Div x (int32 2l) = int32 2l ); - assert (binop (Ty_bitv 32) Rem (int32 10l) (int32 7l) = int32 3l); - assert (binop (Ty_bitv 32) And (int32 1l) (int32 0l) = int32 0l); - assert (binop (Ty_bitv 32) Or (int32 0l) (int32 1l) = int32 1l); - assert (binop (Ty_bitv 32) Xor (int32 1l) (int32 1l) = int32 0l); - assert (binop (Ty_bitv 32) Shl (int32 1l) (int32 2l) = int32 4l); - assert (binop (Ty_bitv 32) ShrA (int32 4l) (int32 2l) = int32 1l); - assert (binop (Ty_bitv 32) Rotl (int32 Int32.min_int) (int32 2l) = int32 2l); - assert (binop (Ty_bitv 32) Rotr (int32 2l) (int32 2l) = int32 Int32.min_int) - -(* i64 *) -let () = - assert (binop (Ty_bitv 64) Add (int64 0L) (int64 1L) = int64 1L); - assert (binop (Ty_bitv 64) Sub (int64 1L) (int64 0L) = int64 1L); - assert ( - let x = binop (Ty_bitv 64) Mul (int64 2L) (int64 2L) in - binop (Ty_bitv 64) Div x (int64 2L) = int64 2L ); - assert (binop (Ty_bitv 64) Rem (int64 10L) (int64 7L) = int64 3L); - assert (binop (Ty_bitv 64) And (int64 1L) (int64 0L) = int64 0L); - assert (binop (Ty_bitv 64) Or (int64 0L) (int64 1L) = int64 1L); - assert (binop (Ty_bitv 64) Xor (int64 1L) (int64 1L) = int64 0L); - assert (binop (Ty_bitv 64) Shl (int64 1L) (int64 2L) = int64 4L); - assert (binop (Ty_bitv 64) ShrA (int64 4L) (int64 2L) = int64 1L); - assert (binop (Ty_bitv 64) Rotl (int64 Int64.min_int) (int64 2L) = int64 2L); - assert (binop (Ty_bitv 64) Rotr (int64 2L) (int64 2L) = int64 Int64.min_int) - -(* f32 *) -let () = - let ty = Ty_fp 32 in - assert (binop ty Copysign (float32 (-4.2)) (float32 2.0) = float32 4.2); - assert (binop ty Copysign (float32 4.2) (float32 (-2.0)) = float32 (-4.2)); - assert (binop ty Copysign (float32 4.2) (float32 2.0) = float32 4.2); - assert (binop ty Copysign (float32 (-4.2)) (float32 (-2.0)) = float32 (-4.2)) - -(* f64 *) -let () = - let ty = Ty_fp 64 in - assert (binop ty Copysign (float64 (-4.2)) (float64 2.0) = float64 4.2); - assert (binop ty Copysign (float64 4.2) (float64 (-2.0)) = float64 (-4.2)); - assert (binop ty Copysign (float64 4.2) (float64 2.0) = float64 4.2); - assert (binop ty Copysign (float64 (-4.2)) (float64 (-2.0)) = float64 (-4.2)) - -(* ptr *) -let () = - let p0 = ptr 0l (int32 0l) in - let p1 = binop (Ty_bitv 32) Add p0 (int32 4l) in - assert (p1 = ptr 0l (int32 4l)); - assert (binop (Ty_bitv 32) Sub p1 p0 = int32 4l); - assert (binop (Ty_bitv 32) Sub p1 (int32 4l) = p0); - assert (binop (Ty_bitv 32) Add (int32 4l) p0 = p1) - -(* Simplification *) -let () = - let x = symbol @@ Symbol.make (Ty_bitv 32) "x" in - let zero = int32 0l in - let binop32 = binop (Ty_bitv 32) in - assert (binop32 And x zero = zero && binop32 And zero x = zero); - assert (binop32 Or zero x = x && binop32 Or x zero = x); - assert ( - binop32 Sub (binop32 Sub x (int32 1l)) (int32 1l) = binop32 Sub x (int32 2l) ); - assert ( - binop32 Mul (binop32 Mul x (int32 2l)) (int32 2l) = binop32 Mul x (int32 4l) ); - assert ( - binop32 Mul (int32 2l) (binop32 Mul x (int32 2l)) = binop32 Mul (int32 4l) x ) diff --git a/test/unit/test_cvtop.ml b/test/unit/test_cvtop.ml deleted file mode 100644 index e5eaa968..00000000 --- a/test/unit/test_cvtop.ml +++ /dev/null @@ -1,59 +0,0 @@ -open Smtml -open Ty -open Expr -open Value - -let int i = value (Int i) - -let str s = value (Str s) - -let real r = value (Real r) - -let i32 i = value (Num (I32 i)) - -let i64 i = value (Num (I64 i)) - -let f32 f = value (Num (F32 (Int32.bits_of_float f))) - -let f64 f = value (Num (F64 (Int64.bits_of_float f))) - -(* int *) -let () = - assert (cvtop Ty_int OfBool (value True) = int 1); - assert (cvtop Ty_int OfBool (value False) = int 0); - assert (cvtop Ty_int Reinterpret_float (real 1.) = int 1); - assert (cvtop Ty_int ToString (int 1) = str "1") - -(* real *) -let () = - assert (cvtop Ty_real ToString (real 1.) = str "1."); - assert (cvtop Ty_real OfString (str "1.") = real 1.); - assert (cvtop Ty_real Reinterpret_int (int 1) = real 1.) - -(* str *) -let () = - assert (cvtop Ty_str String_to_code (str "a") = int 97); - assert (cvtop Ty_str String_from_code (int 97) = str "a"); - assert (cvtop Ty_str String_to_int (str "42") = int 42); - assert (cvtop Ty_str String_from_int (int 42) = str "42"); - assert (cvtop Ty_str String_to_float (str "1.") = real 1.) - -(* i32 *) -let () = - assert (cvtop (Ty_bitv 32) TruncSF32 (f32 8.5) = i32 8l); - assert (cvtop (Ty_bitv 32) TruncSF64 (f64 8.5) = i32 8l) - -(* i64 *) -let () = - assert (cvtop (Ty_bitv 64) TruncSF32 (f32 8.5) = i64 8L); - assert (cvtop (Ty_bitv 64) TruncSF64 (f64 8.5) = i64 8L) - -(* f32 *) -let () = - assert (cvtop (Ty_fp 32) ConvertSI32 (i32 8l) = f32 8.0); - assert (cvtop (Ty_fp 32) ConvertSI64 (i64 8L) = f32 8.0) - -(* f64 *) -let () = - assert (cvtop (Ty_fp 64) ConvertSI32 (i32 8l) = f64 8.0); - assert (cvtop (Ty_fp 64) ConvertSI64 (i64 8L) = f64 8.0) diff --git a/test/unit/test_expr.ml b/test/unit/test_expr.ml new file mode 100644 index 00000000..ccf3a470 --- /dev/null +++ b/test/unit/test_expr.ml @@ -0,0 +1,563 @@ +open Smtml +open Smtml_test.Test_harness + +let test_hc () = + let open Infix in + let length0 = Expr.Hc.length () in + let ty = Ty.Ty_bitv 32 in + assert (symbol "x" ty == symbol "x" ty); + assert (symbol "x" ty != symbol "y" ty); + let left_a = symbol "x" ty in + let right_a = symbol "y" ty in + let left_b = symbol "x" ty in + let right_b = symbol "y" ty in + let a = Expr.binop ty Add left_a right_a in + let b = Expr.binop ty Add left_b right_b in + assert (a == b); + (* There should be only 3 elements added in the hashcons table: *) + (* 1. x *) + (* 2. y *) + (* 3. x + y *) + assert (Expr.Hc.length () - length0 == 3) + +let test_unop_int () = + let open Infix in + let ty = Ty.Ty_int in + assert_equal (Expr.unop ty Neg (int 1)) (int ~-1); + assert_equal (Expr.unop ty Abs (int ~-1)) (int 1); + let x = symbol "x" ty in + assert_equal (Expr.unop ty Neg (Expr.unop ty Neg x)) x + +let test_unop_real () = + let open Infix in + let ty = Ty.Ty_real in + assert_equal (Expr.unop ty Neg (real 1.0)) (real (-1.0)); + assert_equal (Expr.unop ty Abs (real 1.0)) (real 1.0); + assert_equal (Expr.unop ty Sqrt (real 4.0)) (real 2.0); + assert_equal (Expr.unop ty Nearest (real 0.504)) (real 1.0); + assert_equal (Expr.unop ty Ceil (real 0.3)) (real 1.0); + assert_equal (Expr.unop ty Floor (real 0.7)) (real 0.0); + assert_equal (Expr.unop ty Trunc (real 1.504)) (real 1.0); + assert_equal (Expr.unop ty Is_nan (real Float.nan)) (true_ ()) + +let test_unop_string () = + let open Infix in + let ty = Ty.Ty_str in + assert_equal (Expr.unop ty Length (string "abc")) (int 3); + assert_equal (Expr.unop ty Trim (string " abc\t\n")) (string "abc") + +let test_unop_bool () = + let ty = Ty.Ty_bool in + assert_equal (Expr.unop ty Not Expr.Bool.true_) Expr.Bool.false_; + let x = Expr.symbol (Symbol.make ty "x") in + assert_equal (Expr.unop ty Not (Expr.unop ty Not x)) x + +let test_unop_list () = + let open Infix in + let ty = Ty.Ty_list in + let vlist = list [ Int 1; Int 2; Int 3 ] in + let x = symbol "x" Ty_int in + let y = symbol "y" Ty_int in + let slist = Expr.make (List [ x; y ]) in + assert_equal (Expr.unop ty Head vlist) (int 1); + assert_equal (Expr.unop ty Tail vlist) (list [ Int 2; Int 3 ]); + assert_equal (Expr.unop ty Length vlist) (int 3); + assert_equal (Expr.unop ty Reverse vlist) (list [ Int 3; Int 2; Int 1 ]); + assert_equal (Expr.unop ty Head slist) x; + assert_equal (Expr.unop ty Tail slist) (Expr.make (List [ y ])); + assert_equal (Expr.unop ty Length slist) (int 2); + assert_equal (Expr.unop ty Reverse (Expr.unop ty Reverse slist)) slist + +(* TODO: i32 *) +(* let () = *) +(* let ty = Ty_bitv 32 in *) +(* let v i = value (Num (I32 i)) in *) +(* assert (unop ty Neg (v 1l) = v (-1l)); *) +(* assert (unop ty Not (v (-1l)) = v 0l) *) + +(* TODO: i64 *) +(* let () = *) +(* let ty = Ty_bitv 64 in *) +(* let v i = value (Num (I64 i)) in *) +(* assert (unop ty Neg (v 1L) = v (-1L)); *) +(* assert (unop ty Not (v (-1L)) = v 0L) *) + +(* f32 *) +let test_unop_f32 () = + let open Infix in + let ty = Ty.Ty_fp 32 in + assert_equal (Expr.unop ty Trunc (float32 0.75)) (float32 0.0) + +(* f64 *) +let test_unop_f64 () = + let open Infix in + let ty = Ty.Ty_fp 64 in + assert_equal (Expr.unop ty Trunc (float64 0.75)) (float64 0.0) + +let test_unop () = + test_unop_int (); + test_unop_real (); + test_unop_string (); + test_unop_bool (); + test_unop_list (); + test_unop_f32 (); + test_unop_f64 () + +let test_binop_int () = + let open Infix in + let ty = Ty.Ty_int in + assert_equal (Expr.binop ty Add (int 0) (int 42)) (int 42); + assert_equal (Expr.binop ty Sub (int 0) (int 1)) (int (-1)); + assert_equal (Expr.binop ty Mul (int 2) (int 21)) (int 42); + assert_equal (Expr.binop ty Div (int 84) (int 2)) (int 42); + assert_equal (Expr.binop ty Rem (int 0) (int 1)) (int 0); + assert_equal (Expr.binop ty Pow (int 2) (int 2)) (int 4); + assert_equal (Expr.binop ty Min (int 2) (int 4)) (int 2); + assert_equal (Expr.binop ty Max (int 2) (int 4)) (int 4); + assert_equal (Expr.binop ty And (int 1) (int 0)) (int 0); + assert_equal (Expr.binop ty Or (int 0) (int 1)) (int 1); + assert_equal (Expr.binop ty Xor (int 1) (int 1)) (int 0); + assert_equal (Expr.binop ty Shl (int 1) (int 2)) (int 4); + assert_equal (Expr.binop ty ShrA (int 4) (int 2)) (int 1); + assert_equal (Expr.binop ty ShrA (int (-4)) (int 2)) (int (-1)) +(* assert_equal (Expr.binop ty ShrL (int (-4)) (int 2)) (int (-1)) *) + +let test_binop_real () = + let open Infix in + let ty = Ty.Ty_real in + assert_equal (Expr.binop ty Add (real 0.0) (real 42.0)) (real 42.0); + assert_equal (Expr.binop ty Sub (real 0.0) (real 1.0)) (real (-1.0)); + assert_equal (Expr.binop ty Mul (real 2.0) (real 21.0)) (real 42.0); + assert_equal (Expr.binop ty Div (real 84.0) (real 2.0)) (real 42.0); + assert_equal (Expr.binop ty Rem (real 0.0) (real 1.0)) (real 0.0); + assert_equal (Expr.binop ty Min (real 2.0) (real 4.0)) (real 2.0); + assert_equal (Expr.binop ty Max (real 2.0) (real 4.0)) (real 4.0) + +let test_binop_string () = + let open Infix in + let ty = Ty.Ty_str in + assert_equal (Expr.binop ty At (string "abc") (int 0)) (string "a"); + assert_equal + (Expr.binop ty String_prefix (string "ab") (string "abcd")) + (true_ ()); + assert_equal + (Expr.binop ty String_suffix (string "ab") (string "abcd")) + (false_ ()); + assert_equal + (Expr.binop ty String_contains (string "abcd") (string "bc")) + (true_ ()) + +let test_binop_list () = + let open Infix in + let ty = Ty.Ty_list in + let clist = list [ Int 0; Int 1; Int 2 ] in + assert_equal (Expr.binop Ty_list At clist (int 0)) (int 0); + assert_equal + (Expr.binop Ty_list List_cons (int 0) (list [ Int 1; Int 2 ])) + clist; + assert_equal + (Expr.binop Ty_list List_append (list [ Int 0; Int 1 ]) (list [ Int 2 ])) + clist; + let slist2 = Expr.make (List [ int 0; int 1 ]) in + let slist3 = Expr.make (List [ int 0; int 1; int 2 ]) in + assert_equal (Expr.binop ty At slist3 (int 0)) (int 0); + assert_equal (Expr.binop ty List_append slist2 (list [ Int 2 ])) slist3; + assert_equal + (Expr.binop ty List_cons (int 0) (Expr.make (List [ int 1; int 2 ]))) + slist3 + +(* TODO: bring back *) +let test_binop_i32 () = () + +(* assert ( *) +(* let ptr = ptr 8390670l (int32 2l) in *) +(* binop (Ty_bitv 32) Rem ptr (int32 1l) = int32 0l ); *) +(* assert (binop (Ty_bitv 32) Add (int32 0l) (int32 1l) = int32 1l); *) +(* assert (binop (Ty_bitv 32) Sub (int32 1l) (int32 0l) = int32 1l); *) +(* assert ( *) +(* let x = binop (Ty_bitv 32) Mul (int32 2l) (int32 2l) in *) +(* binop (Ty_bitv 32) Div x (int32 2l) = int32 2l ); *) +(* assert (binop (Ty_bitv 32) Rem (int32 10l) (int32 7l) = int32 3l); *) +(* assert (binop (Ty_bitv 32) And (int32 1l) (int32 0l) = int32 0l); *) +(* assert (binop (Ty_bitv 32) Or (int32 0l) (int32 1l) = int32 1l); *) +(* assert (binop (Ty_bitv 32) Xor (int32 1l) (int32 1l) = int32 0l); *) +(* assert (binop (Ty_bitv 32) Shl (int32 1l) (int32 2l) = int32 4l); *) +(* assert (binop (Ty_bitv 32) ShrA (int32 4l) (int32 2l) = int32 1l); *) +(* assert (binop (Ty_bitv 32) Rotl (int32 Int32.min_int) (int32 2l) = int32 2l); *) +(* assert (binop (Ty_bitv 32) Rotr (int32 2l) (int32 2l) = int32 Int32.min_int) *) + +(* TODO: bring back *) +let test_binop_i64 () = () +(* assert (binop (Ty_bitv 64) Add (int64 0L) (int64 1L) = int64 1L); *) +(* assert (binop (Ty_bitv 64) Sub (int64 1L) (int64 0L) = int64 1L); *) +(* assert ( *) +(* let x = binop (Ty_bitv 64) Mul (int64 2L) (int64 2L) in *) +(* binop (Ty_bitv 64) Div x (int64 2L) = int64 2L ); *) +(* assert (binop (Ty_bitv 64) Rem (int64 10L) (int64 7L) = int64 3L); *) +(* assert (binop (Ty_bitv 64) And (int64 1L) (int64 0L) = int64 0L); *) +(* assert (binop (Ty_bitv 64) Or (int64 0L) (int64 1L) = int64 1L); *) +(* assert (binop (Ty_bitv 64) Xor (int64 1L) (int64 1L) = int64 0L); *) +(* assert (binop (Ty_bitv 64) Shl (int64 1L) (int64 2L) = int64 4L); *) +(* assert (binop (Ty_bitv 64) ShrA (int64 4L) (int64 2L) = int64 1L); *) +(* assert (binop (Ty_bitv 64) Rotl (int64 Int64.min_int) (int64 2L) = int64 2L); *) +(* assert (binop (Ty_bitv 64) Rotr (int64 2L) (int64 2L) = int64 Int64.min_int) *) + +let test_binop_f32 () = + let open Infix in + let ty = Ty.Ty_fp 32 in + assert_equal + (Expr.binop ty Copysign (float32 (-4.2)) (float32 2.0)) + (float32 4.2); + assert_equal + (Expr.binop ty Copysign (float32 4.2) (float32 (-2.0))) + (float32 (-4.2)); + assert_equal + (Expr.binop ty Copysign (float32 4.2) (float32 2.0)) + (float32 4.2); + assert_equal + (Expr.binop ty Copysign (float32 (-4.2)) (float32 (-2.0))) + (float32 (-4.2)) + +let test_binop_f64 () = + let open Infix in + let ty = Ty.Ty_fp 64 in + assert_equal + (Expr.binop ty Copysign (float64 (-4.2)) (float64 2.0)) + (float64 4.2); + assert_equal + (Expr.binop ty Copysign (float64 4.2) (float64 (-2.0))) + (float64 (-4.2)); + assert_equal + (Expr.binop ty Copysign (float64 4.2) (float64 2.0)) + (float64 4.2); + assert_equal + (Expr.binop ty Copysign (float64 (-4.2)) (float64 (-2.0))) + (float64 (-4.2)) + +(* TODO: ptr *) +let test_binop_ptr () = () + +(* let p0 = ptr 0l (int32 0l) in *) +(* let p1 = binop (Ty_bitv 32) Add p0 (int32 4l) in *) +(* assert (p1 = ptr 0l (int32 4l)); *) +(* assert (binop (Ty_bitv 32) Sub p1 p0 = int32 4l); *) +(* assert (binop (Ty_bitv 32) Sub p1 (int32 4l) = p0); *) +(* assert (binop (Ty_bitv 32) Add (int32 4l) p0 = p1) *) + +(* TODO: Simplification *) +let test_binop_simplifications () = () +(* let x = symbol @@ Symbol.make (Ty_bitv 32) "x" in *) +(* let zero = int32 0l in *) +(* let binop32 = binop (Ty_bitv 32) in *) +(* assert (binop32 And x zero = zero && binop32 And zero x = zero); *) +(* assert (binop32 Or zero x = x && binop32 Or x zero = x); *) +(* assert ( *) +(* binop32 Sub (binop32 Sub x (int32 1l)) (int32 1l) = binop32 Sub x (int32 2l) ); *) +(* assert ( *) +(* binop32 Mul (binop32 Mul x (int32 2l)) (int32 2l) = binop32 Mul x (int32 4l) ); *) +(* assert ( *) +(* binop32 Mul (int32 2l) (binop32 Mul x (int32 2l)) = binop32 Mul (int32 4l) x ) *) + +let test_binop () = + test_binop_int (); + test_binop_real (); + test_binop_string (); + test_binop_list (); + test_binop_i32 (); + test_binop_i64 (); + test_binop_f32 (); + test_binop_f64 (); + test_binop_ptr (); + test_binop_simplifications () + +let test_relop_bool () = + let open Infix in + let ty = Ty.Ty_bool in + assert_equal (Expr.relop ty Eq (int 0) (int 0)) Expr.Bool.true_; + assert_equal (Expr.relop ty Ne (int 0) (int 0)) Expr.Bool.false_; + assert_equal (Expr.relop ty Eq (real 0.0) (real 0.0)) Expr.Bool.true_; + assert_equal (Expr.relop ty Ne (real 0.0) (real 0.0)) Expr.Bool.false_; + assert_equal (Expr.relop ty Eq (int32 0l) (int32 0l)) Expr.Bool.true_; + assert_equal (Expr.relop ty Ne (int32 0l) (int32 0l)) Expr.Bool.false_; + assert_equal (Expr.relop ty Eq (int64 0L) (int64 0L)) Expr.Bool.true_; + assert_equal (Expr.relop ty Ne (int64 0L) (int64 0L)) Expr.Bool.false_ + +(* TODO: remove useless tests? *) +(* assert (relop Ty_bool Eq (float32 0.0) (float32 0.0) = true_); *) +(* assert (relop Ty_bool Ne (float32 0.0) (float32 0.0) = false_); *) +(* assert (relop Ty_bool Eq (float64 0.0) (float64 0.0) = true_); *) +(* assert (relop Ty_bool Ne (float64 0.0) (float64 0.0) = false_) *) + +let test_relop_int () = + let open Infix in + let ty = Ty.Ty_int in + assert_equal (Expr.relop ty Lt (int 0) (int 1)) Expr.Bool.true_; + assert_equal (Expr.relop ty Le (int 0) (int 1)) Expr.Bool.true_; + assert_equal (Expr.relop ty Gt (int 0) (int 1)) Expr.Bool.false_; + assert_equal (Expr.relop ty Ge (int 0) (int 1)) Expr.Bool.false_ + +let test_relop_real () = + let open Infix in + let ty = Ty.Ty_real in + let x = symbol "x" ty in + assert_equal (Expr.relop Ty_bool Ne (real Float.nan) x) Expr.Bool.true_; + assert_equal (Expr.relop Ty_bool Eq x (real Float.nan)) Expr.Bool.false_; + assert_equal (Expr.relop ty Lt (real 0.0) (real 1.0)) Expr.Bool.true_; + assert_equal (Expr.relop ty Le (real 0.0) (real 1.0)) Expr.Bool.true_; + assert_equal (Expr.relop ty Gt (real 0.0) (real 1.0)) Expr.Bool.false_; + assert_equal (Expr.relop ty Ge (real 0.0) (real 1.0)) Expr.Bool.false_ + +let test_relop_string () = + let open Infix in + let ty = Ty.Ty_str in + assert_equal (Expr.relop ty Lt (string "a") (string "b")) Expr.Bool.true_; + assert_equal (Expr.relop ty Le (string "a") (string "b")) Expr.Bool.true_; + assert_equal (Expr.relop ty Gt (string "a") (string "b")) Expr.Bool.false_; + assert_equal (Expr.relop ty Ge (string "a") (string "b")) Expr.Bool.false_; + assert_equal (Expr.relop ty Eq (string "a") (string "a")) Expr.Bool.true_; + assert_equal (Expr.relop ty Ne (string "a") (string "a")) Expr.Bool.false_; + assert_equal (Expr.relop ty Eq (string "a") (string "b")) Expr.Bool.false_; + assert_equal (Expr.relop ty Ne (string "a") (string "b")) Expr.Bool.true_ + +(* TODO: i32 *) +(* let () = *) +(* assert (relop (Ty_bitv 32) Lt (int32 0l) (int32 1l) = true_); *) +(* assert (relop (Ty_bitv 32) LtU (int32 (-1l)) (int32 0l) = false_); *) +(* assert (relop (Ty_bitv 32) Le (int32 0l) (int32 1l) = true_); *) +(* assert (relop (Ty_bitv 32) LeU (int32 (-1l)) (int32 0l) = false_); *) +(* assert (relop (Ty_bitv 32) Gt (int32 1l) (int32 0l) = true_); *) +(* assert (relop (Ty_bitv 32) GtU (int32 0l) (int32 (-1l)) = false_); *) +(* assert (relop (Ty_bitv 32) Ge (int32 1l) (int32 0l) = true_); *) +(* assert (relop (Ty_bitv 32) GeU (int32 0l) (int32 (-1l)) = false_) *) + +(* TODO: i64 *) +(* let () = *) +(* assert (relop (Ty_bitv 64) Lt (int64 0L) (int64 1L) = true_); *) +(* assert (relop (Ty_bitv 64) LtU (int64 (-1L)) (int64 0L) = false_); *) +(* assert (relop (Ty_bitv 64) Le (int64 0L) (int64 1L) = true_); *) +(* assert (relop (Ty_bitv 64) LeU (int64 (-1L)) (int64 0L) = false_); *) +(* assert (relop (Ty_bitv 64) Gt (int64 1L) (int64 0L) = true_); *) +(* assert (relop (Ty_bitv 64) GtU (int64 0L) (int64 (-1L)) = false_); *) +(* assert (relop (Ty_bitv 64) Ge (int64 1L) (int64 0L) = true_); *) +(* assert (relop (Ty_bitv 64) GeU (int64 0L) (int64 (-1L)) = false_) *) + +let test_relop_f32 () = + let open Infix in + let ty = Ty.Ty_fp 32 in + let nan0 = float32 Float.nan in + let nan1 = float32 Float.nan in + (* Structual equaility should say nan = nan *) + assert_equal nan0 nan1; + (* Concrete evaluation should say nan <> nan *) + assert_equal (Expr.relop ty Eq nan0 nan1) Expr.Bool.false_; + assert_equal (Expr.relop ty Lt (float32 0.0) (float32 1.0)) Expr.Bool.true_; + assert_equal (Expr.relop ty Le (float32 0.0) (float32 1.0)) Expr.Bool.true_; + assert_equal (Expr.relop ty Gt (float32 0.0) (float32 1.0)) Expr.Bool.false_; + assert_equal (Expr.relop ty Ge (float32 0.0) (float32 1.0)) Expr.Bool.false_ + +let test_relop_f64 () = + let open Infix in + let ty = Ty.Ty_fp 64 in + assert_equal (Expr.relop ty Lt (float64 0.0) (float64 1.0)) Expr.Bool.true_; + assert_equal (Expr.relop ty Le (float64 0.0) (float64 1.0)) Expr.Bool.true_; + assert_equal (Expr.relop ty Gt (float64 0.0) (float64 1.0)) Expr.Bool.false_; + assert_equal (Expr.relop ty Ge (float64 0.0) (float64 1.0)) Expr.Bool.false_ + +let test_relop_app () = + let open Infix in + let ty = Ty.Ty_bool in + assert_equal + (Expr.relop ty Eq (app (`Op "undefined")) (app (`Op "undefined"))) + Expr.Bool.true_; + assert_equal + (Expr.relop ty Ne (app (`Op "undefined")) (app (`Op "undefined"))) + Expr.Bool.false_; + assert_equal + (Expr.relop ty Eq (app (`Op "undefined")) (int 1)) + Expr.Bool.false_; + assert_equal + (Expr.relop ty Ne (int 1) (app (`Op "undefined"))) + Expr.Bool.true_ + +let test_relop_ptr () = + let open Infix in + let ty = Ty.Ty_bitv 32 in + let p0 = Expr.ptr 0l (int32 0l) in + let p1 = Expr.ptr 4l (int32 0l) in + assert_equal (Expr.relop Ty_bool Eq p0 p0) Expr.Bool.true_; + assert_equal (Expr.relop Ty_bool Eq p0 p1) Expr.Bool.false_; + assert_equal (Expr.relop Ty_bool Ne p0 p0) Expr.Bool.false_; + assert_equal (Expr.relop Ty_bool Ne p0 p1) Expr.Bool.true_; + assert_equal (Expr.relop ty LtU p0 p0) Expr.Bool.false_; + assert_equal (Expr.relop ty LeU p0 p1) Expr.Bool.true_; + assert_equal (Expr.relop ty GeU p0 p0) Expr.Bool.true_; + assert_equal (Expr.relop ty GtU p0 p1) Expr.Bool.false_; + assert_equal (Expr.relop ty Le p0 (int32 4l)) Expr.Bool.true_; + assert_equal (Expr.relop ty Lt (int32 4l) p0) Expr.Bool.false_; + assert_equal (Expr.relop ty Gt p1 (int32 4l)) Expr.Bool.false_; + assert_equal (Expr.relop ty Ge (int32 4l) p1) Expr.Bool.true_ + +let test_relop () = + test_relop_bool (); + test_relop_int (); + test_relop_real (); + test_relop_string (); + test_relop_f32 (); + test_relop_f64 (); + test_relop_app (); + test_relop_ptr () + +let test_triop_bool () = + let open Infix in + let ty = Ty.Ty_bool in + assert_equal (Expr.triop ty Ite (true_ ()) (int 1) (int 0)) (int 1); + assert_equal (Expr.triop ty Ite (false_ ()) (int 1) (int 0)) (int 0) + +let test_triop_string () = + let open Infix in + let ty = Ty.Ty_str in + assert_equal + (Expr.triop ty String_extract (string "abcd") (int 1) (int 2)) + (string "bc"); + assert_equal + (Expr.triop ty String_index (string "abcd") (string "bc") (int 0)) + (int 1); + assert_equal + (Expr.triop ty String_replace (string "abcd") (string "bc") (string "ef")) + (string "aefd") + +let test_triop_list () = + let open Infix in + let ty = Ty.Ty_list in + assert_equal + (Expr.triop ty List_set (list [ Int 0; Int 1; Int 2 ]) (int 1) (int 3)) + (list [ Int 0; Int 3; Int 2 ]) + +let test_triop () = + test_triop_bool (); + test_triop_string (); + test_triop_list () + +let test_cvtop_int () = + let open Infix in + let ty = Ty.Ty_int in + assert_equal (Expr.cvtop ty OfBool (true_ ())) (int 1); + assert_equal (Expr.cvtop ty OfBool (false_ ())) (int 0); + assert_equal (Expr.cvtop ty Reinterpret_float (real 1.)) (int 1); + assert_equal (Expr.cvtop ty ToString (int 1)) (string "1") + +let test_cvtop_real () = + let open Infix in + let ty = Ty.Ty_real in + assert_equal (Expr.cvtop ty ToString (real 1.)) (string "1."); + assert_equal (Expr.cvtop ty OfString (string "1.")) (real 1.); + assert_equal (Expr.cvtop ty Reinterpret_int (int 1)) (real 1.) + +let test_cvtop_string () = + let open Infix in + let ty = Ty.Ty_str in + assert_equal (Expr.cvtop ty String_to_code (string "a")) (int 97); + assert_equal (Expr.cvtop ty String_from_code (int 97)) (string "a"); + assert_equal (Expr.cvtop ty String_to_int (string "42")) (int 42); + assert_equal (Expr.cvtop ty String_from_int (int 42)) (string "42"); + assert_equal (Expr.cvtop ty String_to_float (string "1.")) (real 1.) + +(* TODO: bring back *) +(* let () = *) +(* assert (cvtop (Ty_bitv 32) TruncSF32 (f32 8.5) = i32 8l); *) +(* assert (cvtop (Ty_bitv 32) TruncSF64 (f64 8.5) = i32 8l) *) +let test_cvtop_bitv32 () = + let x = Expr.symbol (Symbol.make (Ty_bitv 32) "x") in + let x = Expr.extract x ~high:2 ~low:0 in + assert (Ty.equal (Expr.ty x) (Ty_bitv 16)); + let x = Expr.cvtop (Ty_bitv 32) (Sign_extend 16) x in + assert (Ty.equal (Expr.ty x) (Ty_bitv 32)) + +(* TODO: bring back *) +(* let () = *) +(* assert (cvtop (Ty_bitv 64) TruncSF32 (f32 8.5) = i64 8L); *) +(* assert (cvtop (Ty_bitv 64) TruncSF64 (f64 8.5) = i64 8L) *) + +let test_cvtop_f32 () = + let open Infix in + let ty = Ty.Ty_fp 32 in + assert_equal (Expr.cvtop ty ConvertSI32 (int32 8l)) (float32 8.0); + assert_equal (Expr.cvtop ty ConvertSI64 (int64 8L)) (float32 8.0) + +let test_cvtop_f64 () = + let open Infix in + let ty = Ty.Ty_fp 64 in + assert_equal (Expr.cvtop ty ConvertSI32 (int32 8l)) (float64 8.0); + assert_equal (Expr.cvtop ty ConvertSI64 (int64 8L)) (float64 8.0) + +let test_cvtop () = + test_cvtop_int (); + test_cvtop_real (); + test_cvtop_string (); + test_cvtop_bitv32 (); + test_cvtop_f32 (); + test_cvtop_f64 () + +let test_naryop_bool () = + let open Infix in + let ty = Ty.Ty_bool in + let t = true_ () in + let f = false_ () in + assert_equal (Expr.naryop ty Logand [ t; t; t; t ]) t; + assert_equal (Expr.naryop ty Logor [ f; f; f; f ]) f; + assert_equal (Expr.naryop ty Logand [ t; f; t ]) f; + assert_equal (Expr.naryop ty Logor [ f; t; f ]) t + +let test_naryop_string () = + let open Infix in + let ty = Ty.Ty_str in + assert_equal + (Expr.naryop ty Concat [ string "a"; string "b"; string "c" ]) + (string "abc"); + assert_equal (Expr.naryop ty Concat [ string "abc" ]) (string "abc"); + assert_equal (Expr.naryop ty Concat [ string ""; string "" ]) (string "") + +let test_naryop () = + test_naryop_bool (); + test_naryop_string () + +let test_simplify_assoc () = + (* Test simplify of left- and righ- associative operators *) + let open Infix in + let ty = Ty.Ty_int in + let x = symbol "x" ty in + let binary = Expr.binop' Ty_int Add x (int 10) in + let sym = Expr.binop' Ty_int Add binary (int 3) in + assert_equal (Expr.simplify sym) (Expr.binop' Ty_int Add x (int 13)); + let binary = Expr.binop' Ty_int Add x (int 10) in + let sym = Expr.binop' Ty_int Add (int 3) binary in + assert_equal (Expr.simplify sym) (Expr.binop' Ty_int Add (int 13) x) + +let test_simplify_concat () = + (* Test Concat of Extracts simplifications *) + let open Infix in + let x = symbol "x" (Ty_bitv 32) in + let b0 = Expr.extract' x ~high:1 ~low:0 in + let b1 = Expr.extract' x ~high:2 ~low:1 in + let b2 = Expr.extract' x ~high:3 ~low:2 in + let b3 = Expr.extract' x ~high:4 ~low:3 in + let b3210 = Expr.concat' b3 (Expr.concat' b2 (Expr.concat' b1 b0)) in + assert_equal x (Expr.simplify b3210) + +let test_simplify () = + test_simplify_assoc (); + test_simplify_concat () + +let () = + try + test_hc (); + test_unop (); + test_binop (); + test_relop (); + test_triop (); + test_cvtop (); + test_naryop (); + test_simplify () + with Eval.TypeError { index; value; ty; _ } -> + Fmt.failwith "type error: operator %a argument %d got unexpected value %a" + Ty.pp ty index Value.pp value diff --git a/test/unit/test_expr_hc.ml b/test/unit/test_expr_hc.ml deleted file mode 100644 index 5c1bc257..00000000 --- a/test/unit/test_expr_hc.ml +++ /dev/null @@ -1,24 +0,0 @@ -open Smtml -open Expr - -(* We already have some hc exprs in the table *) -let length0 = Expr.Hc.length () - -let () = - let module I32 = Expr.Bitv.I32 in - assert (I32.sym "x" == I32.sym "x"); - assert (I32.sym "x" != I32.sym "y"); - let left_a = I32.sym "x" in - let right_a = I32.sym "y" in - let left_b = I32.sym "x" in - let right_b = I32.sym "y" in - let a = binop (Ty_bitv 32) Add left_a right_a in - let b = binop (Ty_bitv 32) Add left_b right_b in - assert (a == b); - (* - There should be only 3 elements added in the hashcons table: - 1. x - 2. y - 3. x + y - *) - assert (Expr.Hc.length () - length0 == 3) diff --git a/test/unit/test_model.ml b/test/unit/test_model.ml index e7e95538..6ef5980b 100644 --- a/test/unit/test_model.ml +++ b/test/unit/test_model.ml @@ -1,7 +1,6 @@ open Smtml -(* Test Model.to_json *) -let () = +let test_to_json () = let x = Symbol.make Ty_int "x" in let y = Symbol.make Ty_real "y" in let z = Symbol.make Ty_bool "z" in @@ -16,10 +15,9 @@ let () = let model_to_json = Model.to_json model in Format.printf "%a@." (Yojson.pretty_print ~std:true) model_to_json -(* Parsing *) +let test_serialization () = test_to_json () -(* json *) -let () = +let test_of_json () = let open Result in let model_str = {| @@ -35,8 +33,7 @@ let () = let model = Model.Parse.Json.from_string model_str in assert (match model with Ok _ -> true | _ -> false) -(* scfg *) -let () = +let test_of_scfg () = let open Result in let model_str = {| @@ -49,3 +46,11 @@ let () = in let model = Model.Parse.Scfg.from_string model_str in assert (match model with Ok _ -> true | _ -> false) + +let test_deserialization () = + test_of_json (); + test_of_scfg () + +let () = + test_serialization (); + test_deserialization () diff --git a/test/unit/test_naryop.ml b/test/unit/test_naryop.ml deleted file mode 100644 index 2838b433..00000000 --- a/test/unit/test_naryop.ml +++ /dev/null @@ -1,20 +0,0 @@ -open Smtml -open Ty -open Expr -open Value - -(* bool *) -let () = - let t = value True in - let f = value False in - assert (naryop Ty_bool Logand [ t; t; t; t ] = t); - assert (naryop Ty_bool Logor [ f; f; f; f ] = f); - assert (naryop Ty_bool Logand [ t; f; t ] = f); - assert (naryop Ty_bool Logor [ f; t; f ] = t) - -(* str *) -let () = - let v s = value (Str s) in - assert (naryop Ty_str Concat [ v "a"; v "b"; v "c" ] = v "abc"); - assert (naryop Ty_str Concat [ v "abc" ] = v "abc"); - assert (naryop Ty_str Concat [ v ""; v "" ] = v "") diff --git a/test/unit/test_relop.ml b/test/unit/test_relop.ml deleted file mode 100644 index 7c12a697..00000000 --- a/test/unit/test_relop.ml +++ /dev/null @@ -1,132 +0,0 @@ -open Smtml -open Ty -open Expr -open Value - -let ( = ) = Expr.equal - -let true_ = value True - -let false_ = value False - -let int i = value (Int i) - -let real f = value (Real f) - -let str s = value (Str s) - -let int32 i = value (Num (I32 i)) - -let int64 i = value (Num (I64 i)) - -let float32 f = value (Num (F32 (Int32.bits_of_float f))) - -let float64 f = value (Num (F64 (Int64.bits_of_float f))) - -let app f = value (App (f, [])) - -(* bool *) -let () = - assert (relop Ty_bool Eq (int 0) (int 0) = true_); - assert (relop Ty_bool Ne (int 0) (int 0) = false_); - assert (relop Ty_bool Eq (real 0.0) (real 0.0) = true_); - assert (relop Ty_bool Ne (real 0.0) (real 0.0) = false_); - assert (relop Ty_bool Eq (int32 0l) (int32 0l) = true_); - assert (relop Ty_bool Ne (int32 0l) (int32 0l) = false_); - assert (relop Ty_bool Eq (int64 0L) (int64 0L) = true_); - assert (relop Ty_bool Ne (int64 0L) (int64 0L) = false_); - assert (relop Ty_bool Eq (float32 0.0) (float32 0.0) = true_); - assert (relop Ty_bool Ne (float32 0.0) (float32 0.0) = false_); - assert (relop Ty_bool Eq (float64 0.0) (float64 0.0) = true_); - assert (relop Ty_bool Ne (float64 0.0) (float64 0.0) = false_) - -(* int *) -let () = - assert (relop Ty_int Lt (int 0) (int 1) = true_); - assert (relop Ty_int Le (int 0) (int 1) = true_); - assert (relop Ty_int Gt (int 0) (int 1) = false_); - assert (relop Ty_int Ge (int 0) (int 1) = false_) - -(* real *) -let () = - let x = symbol @@ Symbol.make Ty_real "x" in - assert (relop Ty_bool Ne (real Float.nan) x = true_); - assert (relop Ty_bool Eq x (real Float.nan) = false_); - assert (relop Ty_real Lt (real 0.0) (real 1.0) = true_); - assert (relop Ty_real Le (real 0.0) (real 1.0) = true_); - assert (relop Ty_real Gt (real 0.0) (real 1.0) = false_); - assert (relop Ty_real Ge (real 0.0) (real 1.0) = false_) - -(* str *) -let () = - assert (relop Ty_str Lt (str "a") (str "b") = true_); - assert (relop Ty_str Le (str "a") (str "b") = true_); - assert (relop Ty_str Gt (str "a") (str "b") = false_); - assert (relop Ty_str Ge (str "a") (str "b") = false_); - assert (relop Ty_str Eq (str "a") (str "a") = true_); - assert (relop Ty_str Ne (str "a") (str "a") = false_); - assert (relop Ty_str Eq (str "a") (str "b") = false_); - assert (relop Ty_str Ne (str "a") (str "b") = true_) - -(* i32 *) -let () = - assert (relop (Ty_bitv 32) Lt (int32 0l) (int32 1l) = true_); - assert (relop (Ty_bitv 32) LtU (int32 (-1l)) (int32 0l) = false_); - assert (relop (Ty_bitv 32) Le (int32 0l) (int32 1l) = true_); - assert (relop (Ty_bitv 32) LeU (int32 (-1l)) (int32 0l) = false_); - assert (relop (Ty_bitv 32) Gt (int32 1l) (int32 0l) = true_); - assert (relop (Ty_bitv 32) GtU (int32 0l) (int32 (-1l)) = false_); - assert (relop (Ty_bitv 32) Ge (int32 1l) (int32 0l) = true_); - assert (relop (Ty_bitv 32) GeU (int32 0l) (int32 (-1l)) = false_) - -(* i64 *) -let () = - assert (relop (Ty_bitv 64) Lt (int64 0L) (int64 1L) = true_); - assert (relop (Ty_bitv 64) LtU (int64 (-1L)) (int64 0L) = false_); - assert (relop (Ty_bitv 64) Le (int64 0L) (int64 1L) = true_); - assert (relop (Ty_bitv 64) LeU (int64 (-1L)) (int64 0L) = false_); - assert (relop (Ty_bitv 64) Gt (int64 1L) (int64 0L) = true_); - assert (relop (Ty_bitv 64) GtU (int64 0L) (int64 (-1L)) = false_); - assert (relop (Ty_bitv 64) Ge (int64 1L) (int64 0L) = true_); - assert (relop (Ty_bitv 64) GeU (int64 0L) (int64 (-1L)) = false_) - -(* f32 *) -let () = - assert (relop (Ty_fp 32) Lt (float32 0.0) (float32 1.0) = true_); - assert (relop (Ty_fp 32) Le (float32 0.0) (float32 1.0) = true_); - assert (relop (Ty_fp 32) Gt (float32 0.0) (float32 1.0) = false_); - assert (relop (Ty_fp 32) Ge (float32 0.0) (float32 1.0) = false_) - -(* f64 *) -let () = - assert (relop (Ty_fp 64) Lt (float64 0.0) (float64 1.0) = true_); - assert (relop (Ty_fp 64) Le (float64 0.0) (float64 1.0) = true_); - assert (relop (Ty_fp 64) Gt (float64 0.0) (float64 1.0) = false_); - assert (relop (Ty_fp 64) Ge (float64 0.0) (float64 1.0) = false_) - -(* app *) -let () = - assert ( - relop Ty_bool Eq (app (`Op "undefined")) (app (`Op "undefined")) = true_ ); - assert ( - relop Ty_bool Ne (app (`Op "undefined")) (app (`Op "undefined")) = false_ ); - assert (relop Ty_bool Eq (app (`Op "undefined")) (int 1) = false_); - assert (relop Ty_bool Ne (int 1) (app (`Op "undefined")) = true_) - -(* ptr *) -let () = - let ty = Ty_bitv 32 in - let p0 = ptr 0l (int32 0l) in - let p1 = ptr 4l (int32 0l) in - assert (relop Ty_bool Eq p0 p0 = true_); - assert (relop Ty_bool Eq p0 p1 = false_); - assert (relop Ty_bool Ne p0 p0 = false_); - assert (relop Ty_bool Ne p0 p1 = true_); - assert (relop ty LtU p0 p0 = false_); - assert (relop ty LeU p0 p1 = true_); - assert (relop ty GeU p0 p0 = true_); - assert (relop ty GtU p0 p1 = false_); - assert (relop ty Le p0 (int32 4l) = true_); - assert (relop ty Lt (int32 4l) p0 = false_); - assert (relop ty Gt p1 (int32 4l) = false_); - assert (relop ty Ge (int32 4l) p1 = true_) diff --git a/test/unit/test_simplify.ml b/test/unit/test_simplify.ml deleted file mode 100644 index b0921a0b..00000000 --- a/test/unit/test_simplify.ml +++ /dev/null @@ -1,47 +0,0 @@ -open Smtml -open Expr -module I8 = Bitv.I8 -module I32 = Bitv.I32 -module I64 = Bitv.I64 - -(* Test concrete simplification *) -let () = - assert ( - let unary = unop' (Ty_bitv 32) Neg (I32.v 1l) in - simplify unary = I32.v (-1l) ); - assert ( - let binary = binop' (Ty_bitv 32) Add (I32.v 1l) (I32.v 1l) in - simplify binary = I32.v 2l ); - assert ( - let triop = triop' Ty_bool Ite Bool.true_ (I32.v 1l) (I32.v 0l) in - simplify triop = I32.v 1l ); - assert ( - let relop = relop' (Ty_bitv 32) Lt (I32.v 2l) (I32.v 1l) in - simplify relop = make @@ Val False ); - assert ( - let cvtop = cvtop' (Ty_bitv 32) WrapI64 (I64.v 1L) in - simplify cvtop = I32.v 1l ) - -(* Test simplify of left- and righ- associative operators *) -let () = - let x = symbol (Symbol.make Ty_int "x") in - let v i = value (Int i) in - assert ( - let binary = binop' Ty_int Add x (v 10) in - let sym = binop' Ty_int Add binary (v 3) in - simplify sym = binop' Ty_int Add x (v 13) ); - assert ( - let binary = binop' Ty_int Add x (v 10) in - let sym = binop' Ty_int Add (v 3) binary in - simplify sym = binop' Ty_int Add (v 13) x ) - -(* Test Concat of Extracts simplifications *) -let () = - assert ( - let x = I32.sym "x" in - let b0 = extract' x ~high:1 ~low:0 in - let b1 = extract' x ~high:2 ~low:1 in - let b2 = extract' x ~high:3 ~low:2 in - let b3 = extract' x ~high:4 ~low:3 in - let b3210 = concat' b3 (concat' b2 (concat' b1 b0)) in - x = simplify b3210 ) diff --git a/test/unit/test_triop.ml b/test/unit/test_triop.ml deleted file mode 100644 index 358dcbf3..00000000 --- a/test/unit/test_triop.ml +++ /dev/null @@ -1,33 +0,0 @@ -open Smtml -open Ty -open Expr -open Value - -let ( = ) = Expr.equal - -let int i = value (Int i) - -let str str = value (Str str) - -(* bool *) -let () = - let ty = Ty_bool in - assert (Expr.equal (triop ty Ite (value True) (int 1) (int 0)) (int 1)); - assert (Expr.equal (triop ty Ite (value False) (int 1) (int 0)) (int 0)) - -(* str *) -let () = - let ty = Ty_str in - assert (triop ty String_extract (str "abcd") (int 1) (int 2) = str "bc"); - assert (triop ty String_index (str "abcd") (str "bc") (int 0) = int 1); - assert ( - triop ty String_replace (str "abcd") (str "bc") (str "ef") = str "aefd" ) - -(* list *) -let () = - let ty = Ty_list in - let list l = value (List l) in - assert ( - Expr.equal - (triop ty List_set (list [ Int 0; Int 1; Int 2 ]) (int 1) (int 3)) - (list [ Int 0; Int 3; Int 2 ]) ) diff --git a/test/unit/test_ty.ml b/test/unit/test_ty.ml deleted file mode 100644 index 210c6e88..00000000 --- a/test/unit/test_ty.ml +++ /dev/null @@ -1,8 +0,0 @@ -open Smtml - -let () = - let x = Expr.symbol (Symbol.make (Ty_bitv 32) "x") in - let x = Expr.extract x ~high:2 ~low:0 in - assert (Ty.equal (Expr.ty x) (Ty_bitv 16)); - let x = Expr.cvtop (Ty_bitv 32) (Sign_extend 16) x in - assert (Ty.equal (Expr.ty x) (Ty_bitv 32)) diff --git a/test/unit/test_unop.ml b/test/unit/test_unop.ml deleted file mode 100644 index 4eeb3324..00000000 --- a/test/unit/test_unop.ml +++ /dev/null @@ -1,88 +0,0 @@ -open Smtml -open Ty -open Expr -open Value - -let ( = ) = Expr.equal - -(* int *) -let () = - let ty = Ty_int in - let v i = value (Int i) in - assert (unop ty Neg (v 1) = v ~-1); - assert (unop ty Abs (v ~-1) = v 1); - assert ( - let x = symbol (Symbol.make ty "x") in - Expr.equal (unop ty Neg (unop ty Neg x)) x ) - -(* real *) -let () = - let ty = Ty_real in - let v f = value (Real f) in - assert (unop ty Neg (v 1.0) = v (-1.0)); - assert (unop ty Abs (v 1.0) = v 1.0); - assert (unop ty Sqrt (v 4.0) = v 2.0); - assert (unop ty Nearest (v 0.504) = v 1.0); - assert (unop ty Ceil (v 0.3) = v 1.0); - assert (unop ty Floor (v 0.7) = v 0.0); - assert (unop ty Trunc (v 1.504) = v 1.0); - assert (unop ty Is_nan (v Float.nan) = value True) - -(* string*) -let () = - let ty = Ty_str in - let v s = value (Str s) in - assert (unop ty Length (v "abc") = value (Int 3)); - assert (unop ty Trim (v " abc\t\n") = value (Str "abc")) - -(* bool *) -let () = - let ty = Ty_bool in - assert (unop ty Not Bool.true_ = Bool.false_); - assert ( - let x = Expr.symbol (Symbol.make ty "x") in - Expr.equal (unop ty Not (unop ty Not x)) x ) - -(* list *) -let () = - let ty = Ty_list in - let v l = value (List l) in - let vlist = v [ Int 1; Int 2; Int 3 ] in - let x = Expr.symbol (Symbol.make Ty_int "x") in - let y = Expr.symbol (Symbol.make Ty_int "y") in - let slist = Expr.make (List [ x; y ]) in - assert (unop ty Head vlist = value (Int 1)); - assert (Expr.equal (unop ty Tail vlist) (v [ Int 2; Int 3 ])); - assert (Expr.equal (unop ty Length vlist) (value (Int 3))); - assert ( - Expr.equal (unop ty Reverse vlist) (value (List [ Int 3; Int 2; Int 1 ])) ); - assert (Expr.equal (unop ty Head slist) x); - assert (Expr.equal (unop ty Tail slist) (Expr.make (List [ y ]))); - assert (Expr.equal (unop ty Length slist) (value (Int 2))); - assert (Expr.equal (unop ty Reverse (unop Ty_list Reverse slist)) slist) - -(* i32 *) -let () = - let ty = Ty_bitv 32 in - let v i = value (Num (I32 i)) in - assert (unop ty Neg (v 1l) = v (-1l)); - assert (unop ty Not (v (-1l)) = v 0l) - -(* i64 *) -let () = - let ty = Ty_bitv 64 in - let v i = value (Num (I64 i)) in - assert (unop ty Neg (v 1L) = v (-1L)); - assert (unop ty Not (v (-1L)) = v 0L) - -(* f32 *) -let () = - let ty = Ty_fp 32 in - let v f = value (Num (F32 (Int32.bits_of_float f))) in - assert (unop ty Trunc (v 0.75) = v 0.0) - -(* f64 *) -let () = - let ty = Ty_fp 64 in - let v f = value (Num (F64 (Int64.bits_of_float f))) in - assert (unop ty Trunc (v 0.75) = v 0.0)