-
BRUN Lelio authoredBRUN Lelio authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
c_backend_spec.ml 62.83 KiB
(********************************************************************)
(* *)
(* The LustreC compiler toolset / The LustreC Development Team *)
(* Copyright 2012 - -- ONERA - CNRS - INPT *)
(* *)
(* LustreC is free software, distributed WITHOUT ANY WARRANTY *)
(* under the terms of the GNU Lesser General Public License *)
(* version 2.1. *)
(* *)
(********************************************************************)
open Utils
open Format
open Lustre_types
open Machine_code_types
open C_backend_common
open Corelang
open Spec_types
open Machine_code_common
module Mpfr = Lustrec_mpfr
(**************************************************************************)
(* Printing spec for c *)
(**************************************************************************)
let pp_acsl_basic_type_desc t_desc =
if Types.is_bool_type t_desc then
(* if !Options.cpp then "bool" else "_Bool" *)
"_Bool"
else if Types.is_int_type t_desc then
(* !Options.int_type *)
if t_desc.tid = -1 then "int" else "integer"
else if Types.is_real_type t_desc then
if !Options.mpfr then Mpfr.mpfr_t else !Options.real_type
else assert false
(* Not a basic C type. Do not handle arrays or pointers *)
let pp_acsl ?(ghost = false) pp fmt x =
let op = if ghost then "" else "*" in
let cl = if ghost then "@" else "*" in
fprintf fmt "@[<v>/%s%@ @[<v>%a@]@,%s/@]" op pp x cl
let pp_acsl_cut ?ghost pp fmt = fprintf fmt "%a@," (pp_acsl ?ghost pp)
let pp_acsl_line pp fmt = fprintf fmt "//%@ @[<h>%a@]" pp
let pp_acsl_line_cut pp fmt = fprintf fmt "%a@," (pp_acsl_line pp)
let pp_acsl_line' ?(ghost = false) pp fmt x =
let op = if ghost then "" else "*" in
let cl = if ghost then "@" else "*" in
fprintf fmt "/%s%@ @[<h>%a@] %s/" op pp x cl
let pp_acsl_line'_cut ?ghost pp fmt =
fprintf fmt "%a@," (pp_acsl_line' ?ghost pp)
let pp_requires pp fmt = fprintf fmt "requires %a;@," pp
let pp_ensures pp fmt = fprintf fmt "ensures %a;@," pp
let pp_terminates pp fmt = fprintf fmt "terminates %a;@," pp
let pp_assigns pp =
pp_comma_list
~pp_prologue:(fun fmt () -> pp_print_string fmt "assigns ")
~pp_epilogue:(fun fmt () -> fprintf fmt ";@,")
pp
let pp_ghost pp fmt = fprintf fmt "ghost %a" pp
let pp_assert pp fmt = fprintf fmt "assert %a;@," pp
let pp_loop_invariant pp fmt = fprintf fmt "loop invariant %a;@," pp
let pp_mem_valid pp_var fmt (name, var) =
fprintf fmt "%s_valid(%a)" name pp_var var
let pp_mem_valid' = pp_mem_valid pp_print_string
let pp_ref pp fmt = fprintf fmt "&%a" pp
let pp_ref' = pp_ref pp_print_string
let pp_indirect pp_ptr pp_field fmt (ptr, field) =
fprintf fmt "%a->%a" pp_ptr ptr pp_field field
let pp_indirect' = pp_indirect pp_print_string pp_print_string
let pp_access pp_stru pp_field fmt (stru, field) =
fprintf fmt "%a.%a" pp_stru stru pp_field field
let pp_access' = pp_access pp_print_string pp_print_string
let pp_var_decl fmt v = pp_print_string fmt v.var_id
let pp_true fmt () = pp_print_string fmt "\\true"
let pp_cast pp_ty pp fmt (ty, x) = fprintf fmt "(%a) %a" pp_ty ty pp x
let pp_bool_cast pp fmt x = pp_cast pp_print_string pp fmt ("_Bool", x)
let pp_double_cast pp fmt x = pp_cast pp_print_string pp fmt ("double", x)
let pp_int_cast pp fmt x = pp_cast pp_print_string pp fmt ("int", x)
let pp_true_c_bool fmt () = pp_bool_cast pp_print_string fmt "1"
let pp_false fmt () = pp_print_string fmt "\\false"
let pp_nothing fmt () = pp_print_string fmt "\\nothing"
let pp_null fmt () = pp_print_string fmt "\\null"
let pp_stdout fmt () = pp_print_string fmt "stdout"
let instances machines m =
let rec aux m =
List.(
fold_left
(fun insts (inst, (td, _)) ->
let mems, insts' =
try
let m' = find_machine (node_name td) machines in
m'.mmemory, aux m'
with Not_found ->
if Arrow.td_is_arrow td then arrow_machine.mmemory, [ [] ]
else assert false
in
insts @ map (cons (inst, (td, mems))) insts')
[ [] ]
m.minstances)
in
match aux m with [] :: l -> l | l -> l
let pp_instance ?(indirect = true) ?pp_epilogue fmt =
pp_print_list
~pp_sep:(fun fmt () -> pp_print_string fmt (if indirect then "->" else "."))
?pp_epilogue
(fun fmt (i, _) -> pp_print_string fmt i)
fmt
let pp_reg ?(indirect = true) self fmt paths =
fprintf
fmt
"%s->%a%s"
self
(pp_instance ~indirect ~pp_epilogue:(fun fmt () ->
pp_print_string fmt (if indirect then "->" else ".")))
paths
"_reg"
let pp_separated pp_self pp_mem pp_ptr fmt (self, mem, paths, ptrs) =
fprintf
fmt
"\\separated(@[<v>%a, %a%a%a@])"
pp_self
self
pp_mem
mem
(pp_comma_list ~pp_prologue:pp_print_comma (fun fmt path ->
pp_indirect pp_self pp_instance fmt (self, path)))
paths
(pp_comma_list ~pp_prologue:pp_print_comma pp_ptr)
ptrs
let pp_separated' self mem fmt (paths, ptrs) =
pp_separated
pp_print_string
pp_print_string
pp_var_decl
fmt
(self, mem, paths, ptrs)
let pp_separated'' =
pp_comma_list
~pp_prologue:(fun fmt () -> pp_print_string fmt "\\separated(")
~pp_epilogue:pp_print_cpar
pp_var_decl
let pp_forall pp_l pp_r fmt (l, r) =
fprintf fmt "@[<v 2>\\forall @[<hov>%a@];@,%a@]" pp_l l pp_r r
let pp_exists pp_l pp_r fmt (l, r) =
fprintf fmt "@[<v 2>\\exists %a;@,%a@]" pp_l l pp_r r
let pp_equal pp_l pp_r fmt (l, r) = fprintf fmt "%a == %a" pp_l l pp_r r
let pp_gequal pp_l pp_r fmt (l, r) = fprintf fmt "%a >= %a" pp_l l pp_r r
let pp_implies pp_l pp_r fmt (l, r) =
fprintf fmt "@[<v>%a ==>@ %a@]" pp_l l pp_r r
let pp_and pp_l pp_r fmt (l, r) = fprintf fmt "@[<v>%a @ && %a@]" pp_l l pp_r r
let pp_and_l pp_v fmt =
pp_print_list
~pp_open_box:pp_open_vbox0
~pp_sep:(fun fmt () -> fprintf fmt "@,&& ")
~pp_nil:pp_true
pp_v
fmt
let pp_or pp_l pp_r fmt (l, r) = fprintf fmt "@[<v>%a @ || %a@]" pp_l l pp_r r
let pp_or_l pp_v fmt =
pp_print_list
~pp_open_box:pp_open_vbox0
~pp_sep:(fun fmt () -> fprintf fmt "@,|| ")
pp_v
fmt
let pp_not pp fmt = fprintf fmt "!%a" pp
let pp_valid pp = pp_and_l (fun fmt x -> fprintf fmt "\\valid(%a)" pp x)
let pp_valid_read pp fmt = fprintf fmt "\\valid_read(%a)" pp
let pp_old pp fmt = fprintf fmt "\\old(%a)" pp
let pre_label = "Pre"
let pp_at pp l fmt x = fprintf fmt "\\at(%a, %s)" pp x l
let pp_ite pp_c pp_t pp_f fmt (c, t, f) =
fprintf fmt "(%a @[<hov>? %a@ : %a)@]" pp_c c pp_t t pp_f f
let pp_paren pp fmt v = fprintf fmt "(%a)" pp v
let pp_initialization pp_mem fmt (name, mem) =
fprintf fmt "%s_initialization(%a)" name pp_mem mem
let pp_initialization' = pp_initialization pp_print_string
let pp_local m =
pp_c_decl_local_var ~pp_c_basic_type_desc:pp_acsl_basic_type_desc m
let pp_locals m =
pp_comma_list ~pp_open_box:(fun fmt () -> pp_open_hovbox fmt 0) (pp_local m)
let pp_ptr_decl fmt v = pp_ptr fmt v.var_id
let pp_basic_assign_spec ?(pp_op = pp_equal) pp_l pp_r fmt (typ, var_name, value)
=
if Types.is_real_type typ && !Options.mpfr then assert false
(* Mpfr.pp_inject_assign pp_var fmt (var_name, value) *)
else pp_op pp_l pp_r fmt (var_name, value)
let pp_assign_spec ?pp_op m self_l pp_var_l indirect_l self_r pp_var_r
indirect_r fmt (var_type, var_name, value) =
let depth = expansion_depth value in
let loop_vars = mk_loop_variables m var_type depth in
let reordered_loop_vars = reorder_loop_variables loop_vars in
let aux typ fmt vars =
match vars with
| [] ->
pp_basic_assign_spec
?pp_op
(pp_value_suffix
~indirect:indirect_l
m
self_l
var_type
loop_vars
pp_var_l)
(pp_value_suffix
~indirect:indirect_r
m
self_r
var_type
loop_vars
pp_var_r)
fmt
(typ, var_name, value)
| (_d, LVar _i) :: _q ->
assert false
(* let typ' = Types.array_element_type typ in
* fprintf fmt "@[<v 2>{@,int %s;@,for(%s=0;%s<%a;%s++)@,%a @]@,}"
* i i i pp_c_dimension d i
* (aux typ') q *)
| (_d, LInt _r) :: _q ->
assert false
(* let typ' = Types.array_element_type typ in
* let szl = Utils.enumerate (Dimension.size_const_dimension d) in
* fprintf fmt "@[<v 2>{@,%a@]@,}"
* (pp_print_list (fun fmt i -> r := i; aux typ' fmt q)) szl *)
| _ ->
assert false
in
reset_loop_counter ();
aux var_type fmt reordered_loop_vars
let pp_memory_pack_base_aux pp_mem pp_self fmt (name, mem, self) =
fprintf fmt "%s_pack_base(@[<hov>%a,@ %a@])" name pp_mem mem pp_self self
let pp_memory_pack_aux_taint ?i pp_mem_reset pp_mem pp_self fmt
(name, mem_reset, mem, self) =
fprintf
fmt
"%s_pack%a(@[<hov>%a,@ %a,@ %a@])"
name
(pp_print_option pp_print_int)
i
pp_mem_reset
mem_reset
pp_mem
mem
pp_self
self
let pp_memory_pack_aux pp_mem pp_self fmt (name, mem, self) =
fprintf fmt "%s_pack(@[<hov>%a,@ %a@])" name pp_mem mem pp_self self
let pp_memory_pack_taint pp_mem_reset pp_mem pp_self fmt
(mp, mem_reset, mem, self) =
pp_memory_pack_aux_taint
?i:mp.mpindex
pp_mem_reset
pp_mem
pp_self
fmt
(mp.mpname.node_id, mem_reset, mem, self)
let pp_memory_pack pp_mem pp_self fmt (mp, mem, self) =
pp_memory_pack_aux pp_mem pp_self fmt (mp.mpname.node_id, mem, self)
let pp_transition_aux ?i stateless pp_mem_in pp_mem_out pp_var fmt
(name, vars, mem_in, mem_out) =
fprintf
fmt
"%s_transition%a(@[<hov>%t%a%t@])"
name
(pp_print_option pp_print_int)
i
(fun fmt -> if not stateless then pp_mem_in fmt mem_in)
(pp_comma_list
~pp_prologue:(fun fmt () -> if not stateless then pp_print_comma fmt ())
pp_var)
vars
(fun fmt -> if not stateless then fprintf fmt ",@ %a" pp_mem_out mem_out)
let pp_transition stateless pp_mem_in pp_mem_out pp_var fmt (t, mem_in, mem_out)
=
pp_transition_aux
?i:t.tindex
stateless
pp_mem_in
pp_mem_out
pp_var
fmt
(t.tname.node_id, t.tvars, mem_in, mem_out)
let pp_transition_aux' ?i m =
let stateless = fst (get_stateless_status m) in
pp_transition_aux ?i stateless pp_print_string pp_print_string (fun fmt v ->
(if is_output m v then pp_ptr_decl else pp_var_decl) fmt v)
let pp_reset_set pp_mem fmt (name, mem) =
fprintf fmt "%s_reset_set(%a)" name pp_mem mem
let pp_reset_set' = pp_reset_set pp_print_string
let pp_functional_update mems insts fmt mem =
let rec aux fmt = function
| [] ->
pp_print_string fmt mem
| (x, is_mem) :: fields ->
fprintf
fmt
"{ @[<hov>%a@ \\with .%s%s = %s@] }"
aux
fields
(if is_mem then "_reg." else "")
x
x
in
aux
fmt
(List.map (fun (x, _) -> x, false) (Utils.IMap.bindings insts)
@ List.map (fun x -> x, true) (Utils.ISet.elements mems))
module PrintSpec = struct
type mode =
| MemoryPackMode
| TransitionMode
| TransitionFootprintMode
| ResetIn
| ResetOut
| InstrMode of ident
let not_var v = match v.value_desc with Var _ -> false | _ -> true
let is_const v = match v.value_desc with Cst _ -> true | _ -> false
let pp_expr ?(test_output = false) m mem fmt = function
| Val v ->
let pp = pp_c_val ~indirect:false m mem (pp_c_var_read ~test_output m) in
(if not_var v then
if Types.is_bool_type v.value_type then pp_bool_cast pp
else if Types.is_real_type v.value_type then pp_double_cast pp
else if is_const v && Types.is_int_type v.value_type then
pp_int_cast pp
else pp
else pp)
fmt
v
| Tag (t, _) ->
pp_print_string fmt t
| Var v ->
pp_var_decl fmt v
| Memory r ->
fprintf fmt "%s.%a" mem pp_var_decl r
let pp_predicate mode m mem_in mem_in' mem_out mem_out' fmt p =
let test_output, mem_update =
match mode with
| InstrMode _ ->
true, false
| TransitionFootprintMode ->
false, true
| _ ->
false, false
in
let pp_expr test_output fmt e = pp_expr ~test_output m mem_out fmt e in
match p with
| Transition (stateless, f, inst, i, vars, r, mems, insts) ->
let pp_mem_in, pp_mem_out =
match inst with
| None ->
( pp_print_string,
if mem_update then pp_functional_update mems insts
else pp_print_string )
| Some inst ->
( (fun fmt mem_in ->
if r then pp_print_string fmt mem_in
else pp_access' fmt (mem_in, inst)),
fun fmt mem_out -> pp_access' fmt (mem_out, inst) )
in
pp_transition_aux
?i
stateless
pp_mem_in
pp_mem_out
(pp_expr test_output)
fmt
(f, vars, mem_in', mem_out')
| Reset (f, inst, r) ->
pp_ite
(pp_c_val m mem_in (pp_c_var_read m))
pp_initialization'
(* (pp_equal (pp_reset_flag' ~indirect:false) pp_print_int) *)
(pp_equal pp_print_string pp_access')
fmt
(r, (f, mem_out), (mem_out, (mem_in, inst)))
| MemoryPackBase f ->
pp_memory_pack_base_aux
pp_print_string
pp_print_string
fmt
(f, mem_out, mem_in)
| MemoryPack (f, inst, i) -> (
match inst with
| Some inst ->
let pp_mem, pp_self =
( (fun fmt mem -> pp_access' fmt (mem, inst)),
fun fmt self -> pp_indirect' fmt (self, inst) )
in
pp_memory_pack_aux pp_mem pp_self fmt (f, mem_out, mem_in)
| None ->
pp_memory_pack_aux_taint
?i
pp_print_string
pp_print_string
pp_print_string
fmt
(f, mem_in', mem_out, mem_in))
| GhostAssign (v1, v2) ->
pp_ghost (pp_assign m mem_in (pp_c_var_read m)) fmt (v1, v2)
let reset_flag = dummy_var_decl "_reset" Type_predef.type_bool
let val_of_expr = function
| Val v ->
v
| Tag (t, _) ->
id_to_tag t
| Var v ->
vdecl_to_val v
| Memory v ->
vdecl_to_val v
let find_arrow_val =
let bad_inits = Hashtbl.create 32 in
let rec find_arrow_val loc m v =
let find = find_arrow_val loc m in
match v.value_desc with
| Var v -> (
match find_tainter_arrow m v with
| Some (Some a) ->
Some a
| Some None ->
if not (Hashtbl.mem bad_inits v) then (
Hashtbl.add bad_inits v ();
Error.pp_warning loc (fun fmt ->
fprintf
fmt
"Generating stateful spec for uninitialized state variable \
%s."
v.var_id));
None
| None ->
None)
| Array vl | Fun (_, vl) ->
List.find_map find vl
| Access (t, i) | Power (t, i) -> (
match find t with None -> find i | a -> a)
| _ ->
None
in
find_arrow_val
let find_arrow loc m = function Val v -> find_arrow_val loc m v | _ -> None
let pp_spec mode m fmt f =
let rec pp_spec mode fmt f =
let mem_in, mem_in', indirect_r, mem_out, mem_out', indirect_l =
let self = mk_self m in
let mem = mk_mem m in
let mem_in = mk_mem_in m in
let mem_out = mk_mem_out m in
let mem_reset = mk_mem_reset m in
match mode with
| MemoryPackMode ->
self, mem, true, mem, mem, false
| TransitionMode ->
mem_in, mem_in, false, mem_out, mem_out, false
| TransitionFootprintMode ->
mem_in, mem_in, false, mem_out, mem_out, false
| ResetIn ->
mem_reset, mem_reset, false, mem_out, mem_out, false
| ResetOut ->
mem_in, mem_in, false, mem_reset, mem_reset, false
| InstrMode self ->
pp_at pp_ptr pre_label str_formatter mem;
let mem_reset = flush_str_formatter () in
fprintf str_formatter "(%a)" pp_ptr mem;
let mem = flush_str_formatter () in
self, mem_reset, false, mem, mem, false
in
let pp_expr fmt e = pp_expr m mem_in' fmt e in
let pp_spec' = pp_spec mode in
match f with
| True ->
pp_true fmt ()
| False ->
pp_false fmt ()
| Equal (a, b) ->
let pp_eq fmt () =
pp_assign_spec
m
mem_out
(pp_c_var_read ~test_output:false m)
indirect_l
mem_in
(pp_c_var_read ~test_output:false m)
indirect_r
fmt
(Spec_common.type_of_value a, val_of_expr a, val_of_expr b)
in
let inst = find_arrow Location.dummy m b in
pp_print_option
~none:pp_eq
(fun fmt inst ->
pp_paren
(pp_implies (pp_not (pp_initialization pp_access')) pp_eq)
fmt
((Arrow.arrow_id, (mem_in, inst)), ()))
fmt
inst
| GEqual (a, b) ->
pp_assign_spec
~pp_op:pp_gequal
m
mem_out
(pp_c_var_read ~test_output:false m)
indirect_l
mem_in
(pp_c_var_read ~test_output:false m)
indirect_r
fmt
(Spec_common.type_of_value a, val_of_expr a, val_of_expr b)
| And fs ->
pp_and_l pp_spec' fmt fs
| Or fs ->
pp_or_l pp_spec' fmt fs
| Imply (a, b) ->
pp_paren (pp_implies pp_spec' pp_spec') fmt (a, b)
| Exists ([ x ], a) ->
pp_exists (pp_local m) pp_spec' fmt (x, a)
| Exists (xs, a) ->
pp_spec' fmt (List.fold_left (fun spec x -> Exists ([ x ], spec)) a xs)
| Forall (xs, a) ->
pp_forall (pp_locals m) pp_spec' fmt (xs, a)
| Ternary (e, a, b) ->
let pp_ite fmt () = pp_ite pp_expr pp_spec' pp_spec' fmt (e, a, b) in
let inst = find_arrow Location.dummy m e in
pp_print_option
~none:pp_ite
(fun fmt inst ->
pp_paren
(pp_implies (pp_not (pp_initialization pp_access')) pp_ite)
fmt
((Arrow.arrow_id, (mem_in, inst)), ()))
fmt
inst
| Predicate p ->
pp_predicate mode m mem_in mem_in' mem_out mem_out' fmt p
| StateVarPack (v, tainted) ->
let v' = vdecl_to_val v in
let pp_eq fmt () =
pp_assign_spec
m
mem_out
(pp_c_var_read ~test_output:false m)
indirect_l
mem_in
(pp_c_var_read ~test_output:false m)
indirect_r
fmt
(v.var_type, v', v')
in
let inst = find_arrow Location.dummy m (Val v') in
let mem_reset = mk_mem_reset m in
pp_print_option
~none:pp_eq
(fun fmt inst ->
pp_paren
(pp_implies (pp_not (pp_initialization pp_access')) pp_eq)
fmt
( ( Arrow.arrow_id,
((if tainted then mem_reset else mem_out), inst) ),
() ))
fmt
inst
| ExistsMem (f, rc, tr) ->
pp_exists
(pp_machine_decl' ~ghost:true)
(pp_and (pp_spec ResetOut) (pp_spec ResetIn))
fmt
((f, mk_mem_reset m), (rc, tr))
| Value v ->
pp_c_val m mem_in (pp_c_var_read ~test_output:true m) fmt v
| MemoryPackToplevel (f, i) ->
pp_ite
(pp_reset_flag' ~indirect:true)
pp_initialization'
(pp_memory_pack_aux_taint
~i
pp_print_string
pp_print_string
pp_print_string)
fmt
(mem_in, (f, mem_out), (f, mem_out, mem_out, mem_in))
in
pp_spec mode fmt (Spec_common.red f)
end
let pp_predicate pp_l pp_r fmt (l, r) =
fprintf fmt "@[<v 2>predicate %a =@,%a;@]" pp_l l pp_r r
let pp_lemma pp_l pp_r fmt (l, r) =
fprintf fmt "@[<v 2>lemma %a:@,%a;@]" pp_l l pp_r r
let pp_mem_valid_def fmt m =
if not (fst (get_stateless_status m) || m.mis_contract) then
let name = m.mname.node_id in
let self = mk_self m in
pp_acsl
(pp_predicate
(pp_mem_valid (pp_machine_decl pp_ptr))
(pp_and
(pp_and_l (fun fmt (inst, (td, _)) ->
if Arrow.td_is_arrow td then
pp_valid pp_indirect' fmt [ self, inst ]
else pp_mem_valid pp_indirect' fmt (node_name td, (self, inst))))
(pp_valid pp_print_string)))
fmt
((name, (name, self)), (m.minstances, [ self ]))
let pp_memory_pack_base_def m fmt f =
if not (fst (get_stateless_status m) || m.mis_contract) then
let name = m.mname.node_id in
let self = mk_self m in
let mem = mk_mem m in
pp_acsl_cut
(pp_predicate
(pp_memory_pack_base_aux
(pp_machine_decl' ~ghost:true)
(pp_machine_decl pp_ptr))
(pp_and
(pp_equal (pp_reset_flag' ~indirect:true) pp_print_int)
(PrintSpec.pp_spec MemoryPackMode m)))
fmt
((name, (name, mem), (name, self)), ((self, 0), f))
let pp_memory_pack_def m fmt mp =
if not (fst (get_stateless_status m) || m.mis_contract) then
let name = mp.mpname.node_id in
let self = mk_self m in
let mem = mk_mem m in
let mem_reset = mk_mem_reset m in
if mp.mpindex = None then
pp_acsl_cut
(pp_predicate
(pp_memory_pack
(pp_machine_decl' ~ghost:true)
(pp_machine_decl pp_ptr))
(PrintSpec.pp_spec MemoryPackMode m))
fmt
((mp, (name, mem), (name, self)), mp.mpformula)
else
pp_acsl_cut
(pp_predicate
(pp_memory_pack_taint
(pp_machine_decl' ~ghost:true)
(pp_machine_decl' ~ghost:true)
(pp_machine_decl pp_ptr))
(PrintSpec.pp_spec MemoryPackMode m))
fmt
((mp, (name, mem_reset), (name, mem), (name, self)), mp.mpformula)
let pp_machine_ghost_struct fmt m =
pp_acsl (pp_ghost (pp_machine_struct ~ghost:true)) fmt m
let pp_memory_pack_defs fmt m =
if not (fst (get_stateless_status m)) then
fprintf
fmt
"%a%a"
(pp_memory_pack_base_def m)
m.mspec.mmemory_pack_base
(pp_print_list
~pp_sep:pp_print_nothing
~pp_epilogue:pp_print_cut
~pp_open_box:pp_open_vbox0
(pp_memory_pack_def m))
(snd m.mspec.mmemory_packs)
let pp_transition_def m fmt t =
let name = t.tname.node_id in
let mem_in = mk_mem_in m in
let mem_out = mk_mem_out m in
let stateless = fst (get_stateless_status m) in
pp_acsl
(pp_predicate
(pp_transition
stateless
(pp_machine_decl' ~ghost:true)
(pp_machine_decl' ~ghost:true)
(pp_local m))
(PrintSpec.pp_spec TransitionMode m))
fmt
((t, (name, mem_in), (name, mem_out)), t.tformula)
let pp_transition_defs fmt m =
pp_print_list
~pp_epilogue:pp_print_cut
~pp_open_box:pp_open_vbox0
(pp_transition_def m)
fmt
m.mspec.mtransitions
let pp_transition_footprint fmt t =
fprintf
fmt
"%s_transition%a_footprint"
t.tname.node_id
(pp_print_option pp_print_int)
t.tindex
let pp_transition_footprint_lemma m fmt t =
let name = t.tname.node_id in
let mem_in = mk_mem_in m in
let mem_out = mk_mem_out m in
let stateless = fst (get_stateless_status m) in
let mems =
ISet.(
diff
(of_list (List.map (fun (v, _) -> v.var_id) m.mmemory))
t.tmem_footprint)
in
let insts =
IMap.(
diff
(of_list (List.map (fun (x, (td, _)) -> x, node_name td) m.minstances))
t.tinst_footprint)
in
let memories =
List.map
(fun v -> { v with var_type = { v.var_type with tid = -1 } })
(List.filter_map
(fun (v, _) -> if ISet.mem v.var_id mems then Some v else None)
m.mmemory)
in
let mems_empty = ISet.is_empty mems in
let insts_empty = IMap.is_empty insts in
let instances = List.map (fun (i, f) -> f, i) (IMap.bindings insts) in
let tr ?mems ?insts () =
Spec_common.mk_transition
?mems
?insts
?i:t.tindex
stateless
name
(vdecls_to_vals t.tvars)
in
if not (mems_empty && insts_empty) then
pp_acsl_cut
(pp_lemma
pp_transition_footprint
(pp_forall
(pp_machine_decl ~ghost:true (pp_comma_list pp_print_string))
((if insts_empty then fun pp fmt (_, x) -> pp fmt x
else pp_forall (pp_comma_list (pp_machine_decl' ~ghost:true)))
((if mems_empty then fun pp fmt (_, x) -> pp fmt x
else pp_forall (pp_locals m))
(PrintSpec.pp_spec TransitionFootprintMode m)))))
fmt
( t,
( (m.mname.node_id, [ mem_in; mem_out ]),
( instances,
(memories, Forall (t.tvars, Imply (tr (), tr ~mems ~insts ()))) ) )
)
let pp_transition_footprint_lemmas fmt m =
pp_print_list
~pp_epilogue:pp_print_cut
~pp_open_box:pp_open_vbox0
~pp_sep:pp_print_nothing
(pp_transition_footprint_lemma m)
fmt
(List.filter
(fun t -> match t.tindex with Some i when i > 0 -> true | _ -> false)
m.mspec.mtransitions)
let pp_initialization_def fmt m =
if not (fst (get_stateless_status m)) then
let name = m.mname.node_id in
let mem_in = mk_mem_in m in
pp_acsl
(pp_predicate
(pp_initialization (pp_machine_decl' ~ghost:true))
(pp_and_l (fun fmt (i, (td, _)) ->
pp_initialization pp_access' fmt (node_name td, (mem_in, i)))))
fmt
((name, (name, mem_in)), m.minstances)
let pp_register_chain ?(indirect = true) ptr =
pp_print_list
~pp_prologue:(fun fmt () -> fprintf fmt "%s->" ptr)
~pp_epilogue:(fun fmt () ->
fprintf fmt "%s_reg._first" (if indirect then "->" else "."))
~pp_sep:(fun fmt () -> pp_print_string fmt (if indirect then "->" else "."))
(fun fmt (i, _) -> pp_print_string fmt i)
let pp_reset_flag_chain ?(indirect = true) ptr fmt mems =
pp_print_list
~pp_prologue:(fun fmt () -> fprintf fmt "%s->" ptr)
~pp_epilogue:(fun fmt () -> pp_reset_flag' ~indirect fmt "")
~pp_sep:(fun fmt () -> pp_print_string fmt (if indirect then "->" else "."))
(fun fmt (i, _) -> pp_print_string fmt i)
fmt
mems
let rename n x = sprintf "%s_%d" x n
let rename_var_decl n vd = { vd with var_id = rename n vd.var_id }
let pp_k_induction_case base m m_c pp_mem_out pp_mem_c_out pp_vars fmt
(n, mem_out, mem_c_out) =
let stateless_c = fst (get_stateless_status m_c) in
let name = m.mname.node_id in
fprintf
fmt
"%s_%s_%d(@[<hov>%a,@;%a%a@])"
name
(if base then "base" else "inductive")
n
pp_mem_out
mem_out
(pp_print_only_if (not stateless_c) (fun fmt ->
fprintf fmt "%a,@;" pp_mem_c_out))
mem_c_out
pp_vars
(List.map (rename_var_decl n) m_c.mstep.step_outputs)
let pp_k_induction_case_def base m (_, m_c, _) fmt n =
let name = m.mname.node_id in
let name_c = m_c.mname.node_id in
let mem = mk_mem m in
let mem_c = mk_mem_c m in
let inputs = m.mstep.step_inputs in
let outputs = m.mstep.step_outputs in
let stateless = fst (get_stateless_status m) in
let stateless_c = fst (get_stateless_status m_c) in
let l = List.init (n + 1) Fun.id in
let l_pp =
List.concat_map
(function
| 0 ->
let pp = pp_reset_set' in
[
(fun fmt ->
(if stateless_c then fun fmt (x, _) -> pp fmt x else pp_and pp pp)
fmt
((name, rename 0 mem), (name_c, rename 0 mem_c)));
]
| n' ->
let pp_var_c fmt (out, vd) =
if out && n' < n then pp_true_c_bool fmt () else pp_var_decl fmt vd
in
let c_inputs =
List.map
(fun v -> false, rename_var_decl n' v)
m_c.mstep.step_inputs
in
let c_outputs =
List.map
(fun v -> true, rename_var_decl n' v)
m_c.mstep.step_outputs
in
let pp stateless pp_var =
pp_transition_aux stateless pp_print_string pp_print_string pp_var
in
[
(fun fmt ->
pp
stateless
pp_var_decl
fmt
( name,
List.map (rename_var_decl n') (inputs @ outputs),
rename (n' - 1) mem,
rename n' mem ));
(fun fmt ->
pp
stateless_c
pp_var_c
fmt
( name_c,
c_inputs @ c_outputs,
rename (n' - 1) mem_c,
rename n' mem_c ));
])
l
in
let l_pp = if base then l_pp else List.tl l_pp in
let pp fmt () =
let pp fmt () = pp_and_l (fun fmt f -> f fmt) fmt l_pp in
if stateless_c then pp fmt ()
else
pp_exists
(pp_machine_decl
~ghost:true
(pp_comma_list (fun fmt n ->
pp_print_string fmt (rename (n - 1) mem_c))))
pp
fmt
((name_c, List.tl l), ())
in
pp_predicate
(pp_k_induction_case
base
m
m_c
(pp_machine_decl' ~ghost:true)
(pp_machine_decl' ~ghost:true)
(pp_locals m_c))
(pp_exists
(fun fmt l ->
fprintf
fmt
"%a@,%a"
(pp_machine_decl
~ghost:true
(pp_comma_list ~pp_eol:pp_print_comma (fun fmt n ->
pp_print_string fmt (rename (n - 1) mem))))
(name, l)
(pp_locals m)
(List.concat_map
(fun n -> List.map (rename_var_decl n) (inputs @ outputs))
l))
pp)
fmt
((n, (name, rename n mem), (name_c, rename n mem_c)), (List.tl l, ()))
let pp_base_case_defs m fmt ((_, _, k) as c_m_k) =
let l = List.init (k - 1) succ in
pp_print_list
~pp_open_box:pp_open_vbox0
~pp_sep:pp_print_cutcut
(pp_k_induction_case_def true m c_m_k)
fmt
l
let pp_inductive_case_def m fmt ((_, _, k) as c_m_k) =
pp_k_induction_case_def false m c_m_k fmt k
let pp_k_induction_lemmas m fmt (_, m_c, k) =
let name = m.mname.node_id in
let name_c = m_c.mname.node_id in
let mem = mk_mem m in
let mem_c = mk_mem_c m in
let stateless_c = fst (get_stateless_status m_c) in
let l = List.init k (fun n -> n + 1) in
pp_print_list
~pp_open_box:pp_open_vbox0
~pp_sep:pp_print_cutcut
(fun fmt n ->
let outputs = List.map (rename_var_decl n) m_c.mstep.step_outputs in
pp_lemma
(fun fmt n -> fprintf fmt "%s_k_induction_%d" name n)
(pp_forall
(fun fmt () ->
fprintf
fmt
"%a,@;%a%a"
(pp_machine_decl' ~ghost:true)
(name, mem)
(pp_print_only_if (not stateless_c) (fun fmt ->
fprintf fmt "%a,@;" (pp_machine_decl' ~ghost:true)))
(name_c, mem_c)
(pp_locals m_c)
outputs)
(pp_implies
(pp_k_induction_case
(n <> k)
m
m_c
pp_print_string
pp_print_string
(pp_comma_list pp_var_decl))
(pp_and_l (fun fmt x ->
pp_equal pp_var_decl pp_print_int fmt (x, 1)))))
fmt
(n, ((), ((n, mem, mem_c), outputs))))
fmt
l
let pp_k_induction m fmt c_m_k =
pp_acsl_cut
(fun fmt () ->
fprintf
fmt
"%a@,@,%a@,@,%a"
(pp_base_case_defs m)
c_m_k
(pp_inductive_case_def m)
c_m_k
(pp_k_induction_lemmas m)
c_m_k)
fmt
()
let pp_proof_annotation m m_c fmt c =
let pp m_c fmt = function
| Kinduction k ->
pp_k_induction m fmt (c, m_c, k)
in
match m_c with
| Some m_c ->
pp_print_option (pp m_c) fmt c.mc_proof
| None ->
()
let spec_from_contract c = Spec_common.red (Imply (c.mc_pre, c.mc_post))
module GhostProto : MODIFIERS_GHOST_PROTO = struct
let pp_ghost_parameters ?(cut = true) fmt vs =
fprintf
fmt
"%a%a"
(pp_print_only_if cut pp_print_cut)
()
(pp_acsl_line'
(pp_ghost (pp_print_parenthesized (fun fmt (x, pp) -> pp fmt x))))
vs
end
let pp_is_contract pp fmt =
pp_acsl (pp_ghost (fun fmt () -> fprintf fmt "@,%t" pp)) fmt ()
module HdrMod = struct
module GhostProto = GhostProto
let pp_is_contract = pp_is_contract
let pp_predicates fmt machines =
let pp_preds comment pp =
pp_print_list
~pp_open_box:pp_open_vbox0
~pp_prologue:(pp_print_endcut comment)
pp
~pp_epilogue:pp_print_cutcut
in
let machines' =
List.filter (fun m -> not (fst (get_stateless_status m))) machines
in
fprintf
fmt
"%a%a%a%a%a%a%a"
(pp_preds "/* ACSL `valid` predicates */" pp_mem_valid_def)
machines'
(pp_preds "/* ACSL ghost structures */" pp_machine_ghost_struct)
machines'
(pp_preds "/* ACSL initialization annotations */" pp_initialization_def)
machines'
(pp_preds "/* ACSL `memory pack` simulations */" pp_memory_pack_defs)
machines'
(pp_preds "/* ACSL transition annotations */" pp_transition_defs)
machines
(pp_preds
"/* ACSL transition memory footprints lemmas */"
pp_transition_footprint_lemmas)
machines'
(pp_preds "/* k-induction predicates and lemmas */" (fun fmt m ->
let c, m_c = contract_of machines m in
pp_print_option (pp_proof_annotation m m_c) fmt c))
machines
let pp_machine_decl_prefix _ _ = ()
let pp_import_arrow fmt () =
fprintf
fmt
"#include \"%s/arrow_spec.h%s\""
(Arrow.arrow_top_decl ()).top_decl_owner
(if !Options.cpp then "pp" else "")
let pp_machine_alloc_decl fmt m =
pp_machine_decl_prefix fmt m;
if not (fst (get_stateless_status m)) then
if !Options.static_mem then
(* Static allocation *)
let macro = m, mk_attribute m, mk_instance m in
fprintf
fmt
"%a@,%a@,%a"
(pp_static_declare_macro ~ghost:true)
macro
(pp_static_link_macro ~ghost:true)
macro
(pp_static_alloc_macro ~ghost:true)
macro
else
(* Dynamic allocation *)
(* TODO: handle dynamic alloc *)
assert false
(* fprintf fmt "extern %a;@,extern %a" pp_alloc_prototype
* (m.mname.node_id, m.mstatic)
* pp_dealloc_prototype m.mname.node_id *)
end
module SrcMod = struct
module GhostProto = GhostProto
let pp_contract_step_call m proto_c fmt () =
pp_print_option
(pp_acsl_line'_cut
(pp_ghost (fun fmt (mem_c, name, inputs, outputs) ->
fprintf
fmt
"%a(@[<hov>%a%a@]);"
pp_machine_step_name
name
(pp_comma_list (pp_c_var_read ~test_output:true m))
(inputs @ outputs)
(pp_print_option (fun fmt -> fprintf fmt ",@ %s"))
mem_c)))
fmt
proto_c
let pp_contract_arrow_reset_name fmt =
fprintf fmt "%s_reset_ghost" Arrow.arrow_id
let pp_contract_arrow_step_name fmt =
fprintf fmt "%s_step_ghost" Arrow.arrow_id
let pp_arrow_reset_ghost mem fmt inst =
fprintf fmt "%t(%a)" pp_contract_arrow_reset_name pp_indirect' (mem, inst)
let pp_is_contract = pp_is_contract
let pp_import_spec_prototype fmt dep =
fprintf fmt "#include \"%s_spec.h\"@," dep.name
let pp_clear_reset_spec fmt self mem m =
let name = m.mname.node_id in
let arws, narws =
List.partition (fun (_, (td, _)) -> Arrow.td_is_arrow td) m.minstances
in
let mk_insts = List.map (fun x -> [ x ]) in
let pp_if_not_contract pp = pp_print_only_if (not m.mis_contract) pp in
pp_acsl_cut
~ghost:m.mis_contract
(fun fmt () ->
fprintf
fmt
"%a%a%a%a%a%a%a"
(pp_if_not_contract (pp_requires pp_mem_valid'))
(name, self)
(pp_if_not_contract (pp_requires (pp_separated' self mem)))
(mk_insts m.minstances, [])
(pp_if_not_contract
(pp_requires (pp_memory_pack_aux pp_ptr pp_print_string)))
(name, mem, self)
(pp_if_not_contract
(pp_ensures
(pp_memory_pack_aux_taint
~i:(fst m.mspec.mmemory_packs)
pp_ptr
pp_ptr
pp_print_string)))
(name, mem, mem, self)
(pp_if_not_contract (pp_assigns pp_reset_flag'))
[ self ]
(pp_if_not_contract (pp_assigns (pp_register_chain self)))
(mk_insts arws)
(pp_if_not_contract (pp_assigns (pp_reset_flag_chain self)))
(mk_insts narws))
fmt
()
(* let pp_set_reset_spec fmt machines self mem m = *)
(* let name = m.mname.node_id in *)
(* let insts = instances machines m in *)
(* let stateful_insts = *)
(* List.( *)
(* filter *)
(* (fun path -> *)
(* let _, (_, mems) = hd (rev path) in *)
(* mems <> []) *)
(* insts) *)
(* in *)
(* let pp_if_not_contract pp = pp_print_only_if (not m.mis_contract) pp in *)
(* pp_acsl_cut *)
(* ~ghost:m.mis_contract *)
(* (fun fmt () -> *)
(* fprintf *)
(* fmt *)
(* "%a%a%a%a" *)
(* (pp_if_not_contract *)
(* (pp_ensures (pp_memory_pack_aux pp_ptr pp_print_string))) *)
(* (name, mem, self) *)
(* (pp_if_not_contract *)
(* (pp_ensures (pp_initialization pp_ptr))) *)
(* (name, mem) *)
(* (pp_assigns pp_reset_flag') *)
(* (if m.mis_contract then [ ] else [ self ]) *)
(* (pp_assigns (pp_reg ~indirect:false mem)) *)
(* stateful_insts) *)
(* fmt *)
(* () *)
let pp_ghost_reset_spec fmt machines mem m =
let name = m.mname.node_id in
let insts = instances machines m in
let stateful_insts =
List.(
filter
(fun path ->
let _, (_, mems) = hd (rev path) in
mems <> [])
insts)
in
pp_acsl_cut
~ghost:true
(fun fmt () ->
fprintf
fmt
"%a%a"
(pp_ensures (pp_initialization pp_ptr))
(name, mem)
(pp_assigns (pp_reg ~indirect:false mem))
stateful_insts)
fmt
()
(** UNUSED *)
(* let pp_contract m fmt c = *)
(* PrintSpec.pp_spec PrintSpec.TransitionMode m fmt (spec_from_contract c) *)
(** UNUSED *)
(* let rec rename_value n v = *)
(* { *)
(* v with *)
(* value_desc = *)
(* (match v.value_desc with *)
(* | Machine_code_types.Var v -> *)
(* Machine_code_types.Var (rename_var_decl n v) *)
(* | Fun (f, vs) -> *)
(* Fun (f, List.map (rename_value n) vs) *)
(* | Array vs -> *)
(* Array (List.map (rename_value n) vs) *)
(* | Access (v1, v2) -> *)
(* Access (rename_value n v1, rename_value n v2) *)
(* | Power (v1, v2) -> *)
(* Power (rename_value n v1, rename_value n v2) *)
(* | v -> *)
(* v); *)
(* } *)
(* let rename_expression n = function *)
(* | Val v -> *)
(* Val (rename_value n v) *)
(* | Var v -> *)
(* Var (rename_var_decl n v) *)
(* | e -> *)
(* e *)
(* let rename_predicate n = function *)
(* | Transition (s, f, inst, i, es, r, mf, mif) -> *)
(* Transition (s, f, inst, i, List.map (rename_expression n) es, r, mf,
mif) *)
(* | p -> *)
(* p *)
(* let rec rename_formula n = function *)
(* | Equal (e1, e2) -> *)
(* Equal (rename_expression n e1, rename_expression n e2) *)
(* | And fs -> *)
(* And (List.map (rename_formula n) fs) *)
(* | Or fs -> *)
(* Or (List.map (rename_formula n) fs) *)
(* | Imply (f1, f2) -> *)
(* Imply (rename_formula n f1, rename_formula n f2) *)
(* | Exists (xs, f) -> *)
(* Exists (List.map (rename_var_decl n) xs, rename_formula n f) *)
(* | Forall (xs, f) -> *)
(* Forall (List.map (rename_var_decl n) xs, rename_formula n f) *)
(* | Ternary (e, t, f) -> *)
(* Ternary (rename_expression n e, rename_formula n t, rename_formula n f) *)
(* | Predicate p -> *)
(* Predicate (rename_predicate n p) *)
(* | ExistsMem (x, f1, f2) -> *)
(* ExistsMem (rename n x, rename_formula n f1, rename_formula n f2) *)
(* | Value v -> *)
(* Value (rename_value n v) *)
(* | f -> *)
(* f *)
(* let rename_contract n c = *)
(* { *)
(* c with *)
(* mc_pre = rename_formula n c.mc_pre; *)
(* mc_post = rename_formula n c.mc_post; *)
(* } *)
let pp_step_spec fmt machines self mem m =
let name = m.mname.node_id in
let insts = instances machines m in
let insts_no_arrow =
List.(
filter
(fun path ->
let _, (td, _) = hd (rev path) in
not (Arrow.td_is_arrow td))
insts)
in
let stateful_insts =
List.(
filter
(fun path ->
let _, (_, mems) = hd (rev path) in
mems <> [])
insts)
in
let inputs = m.mstep.step_inputs in
let outputs = m.mstep.step_outputs in
let stateless = fst (get_stateless_status m) in
let pp_if_outputs pp = pp_print_only_if (outputs = []) pp in
let pp_if_outputs' pp = pp_print_only_if (List.length outputs > 1) pp in
let pp_if_not_contract pp = pp_print_only_if (not m.mis_contract) pp in
let c, m_c = contract_of machines m in
let pp_spec =
pp_if_not_contract
(pp_print_option (fun fmt _c ->
pp_print_option
(fun fmt m_c ->
let mem_c = mk_mem_c m in
let stateless_c = fst (get_stateless_status m_c) in
let insts = instances machines m_c in
let insts_no_arrow =
List.(
filter
(fun path ->
let _, (td, _) = hd (rev path) in
not (Arrow.td_is_arrow td))
insts)
in
let stateful_insts =
List.(
filter
(fun path ->
let _, (_, mems) = hd (rev path) in
mems <> [])
insts)
in
fprintf
fmt
"%a%a%a%a%a%a"
(pp_ensures
(pp_transition_aux
stateless_c
(pp_old pp_ptr)
pp_ptr
(fun fmt v ->
(if is_output m v || is_output m_c v then pp_ptr_decl
else pp_var_decl)
fmt
v)))
( m_c.mname.node_id,
m_c.mstep.step_inputs @ m_c.mstep.step_outputs,
mem_c,
mem_c )
(pp_assigns pp_ptr_decl)
m_c.mstep.step_outputs
(pp_print_only_if
((not stateless_c) && m_c.mmemory <> [])
(pp_assigns (pp_reg mem_c)))
[ [] ]
(pp_print_only_if
(not stateless_c)
(pp_assigns pp_reset_flag'))
[ mem_c ]
(pp_print_only_if
(not stateless_c)
(pp_assigns (pp_reg ~indirect:false mem_c)))
stateful_insts
(pp_print_only_if
(not stateless_c)
(pp_assigns (pp_reset_flag_chain ~indirect:false mem_c)))
insts_no_arrow)
fmt
m_c))
in
pp_acsl_cut
~ghost:m.mis_contract
(fun fmt () ->
if stateless then
fprintf
fmt
"%a%a%a%a%a"
(pp_if_outputs (pp_requires (pp_valid pp_var_decl)))
outputs
(pp_if_outputs' (pp_requires pp_separated''))
outputs
(pp_assigns pp_ptr_decl)
outputs
(pp_ensures (pp_transition_aux' m))
(name, inputs @ outputs, "", "")
pp_spec
c
else
fprintf
fmt
"%a%a%a%a%a%a%a%a%a%a%a%a%a%a"
(pp_if_outputs (pp_requires (pp_valid pp_var_decl)))
outputs
(pp_if_not_contract (pp_requires pp_mem_valid'))
(name, self)
(fun fmt () ->
if m.mis_contract then
pp_requires
(pp_separated
pp_print_string
(pp_comma_list pp_var_decl)
pp_print_nothing)
fmt
(mem, outputs, [], [])
else pp_requires (pp_separated' self mem) fmt (insts, outputs))
()
(pp_if_not_contract
(pp_requires (pp_memory_pack_aux pp_ptr pp_print_string)))
(name, mem, self)
(pp_if_not_contract
(pp_ensures (pp_memory_pack_aux pp_ptr pp_print_string)))
(name, mem, self)
(pp_ensures
(pp_transition_aux stateless (pp_old pp_ptr) pp_ptr (fun fmt v ->
(if is_output m v then pp_ptr_decl else pp_var_decl) fmt v)))
(name, inputs @ outputs, mem, mem)
pp_spec
c
(pp_assigns pp_ptr_decl)
outputs
(pp_print_only_if
((not m.mis_contract) && m.mmemory <> [])
(pp_assigns (pp_reg self)))
[ [] ]
(pp_if_not_contract (pp_assigns pp_reset_flag'))
[ self ]
(pp_if_not_contract (pp_assigns (pp_reg self)))
stateful_insts
(pp_assigns (pp_reset_flag_chain self))
insts_no_arrow
(pp_print_only_if (m.mmemory <> []) (pp_assigns (pp_reg mem)))
[ [] ]
(pp_assigns (pp_reg ~indirect:false mem))
stateful_insts)
fmt
()
let pp_ghost_reset pp_mem name fmt mem =
fprintf fmt "%a(%a);" pp_machine_ghost_reset_name name pp_mem mem
let pp_ghost_instr_code m mem fmt instr =
match instr.instr_desc with
| MStateAssign (x, v) ->
fprintf
fmt
"@,%a"
(pp_acsl_line' (pp_ghost (pp_assign m mem (pp_c_var_read m))))
(x, v)
(* | MResetAssign b -> *)
(* fprintf fmt "@,%a" (pp_acsl_line (pp_ghost (pp_reset_assign self))) b *)
| MSetReset inst ->
let name =
let node, _ =
try List.assoc inst m.minstances with Not_found -> assert false
in
node_name node
in
fprintf
fmt
"@,%a"
(pp_acsl_line'
(pp_ghost
(pp_ghost_reset (pp_indirect pp_ref' pp_print_string) name)))
(mem, inst)
(* let td, _ = List.assoc inst m.minstances in *)
(* if Arrow.td_is_arrow td then *)
(* fprintf *)
(* fmt *)
(* "@,%a;" *)
(* (pp_acsl_line (pp_ghost (pp_arrow_reset_ghost self))) *)
(* inst *)
| _ ->
()
let pp_step_instr_spec m self mem fmt instr =
let ghost = m.mis_contract in
fprintf
fmt
"%a%a"
(pp_print_only_if (not ghost) (pp_ghost_instr_code m mem))
instr
(pp_print_list
~pp_open_box:pp_open_vbox0
~pp_prologue:pp_print_cut
(pp_acsl_line' ~ghost (fun fmt (spec, asrt) ->
let pp = PrintSpec.pp_spec (InstrMode self) m in
(if asrt then pp_assert pp else pp) fmt spec)))
instr.instr_spec
let pp_ghost_parameter mem fmt inst =
GhostProto.pp_ghost_parameters
~cut:false
fmt
(match inst with
| Some inst ->
[ (inst, fun fmt inst -> pp_ref pp_indirect' fmt (mem, inst)) ]
| None ->
[ mem, pp_print_string ])
let pp_c_decl_local_spec_var m fmt v =
pp_acsl_line'
(fun fmt v -> fprintf fmt "%a;" (pp_ghost (pp_c_decl_local_var m)) v)
fmt
v
let get_spec_locals m =
let rec gather vs instr =
let vs =
List.fold_left
(fun vs (spec, _) ->
match Spec_common.red spec with
| Predicate (GhostAssign (v, _)) ->
VSet.add v vs
| _ ->
vs)
vs
instr.instr_spec
in
match instr.instr_desc with
| MBranch (_, hl) ->
List.fold_left (fun vs (_, il) -> List.fold_left gather vs il) vs hl
| _ ->
vs
in
List.fold_left gather VSet.empty m.mstep.step_instrs |> VSet.elements
(* let pp_ghost_reset_memory m fmt mem = *)
(* let name = m.mname.node_id in *)
(* let mem_r = mk_mem_reset m in *)
(* let pp fmt () = *)
(* fprintf *)
(* fmt *)
(* "%a = %a;" *)
(* (pp_machine_decl' ~ghost:true) *)
(* (name, mem_r) *)
(* pp_ptr *)
(* mem *)
(* in *)
(* (if m.mis_contract then pp else pp_acsl_line' (pp_ghost pp)) fmt () *)
end
module MainMod = struct
let pp_import_spec_prototype = SrcMod.pp_import_spec_prototype
(* let main_mem_ghost = "main_mem_ghost" *)
(* let main_mem_ghost_c = "main_mem_ghost_c" *)
let pp_reset_contract m fmt m_c =
let stateless_c = fst (get_stateless_status m_c) in
let name_c = m_c.mname.node_id in
pp_print_only_if
(not stateless_c)
(fun fmt ->
fprintf
fmt
"@;%a"
(pp_acsl_line'
(pp_ghost (fun fmt () ->
fprintf
fmt
"%a(%a);"
pp_machine_set_reset_name
name_c
pp_ref'
(mk_main_mem_ghost_c m)))))
fmt
()
let pp_declare_ghost_state m m_c fmt name =
fprintf
fmt
"%a%a@;"
(pp_acsl_line'
(pp_ghost (fun fmt () ->
fprintf
fmt
"%a(,%s);"
(pp_machine_static_alloc_name ~ghost:true)
name
(mk_main_mem_ghost m))))
()
(pp_print_option (fun fmt m_c ->
let stateless_c = fst (get_stateless_status m_c) in
let name_c = m_c.mname.node_id in
pp_print_only_if
(not stateless_c)
(fun fmt ->
fprintf
fmt
"@;%a"
(pp_acsl_line'
(pp_ghost (fun fmt ->
fprintf fmt "%a;" (pp_machine_decl' ~ghost:true)))))
fmt
(name_c, mk_main_mem_ghost_c m)))
m_c
let pp_ghost_state_parameter m fmt m_c =
let stateless = fst (get_stateless_status m) in
let proto_c =
match m_c with
| None ->
[]
| Some m_c ->
let stateless_c = fst (get_stateless_status m_c) in
let l =
List.map
(fun v -> v.var_id, pp_ref pp_print_string)
m_c.mstep.step_outputs
in
if stateless_c then l
else (mk_main_mem_ghost_c m, pp_ref pp_print_string) :: l
in
GhostProto.pp_ghost_parameters
~cut:false
fmt
(if stateless then proto_c
else (mk_main_mem_ghost m, pp_ref pp_print_string) :: proto_c)
let pp_main_loop_invariants main_mem machines fmt m =
let name = m.mname.node_id in
let insts = instances machines m in
let c, m_c = contract_of machines m in
let m_c_k =
match c, m_c with
| Some c, Some m_c -> (
match c.mc_proof with Some (Kinduction k) -> Some (m_c, k) | _ -> None)
| _ ->
None
in
let var_k = mk_k m in
let stateless = fst (get_stateless_status m) in
fprintf
fmt
"%a%a%a"
(pp_print_option (fun fmt _ ->
pp_print_option
(fun fmt m_c ->
pp_acsl_cut
(pp_ghost
(pp_print_list
~pp_open_box:pp_open_vbox0
~pp_sep:pp_print_semicolon
~pp_epilogue:pp_print_semicolon'
(pp_local m_c)))
fmt
m_c.mstep.step_outputs)
fmt
m_c))
c
(pp_print_option (fun fmt _ ->
fprintf
fmt
"%a@,"
(pp_acsl_line (pp_ghost (fun fmt -> fprintf fmt "int %s = 0;")))
var_k))
m_c_k
(pp_acsl_cut (fun fmt () ->
fprintf
fmt
"%a%a%a%a%a"
(pp_print_only_if
(not stateless)
(pp_loop_invariant pp_mem_valid'))
(name, main_mem)
(pp_print_only_if
(not stateless)
(pp_loop_invariant
(pp_memory_pack_aux pp_print_string pp_print_string)))
(name, mk_main_mem_ghost m, main_mem)
(fun fmt ((_, _, _, outputs) as x) ->
if stateless then (
if List.length outputs > 1 then
pp_loop_invariant pp_separated'' fmt outputs)
else
pp_loop_invariant
(pp_separated
(pp_paren pp_print_string)
pp_ref'
(pp_ref pp_var_decl))
fmt
x)
(main_mem, mk_main_mem_ghost m, insts, m.mstep.step_outputs)
(pp_loop_invariant
(pp_or (pp_valid_read pp_stdout) (pp_equal pp_stdout pp_null)))
((), ((), ()))
(pp_print_option (fun fmt (m_c, k) ->
let stateless_c = fst (get_stateless_status m_c) in
let name_c = m_c.mname.node_id in
fprintf
fmt
"@,%a@,%a"
(pp_loop_invariant (pp_gequal pp_print_string pp_print_int))
(var_k, 0)
(pp_loop_invariant
(pp_and_l (fun fmt k' ->
pp_paren
(pp_implies
((if k' = k then pp_gequal else pp_equal)
pp_print_string
pp_print_int)
(fun fmt mem ->
if k' = 0 then
if stateless_c then
pp_reset_set' fmt (name, mem)
else
pp_and
pp_reset_set'
pp_reset_set'
fmt
( (name, mem),
(name_c, mk_main_mem_ghost_c m) )
else
pp_k_induction_case
(k' < k)
m
m_c
pp_print_string
pp_print_string
(pp_comma_list
~pp_open_box:(fun fmt () ->
pp_open_hovbox fmt 0)
(fun fmt _ -> pp_true_c_bool fmt ()))
fmt
(k', mem, mk_main_mem_ghost_c m)))
fmt
((var_k, k'), mk_main_mem_ghost m))))
(List.init (k + 1) Fun.id)))
m_c_k))
()
let pp_main_loop_end _main_mem machines fmt m =
let c, m_c = contract_of machines m in
fprintf
fmt
"@,%a"
(pp_print_option (fun fmt c ->
pp_print_option
(fun fmt _ ->
fprintf
fmt
"%a%a"
(match c.mc_proof with
| Some (Kinduction _) ->
pp_acsl_line_cut (pp_ghost (fun fmt -> fprintf fmt "%s++;"))
| None ->
pp_print_nothing)
(mk_k m)
(pp_acsl_line'
(pp_assert (PrintSpec.pp_spec TransitionMode m)))
(spec_from_contract c))
(* (pp_and_l (fun fmt v -> *)
(* pp_equal pp_var_decl pp_print_int fmt (v, 1))))) *)
(* m_c.mstep.step_outputs) *)
fmt
m_c))
c
let pp_main_spec fmt =
pp_acsl_cut
(fun fmt () ->
fprintf
fmt
"%a%a%a%a"
(pp_requires
(pp_or (pp_valid_read pp_stdout) (pp_equal pp_stdout pp_null)))
((), ((), ()))
(pp_terminates pp_false)
()
(pp_ensures pp_false)
()
(pp_assigns pp_nothing)
[ () ])
fmt
()
end
(**************************************************************************)
(* MAKEFILE *)
(**************************************************************************)
module MakefileMod = struct
let pp_print_dependencies = C_backend_makefile.pp_print_dependencies "_spec"
let pp_arrow_o fmt () = pp_print_string fmt "arrow_spec.o"
let other_targets basename _nodename dependencies fmt =
fprintf fmt "FRAMACEACSL=`frama-c -print-share-path`/e-acsl@.";
(* EACSL version of library file . c *)
fprintf fmt "%s_eacsl.c: %s.c %s.h@." basename basename basename;
fprintf
fmt
"\tframa-c -e-acsl-full-mmodel -machdep x86_64 -e-acsl %s.c -then-on \
e-acsl -print -ocode %s_eacsl.c@."
basename
basename;
fprintf fmt "@.";
fprintf fmt "@.";
(* EACSL version of library file . c + main .c *)
fprintf
fmt
"%s_main_eacsl.c: %s.c %s.h %s_main.c@."
basename
basename
basename
basename;
fprintf
fmt
"\tframa-c -e-acsl-full-mmodel -machdep x86_64 -e-acsl %s.c %s_main.c \
-then-on e-acsl -print -ocode %s_main_eacsl.i@."
basename
basename
basename;
(* Ugly hack to deal with eacsl bugs *)
fprintf
fmt
"\tgrep -v _fc_stdout %s_main_eacsl.i > %s_main_eacsl.c"
basename
basename;
fprintf fmt "@.";
fprintf fmt "@.";
(* EACSL version of binary *)
fprintf fmt "%s_main_eacsl: %s_main_eacsl.c@." basename basename;
fprintf
fmt
"\t${GCC} -Wno-attributes -I${INC} -I. -c %s_main_eacsl.c@."
basename;
(* compiling instrumented lib + main *)
pp_print_dependencies fmt dependencies;
fprintf
fmt
"\t${GCC} -Wno-attributes -o %s_main_eacsl io_frontend.o %a %s \
%s_main_eacsl.o %a@."
basename
(pp_print_list (fun fmt dep -> fprintf fmt "%s.o" dep.name))
(C_backend_makefile.compiled_dependencies dependencies)
("${FRAMACEACSL}/e_acsl.c "
^ "${FRAMACEACSL}/memory_model/e_acsl_bittree.c "
^ "${FRAMACEACSL}/memory_model/e_acsl_mmodel.c")
basename
(pp_print_list (fun fmt lib -> fprintf fmt "-l%s" lib))
(C_backend_makefile.lib_dependencies dependencies);
fprintf fmt "@."
end
(* TODO: complete this list *)
let acsl_keywords = ISet.of_list [ "set" ]
let sanitize x = if ISet.mem x acsl_keywords then "__" ^ x else x
let sanitize_var_decl vd = { vd with var_id = sanitize vd.var_id }
let sanitize_var_decls = List.map sanitize_var_decl
let rec sanitize_value v =
let value_desc =
match v.value_desc with
| Machine_code_types.Var vd ->
Machine_code_types.Var (sanitize_var_decl vd)
| Fun (f, vs) ->
Fun (f, sanitize_values vs)
| Array vs ->
Array (sanitize_values vs)
| Access (v1, v2) ->
Access (sanitize_value v1, sanitize_value v2)
| Power (v1, v2) ->
Power (sanitize_value v1, sanitize_value v2)
| v ->
v
in
{ v with value_desc }
and sanitize_values vs = List.map sanitize_value vs
let sanitize_expr = function
| Val v ->
Val (sanitize_value v)
| Var v ->
Var (sanitize_var_decl v)
| e ->
e
let sanitize_predicate = function
| Transition (st, f, inst, i, vs, r, mf, mfinsts) ->
Transition (st, f, inst, i, List.map sanitize_expr vs, r, mf, mfinsts)
| GhostAssign (x, v) ->
GhostAssign (sanitize_var_decl x, sanitize_value v)
| (Reset _ | MemoryPack _ | MemoryPackBase _) as p ->
p
let rec sanitize_formula = function
| Equal (e1, e2) ->
Equal (sanitize_expr e1, sanitize_expr e2)
| GEqual (e1, e2) ->
GEqual (sanitize_expr e1, sanitize_expr e2)
| And fs ->
And (sanitize_formulae fs)
| Or fs ->
Or (sanitize_formulae fs)
| Imply (f1, f2) ->
Imply (sanitize_formula f1, sanitize_formula f2)
| Exists (vs, f) ->
Exists (sanitize_var_decls vs, sanitize_formula f)
| Forall (vs, f) ->
Forall (sanitize_var_decls vs, sanitize_formula f)
| Ternary (e, t, f) ->
Ternary (sanitize_expr e, sanitize_formula t, sanitize_formula f)
| Predicate p ->
Predicate (sanitize_predicate p)
| ExistsMem (m, f1, f2) ->
ExistsMem (m, sanitize_formula f1, sanitize_formula f2)
| Value v ->
Value (sanitize_value v)
| (True | False | StateVarPack _ | MemoryPackToplevel _) as f ->
f
and sanitize_formulae fs = List.map (fun spec -> sanitize_formula spec) fs
let sanitize_spec fs =
List.map (fun (spec, asrt) -> sanitize_formula spec, asrt) fs
let rec sanitize_instr i =
let sanitize_instr_desc = function
| MLocalAssign (x, v) ->
MLocalAssign (sanitize_var_decl x, sanitize_value v)
| MStateAssign (x, v) ->
MStateAssign (x, sanitize_value v)
| MStep (xs, f, vs) ->
MStep (sanitize_var_decls xs, f, sanitize_values vs)
| MBranch (v, brs) ->
MBranch
( sanitize_value v,
List.map (fun (t, instrs) -> t, sanitize_instrs instrs) brs )
| i ->
i
in
{
i with
instr_desc = sanitize_instr_desc i.instr_desc;
instr_spec = sanitize_spec i.instr_spec;
}
and sanitize_instrs instrs = List.map sanitize_instr instrs
let sanitize_step s =
{
s with
step_inputs = sanitize_var_decls s.step_inputs;
step_outputs = sanitize_var_decls s.step_outputs;
step_locals = sanitize_var_decls s.step_locals;
step_instrs = sanitize_instrs s.step_instrs;
}
let sanitize_transition t =
{
t with
tvars = sanitize_var_decls t.tvars;
tformula = sanitize_formula t.tformula;
}
let sanitize_transitions = List.map sanitize_transition
let sanitize_memory_pack mp =
{ mp with mpformula = sanitize_formula mp.mpformula }
let sanitize_memory_packs (n, mps) = n, List.map sanitize_memory_pack mps
let sanitize_spec s =
{
s with
mtransitions = sanitize_transitions s.mtransitions;
mmemory_packs = sanitize_memory_packs s.mmemory_packs;
}
let sanitize_machine m =
{ m with mstep = sanitize_step m.mstep; mspec = sanitize_spec m.mspec }
let sanitize_machines = List.map sanitize_machine
(* Local Variables: *)
(* compile-command:"make -C ../../.." *)
(* End: *)