summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast_util.ml1
-rw-r--r--src/ast_util.mli1
-rw-r--r--src/isail.ml16
-rw-r--r--src/pretty_print_sail.ml4
-rw-r--r--src/rewrites.ml4
-rw-r--r--src/specialize.ml86
-rw-r--r--src/type_check.ml50
7 files changed, 144 insertions, 18 deletions
diff --git a/src/ast_util.ml b/src/ast_util.ml
index fdd20050..074376a9 100644
--- a/src/ast_util.ml
+++ b/src/ast_util.ml
@@ -267,6 +267,7 @@ let ntimes n1 n2 = Nexp_aux (Nexp_times (n1, n2), Parse_ast.Unknown)
let npow2 n = Nexp_aux (Nexp_exp n, Parse_ast.Unknown)
let nvar kid = Nexp_aux (Nexp_var kid, Parse_ast.Unknown)
let nid id = Nexp_aux (Nexp_id id, Parse_ast.Unknown)
+let napp id args = Nexp_aux (Nexp_app (id, args), Parse_ast.Unknown)
let nc_set kid nums = mk_nc (NC_set (kid, nums))
let nc_int_set kid ints = mk_nc (NC_set (kid, List.map Big_int.of_int ints))
diff --git a/src/ast_util.mli b/src/ast_util.mli
index 69bd5a52..ec12d44b 100644
--- a/src/ast_util.mli
+++ b/src/ast_util.mli
@@ -127,6 +127,7 @@ val nsum : nexp -> nexp -> nexp
val ntimes : nexp -> nexp -> nexp
val npow2 : nexp -> nexp
val nvar : kid -> nexp
+val napp : id -> nexp list -> nexp
val nid : id -> nexp (* NOTE: Nexp_id's don't do anything currently *)
(* Numeric constraint builders *)
diff --git a/src/isail.ml b/src/isail.ml
index 31e62fb5..629bf35a 100644
--- a/src/isail.ml
+++ b/src/isail.ml
@@ -250,6 +250,22 @@ let handle_input' input =
":(c)ommand can be called as either :c or :command." ]
in
List.iter print_endline commands
+ | ":poly" ->
+ let is_kopt = match arg with
+ | "Int" -> is_nat_kopt
+ | "Type" -> is_typ_kopt
+ | "Order" -> is_order_kopt
+ | _ -> failwith "Invalid kind"
+ in
+ let ids = Specialize.polymorphic_functions is_kopt !interactive_ast in
+ List.iter (fun id -> print_endline (string_of_id id)) (IdSet.elements ids)
+ | ":ins" ->
+ let id = mk_id arg in
+ let instantiations = Specialize.instantiations_of id !interactive_ast in
+ let print_instantiation i =
+ print_endline (Util.string_of_list ", " (fun (kid, uvar) -> string_of_kid kid ^ " => " ^ Type_check.string_of_uvar uvar) (KBindings.bindings i))
+ in
+ List.iter print_instantiation instantiations
| ":output" ->
let chan = open_out arg in
Value.output_redirect chan
diff --git a/src/pretty_print_sail.ml b/src/pretty_print_sail.ml
index 887b15a0..43be7a00 100644
--- a/src/pretty_print_sail.ml
+++ b/src/pretty_print_sail.ml
@@ -74,6 +74,10 @@ let rec doc_nexp =
let rec atomic_nexp (Nexp_aux (n_aux, _) as nexp) =
match n_aux with
| Nexp_constant c -> string (Big_int.to_string c)
+ | Nexp_app (id, nexps) -> string (string_of_nexp nexp)
+ (* This segfaults??!!!!
+ doc_id id ^^ (parens (separate_map (comma ^^ space) doc_nexp nexps))
+ *)
| Nexp_id id -> doc_id id
| Nexp_var kid -> doc_kid kid
| _ -> parens (nexp0 nexp)
diff --git a/src/rewrites.ml b/src/rewrites.ml
index e14ced08..e4ac71cd 100644
--- a/src/rewrites.ml
+++ b/src/rewrites.ml
@@ -515,8 +515,8 @@ let rewrite_sizeof (Defs defs) =
let (params_map, defs) = List.fold_left rewrite_sizeof_def
(Bindings.empty, []) defs in
let defs = List.map (rewrite_sizeof_valspec params_map) defs in
- Defs defs
-(* fst (check initial_env (Defs defs)) *)
+ (* Defs defs *)
+ fst (check initial_env (Defs defs))
let rewrite_defs_remove_assert defs =
let e_assert ((E_aux (eaux, (l, _)) as exp), str) = match eaux with
diff --git a/src/specialize.ml b/src/specialize.ml
new file mode 100644
index 00000000..881881f4
--- /dev/null
+++ b/src/specialize.ml
@@ -0,0 +1,86 @@
+(**************************************************************************)
+(* Sail *)
+(* *)
+(* Copyright (c) 2013-2017 *)
+(* Kathyrn Gray *)
+(* Shaked Flur *)
+(* Stephen Kell *)
+(* Gabriel Kerneis *)
+(* Robert Norton-Wright *)
+(* Christopher Pulte *)
+(* Peter Sewell *)
+(* Alasdair Armstrong *)
+(* Brian Campbell *)
+(* Thomas Bauereiss *)
+(* Anthony Fox *)
+(* Jon French *)
+(* Dominic Mulligan *)
+(* Stephen Kell *)
+(* Mark Wassell *)
+(* *)
+(* All rights reserved. *)
+(* *)
+(* This software was developed by the University of Cambridge Computer *)
+(* Laboratory as part of the Rigorous Engineering of Mainstream Systems *)
+(* (REMS) project, funded by EPSRC grant EP/K008528/1. *)
+(* *)
+(* Redistribution and use in source and binary forms, with or without *)
+(* modification, are permitted provided that the following conditions *)
+(* are met: *)
+(* 1. Redistributions of source code must retain the above copyright *)
+(* notice, this list of conditions and the following disclaimer. *)
+(* 2. Redistributions in binary form must reproduce the above copyright *)
+(* notice, this list of conditions and the following disclaimer in *)
+(* the documentation and/or other materials provided with the *)
+(* distribution. *)
+(* *)
+(* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *)
+(* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *)
+(* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *)
+(* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *)
+(* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *)
+(* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *)
+(* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *)
+(* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *)
+(* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *)
+(* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *)
+(* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *)
+(* SUCH DAMAGE. *)
+(**************************************************************************)
+
+open Ast
+open Ast_util
+open Rewriter
+
+(* Returns an IdSet with the function ids that have X-kinded
+ parameters, e.g. val f : forall ('a : X). 'a -> 'a. The first
+ argument specifies what X should be - it should be one of:
+ is_nat_kopt, is_order_kopt, or is_type_kopt from Ast_util.
+*)
+let rec polymorphic_functions is_kopt (Defs defs) =
+ match defs with
+ | DEF_spec (VS_aux (VS_val_spec (TypSchm_aux (TypSchm_ts (typq, typ) , _), id, _, externs), _)) :: defs ->
+ let is_type_polymorphic = List.exists is_kopt (quant_kopts typq) in
+ if is_type_polymorphic then
+ IdSet.add id (polymorphic_functions is_kopt (Defs defs))
+ else
+ polymorphic_functions is_kopt (Defs defs)
+ | _ :: defs -> polymorphic_functions is_kopt (Defs defs)
+ | [] -> IdSet.empty
+
+(* Returns a list of all the instantiations of a function id in an
+ ast. *)
+let rec instantiations_of id ast =
+ let instantiations = ref [] in
+
+ let inspect_exp = function
+ | E_aux (E_app (id', _), _) as exp when Id.compare id id' = 0 ->
+ instantiations := Type_check.instantiation_of exp :: !instantiations;
+ exp
+ | exp -> exp
+ in
+
+ let rewrite_exp = { id_exp_alg with e_aux = (fun (exp, annot) -> inspect_exp (E_aux (exp, annot))) } in
+ let _ = rewrite_defs_base { rewriters_base with rewrite_exp = (fun _ -> fold_exp rewrite_exp) } ast in
+
+ !instantiations
diff --git a/src/type_check.ml b/src/type_check.ml
index 3353daf4..30334783 100644
--- a/src/type_check.ml
+++ b/src/type_check.ml
@@ -343,6 +343,7 @@ module Env : sig
val base_typ_of : t -> typ -> typ
val add_smt_op : id -> string -> t -> t
val get_smt_op : id -> t -> string
+ val have_smt_op : id -> t -> bool
(* Well formedness-checks *)
val wf_typ : ?exs:KidSet.t -> t -> typ -> unit
val wf_constraint : ?exs:KidSet.t -> t -> n_constraint -> unit
@@ -466,6 +467,9 @@ end = struct
try Bindings.find id env.smt_ops with
| Not_found -> first_smt_op (get_overloads id env)
+ let have_smt_op id env =
+ try ignore(get_smt_op id env); true with Type_error _ -> false
+
let rec infer_kind env id =
if Bindings.mem id builtin_typs then
Bindings.find id builtin_typs
@@ -1336,15 +1340,27 @@ let rec unify_nexps l env goals (Nexp_aux (nexp_aux1, _) as nexp1) (Nexp_aux (ne
else
if KidSet.is_empty (nexp_frees n1a)
then unify_nexps l env goals n1b (nminus nexp2 n1a)
- else unify_error l ("Both sides of Nat expression " ^ string_of_nexp nexp1
+ else unify_error l ("Both sides of Int expression " ^ string_of_nexp nexp1
^ " contain free type variables so it cannot be unified with " ^ string_of_nexp nexp2)
| Nexp_minus (n1a, n1b) ->
if KidSet.is_empty (nexp_frees n1b)
then unify_nexps l env goals n1a (nsum nexp2 n1b)
- else unify_error l ("Cannot unify minus Nat expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
+ else unify_error l ("Cannot unify minus Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
| Nexp_times (n1a, n1b) ->
- if KidSet.is_empty (nexp_frees n1a)
- then
+ (* If we have SMT operations div and mod, then we can use the
+ property that
+
+ mod(m, C) = 0 && C != 0 --> (C * n = m <--> n = m / C)
+
+ to help us unify multiplications. *)
+ if Env.have_smt_op (mk_id "div") env && Env.have_smt_op (mk_id "mod") env then
+ let valid n c = prove env (nc_eq (napp (mk_id "mod") [n; c]) (nint 0)) && prove env (nc_neq c (nint 0)) in
+ if KidSet.is_empty (nexp_frees n1b) && valid nexp2 n1b then
+ unify_nexps l env goals n1a (napp (mk_id "div") [nexp2; n1b])
+ else if KidSet.is_empty (nexp_frees n1a) && valid nexp2 n1a then
+ unify_nexps l env goals n1b (napp (mk_id "div") [nexp2; n1a])
+ else unify_error l ("Cannot unify Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
+ else if KidSet.is_empty (nexp_frees n1a) then
begin
match nexp_aux2 with
| Nexp_times (n2a, n2b) when prove env (NC_aux (NC_equal (n1a, n2a), Parse_ast.Unknown)) ->
@@ -1354,20 +1370,19 @@ let rec unify_nexps l env goals (Nexp_aux (nexp_aux1, _) as nexp1) (Nexp_aux (ne
match n1a with
| Nexp_aux (Nexp_constant c1,_) when Big_int.equal (Big_int.modulus c2 c1) Big_int.zero ->
unify_nexps l env goals n1b (mk_nexp (Nexp_constant (Big_int.div c2 c1)))
- | _ -> unify_error l ("Cannot unify Nat expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
+ | _ -> unify_error l ("Cannot unify Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
end
- | _ -> unify_error l ("Cannot unify Nat expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
+ | _ -> unify_error l ("Cannot unify Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
end
- else if KidSet.is_empty (nexp_frees n1b)
- then
+ else if KidSet.is_empty (nexp_frees n1b) then
begin
match nexp_aux2 with
| Nexp_times (n2a, n2b) when prove env (NC_aux (NC_equal (n1b, n2b), Parse_ast.Unknown)) ->
unify_nexps l env goals n1a n2a
- | _ -> unify_error l ("Cannot unify Nat expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
+ | _ -> unify_error l ("Cannot unify Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
end
- else unify_error l ("Cannot unify Nat expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
- | _ -> unify_error l ("Cannot unify Nat expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
+ else unify_error l ("Cannot unify Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
+ | _ -> unify_error l ("Cannot unify Int expression " ^ string_of_nexp nexp1 ^ " with " ^ string_of_nexp nexp2)
let string_of_uvar = function
| U_nexp n -> string_of_nexp n
@@ -1415,6 +1430,9 @@ let merge_unifiers l kid uvar1 uvar2 =
| None, None -> None
let rec unify l env typ1 typ2 =
+ let typ1 = Env.expand_synonyms env typ1 in
+ let typ2 = Env.expand_synonyms env typ2 in
+
typ_print ("Unify " ^ string_of_typ typ1 ^ " with " ^ string_of_typ typ2);
let goals = KidSet.inter (KidSet.diff (typ_frees typ1) (typ_frees typ2)) (typ_frees typ1) in
let rec unify_typ l (Typ_aux (typ1_aux, _) as typ1) (Typ_aux (typ2_aux, _) as typ2) =
@@ -1991,13 +2009,13 @@ let rec check_exp env (E_aux (exp_aux, (l, ())) as exp : unit exp) (Typ_aux (typ
| ((E_aux (E_assert (constr_exp, assert_msg), _) as exp) :: exps) ->
let constr_exp = crule check_exp env constr_exp bool_typ in
let checked_msg = crule check_exp env assert_msg string_typ in
- let cexp, env = match assert_constraint env constr_exp with
+ let env = match assert_constraint env constr_exp with
| Some nc ->
typ_print ("Adding constraint " ^ string_of_n_constraint nc ^ " for assert");
- annot_exp (E_constraint nc) bool_typ, Env.add_constraint nc env
- | None ->
- constr_exp, env in
- let texp = annot_exp_effect (E_assert (cexp, checked_msg)) unit_typ (mk_effect [BE_escape]) in
+ Env.add_constraint nc env
+ | None -> env
+ in
+ let texp = annot_exp_effect (E_assert (constr_exp, checked_msg)) unit_typ (mk_effect [BE_escape]) in
texp :: check_block l env exps typ
| (exp :: exps) ->
let texp = crule check_exp env exp (mk_typ (Typ_id (mk_id "unit"))) in