summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jib/jib_smt.ml61
-rw-r--r--src/sail.ml12
2 files changed, 54 insertions, 19 deletions
diff --git a/src/jib/jib_smt.ml b/src/jib/jib_smt.ml
index a8119cd0..eec8ca1e 100644
--- a/src/jib/jib_smt.ml
+++ b/src/jib/jib_smt.ml
@@ -55,26 +55,36 @@ open Jib
open Jib_util
open Smtlib
-let ignore_overflow = ref false
-
let zencode_upper_id id = Util.zencode_upper_string (string_of_id id)
let zencode_id id = Util.zencode_string (string_of_id id)
let zencode_name id = string_of_name ~deref_current_exception:false ~zencode:true id
+let opt_ignore_overflow = ref false
+
type ctx = {
+ (* Arbitrary-precision bitvectors are represented as a (BitVec lbits_index, BitVec (2 ^ lbits_index)) pair. *)
lbits_index : int;
+ (* The size we use for integers where we don't know how large they are statically. *)
lint_size : int;
+ (* A generic vector, vector('a) becomes Array (BitVec vector_index) 'a.
+ We need to take care that vector_index is large enough for all generic vectors. *)
vector_index : int;
register_map : id list CTMap.t;
tc_env : Type_check.Env.t
}
-let opt_lint_size = ref 128
+(* These give the default bounds for various SMT types, stored in the
+ initial_ctx. They shouldn't be read or written by anything else! If
+ they are changed the output of sail -help needs to be updated to
+ reflect this. *)
+let opt_default_lint_size = ref 128
+let opt_default_lbits_index = ref 8
+let opt_default_vector_index = ref 5
let initial_ctx () = {
- lbits_index = 8;
- lint_size = !opt_lint_size;
- vector_index = 5;
+ lbits_index = !opt_default_lbits_index;
+ lint_size = !opt_default_lint_size;
+ vector_index = !opt_default_vector_index;
register_map = CTMap.empty;
tc_env = Type_check.initial_env
}
@@ -86,6 +96,8 @@ let vector_index = ref 5
let smt_unit = mk_enum "Unit" ["Unit"]
let smt_lbits ctx = mk_record "Bits" [("size", Bitvec ctx.lbits_index); ("bits", Bitvec (lbits_size ctx))]
+(* [required_width n] is the required number of bits to losslessly
+ represent an integer n *)
let required_width n =
let rec required_width' n =
if Big_int.equal n Big_int.zero then
@@ -121,6 +133,11 @@ let rec smt_ctyp ctx = function
end
| ctyp -> failwith ("Unhandled ctyp: " ^ string_of_ctyp ctyp)
+(* We often need to create a SMT bitvector of a length sz with integer
+ value x. [bvpint sz x] does this for positive integers, and [bvint sz x]
+ does this for all integers. It's quite awkward because we
+ don't have a very good way to get the binary representation of
+ either an ocaml integer or a big integer. *)
let bvpint sz x =
if Big_int.less_equal Big_int.zero x && Big_int.less_equal x (Big_int.of_int max_int) then (
let open Sail_lib in
@@ -160,11 +177,12 @@ let bvint sz x =
else
bvpint sz x
+(* Translate Jib literals into SMT *)
let smt_value ctx vl ctyp =
let open Value2 in
match vl, ctyp with
| VL_bits (bs, true), CT_fbits (n, _) ->
- (* FIXME: Output the correct number of bits *)
+ (* FIXME: Output the correct number of bits in Jib_compile *)
begin match Sail2_values.hexstring_of_bits (List.rev (Util.take n (List.rev bs))) with
| Some s -> Hex (Xstring.implode s)
| None -> Bin (Xstring.implode (List.map Sail2_values.bitU_char (List.rev (Util.take n (List.rev bs)))))
@@ -227,7 +245,6 @@ let rec smt_cval ctx cval =
end
| V_tuple_member (frag, len, n) ->
Fn (Printf.sprintf "tup_%d_%d" len n, [smt_cval ctx frag])
-
| V_ref (Name (id, _), _) ->
let rmap = CTMap.filter (fun ctyp regs -> List.exists (fun reg -> Id.compare reg id = 0) regs) ctx.register_map in
assert (CTMap.cardinal rmap = 1);
@@ -240,18 +257,20 @@ let rec smt_cval ctx cval =
end
| _ -> assert false
end
-
| cval -> failwith ("Unrecognised cval " ^ string_of_cval ~zencode:false cval)
-
let overflow_checks = Stack.create ()
let overflow_check smt =
- if not !ignore_overflow then (
+ if not !opt_ignore_overflow then (
Util.warn "Adding overflow check in generated SMT";
Stack.push (Define_const ("overflow" ^ string_of_int (Stack.length overflow_checks), Bool, Fn ("not", [smt]))) overflow_checks
)
+(**************************************************************************)
+(* 1. Generating SMT for Sail builtins *)
+(**************************************************************************)
+
let builtin_type_error fn cvals =
let args = Util.string_of_list ", " (fun cval -> string_of_ctyp (cval_ctyp cval)) cvals in
function
@@ -328,7 +347,7 @@ let builtin_arith fn big_int_fn padding ctx v1 v2 ret_ctyp =
to some size determined by a padding function, then check we
don't lose precision when going back after performing the
operation. *)
- let padding = if !ignore_overflow then (fun x -> x) else padding in
+ let padding = if !opt_ignore_overflow then (fun x -> x) else padding in
match cval_ctyp v1, cval_ctyp v2, ret_ctyp with
| _, _, CT_constant c ->
bvint (required_width c) c
@@ -401,6 +420,13 @@ let builtin_abs_int ctx v ret_ctyp =
force_size (int_size ctx ret_ctyp) sz (Fn ("bvneg", [smt])),
force_size (int_size ctx ret_ctyp) sz smt)
+let builtin_pow2 ctx v ret_ctyp =
+ match cval_ctyp v, ret_ctyp with
+ | CT_constant n, _ when Big_int.greater_equal n Big_int.zero ->
+ bvint (int_size ctx ret_ctyp) (Big_int.pow_int_positive 2 (Big_int.to_int n))
+
+ | _ -> builtin_type_error "pow2" [v] (Some ret_ctyp)
+
let builtin_zeros ctx v ret_ctyp =
match cval_ctyp v, ret_ctyp with
| _, CT_fbits (n, _) -> bvzero n
@@ -847,6 +873,7 @@ let smt_builtin ctx name args ret_ctyp =
| "shl_mach_int", [v1; v2], _ -> builtin_shl_int ctx v1 v2 ret_ctyp
| "shr_mach_int", [v1; v2], _ -> builtin_shr_int ctx v1 v2 ret_ctyp
| "abs_int", [v], _ -> builtin_abs_int ctx v ret_ctyp
+ | "pow2", [v], _ -> builtin_pow2 ctx v ret_ctyp
(* All signed and unsigned bitvector comparisons *)
| "slt_bits", [v1; v2], CT_bool -> builtin_compare_bits "bvslt" ctx v1 v2 ret_ctyp
@@ -888,7 +915,7 @@ let smt_builtin ctx name args ret_ctyp =
| "get_slice_int", [v1; v2; v3], ret_ctyp -> builtin_get_slice_int ctx v1 v2 v3 ret_ctyp
| "set_slice", [v1; v2; v3; v4; v5], ret_ctyp -> builtin_set_slice_bits ctx v1 v2 v3 v4 v5 ret_ctyp
- | _ -> failwith ("Bad builtin " ^ name ^ " " ^ Util.string_of_list ", " string_of_ctyp (List.map cval_ctyp args) ^ " -> " ^ string_of_ctyp ret_ctyp)
+ | _ -> failwith ("Unknown builtin " ^ name ^ " " ^ Util.string_of_list ", " string_of_ctyp (List.map cval_ctyp args) ^ " -> " ^ string_of_ctyp ret_ctyp)
let rec smt_conversion ctx from_ctyp to_ctyp x =
match from_ctyp, to_ctyp with
@@ -1248,7 +1275,7 @@ let smt_instr ctx =
[declare_const ctx id ctyp]
| I_aux (I_end id, _) ->
- if !ignore_overflow then
+ if !opt_ignore_overflow then
[Assert (Fn ("not", [Var (zencode_name id)]))]
else
let checks =
@@ -1456,7 +1483,8 @@ let smt_cdef props lets name_file ctx all_cdefs = function
) visit_order;
let out_chan = open_out (name_file (string_of_id function_id)) in
- (* output_string out_chan "(set-option :produce-models true)\n"; *)
+ if prop_type = "counterexample" then
+ output_string out_chan "(set-option :produce-models true)\n";
output_string out_chan "(set-logic QF_AUFBVDT)\n";
(* let stack' = Stack.create () in
@@ -1466,7 +1494,8 @@ let smt_cdef props lets name_file ctx all_cdefs = function
Queue.iter (fun def -> output_string out_chan (string_of_smt_def def); output_string out_chan "\n") queue;
output_string out_chan "(check-sat)\n";
- (* output_string out_chan "(get-model)\n" *)
+ if prop_type = "counterexample" then
+ output_string out_chan "(get-model)\n"
| _ -> failwith "Bad function body"
end
diff --git a/src/sail.ml b/src/sail.ml
index 6ef2bd3a..d9f4c55a 100644
--- a/src/sail.ml
+++ b/src/sail.ml
@@ -128,11 +128,17 @@ let options = Arg.align ([
set_target "smt",
" print SMT translated version of input");
( "-smt_ignore_overflow",
- Arg.Set Jib_smt.ignore_overflow,
+ Arg.Set Jib_smt.opt_ignore_overflow,
" ignore integer overflow in generated SMT");
( "-smt_int_size",
- Arg.String (fun n -> Jib_smt.opt_lint_size := int_of_string n),
- " set a bound on the maximum integer bitwidth for generated SMT");
+ Arg.String (fun n -> Jib_smt.opt_default_lint_size := int_of_string n),
+ "<n> set a bound of n on the maximum integer bitwidth for generated SMT (default 128)");
+ ( "-smt_bits_size",
+ Arg.String (fun n -> Jib_smt.opt_default_lbits_index := int_of_string n),
+ "<n> set a bound of 2 ^ n for bitvector bitwidth in generated SMT (default 8)");
+ ( "-smt_vector_size",
+ Arg.String (fun n -> Jib_smt.opt_default_vector_index := int_of_string n),
+ "<n> set a bound of 2 ^ n for generic vectors in generated SMT (default 5)");
( "-c",
Arg.Tuple [set_target "c"; Arg.Set Initial_check.opt_undefined_gen],
" output a C translated version of the input");