diff --git a/src/plugins/e-acsl/Makefile.in b/src/plugins/e-acsl/Makefile.in index a44d27242911d78ca3342a8cac5779d96a85f5d7..06edca935965881a93c24f23401dc0211922ed8e 100644 --- a/src/plugins/e-acsl/Makefile.in +++ b/src/plugins/e-acsl/Makefile.in @@ -64,7 +64,8 @@ SRC_ANALYSES:=$(addprefix src/analyses/, $(SRC_ANALYSES)) # code generator SRC_CODE_GENERATOR:= \ - constructor \ + smart_exp \ + smart_stmt \ gmp \ label \ env \ diff --git a/src/plugins/e-acsl/headers/header_spec.txt b/src/plugins/e-acsl/headers/header_spec.txt index 41708b793a5ad7c2b97a1cf4fb703068e7457a1f..f5d1c3fe39a487370af0db226395887366102ade 100644 --- a/src/plugins/e-acsl/headers/header_spec.txt +++ b/src/plugins/e-acsl/headers/header_spec.txt @@ -52,8 +52,6 @@ src/analyses/typing.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/analyses/typing.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/at_with_lscope.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/at_with_lscope.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL -src/code_generator/constructor.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL -src/code_generator/constructor.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/env.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/env.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/global_observer.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL @@ -80,6 +78,10 @@ src/code_generator/quantif.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/quantif.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/rational.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/rational.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL +src/code_generator/smart_exp.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL +src/code_generator/smart_exp.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL +src/code_generator/smart_stmt.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL +src/code_generator/smart_stmt.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/temporal.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/temporal.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL src/code_generator/translate.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL diff --git a/src/plugins/e-acsl/src/code_generator/smart_exp.ml b/src/plugins/e-acsl/src/code_generator/smart_exp.ml new file mode 100644 index 0000000000000000000000000000000000000000..f3dac85ffd20bd197d046e874ae3a7a40f68e207 --- /dev/null +++ b/src/plugins/e-acsl/src/code_generator/smart_exp.ml @@ -0,0 +1,46 @@ +(**************************************************************************) +(* *) +(* This file is part of the Frama-C's E-ACSL plug-in. *) +(* *) +(* Copyright (C) 2012-2020 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +open Cil_types + +let lval ~loc lv = + Cil.new_exp ~loc (Lval lv) + +let deref ~loc lv = lval ~loc (Mem lv, NoOffset) + +let subscript ~loc array idx = + match Misc.extract_uncoerced_lval array with + | Some { enode = Lval lv } -> + let subscript_lval = Cil.addOffsetLval (Index(idx, NoOffset)) lv in + lval ~loc subscript_lval + | Some _ | None -> + Options.fatal + ~current:true + "Trying to create a subscript on an array that is not an Lval: %a" + Cil_types_debug.pp_exp + array + +(* +Local Variables: +compile-command: "make -C ../../../../.." +End: +*) diff --git a/src/plugins/e-acsl/src/code_generator/smart_exp.mli b/src/plugins/e-acsl/src/code_generator/smart_exp.mli new file mode 100644 index 0000000000000000000000000000000000000000..566702f1e8012f361cfb3beaf9e3683bf50f94a4 --- /dev/null +++ b/src/plugins/e-acsl/src/code_generator/smart_exp.mli @@ -0,0 +1,43 @@ +(**************************************************************************) +(* *) +(* This file is part of the Frama-C's E-ACSL plug-in. *) +(* *) +(* Copyright (C) 2012-2020 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +open Cil_types + +(* ********************************************************************** *) +(* Helper functions to build expressions *) +(* ********************************************************************** *) + +val lval: loc:location -> lval -> exp +(** Construct an lval expression from an lval. *) + +val deref: loc:location -> exp -> exp +(** Construct a dereference of an expression. *) + +val subscript: loc:location -> exp -> exp -> exp +(** [mk_subscript ~loc array idx] Create an expression to access the [idx]'th + element of the [array]. *) + +(* +Local Variables: +compile-command: "make -C ../../../../.." +End: +*) diff --git a/src/plugins/e-acsl/src/code_generator/constructor.ml b/src/plugins/e-acsl/src/code_generator/smart_stmt.ml similarity index 70% rename from src/plugins/e-acsl/src/code_generator/constructor.ml rename to src/plugins/e-acsl/src/code_generator/smart_stmt.ml index a38f36ce70e425255853780dbbf358bef43cc0ab..dec6438762f3afb494812fa1799af9bb3557ebc6 100644 --- a/src/plugins/e-acsl/src/code_generator/constructor.ml +++ b/src/plugins/e-acsl/src/code_generator/smart_stmt.ml @@ -22,51 +22,21 @@ open Cil_types -(* ********************************************************************** *) -(* Expressions *) -(* ********************************************************************** *) - -let extract_uncoerced_lval e = - let rec aux e = - match e.enode with - | Lval _ -> Some e - | CastE (_, e) -> aux e - | _ -> None - in - aux e - -let mk_lval ~loc lval = - Cil.new_exp ~loc (Lval lval) - -let mk_deref ~loc lv = mk_lval ~loc (Mem lv, NoOffset) - -let mk_subscript ~loc array idx = - match extract_uncoerced_lval array with - | Some { enode = Lval lval } -> - let subscript_lval = Cil.addOffsetLval (Index(idx, NoOffset)) lval in - mk_lval ~loc subscript_lval - | Some _ | None -> - Options.fatal - ~current:true - "Trying to create a subscript on an array that is not an Lval: %a" - Cil_types_debug.pp_exp - array - (* ********************************************************************** *) (* Statements *) (* ********************************************************************** *) -let mk_stmt sk = Cil.mkStmt ~valid_sid:true sk -let mk_instr i = mk_stmt (Instr i) -let mk_block_stmt blk = mk_stmt (Block blk) -let mk_call ~loc ?result e args = mk_instr (Call(result, e, args, loc)) +let stmt sk = Cil.mkStmt ~valid_sid:true sk +let instr i = stmt (Instr i) +let block_stmt blk = stmt (Block blk) +let call ~loc ?result e args = instr (Call(result, e, args, loc)) -let mk_assigns ~loc ~result e = mk_instr (Set(result, e, loc)) +let assigns ~loc ~result e = instr (Set(result, e, loc)) -let mk_if ~loc ~cond ?(else_blk=Cil.mkBlock []) then_blk = - mk_stmt (If (cond, then_blk, else_blk, loc)) +let if_stmt ~loc ~cond ?(else_blk=Cil.mkBlock []) then_blk = + stmt (If (cond, then_blk, else_blk, loc)) -let mk_break ~loc = mk_stmt (Break loc) +let break ~loc = stmt (Break loc) type annotation_kind = | Assertion @@ -85,19 +55,19 @@ let kind_to_string loc k = | Invariant -> "Invariant" | RTE -> "RTE") -let mk_block stmt b = match b.bstmts with +let block stmt b = match b.bstmts with | [] -> (match stmt.skind with | Instr(Skip _) -> stmt | _ -> assert false) | [ s ] -> s - | _ :: _ -> mk_block_stmt b + | _ :: _ -> block_stmt b (* ********************************************************************** *) (* E-ACSL specific code *) (* ********************************************************************** *) -let mk_lib_call ~loc ?result fname args = +let lib_call ~loc ?result fname args = let vi = try Rtl.Symbols.find_vi fname with Rtl.Symbols.Unregistered _ as exn -> @@ -133,32 +103,32 @@ let mk_lib_call ~loc ?result fname args = | TFun(_, None, _, _) -> [] | _ -> assert false in - mk_call ~loc ?result f args + call ~loc ?result f args -let mk_rtl_call ~loc ?result fname args = - mk_lib_call ~loc ?result (Functions.RTL.mk_api_name fname) args +let rtl_call ~loc ?result fname args = + lib_call ~loc ?result (Functions.RTL.mk_api_name fname) args (* ************************************************************************** *) (** {2 Handling the E-ACSL's C-libraries, part II} *) (* ************************************************************************** *) -let mk_full_init_stmt vi = +let full_init_stmt vi = let loc = vi.vdecl in - mk_rtl_call ~loc "full_init" [ Cil.evar ~loc vi ] + rtl_call ~loc "full_init" [ Cil.evar ~loc vi ] -let mk_initialize ~loc (host, offset as lv) = match host, offset with +let initialize ~loc (host, offset as lv) = match host, offset with | Var _, NoOffset -> - mk_rtl_call ~loc "full_init" [ Cil.mkAddrOf ~loc lv ] + rtl_call ~loc "full_init" [ Cil.mkAddrOf ~loc lv ] | _ -> let typ = Cil.typeOfLval lv in - mk_rtl_call ~loc + rtl_call ~loc "initialize" [ Cil.mkAddrOf ~loc lv; Cil.new_exp loc (SizeOf typ) ] -let mk_named_store_stmt name ?str_size vi = +let named_store_stmt name ?str_size vi = let ty = Cil.unrollType vi.vtype in let loc = vi.vdecl in - let store = mk_rtl_call ~loc name in + let store = rtl_call ~loc name in match ty, str_size with | TArray(_, Some _,_,_), None -> store [ Cil.evar ~loc vi; Cil.sizeOf ~loc ty ] @@ -178,27 +148,27 @@ let mk_named_store_stmt name ?str_size vi = Printer.pp_typ ty Printer.pp_exp size -let mk_store_stmt ?str_size vi = - mk_named_store_stmt "store_block" ?str_size vi +let store_stmt ?str_size vi = + named_store_stmt "store_block" ?str_size vi -let mk_duplicate_store_stmt ?str_size vi = - mk_named_store_stmt "store_block_duplicate" ?str_size vi +let duplicate_store_stmt ?str_size vi = + named_store_stmt "store_block_duplicate" ?str_size vi -let mk_delete_stmt ?(is_addr=false) vi = +let delete_stmt ?(is_addr=false) vi = let loc = vi.vdecl in - let mk = mk_rtl_call ~loc "delete_block" in + let mk = rtl_call ~loc "delete_block" in match is_addr, Cil.unrollType vi.vtype with | _, TArray(_, Some _, _, _) | true, _ -> mk [ Cil.evar ~loc vi ] | _ -> mk [ Cil.mkAddrOfVi vi ] -let mk_mark_readonly vi = +let mark_readonly vi = let loc = vi.vdecl in - mk_rtl_call ~loc "mark_readonly" [ Cil.evar ~loc vi ] + rtl_call ~loc "mark_readonly" [ Cil.evar ~loc vi ] -let mk_runtime_check_with_msg ~loc msg kind kf e = +let runtime_check_with_msg ~loc msg kind kf e = let file = (fst loc).Filepath.pos_path in let line = (fst loc).Filepath.pos_lnum in - mk_rtl_call ~loc + rtl_call ~loc "assert" [ e; kind_to_string loc kind; @@ -207,13 +177,13 @@ let mk_runtime_check_with_msg ~loc msg kind kf e = Cil.mkString ~loc (Filepath.Normalized.to_pretty_string file); Cil.integer loc line ] -let mk_runtime_check kind kf e p = +let runtime_check kind kf e p = let loc = p.pred_loc in let msg = Kernel.Unicode.without_unicode (Format.asprintf "%a@?" Printer.pp_predicate) p in - mk_runtime_check_with_msg ~loc msg kind kf e + runtime_check_with_msg ~loc msg kind kf e (* Local Variables: diff --git a/src/plugins/e-acsl/src/code_generator/constructor.mli b/src/plugins/e-acsl/src/code_generator/smart_stmt.mli similarity index 64% rename from src/plugins/e-acsl/src/code_generator/constructor.mli rename to src/plugins/e-acsl/src/code_generator/smart_stmt.mli index d21c71e53a434f9905a89fc1ca49ab31df10a781..e0c919a7f8847b7c23e71d536b619837ed59a2f5 100644 --- a/src/plugins/e-acsl/src/code_generator/constructor.mli +++ b/src/plugins/e-acsl/src/code_generator/smart_stmt.mli @@ -20,97 +20,73 @@ (* *) (**************************************************************************) -(** Smart constructors for building C code. *) - open Cil_types -open Cil_datatype - -(* ********************************************************************** *) -(* Expressions *) -(* ********************************************************************** *) - -val extract_uncoerced_lval: exp -> exp option -(** Unroll the [CastE] part of the expression until an [Lval] is found, and - return it. - - If at some point the expression is neither a [CastE] nor an [Lval], then - return [None]. *) - -val mk_lval: loc:location -> lval -> exp -(** Construct an lval expression from an lval. *) - -val mk_deref: loc:Location.t -> exp -> exp -(** Construct a dereference of an expression. *) - -val mk_subscript: loc:location -> exp -> exp -> exp -(** [mk_subscript ~loc array idx] Create an expression to access the [idx]'th - element of the [array]. *) (* ********************************************************************** *) -(* Statements *) +(* Helper functions to build statements *) (* ********************************************************************** *) -val mk_stmt: stmtkind -> stmt +val stmt: stmtkind -> stmt (** Create a statement from a statement kind. *) -val mk_block: stmt -> block -> stmt +val block: stmt -> block -> stmt (** Create a block statement from a block to replace a given statement. Requires that (1) the block is not empty, or (2) the statement is a skip. *) -val mk_block_stmt: block -> stmt +val block_stmt: block -> stmt (** Create a block statement from a block *) -val mk_assigns: loc:location -> result:lval -> exp -> stmt -(** [mk_assigns ~loc ~result value] create a statement to assign the [value] +val assigns: loc:location -> result:lval -> exp -> stmt +(** [assigns ~loc ~result value] create a statement to assign the [value] expression to the [result] lval. *) -val mk_if: +val if_stmt: loc:location -> cond:exp -> ?else_blk:block -> block -> stmt -(** [mk_if ~loc ~cond ~then_blk ~else_blk] create an if statement with [cond] +(** [if ~loc ~cond ~then_blk ~else_blk] create an if statement with [cond] as condition and [then_blk] and [else_blk] as respectively "then" block and "else" block. *) -val mk_break: loc:location -> stmt +val break: loc:location -> stmt (** Create a break statement *) (* ********************************************************************** *) (* E-ACSL specific code: build calls to its RTL API *) (* ********************************************************************** *) -val mk_lib_call: loc:Location.t -> ?result:lval -> string -> exp list -> stmt +val lib_call: loc:location -> ?result:lval -> string -> exp list -> stmt (** Construct a call to a library function with the given name. @raise Rtl.Symbols.Unregistered if the given string does not represent such a function or if library functions were never registered (only possible when using E-ACSL through its API). *) -val mk_rtl_call: loc:Location.t -> ?result:lval -> string -> exp list -> stmt -(** Special version of [mk_lib_call] for E-ACSL's RTL functions. *) +val rtl_call: loc:location -> ?result:lval -> string -> exp list -> stmt +(** Special version of [lib_call] for E-ACSL's RTL functions. *) -val mk_store_stmt: ?str_size:exp -> varinfo -> stmt +val store_stmt: ?str_size:exp -> varinfo -> stmt (** Construct a call to [__e_acsl_store_block] that observes the allocation of the given varinfo. See [share/e-acsl/e_acsl.h] for details about this function. *) -val mk_duplicate_store_stmt: ?str_size:exp -> varinfo -> stmt -(** Same as [mk_store_stmt] for [__e_acsl_duplicate_store_block] that first +val duplicate_store_stmt: ?str_size:exp -> varinfo -> stmt +(** Same as [store_stmt] for [__e_acsl_duplicate_store_block] that first checks for a previous allocation of the given varinfo. *) -val mk_delete_stmt: ?is_addr:bool -> varinfo -> stmt -(** Same as [mk_store_stmt] for [__e_acsl_delete_block] that observes the +val delete_stmt: ?is_addr:bool -> varinfo -> stmt +(** Same as [store_stmt] for [__e_acsl_delete_block] that observes the de-allocation of the given varinfo. If [is_addr] is false (default), take the address of varinfo. *) -val mk_full_init_stmt: varinfo -> stmt -(** Same as [mk_store_stmt] for [__e_acsl_full_init] that observes the +val full_init_stmt: varinfo -> stmt +(** Same as [store_stmt] for [__e_acsl_full_init] that observes the initialization of the given varinfo. The varinfo is the address to fully initialize, no [addrOf] is taken. *) -val mk_initialize: loc:location -> lval -> stmt -(** Same as [mk_store_stmt] for [__e_acsl_initialize] that observes the +val initialize: loc:location -> lval -> stmt +(** Same as [store_stmt] for [__e_acsl_initialize] that observes the initialization of the given left-value. *) -val mk_mark_readonly: varinfo -> stmt -(** Same as [mk_store_stmt] for [__e_acsl_markreadonly] that observes the +val mark_readonly: varinfo -> stmt +(** Same as [store_stmt] for [__e_acsl_markreadonly] that observes the read-onlyness of the given varinfo. *) type annotation_kind = @@ -120,16 +96,16 @@ type annotation_kind = | Invariant | RTE -val mk_runtime_check: +val runtime_check: annotation_kind -> kernel_function -> exp -> predicate -> stmt -(** [mk_runtime_check kind kf e p] generates a runtime check for predicate [p] +(** [runtime_check kind kf e p] generates a runtime check for predicate [p] by building a call to [__e_acsl_assert]. [e] (or [!e] if [reverse] is set to [true]) is the C translation of [p], [kf] is the current kernel_function and [kind] is the annotation kind of [p]. *) -val mk_runtime_check_with_msg: +val runtime_check_with_msg: loc:location -> string -> annotation_kind -> kernel_function -> exp -> stmt -(** [mk_runtime_check_with_msg kind kf e msg] generates a runtime check for [e] +(** [runtime_check_with_msg kind kf e msg] generates a runtime check for [e] (or [!e] if [reverse] is [true]) by building a call to [__e_acsl_assert]. [msg] is the message printed if the runtime check fails. [loc] is the location printed in the message if the runtime check fails. [kf] is the diff --git a/src/plugins/e-acsl/src/libraries/misc.ml b/src/plugins/e-acsl/src/libraries/misc.ml index 0b2cd0d3ad79f9a6f08f442da392e7013fd38041..284d57621d5e2f242f8ada787f1acc8c0d8648af 100644 --- a/src/plugins/e-acsl/src/libraries/misc.ml +++ b/src/plugins/e-acsl/src/libraries/misc.ml @@ -189,6 +189,15 @@ module Id_term = let mem_project = Datatype.never_any_project end) +let extract_uncoerced_lval e = + let rec aux e = + match e.enode with + | Lval _ -> Some e + | CastE (_, e) -> aux e + | _ -> None + in + aux e + (* Local Variables: compile-command: "make -C ../../../../.." diff --git a/src/plugins/e-acsl/src/libraries/misc.mli b/src/plugins/e-acsl/src/libraries/misc.mli index f9c92c19e8097a872a37edc83fa83301a79dd645..6ea105fd88a00e4e4c3621fc90511f9eb943bdc0 100644 --- a/src/plugins/e-acsl/src/libraries/misc.mli +++ b/src/plugins/e-acsl/src/libraries/misc.mli @@ -81,6 +81,13 @@ val finite_min_and_max: Ival.t -> Integer.t * Integer.t module Id_term: Datatype.S_with_collections with type t = term (** Datatype for terms that relies on physical equality. *) +val extract_uncoerced_lval: exp -> exp option +(** Unroll the [CastE] part of the expression until an [Lval] is found, and + return it. + + If at some point the expression is neither a [CastE] nor an [Lval], then + return [None]. *) + (* Local Variables: compile-command: "make -C ../../../../.."