diff --git a/Makefile b/Makefile index 5136dd9a8b93c557310c9baea7309210b55371ed..d72ead1c599395731de6ce68dd59559fbe4a8410 100644 --- a/Makefile +++ b/Makefile @@ -565,6 +565,7 @@ KERNEL_CMO=\ src/kernel_internals/typing/rmtmps.cmo \ src/kernel_internals/typing/oneret.cmo \ src/kernel_internals/typing/frontc.cmo \ + src/kernel_internals/typing/substitute_const_globals.cmo \ src/kernel_services/analysis/ordered_stmt.cmo \ src/kernel_services/analysis/wto_statement.cmo \ src/kernel_services/analysis/dataflows.cmo \ diff --git a/headers/header_spec.txt b/headers/header_spec.txt index f93a3797c6f1586aaeaa52de9858856bd5509e5b..035be22244998a83b6c849bbf177f4298364856e 100644 --- a/headers/header_spec.txt +++ b/headers/header_spec.txt @@ -405,6 +405,8 @@ src/kernel_internals/typing/translate_lightweight.ml: CEA_INRIA_LGPL src/kernel_internals/typing/translate_lightweight.mli: CEA_INRIA_LGPL src/kernel_internals/typing/unroll_loops.ml: CEA_LGPL src/kernel_internals/typing/unroll_loops.mli: CEA_LGPL +src/kernel_internals/typing/substitute_const_globals.ml: CEA_LGPL +src/kernel_internals/typing/substitute_const_globals.mli: CEA_LGPL src/kernel_services/README.md: .ignore src/kernel_services/abstract_interp/README.md: .ignore src/kernel_services/abstract_interp/abstract_interp.ml: CEA_LGPL diff --git a/src/kernel_internals/typing/substitute_const_globals.ml b/src/kernel_internals/typing/substitute_const_globals.ml new file mode 100644 index 0000000000000000000000000000000000000000..f83359c0980171c11e5bd7e8d37a716598389574 --- /dev/null +++ b/src/kernel_internals/typing/substitute_const_globals.ml @@ -0,0 +1,109 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2019 *) +(* 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). *) +(* *) +(**************************************************************************) + +(* Syntactic substitution of globals, defined with the attribute 'const', with + respective initializers. *) + +open Cil_types +open Cil_datatype +open Cil + +class constGlobSubstVisitorClass : cilVisitor = object + inherit nopCilVisitor + + val vi_to_init_opt = Varinfo.Hashtbl.create 7 + + (* Visit globals and register only the association between globals with attribute + 'const' and respective initializers. *) + method! vglob g = + let rec is_arithmetic_type = function + | TArray (typ, _, _, _) -> is_arithmetic_type typ + | TInt _ | TFloat _ | TEnum _ -> true + | _ -> false + in + match g with + | GVar (vi, _, _) -> + (* Register in [vi_to_init_opt] the association between [vi] and its + initializer [init_opt]. The latter is assumed to be an expression of + literal constants only, as the lvals originally appearing in it have + been substituted by the respective initializers in method [vexpr]. *) + let register = function + | GVar (vi, { init = init_opt }, _loc) as g -> + Varinfo.Hashtbl.add vi_to_init_opt vi init_opt; + g + | _ -> + (* Cannot happen as we treat only [GVar _] cases in the outer + pattern matching. *) + assert false + in + let typ = unrollTypeDeep vi.vtype in + if is_arithmetic_type typ && isConstType typ + then ChangeDoChildrenPost ([g], List.map register) + else DoChildren + | _ -> + DoChildren + + (* Visit expressions and replace lvals, with a registered varinfo in + [vi_to_init_opt], with respective initializing constant expressions. *) + method! vexpr e = + match e.enode with + | Lval (Var vi, (NoOffset | Index _ as offset)) -> + (* Support for variables and array, on arithmetic types only. *) + begin match Varinfo.Hashtbl.find vi_to_init_opt vi with + | None -> + (* Since [vi] is a global, we replace it with the zero expression, + i.e. the implicit initializer for such globals. *) + let newexp = zero ~loc:e.eloc in + ChangeTo newexp + | Some init -> + let offset = constFoldOffset true offset in + let zero_exp = zero ~loc:e.eloc in + let rec find_replace current_offset current_init current_newexp = + match current_init with + | SingleInit si -> + if Cil_datatype.OffsetStructEq.equal offset current_offset + then new_exp ~loc:e.eloc si.enode + else current_newexp + | CompoundInit (ct, initl) -> + (* We are dealing with an array: recursively [find_replace] among + its initializers. *) + foldLeftCompound + ~implicit:true + ~doinit:(fun coffset cinit _ acc -> + find_replace + (addOffset coffset current_offset) + cinit + acc) + ~ct + ~initl + ~acc:current_newexp + in + let newexp = find_replace NoOffset init zero_exp in + ChangeTo newexp + | exception Not_found -> + DoChildren + end + | _ -> + DoChildren +end + +let constGlobSubstVisitor = new constGlobSubstVisitorClass diff --git a/src/kernel_internals/typing/substitute_const_globals.mli b/src/kernel_internals/typing/substitute_const_globals.mli new file mode 100644 index 0000000000000000000000000000000000000000..b38eba1ea90bd212460e9f2cbb6db5b95e17ebb7 --- /dev/null +++ b/src/kernel_internals/typing/substitute_const_globals.mli @@ -0,0 +1,25 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2019 *) +(* 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). *) +(* *) +(**************************************************************************) + +(** A visitor that substitutes globals, defined with the attribute 'const', with + respective initializers. *) +val constGlobSubstVisitor: Cil.cilVisitor diff --git a/src/kernel_services/ast_queries/cil.ml b/src/kernel_services/ast_queries/cil.ml index d19c4462c5a0b2174ee065e11726de1e97b85011..296fe6418d175111fe618bb268b5ba7319a131c5 100644 --- a/src/kernel_services/ast_queries/cil.ml +++ b/src/kernel_services/ast_queries/cil.ml @@ -6305,86 +6305,6 @@ let foldLeftCompound | _ -> Kernel.fatal ~current:true "Type of Compound is not array or struct or union" -class constGlobSubstVisitorClass : cilVisitor = object - inherit nopCilVisitor - - val vi_to_init_opt = Varinfo.Hashtbl.create 7 - - (* Visit globals and register only the association between globals with attribute - 'const' and respective initializers. *) - method! vglob g = - let rec is_arithmetic_type = function - | TArray (typ, _, _, _) -> is_arithmetic_type typ - | TInt _ | TFloat _ | TEnum _ -> true - | _ -> false - in - match g with - | GVar (vi, _, _) -> - (* Register in [vi_to_init_opt] the association between [vi] and its - initializer [init_opt]. The latter is assumed to be an expression of - literal constants only, as the lvals originally appearing in it have - been substituted by the respective initializers in method [vexpr]. *) - let register = function - | GVar (vi, { init = init_opt }, _loc) as g -> - Varinfo.Hashtbl.add vi_to_init_opt vi init_opt; - g - | _ -> - (* Cannot happen as we treat only [GVar _] cases in the outer - pattern matching. *) - assert false - in - let typ = unrollTypeDeep vi.vtype in - if is_arithmetic_type typ && isConstType typ - then ChangeDoChildrenPost ([g], List.map register) - else DoChildren - | _ -> - DoChildren - - (* Visit expressions and replace lvals, with a registered varinfo in - [vi_to_init_opt], with respective initializing constant expressions. *) - method! vexpr e = - match e.enode with - | Lval (Var vi, (NoOffset | Index _ as offset)) -> - (* Support for variables and array, on arithmetic types only. *) - begin match Varinfo.Hashtbl.find vi_to_init_opt vi with - | None -> - (* Since [vi] is a global, we replace it with the zero expression, - i.e. the implicit initializer for such globals. *) - let newexp = zero ~loc:e.eloc in - ChangeTo newexp - | Some init -> - let offset = constFoldOffset true offset in - let zero_exp = zero ~loc:e.eloc in - let rec find_replace current_offset current_init current_newexp = - match current_init with - | SingleInit si -> - if Cil_datatype.OffsetStructEq.equal offset current_offset - then new_exp ~loc:e.eloc si.enode - else current_newexp - | CompoundInit (ct, initl) -> - (* We are dealing with an array: recursively [find_replace] among - its initializers. *) - foldLeftCompound - ~implicit:true - ~doinit:(fun coffset cinit _ acc -> - find_replace - (addOffset coffset current_offset) - cinit - acc) - ~ct - ~initl - ~acc:current_newexp - in - let newexp = find_replace NoOffset init zero_exp in - ChangeTo newexp - | exception Not_found -> - DoChildren - end - | _ -> - DoChildren -end -let constGlobSubstVisitor = new constGlobSubstVisitorClass - let has_flexible_array_member t = let is_flexible_array t = match unrollType t with diff --git a/src/kernel_services/ast_queries/cil.mli b/src/kernel_services/ast_queries/cil.mli index c04e0fb5423ba56e143c6533bfadc59955436680..564979fc95ae2a5017bdb73ecb1e062a7dfb3901 100644 --- a/src/kernel_services/ast_queries/cil.mli +++ b/src/kernel_services/ast_queries/cil.mli @@ -893,6 +893,10 @@ val constFoldTermNodeAtTop: term_node -> term_node and [alignof]. *) val constFoldTerm: bool -> term -> term +(** Do constant folding on a {!Cil_types.offset}. If the second argument is true + then will also compute compiler-dependent expressions such as [sizeof]. *) +val constFoldOffset: bool -> offset -> offset + (** Do constant folding on a binary operation. The bulk of the work done by [constFold] is done here. If the second argument is true then will also compute compiler-dependent expressions such as [sizeof]. *) @@ -1971,10 +1975,6 @@ val is_skip: stmtkind -> bool machine specific simplifications to be done, or not. *) val constFoldVisitor: bool -> cilVisitor -(** A visitor that substitutes globals, defined with the attribute 'const', by - their constant initializing expressions. *) -val constGlobSubstVisitor: cilVisitor - (* ************************************************************************* *) (** {2 Debugging support} *) (* ************************************************************************* *) diff --git a/src/kernel_services/ast_queries/file.ml b/src/kernel_services/ast_queries/file.ml index 0737eb2419b220bd49f03d39e37e97f8fb6d2117..32b6ac62cbad411e1f4e2095cf0ce970a35c6225 100644 --- a/src/kernel_services/ast_queries/file.ml +++ b/src/kernel_services/ast_queries/file.ml @@ -1105,7 +1105,10 @@ let () = let constglobfold = register_code_transformation_category "constglobfold" in let syntactic_const_globals_substitution ast = if Kernel.Constfold.get () - then Cil.visitCilFileSameGlobals Cil.constGlobSubstVisitor ast + then + Cil.visitCilFileSameGlobals + Substitute_const_globals.constGlobSubstVisitor + ast in add_code_transformation_before_cleanup ~deps:[ (module Kernel.Constfold: Parameter_sig.S) ]