123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)openCil_typesopenVisitor(* To avoid a performance issue, do not fold implicit zero-initializers of large
arrays. For arrays of scalar elements, the outputs of an initializer is
exactly the zone covered by the array. For arrays containing structs with
padding bits, this is an over-approximation, so we prefer folding the
initializer if the array is not too big (the 100 cells limit is arbitrary).
We still need to fold the explicit initializers to collect the inputs. *)letfold_implicit_initializertyp=not(Ast_types.is_arraytyp&&(Ast_types.(is_scalar(direct_element_typetyp))||Ast_info.array_sizetyp>(Integer.of_int100)))letspecialize_state_on_call?stmtkf=matchstmtwith|None->Eva.Results.(at_start_ofkf|>get_cvalue_model)|Somestmt->letfilter=funcs->matchEva.Callstack.top_callsitecswith|Kstmts->Cil_datatype.Stmt.equalsstmt|Kglobal->falseinEva.Results.(at_start_ofkf|>filter_callstackfilter|>get_cvalue_model)classvirtual['a]cumulative_visitor=objectinheritframa_c_inplaceasselfmethodspecialize_state_on_callkf=specialize_state_on_call?stmt:self#current_stmtkfmethodvirtualcompute_kf:kernel_function->'aendclasstypevirtual['a]cumulative_class=objectinherit['a]cumulative_visitormethodbottom:'amethodresult:'amethodjoin:'a->unitmethodcompute_funspec:kernel_function->'amethodclean_kf_result:kernel_function->'a->'aendmoduleMake(X:sigvalanalysis_name:stringtypetmoduleT:Datatype.Swithtypet=tclassvirtualdo_it:[t]cumulative_classend)=structmoduleMemo=Kernel_function.Make_Table(X.T)(structletname="Inout.Cumulative_analysis.Memo("^X.analysis_name^")"letdependencies=[Eva.Analysis.self]letsize=97end)classdo_it_cachedcall_stack=object(self)inheritX.do_it(* The cycle variable holds the list of functions that are
involved in a cycle. As long as it is not empty, we known that
the results we are computing are not complete, and we do not memorize
them *)valmutablecycle=Kernel_function.Hptset.emptymethodprivateadd_cycles=cycle<-Kernel_function.Hptset.unionscyclemethodcycle=cycle(* Computation using the body of a kernel function. The result is
automatically cached by the function if possible *)methodprivatecompute_kf_with_defkf=letf=Kernel_function.get_definitionkfinifList.exists(Kernel_function.equalkf)call_stackthen(self#add_cycle(Kernel_function.Hptset.singletonkf);self#bottom)elseletcomputer=newdo_it_cached(kf::call_stack)inignore(visitFramacFunction(computer:>frama_c_visitor)f);(* Results on all the statements of the function *)letv=computer#resultinletv=computer#clean_kf_resultkfvin(* recursive calls detected during analysis of the statements*)letcycle_aux=Kernel_function.Hptset.removekfcomputer#cycleinself#add_cyclecycle_aux;ifKernel_function.Hptset.is_emptycyclethen((* No recursive calls, our results are correct *)Inout_parameters.debug"Caching %s result for %a"X.analysis_nameKernel_function.prettykf;Memo.addkfv;)elseInout_parameters.debug"Not caching %s result for %a because of cycle"X.analysis_nameKernel_function.prettykf;v(* Computation and caching for a kernel function, using its spec *)methodprivatecompute_kf_with_spec_generickf=tryMemo.findkfwithNot_found->letr_glob=self#compute_funspeckfinletr_glob=self#clean_kf_resultkfr_globinMemo.addkfr_glob;r_globmethodcompute_kfkf=ifEva.Analysis.use_spec_instead_of_definitionkfthen(* If only a declaration is available, or we are instructed to use
the spec, do so. If a current stmt is available (most of the times),
do not cache the results. Maybe [compute_funspec] will be able
to deliver a more precise result on this given statement *)matchself#current_stmtwith|None->self#compute_kf_with_spec_generickf|Some_stmt->self#compute_funspeckfelsetryMemo.findkfwithNot_found->self#compute_kf_with_defkfendletstatementstmt=letcomputer=newdo_it_cached[]inignore(visitFramacStmt(computer:>frama_c_visitor)stmt);assert(Kernel_function.Hptset.is_emptycomputer#cycle);computer#resultletexprstmte=letcomputer=newdo_it_cached[]incomputer#push_stmtstmt;ignore(visitFramacExpr(computer:>frama_c_visitor)e);assert(Kernel_function.Hptset.is_emptycomputer#cycle);computer#resultletkernel_functionkf=letcomputer=newdo_it_cached[]incomputer#join(computer#compute_kfkf);assert(Kernel_function.Hptset.is_emptycomputer#cycle);computer#resultend