summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlasdair Armstrong2018-11-06 17:57:58 +0000
committerAlasdair Armstrong2018-11-06 18:04:02 +0000
commit18c49a76854408d7c2cea74eeb07fd312a5927aa (patch)
tree8a847ae3c597c120b6386c33aa2cd55e2c986d0e
parente8f8f3e65c9cb541712cec3c38de80f78d8fdedb (diff)
Fix bug with loop indices not being mapped to int64 in C
This should fix the issue in cheri128 Also introduce a feature to more easily debug the C backend: sail -dfunction Name will pretty-print the ANF and IR representation of just the Name function. I want to make this work for the type-checker as well, but it's a bit hard to get that to not fire during re-writing passes right now.
-rw-r--r--src/c_backend.ml44
-rw-r--r--src/c_backend.mli3
-rw-r--r--src/sail.ml5
-rw-r--r--src/util.ml2
-rw-r--r--src/util.mli1
-rw-r--r--test/c/cheri128_hsb.expect0
-rw-r--r--test/c/cheri128_hsb.sail62
7 files changed, 102 insertions, 15 deletions
diff --git a/src/c_backend.ml b/src/c_backend.ml
index 4e1bde7e..0c4ae87d 100644
--- a/src/c_backend.ml
+++ b/src/c_backend.ml
@@ -61,7 +61,8 @@ open Anf
module Big_int = Nat_big_num
let c_verbosity = ref 0
-let opt_ddump_flow_graphs = ref false
+let opt_debug_flow_graphs = ref false
+let opt_debug_function = ref ""
let opt_trace = ref false
let opt_static = ref false
let opt_no_main = ref false
@@ -357,6 +358,8 @@ let rec analyze_functions ctx f (AE_aux (aexp, env, l)) =
let aexp2 = analyze_functions ctx f aexp2 in
let aexp3 = analyze_functions ctx f aexp3 in
let aexp4 = analyze_functions ctx f aexp4 in
+ (* Currently we assume that loop indexes are always safe to put into an int64 *)
+ let ctx = { ctx with locals = Bindings.add id (Immutable, CT_int64) ctx.locals } in
AE_for (id, aexp1, aexp2, aexp3, order, aexp4)
| AE_case (aval, cases, typ) ->
@@ -1227,14 +1230,8 @@ let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
cleanup
| AE_for (loop_var, loop_from, loop_to, loop_step, Ord_aux (ord, _), body) ->
- (* This is a bit of a hack, we force loop_var to be CT_int64 by
- forcing it's type to be a known nexp that will map to
- CT_int64. *)
- let make_small _ _ = function
- | AV_id (id, Local (Immutable, typ)) when Id.compare id loop_var = 0 -> AV_id (id, Local (Immutable, atom_typ (nint 0)))
- | aval -> aval
- in
- let body = map_aval make_small body in
+ (* We assume that all loop indices are safe to put in a CT_int64. *)
+ let ctx = { ctx with locals = Bindings.add loop_var (Immutable, CT_int64) ctx.locals } in
let is_inc = match ord with
| Ord_inc -> true
@@ -1573,7 +1570,18 @@ let rec compile_def ctx = function
let aexp = no_shadow (pat_ids pat) (anf exp) in
c_debug (lazy (Pretty_print_sail.to_string (pp_aexp aexp)));
let aexp = analyze_functions ctx analyze_primop (c_literals ctx aexp) in
- c_debug (lazy (Pretty_print_sail.to_string (pp_aexp aexp)));
+
+ if Id.compare (mk_id !opt_debug_function) id = 0 then
+ let header =
+ Printf.sprintf "Sail ANF for %s %s %s. (%s) -> %s" Util.("function" |> red |> clear) (string_of_id id)
+ (string_of_typquant quant)
+ Util.(string_of_list ", " (fun typ -> string_of_typ typ |> yellow |> clear) arg_typs)
+ Util.(string_of_typ ret_typ |> yellow |> clear)
+
+ in
+ prerr_endline (Util.header header (List.length arg_typs + 2));
+ prerr_endline (Pretty_print_sail.to_string (pp_aexp aexp))
+ else ();
(* Compile the function arguments as patterns. *)
let arg_setup, compiled_args, arg_cleanup = compile_arg_pats ctx fundef_label pat arg_ctyps in
@@ -2779,9 +2787,7 @@ let codegen_def' ctx = function
string (Printf.sprintf "%svoid %s(%s *rop, %s);" static (sgen_id id) (sgen_ctyp ret_ctyp) (Util.string_of_list ", " sgen_ctyp arg_ctyps))
| CDEF_fundef (id, ret_arg, args, instrs) as def ->
- if !opt_ddump_flow_graphs then make_dot id (instrs_graph instrs) else ();
-
- c_debug (lazy (Pretty_print_sail.to_string (separate_map hardline pp_instr instrs)));
+ if !opt_debug_flow_graphs then make_dot id (instrs_graph instrs) else ();
(* Extract type information about the function from the environment. *)
let quant, Typ_aux (fn_typ, _) = Env.get_val_spec id ctx.tc_env in
@@ -2800,6 +2806,18 @@ let codegen_def' ctx = function
^ Util.string_of_list ", " string_of_ctyp arg_ctyps)
else ();
+ (* If this function is set as opt_debug_function, then output its IR *)
+ if Id.compare (mk_id !opt_debug_function) id = 0 then
+ let header =
+ Printf.sprintf "Sail IR for %s %s(%s) : (%s) -> %s" Util.("function" |> red |> clear) (string_of_id id)
+ (Util.string_of_list ", " string_of_id args)
+ (Util.string_of_list ", " (fun ctyp -> Util.(string_of_ctyp ctyp |> yellow |> clear)) arg_ctyps)
+ Util.(string_of_ctyp ret_ctyp |> yellow |> clear)
+ in
+ prerr_endline (Util.header header (List.length arg_ctyps + 2));
+ prerr_endline (Pretty_print_sail.to_string (separate_map hardline pp_instr instrs))
+ else ();
+
let instrs = add_local_labels instrs in
let args = Util.string_of_list ", " (fun x -> x) (List.map2 (fun ctyp arg -> sgen_ctyp ctyp ^ " " ^ sgen_id arg) arg_ctyps args) in
let function_header =
diff --git a/src/c_backend.mli b/src/c_backend.mli
index 170c5bd9..6048f6b6 100644
--- a/src/c_backend.mli
+++ b/src/c_backend.mli
@@ -53,7 +53,8 @@ open Type_check
(** Global compilation options *)
-val opt_ddump_flow_graphs : bool ref
+val opt_debug_flow_graphs : bool ref
+val opt_debug_function : string ref
val opt_trace : bool ref
val opt_static : bool ref
val opt_no_main : bool ref
diff --git a/src/sail.ml b/src/sail.ml
index 4fd35902..3505ecf4 100644
--- a/src/sail.ml
+++ b/src/sail.ml
@@ -223,7 +223,7 @@ let options = Arg.align ([
Arg.String (fun l -> opt_ddump_rewrite_ast := Some (l, 0)),
"<prefix> (debug) dump the ast after each rewriting step to <prefix>_<i>.lem");
( "-ddump_flow_graphs",
- Arg.Set C_backend.opt_ddump_flow_graphs,
+ Arg.Set C_backend.opt_debug_flow_graphs,
" (debug) dump flow analysis for Sail functions when compiling to C");
( "-dtc_verbose",
Arg.Int (fun verbosity -> Type_check.opt_tc_debug := verbosity),
@@ -237,6 +237,9 @@ let options = Arg.align ([
( "-dmagic_hash",
Arg.Set Initial_check.opt_magic_hash,
" (debug) allow special character # in identifiers");
+ ( "-dfunction",
+ Arg.String (fun f -> C_backend.opt_debug_function := f),
+ " (debug) print debugging output for a single function");
( "-Xconstraint_synonyms",
Arg.Set Type_check.opt_constraint_synonyms,
" (extension) allow constraint synonyms");
diff --git a/src/util.ml b/src/util.ml
index c0b88815..2e121a4f 100644
--- a/src/util.ml
+++ b/src/util.ml
@@ -455,3 +455,5 @@ let warn str =
let log_line str line msg =
"\n[" ^ (str ^ ":" ^ string_of_int line |> blue |> clear) ^ "] " ^ msg
+
+let header str n = "\n" ^ str ^ "\n" ^ String.make (String.length str - 9 * n) '='
diff --git a/src/util.mli b/src/util.mli
index 5bb7c559..1d80bc10 100644
--- a/src/util.mli
+++ b/src/util.mli
@@ -260,3 +260,4 @@ val zencode_string : string -> string
val zencode_upper_string : string -> string
val log_line : string -> int -> string -> string
+val header : string -> int -> string
diff --git a/test/c/cheri128_hsb.expect b/test/c/cheri128_hsb.expect
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/c/cheri128_hsb.expect
diff --git a/test/c/cheri128_hsb.sail b/test/c/cheri128_hsb.sail
new file mode 100644
index 00000000..a06a2ad2
--- /dev/null
+++ b/test/c/cheri128_hsb.sail
@@ -0,0 +1,62 @@
+default Order dec
+
+$include <flow.sail>
+$include <arith.sail>
+$include <option.sail>
+$include <vector_dec.sail>
+$include <exception_basic.sail>
+
+val modulus = {ocaml: "modulus", lem: "hardware_mod", coq: "euclid_modulo", _ : "tmod_int"} : forall 'n, 'n > 0 . (int, atom('n)) -> range(0, 'n - 1)
+
+val add_range = {ocaml: "add_int", lem: "integerAdd", coq: "add_range", c: "add_int"} : forall 'n 'm 'o 'p.
+ (range('n, 'm), range('o, 'p)) -> range('n + 'o, 'm + 'p)
+
+val sub_range = {ocaml: "sub_int", lem: "integerMinus", coq: "sub_range"} : forall 'n 'm 'o 'p.
+ (range('n, 'm), range('o, 'p)) -> range('n - 'p, 'm - 'o)
+
+val min = {ocaml: "min_int", lem: "min", coq: "min_atom", c:"min_int"} : forall 'a 'b . (atom('a), atom('b)) -> {'c, ('c = 'a | 'c = 'b) & 'c <= 'a & 'c <= 'b . atom('c)}
+
+overload operator + = {add_range}
+overload operator - = {sub_range}
+
+infix 1 >>
+infix 1 <<
+
+val "shift_bits_right" : forall 'n 'm. (bits('n), bits('m)) -> bits('n) effect {undef}
+val "shift_bits_left" : forall 'n 'm. (bits('n), bits('m)) -> bits('n) effect {undef}
+
+val "shiftl" : forall 'm 'n, 'n >= 0. (bits('m), atom('n)) -> bits('m)
+val "shiftr" : forall 'm 'n, 'n >= 0. (bits('m), atom('n)) -> bits('m)
+
+overload operator >> = {shift_bits_right, shiftr}
+overload operator << = {shift_bits_left, shiftl}
+
+val HighestSetBit : forall 'N , 'N >= 2. bits('N) -> {'n, 0 <= 'n < 'N . (bool, atom('n))}
+
+function HighestSetBit x = {
+ foreach (i from ('N - 1) to 0 by 1 in dec)
+ if [x[i]] == 0b1 then return (true, i);
+ return (false, 0)
+}
+
+/* hw rounds up E to multiple of 4 */
+function roundUp(e) : range(0, 45) -> range(0, 48) =
+ let 'r = modulus(e, 4) in
+ if (r == 0)
+ then e
+ else (e - r + 4)
+
+function computeE (rlength) : bits(65) -> range(0, 48) =
+ let (nonzero, 'msb) = HighestSetBit((rlength + (rlength >> 6)) >> 19) in
+ if nonzero then
+ /* above will always return <= 45 because 19 bits of zero are shifted in from right */
+ {assert(0 <= msb & msb <= 45); roundUp (min(msb,45)) }
+ else
+ 0
+
+val main : unit -> unit effect {escape}
+
+function main() = {
+ let _ = computeE(0xFFFF_FFFF_FFFF_FFFF @ 0b1);
+ ()
+} \ No newline at end of file