123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* 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). *)(* *)(**************************************************************************)openCil_datatypeopenPdg_typesopenPdgIndex(** compute the marks to propagate in the caller nodes from the marks of
* a function inputs [in_marks].
*)letin_marks_to_callerpdgcallm2m?(rqs=[])in_marks=letadd_n_maccnz_optm=letselect=PdgMarks.mk_select_node~z_optninmatchm2mselectmwith|None->acc|Somem->PdgMarks.add_to_selectaccselectminletbuildrqs(in_key,m)=matchin_keywith|Signature.InCtrl->add_n_mrqs(Sets.find_call_ctrl_nodepdgcall)Nonem|Signature.InNumin_num->add_n_mrqs(Sets.find_call_num_input_nodepdgcallin_num)Nonem|Signature.InImplzone->letnodes,undef=Sets.find_location_nodes_at_stmtpdgcall~before:truezoneinletrqs=List.fold_left(funacc(n,z)->add_n_maccnzm)rqsnodesinletrqs=matchundefwithNone->rqs|Somez->matchm2m(PdgMarks.mk_select_undef_zonez)mwithNone->rqs|Somem->PdgMarks.add_undef_in_to_selectrqsundefminrqsinList.fold_leftbuildrqsin_marks(** some new input marks has been added in a called function.
* Build the list of what is to be propagated in the callers.
* Be careful that some Pdg can be top : in that case, a list of mark is
* returned (Beware that m2m has NOT been called in that case).
* *)lettranslate_in_markspdg_calledin_new_marks?(m2m=fun___m->Somem)other_rqs=letkf_called=PdgTypes.Pdg.get_kfpdg_calledinlettranslatepdgrqscall=in_marks_to_callerpdgcall(m2m(Somecall)pdg)~rqsin_new_marksinletbuildrqscaller=letpdg_caller=Pdg_tbl.getcallerinletcaller_rqs=tryletcall_stmts=Sets.find_call_stmts~callerkf_calledin(* TODO : more intelligent merge ? *)letrqs=List.fold_left(translatepdg_caller)[]call_stmtsinPdgMarks.SelListrqswithPdgTypes.Pdg.Top->letmarks=List.fold_left(funacc(_,m)->m::acc)[]in_new_marksinPdgMarks.SelTopMarksmarks(* #345 *)in(pdg_caller,caller_rqs)::rqsinList.fold_leftbuildother_rqs(Eva.Results.callerskf_called)letcall_out_marks_to_calledcalled_pdgm2m?(rqs=[])out_marks=letbuildrqs(out_key,m)=letnodes,undef=Sets.find_output_nodescalled_pdgout_keyinletsel=List.map(fun(n,_z_opt)->PdgMarks.mk_select_node~z_opt:Nonen)nodesinletsel=matchundefwithNone->sel|Someundef->(PdgMarks.mk_select_undef_zoneundef)::selinletaddaccs=matchm2msmwith|None->acc|Somem->(s,m)::accinletrqs=List.fold_leftaddrqsselinrqsinList.fold_leftbuildrqsout_markslettranslate_out_mark_pdgm2mother_rqs(call,l)=letadd_listl_out_mrqscalled_kf=letcalled_pdg=Pdg_tbl.getcalled_kfinletm2m=m2m(Somecall)called_pdgintryletnode_marks=call_out_marks_to_calledcalled_pdgm2m~rqs:[]l_out_min(called_pdg,PdgMarks.SelListnode_marks)::rqswithPdgTypes.Pdg.Top->(* no PDG for this function : forget the new marks
* because anyway, the source function will be called.
* *)rqsinletall_called=Eva.Results.calleecallinList.fold_left(add_listl)other_rqsall_called(** [add_new_marks_to_rqs pdg new_marks other_rqs] translates [new_marks]
* that were computed during intraprocedural propagation into requests,
* and add them to [other_rqs].
*
* The functions [in_m2m] and [out_m2m] can be used to modify the marks during
* propagation :
*- [in_m2m call_stmt call_in_node mark] :
provide the mark to propagate to the [call_in_node]
knowing that the mark of the called function has been modify to [mark]
*- [out_m2m out_node mark] :
provide the mark to propagate to the [out_node]
knowing that a call output mark has been modify to [mark].
*)lettranslate_marks_to_proppdgnew_marks?(in_m2m=fun___m->Somem)?(out_m2m=fun___m->Somem)other_rqs=letin_marks,out_marks=new_marksinletother_rqs=translate_in_markspdgin_marks~m2m:in_m2mother_rqsinletrqs=List.fold_left(translate_out_markpdgout_m2m)other_rqsout_marksinrqs(** To also use interprocedural propagation, the user can instantiate this
* functor. This is, of course, not mandatory because one can want to use a more
* complex propagation (like slicing for instance, that has more than one
* version for a source function). *)moduleF_Proj(C:PdgMarks.Config):PdgMarks.Projwithtypemark=C.M.tandtypecall_info=C.M.call_info=structmoduleF=PdgMarks.F_Fct(C.M)typemark=C.M.ttypecall_info=C.M.call_infotypefct=F.fitypefct_info=F.ttypet=fct_infoVarinfo.Hashtbl.tletempty()=Varinfo.Hashtbl.create10letfind_marksprojfct_var=tryletf=Varinfo.Hashtbl.findprojfct_varinSome(F.get_idxf)withNot_found->Noneletgetprojpdg=letkf=PdgTypes.Pdg.get_kfpdginletfct_var=Kernel_function.get_vikfintryVarinfo.Hashtbl.findprojfct_varwithNot_found->letpdg=Pdg_tbl.getkfinletinfo=F.createpdginVarinfo.Hashtbl.addprojfct_varinfo;info(** Add the marks to the pdg nodes.
* @return a merge between the input [other_rqs] and the new requests produced.
* *)letapply_fct_rqsproj(pdg,mark_list)other_rqs=matchmark_listwith|PdgMarks.SelList[]|PdgMarks.SelTopMarks[]->(* don't want to build the marks when calling [get]
if there is nothing to do... *)other_rqs|PdgMarks.SelListmark_list->letfm=getprojpdginletto_prop=F.mark_and_propagatefmmark_listinletrqs=translate_marks_to_proppdgto_prop~in_m2m:C.mark_to_prop_to_caller_input~out_m2m:C.mark_to_prop_to_called_outputother_rqsinrqs|PdgMarks.SelTopMarks_marks->(* TODO #345 *)Pdg_parameters.not_yet_implemented"mark propagation in Top PDG"(** Add the marks to the pdg nodes and also apply all the produced requests
* to do the interprocedural propagation. *)letmark_and_propagateprojpdgnode_marks=letrecapply_allrqs=matchrqswith|[]->()|rq::tl_rqs->letnew_rqs=apply_fct_rqsprojrqtl_rqsinapply_allnew_rqsinapply_all[(pdg,PdgMarks.SelListnode_marks)]end(*
Local Variables:
compile-command: "make -C ../../.."
End:
*)