From 241ef2a4bbec0523e29151fbf657a66691070932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9lio=20Brun?= <lelio.brun@isae-supaero.fr> Date: Tue, 5 Jul 2022 09:38:05 +0200 Subject: [PATCH] corrections to handle stateless / statefull --- src/backends/C/c_backend_common.ml | 51 ++++++---- src/backends/C/c_backend_common.mli | 4 +- src/backends/C/c_backend_header.ml | 4 +- src/backends/C/c_backend_main.ml | 4 +- src/backends/C/c_backend_spec.ml | 139 ++++++++++++++++------------ src/backends/C/c_backend_src.ml | 33 ++++--- 6 files changed, 140 insertions(+), 95 deletions(-) diff --git a/src/backends/C/c_backend_common.ml b/src/backends/C/c_backend_common.ml index f26b7eb1..4e955f73 100644 --- a/src/backends/C/c_backend_common.ml +++ b/src/backends/C/c_backend_common.ml @@ -878,6 +878,32 @@ module Protos (Mod : MODIFIERS_GHOST_PROTO) = struct (pp_print_only_if (not is_contract) (Mod.pp_ghost_parameters ~cut:true)) [ mem, pp_mem_ghost name ] + let pp_ghost_proto fmt (mem_name, proto_c) = + let ghost_c = + match proto_c with + | None -> + [] + | Some (mem_c, name_c, _, outputs_c) -> ( + let l = + List.map + (fun v -> "", fun fmt _ -> pp_c_decl_output_var fmt v) + outputs_c + in + match mem_c with + | Some mem_c -> + (mem_c, pp_mem_ghost name_c) :: l + | None -> + l) + in + match mem_name, proto_c with + | None, None -> () + | _ -> + Mod.pp_ghost_parameters ~cut:true fmt + (match mem_name with + | Some (mem, name) -> + (mem, pp_mem_ghost name) :: ghost_c + | None -> ghost_c) + let pp_step_prototype is_contract self mem fmt (name, inputs, outputs, proto_c) = fprintf @@ -894,23 +920,8 @@ module Protos (Mod : MODIFIERS_GHOST_PROTO) = struct pp_c_decl_output_var) outputs (pp_self is_contract self mem name) - (pp_print_only_if (not is_contract) (Mod.pp_ghost_parameters ~cut:true)) - ((mem, pp_mem_ghost name) - :: - (match proto_c with - | None -> - [] - | Some (mem_c, name_c, _, outputs_c) -> ( - let l = - List.map - (fun v -> "", fun fmt _ -> pp_c_decl_output_var fmt v) - outputs_c - in - match mem_c with - | Some mem_c -> - (mem_c, pp_mem_ghost name_c) :: l - | None -> - l))) + (pp_print_only_if (not is_contract) pp_ghost_proto) + (Some (mem, name), proto_c) let pp_init_prototype self fmt (name, static) = fprintf @@ -936,16 +947,18 @@ module Protos (Mod : MODIFIERS_GHOST_PROTO) = struct name self - let pp_stateless_prototype fmt (name, inputs, outputs) = + let pp_stateless_prototype fmt (name, inputs, outputs, proto_c) = fprintf fmt - "void %a (@[<v>%a%a@])" + "@[<v>void %a (@[<v>%a%a@])%a@]" pp_machine_step_name name (pp_comma_list pp_c_decl_input_var) inputs (pp_comma_list ~pp_prologue:pp_print_comma pp_c_decl_output_var) outputs + pp_ghost_proto + (None, proto_c) end let pp_import_prototype fmt dep = fprintf fmt "#include \"%s.h\"@," dep.name diff --git a/src/backends/C/c_backend_common.mli b/src/backends/C/c_backend_common.mli index 7ebacfec..8901985c 100644 --- a/src/backends/C/c_backend_common.mli +++ b/src/backends/C/c_backend_common.mli @@ -220,7 +220,9 @@ module EmptyGhostProto : MODIFIERS_GHOST_PROTO module Protos (Mod : MODIFIERS_GHOST_PROTO) : sig val pp_stateless_prototype : - formatter -> ident * var_decl list * var_decl list -> unit + formatter -> ident * var_decl list * var_decl list + * (ident option * ident * var_decl list * var_decl list) option -> + unit val pp_clear_reset_prototype : bool -> ident -> ident -> formatter -> ident * var_decl list -> unit diff --git a/src/backends/C/c_backend_header.ml b/src/backends/C/c_backend_header.ml index 14ca01aa..bd88949a 100644 --- a/src/backends/C/c_backend_header.ml +++ b/src/backends/C/c_backend_header.ml @@ -179,7 +179,7 @@ functor "internal error: pp_machine_decl_top_decl_from_header"; assert false) else if inode.nodei_stateless then - fprintf fmt "extern %a;" Protos.pp_stateless_prototype prototype + fprintf fmt "extern %a;" Protos.pp_stateless_prototype prototype' else let static_inputs = List.filter (fun v -> v.var_dec_const) inode.nodei_inputs @@ -202,7 +202,7 @@ functor Mod.pp_is_contract (fun fmt -> if inode.nodei_stateless then - fprintf fmt "%a;" Protos.pp_stateless_prototype prototype + fprintf fmt "%a;" Protos.pp_stateless_prototype prototype' else let static_inputs = List.filter (fun v -> v.var_dec_const) inode.nodei_inputs diff --git a/src/backends/C/c_backend_main.ml b/src/backends/C/c_backend_main.ml index 5228ef94..14bb64af 100644 --- a/src/backends/C/c_backend_main.ml +++ b/src/backends/C/c_backend_main.ml @@ -289,13 +289,15 @@ module Main (Mod : MODIFIERS_MAINSRC) = struct if fst (get_stateless_status m) then fprintf fmt - "%a(%a%a);" + "%a(%a%a)%a;" pp_machine_step_name mname pp_inputs inputs (pp_outputs ~pp_eol:pp_print_nothing) outputs + (Mod.pp_ghost_state_parameter m) + m_c else fprintf fmt diff --git a/src/backends/C/c_backend_spec.ml b/src/backends/C/c_backend_spec.ml index 86ff0c3d..4668a9f6 100644 --- a/src/backends/C/c_backend_spec.ml +++ b/src/backends/C/c_backend_spec.ml @@ -42,6 +42,8 @@ let pp_acsl ?(ghost = false) pp fmt x = 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 @@ -1102,6 +1104,8 @@ let pp_proof_annotation m m_c fmt c = | 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 @@ -1284,9 +1288,6 @@ module SrcMod = struct fmt () - (** UNUSED *) - (* let spec_from_contract c = Spec_common.red (Imply (c.mc_pre, c.mc_post)) *) - (** UNUSED *) (* let pp_contract m fmt c = *) (* PrintSpec.pp_spec PrintSpec.TransitionMode m fmt (spec_from_contract c) *) @@ -1380,6 +1381,7 @@ module SrcMod = struct 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 = @@ -1453,7 +1455,7 @@ module SrcMod = struct "%a%a%a%a%a" (pp_if_outputs (pp_requires (pp_valid pp_var_decl))) outputs - (pp_if_outputs (pp_requires pp_separated'')) + (pp_if_outputs' (pp_requires pp_separated'')) outputs (pp_assigns pp_ptr_decl) outputs @@ -1645,34 +1647,21 @@ module MainMod = struct (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 - fprintf + 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 - "%a%a" - (pp_print_only_if (not stateless_c) (fun fmt -> - fprintf - fmt - "@;%a" - (pp_acsl_line'_cut - (pp_ghost (fun fmt -> - fprintf fmt "%a;" (pp_machine_decl' ~ghost:true)))))) - (name_c, mk_main_mem_ghost_c m) - (pp_acsl - (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)))) - m_c.mstep.step_outputs)) + (name_c, mk_main_mem_ghost_c m))) m_c let pp_ghost_state_parameter m fmt m_c = - GhostProto.pp_ghost_parameters - ~cut:false - fmt - ((mk_main_mem_ghost m, pp_ref pp_print_string) - :: - (match m_c with + let stateless = fst (get_stateless_status m) in + let proto_c = + match m_c with | None -> [] | Some m_c -> @@ -1683,23 +1672,43 @@ module MainMod = struct m_c.mstep.step_outputs in if stateless_c then l - else (mk_main_mem_ghost_c m, pp_ref pp_print_string) :: l)) - - let k_induction_of machines m = - match contract_of machines m with - | Some c, Some m_c -> ( - match c.mc_proof with Some (Kinduction k) -> Some (m_c, k) | _ -> None) - | _ -> - None + 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 m_c_k = k_induction_of 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%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 @@ -1711,16 +1720,22 @@ module MainMod = struct fprintf fmt "%a%a%a%a%a" - (pp_loop_invariant pp_mem_valid') + (pp_print_only_if (not stateless) (pp_loop_invariant pp_mem_valid')) (name, main_mem) - (pp_loop_invariant - (pp_memory_pack_aux pp_print_string pp_print_string)) + (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) - (pp_loop_invariant - (pp_separated - (pp_paren pp_print_string) - pp_ref' - (pp_ref pp_var_decl))) + (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))) @@ -1771,21 +1786,29 @@ module MainMod = struct () 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 (m_c, _) -> - fprintf - fmt - "%a@,%a" - (pp_acsl_line (pp_ghost (fun fmt -> fprintf fmt "%s++;"))) - (mk_k m) - (pp_acsl_line - (pp_assert - (pp_and_l (fun fmt v -> - pp_equal pp_var_decl pp_print_int fmt (v, 1))))) - m_c.mstep.step_outputs)) - (k_induction_of machines m) + (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 diff --git a/src/backends/C/c_backend_src.ml b/src/backends/C/c_backend_src.ml index 3cfd4a09..2cb2ce25 100644 --- a/src/backends/C/c_backend_src.ml +++ b/src/backends/C/c_backend_src.ml @@ -631,16 +631,29 @@ module Main (Mod : MODIFIERS_SRC) = struct top_decl_itf = false; } + let get_proto_c machines m = + let c, m_c = contract_of machines m in + Option.bind c (fun _ -> + Option.map + (fun m_c -> + let stateless_c = fst (get_stateless_status m_c) in + ( (if stateless_c then None else Some (mk_mem_c m)), + m_c.mname.node_id, + m_c.mstep.step_inputs, + m_c.mstep.step_outputs )) + m_c) + let pp_stateless_code machines dependencies fmt m = let self = "__ERROR__" in let is_contract = m.mis_contract in + let proto_c = get_proto_c machines m in if not (!Options.ansi && is_generic_node (node_of_machine m)) then (* C99 code *) pp_print_function ~is_contract ~pp_spec:(fun fmt () -> Mod.pp_step_spec fmt machines self self m) ~pp_prototype:Protos.pp_stateless_prototype - ~prototype:(m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs) + ~prototype:(m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs, proto_c) ~pp_local:(pp_c_decl_local_var m) ~base_locals:m.mstep.step_locals ~pp_spec_local:(Mod.pp_c_decl_local_spec_var m) @@ -652,6 +665,7 @@ module Main (Mod : MODIFIERS_SRC) = struct ~checks:m.mstep.step_checks ~pp_instr:(pp_machine_instr dependencies m self self) ~instrs:m.mstep.step_instrs + ~pp_extra:(Mod.pp_contract_step_call m proto_c) fmt else (* C90 code *) @@ -673,7 +687,8 @@ module Main (Mod : MODIFIERS_SRC) = struct ~prototype: ( m.mname.node_id, m.mstep.step_inputs @ gen_locals @ gen_calls, - m.mstep.step_outputs ) + m.mstep.step_outputs, + proto_c) ~pp_local:(pp_c_decl_local_var m) ~base_locals ~pp_init_mpfr_local:(pp_initialize m self (pp_c_var_read m)) @@ -683,6 +698,7 @@ module Main (Mod : MODIFIERS_SRC) = struct ~checks:m.mstep.step_checks ~pp_instr:(pp_machine_instr dependencies m self self) ~instrs:m.mstep.step_instrs + ~pp_extra:(Mod.pp_contract_step_call m proto_c) fmt let pp_clear_reset_code dependencies self mem fmt m = @@ -762,18 +778,7 @@ module Main (Mod : MODIFIERS_SRC) = struct let pp_step_code machines dependencies self mem fmt m = let is_contract = m.mis_contract in - let c, m_c = contract_of machines m in - let proto_c = - Option.bind c (fun _ -> - Option.map - (fun m_c -> - let stateless_c = fst (get_stateless_status m_c) in - ( (if stateless_c then None else Some (mk_mem_c m)), - m_c.mname.node_id, - m_c.mstep.step_inputs, - m_c.mstep.step_outputs )) - m_c) - in + let proto_c = get_proto_c machines m in if not (!Options.ansi && is_generic_node (node_of_machine m)) then (* C99 code *) pp_print_function -- GitLab