123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444(**************************************************************************)(* *)(* 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). *)(* *)(**************************************************************************)(** Everything related with the marks. Mainly quite low level function. *)openPdg_types(**/**)letdebug=false(**/**)(** a [Mark] is used to represent some information about the status of
* a PDG element in a slice.
*)moduleMark:sigvalbottom:SlicingInternals.markvalspare:SlicingInternals.markvaldata:SlicingInternals.markvalctrl:SlicingInternals.markvaladdr:SlicingInternals.markvalmk_adc:bool->bool->bool->SlicingInternals.markvalis_bottom:SlicingInternals.mark->boolvalis_top:SlicingInternals.mark->boolvalis_included:SlicingInternals.mark->SlicingInternals.mark->bool(** this operation has to be commutative.
It is used to merge two slices into one.
*)valmerge:SlicingInternals.mark->SlicingInternals.mark->SlicingInternals.markvalinter:SlicingInternals.mark->SlicingInternals.mark->SlicingInternals.mark(** this operation add a new information to the old value.
* @return (new_mark, is_new)
where is_new=true if the new_mark is not included in the old one.
*)valcombine:old:SlicingInternals.mark->SlicingInternals.mark->bool*SlicingInternals.mark(** [minus m1 m2] provides the mark [m] that you have to merge with [m2] to
* get at least [m1]. So : [m1 <= m U m2]
* If [m1 <= m2] then [m = bot].
* *)valminus:SlicingInternals.mark->SlicingInternals.mark->SlicingInternals.markvalpretty:Format.formatter->SlicingInternals.mark->unitend=structletspare=SlicingInternals.Spare(* Internal constructor *)letcreate_adcadc=SlicingInternals.Cav(PdgTypes.Dpd.make~a~d~c())letbottom=SlicingInternals.CavPdgTypes.Dpd.bottomlettop=SlicingInternals.CavPdgTypes.Dpd.topletaddr=create_adctruefalsefalseletdata=create_adcfalsetruefalseletctrl=create_adcfalsefalsetrueletm_ad=create_adctruetruefalseletm_ac=create_adctruefalsetrueletm_dc=create_adcfalsetruetrueletcreateadc=matchadcwith|false,false,false->bottom|true,false,false->addr|false,true,false->data|false,false,true->ctrl|true,true,false->m_ad|true,false,true->m_ac|false,true,true->m_dc|true,true,true->top(* External constructor sharing same values *)letmk_adcadc=create(a,d,c)letmk_markdpd=create(PdgTypes.Dpd.adc_valuedpd)letis_bottomm=(m=bottom)letis_topm=(m=top)letis_includedm1m2=matchm1,m2with|SlicingInternals.Spare,SlicingInternals.Spare->true|SlicingInternals.Spare,SlicingInternals.Cav_->not(is_bottomm2)|SlicingInternals.Cav_,SlicingInternals.Spare->is_bottomm1|SlicingInternals.Cavd1,SlicingInternals.Cavd2->PdgTypes.Dpd.is_includedd1d2letmergem1m2=matchm1,m2with|SlicingInternals.Spare,SlicingInternals.Spare->m1|SlicingInternals.Spare,SlicingInternals.Cav_->ifis_bottomm2thenm1elsem2|SlicingInternals.Cav_,SlicingInternals.Spare->ifis_bottomm1thenm2elsem1|SlicingInternals.Cavd1,SlicingInternals.Cavd2->mk_mark(PdgTypes.Dpd.combined1d2)letinterm1m2=ifis_bottomm1thenm1elseifis_bottomm2thenm2else(* m1 and m2 are not bottom => the result cannot be bottom *)matchm1,m2with|SlicingInternals.Spare,_->m1|_,SlicingInternals.Spare->m2|SlicingInternals.Cavd1,SlicingInternals.Cavd2->letm=mk_mark(PdgTypes.Dpd.interd1d2)inifis_bottommthenspareelsemletcombine~oldm=matchold,mwith|SlicingInternals.Spare,SlicingInternals.Spare->(false,old)|SlicingInternals.Cavold_d,SlicingInternals.Spare->ifPdgTypes.Dpd.is_bottomold_dthen(true,m)else(false,old)|SlicingInternals.Spare,SlicingInternals.Cavnew_d->ifPdgTypes.Dpd.is_bottomnew_dthen(false,old)else(true,m)|SlicingInternals.Cavold_d,SlicingInternals.Cavnew_d->letnew_d=PdgTypes.Dpd.combineold_dnew_dinifold_d=new_dthen(false,old)else(true,mk_marknew_d)letminusm1m2=matchm1,m2with|SlicingInternals.Spare,SlicingInternals.Spare->bottom|SlicingInternals.Spare,SlicingInternals.Cavd2->ifPdgTypes.Dpd.is_bottomd2thenm1elsebottom|SlicingInternals.Cav_,SlicingInternals.Spare->m1(* even if [PdgTypes.Dpd.is_bottom d1] because m1 = bot *)|SlicingInternals.Cavd1,SlicingInternals.Cavd2->mk_mark(PdgTypes.Dpd.minusd1d2)letprettyfmtm=matchmwith|SlicingInternals.Cavd->PdgTypes.Dpd.prettyfmtd|SlicingInternals.Spare->Format.fprintffmt"[ S ]"end(** a [SlicingInternals.pdg_mark] is associated with each element of the PDG in a slice.
* The first component gives the mark propagated from a user request, while
* the second one is used to propagate informations to the called functions.
*)letmk_m1m1={SlicingInternals.m1=m1;m2=Mark.bottom}letmk_m2m2={SlicingInternals.m1=Mark.bottom;m2=m2}letbottom_mark={SlicingInternals.m1=Mark.bottom;m2=Mark.bottom}letuser_markm=Mark.mergem.SlicingInternals.m1m.SlicingInternals.m2letis_bottom_markm=(Mark.is_bottom(user_markm))moduleMarkPair=structletmk_m1_spare=mk_m1Mark.spareletmk_gen_spare=mk_m2Mark.spareletis_topm=(Mark.is_topm.SlicingInternals.m1)&&(Mark.is_topm.SlicingInternals.m2)letis_ctrlm=(Mark.is_includedMark.ctrl(user_markm))letis_addrm=(Mark.is_includedMark.addr(user_markm))letis_datam=(Mark.is_includedMark.data(user_markm))letis_sparem=not(is_bottom_markm)&¬(is_ctrlm||is_addrm||is_datam)letcompare=SlicingInternals.compare_pdg_marklet_is_includedmamb=Mark.is_includedma.SlicingInternals.m1mb.SlicingInternals.m1&&Mark.is_includedma.SlicingInternals.m2mb.SlicingInternals.m2letprettyfmtm=Format.fprintffmt"@[<hv><%a,@ %a>@]"Mark.prettym.SlicingInternals.m1Mark.prettym.SlicingInternals.m2letto_stringm=Format.asprintf"%a"prettymletminusmamb={SlicingInternals.m1=Mark.minusma.SlicingInternals.m1mb.SlicingInternals.m1;m2=Mark.minusma.SlicingInternals.m2mb.SlicingInternals.m2}(** see {! Mark.merge} *)letmergemamb=letm1=Mark.mergema.SlicingInternals.m1mb.SlicingInternals.m1inletm2=Mark.mergema.SlicingInternals.m2mb.SlicingInternals.m2in{SlicingInternals.m1=m1;m2=m2}(** merge only ma_1 et mb_1, m_2 is always bottom *)letmerge_user_marksmamb=letm1=Mark.mergema.SlicingInternals.m1mb.SlicingInternals.m1in{SlicingInternals.m1=m1;m2=Mark.bottom}letrecmerge_allmarks=matchmarkswith|[]->bottom_mark|m::[]->m(* to avoid merging with bottom every time ! *)|m::tl->mergem(merge_alltl)letintermamb=letm1=Mark.interma.SlicingInternals.m1mb.SlicingInternals.m1inletm2=Mark.interma.SlicingInternals.m2mb.SlicingInternals.m2in{SlicingInternals.m1=m1;m2=m2}letrecinter_allmarks=matchmarkswith|[]->bottom_mark|m::[]->m|m::tl->interm(inter_alltl)(** [combine ma mb] is used to add the [mb] to the [ma].
* @return two marks : the first one is the new mark (= merge),
* and the second is the one to propagate.
* Notice that if the mark to propagate is bottom,
* it means that [mb] was included in [ma].
*)letcombinemamb=letcombine_mmamb=letis_new,mr=Mark.combine~old:mambinletm_to_prop=ifis_newthenmrelseMark.bottominmr,m_to_propinletnew_m1,prop1=combine_mma.SlicingInternals.m1mb.SlicingInternals.m1inletnew_m2,prop2=combine_mma.SlicingInternals.m2mb.SlicingInternals.m2in{SlicingInternals.m1=new_m1;m2=new_m2},{SlicingInternals.m1=prop1;m2=prop2}(** we want to know if the called function [g] with output marks
* [m_out_called] compute enough things to be used in [f] call
* with output marks [m_out_call].
* Remember the [mf1] marks propagates as [mg2] and the marks to add
* can only be [m2] marks.
* TODO : write this down in the specification
* and check with Patrick if it is ok.
* *)letmissing_output~call:m_out_call~called:m_out_called=ifdebugthenFormat.printf"check_out : call=%a called=%a\n"prettym_out_callprettym_out_called;letmf1=m_out_call.SlicingInternals.m1inletmf2=m_out_call.SlicingInternals.m2inletmg1=m_out_called.SlicingInternals.m1inletmg2=m_out_called.SlicingInternals.m2inletneeded_mg2=(* we need (mf1 + mf2) for this out in the call *)Mark.mergemf1mf2inletmin_mg2=(* let remove from needed_mg2 what we have in mg1 *)Mark.minusneeded_mg2mg1inifMark.is_includedmin_mg2mg2thenNoneelseletm2=mk_m2min_mg2inifdebugthenFormat.printf"check_out missing output -> %a\n"prettym2;(Somem2)(** tells if the caller ([f]) computes enough inputs for the callee ([g]).
* Remember that [mg1] has to be propagated as [mf1],
* but [mg2] has to be propagated as [mf2=spare] *)letmissing_input~call:m_in_call~called:m_in_called=letmf1=m_in_call.SlicingInternals.m1inletmf2=m_in_call.SlicingInternals.m2inletmg1=m_in_called.SlicingInternals.m1inletmg2=m_in_called.SlicingInternals.m2inletnew_mf1=ifMark.is_includedmg1mf1thenMark.bottomelsemg1inletnew_mf2=if(not(Mark.is_bottommg2))&&(Mark.is_bottommf2)thenMark.spareelseMark.bottominletnew_m={SlicingInternals.m1=new_mf1;m2=new_mf2}inifis_bottom_marknew_mthenNoneelseSomenew_mend(** [SigMarks] works on the marks in function signatures.
*)moduleSigMarks=structopenPdgIndextypet=SlicingInternals.pdg_markSignature.tletpretty=Signature.prettyMarkPair.prettyletget_input_mark(sgn:t)n=Signature.find_inputsgnnletget_in_ctrl_mark(sgn:t)=Signature.find_in_ctrlsgnletget_in_top_mark(sgn:t)=Signature.find_in_topsgnletget_all_input_marks(sgn:t)=Signature.fold_all_inputs(funacc(k,m)->(k,m)::acc)[]sgnletget_matching_input_marks(sgn:t)z=Signature.fold_all_inputs(funacc(k,m)->matchkwith|PdgIndex.Signature.InCtrl|PdgIndex.Signature.InNum_->(k,m)::acc|PdgIndex.Signature.InImplz'->ifLocations.Zone.intersectszz'then(k,m)::accelseacc)[]sgnexceptionVisibleletraise_if_visible()(_,m)=ifis_bottom_markmthen()elseraiseVisibleletsome_visible_outcm=trySignature.fold_all_outputsraise_if_visible()cm;falsewithVisible->trueletis_topin_visiblecm=tryletm=get_in_top_markcminnot(is_bottom_markm)withNot_found->falseletctrl_visiblecm=tryletctrl_m=get_in_ctrl_markcminnot(is_bottom_markctrl_m)withNot_found->falseletsome_visible_incm=trySignature.fold_num_inputsraise_if_visible()cm;ctrl_visiblecmwithVisible->trueletmerge_inputs_m1_markcm=Signature.fold_all_inputs(funacc(_,m)->MarkPair.merge_user_marksaccm)bottom_markcm(** @return an under-approximation of the mark for the given location.
* If the location is not included in the union of the implicit inputs,
* it returns bottom.
* Else, it returns the intersection of the inputs that intersect the location.
*)letget_input_loc_under_markcmloc=ifdebugthenFormat.printf"get_input_loc_under_mark of %a"Locations.Zone.prettyloc;assert(not(Locations.Zone.equalLocations.Zone.bottomloc));letdo_in(marked_inputs,marks)(in_loc,m)=ifis_bottom_markmthen(marked_inputs,[])elseifLocations.Zone.intersectsin_loclocthenletmarked_inputs=Locations.Zone.linkmarked_inputsin_locinletmarks=m::marksin(marked_inputs,marks)else(marked_inputs,marks)inletmarked_inputs=Locations.Zone.bottominletmarked_inputs,marks=Signature.fold_impl_inputsdo_in(marked_inputs,[])cminletm=ifLocations.Zone.is_includedlocmarked_inputsthenMarkPair.inter_allmarkselsebottom_markinifdebugthenFormat.printf"get_input_loc_under_mark : m = %a"MarkPair.prettym;mletsomething_visiblecm=some_visible_outcm||some_visible_incm||ctrl_visiblecmletget_marked_out_zonecall_marks=letadd(out0,out_zone)(out_key,m_out)=ifis_bottom_markm_outthen(out0,out_zone)elsematchout_keywith|PdgIndex.Signature.OutRet->true,out_zone|PdgIndex.Signature.OutLocz->out0,Locations.Zone.joinout_zonezinSignature.fold_all_outputsadd(false,Locations.Zone.bottom)call_marksend(** The mark associated with a call stmt is composed of
* marks for the call inputs (numbered form 1 to [max_in])
* and marks for the call outputs (numbered from 0 to [max_out] *)(** {2 Exported things} *)(** {3 on marks} *)letmk_gen_spare=MarkPair.mk_gen_spareletmk_user_spare=MarkPair.mk_m1_spareletmk_user_mark~data~addr~ctrl=ifaddr||data||ctrlthenmk_m1(Mark.mk_adcaddrdatactrl)elsemk_user_spareletis_top_mark=MarkPair.is_topletis_spare_mark=MarkPair.is_spareletis_ctrl_mark=MarkPair.is_ctrlletis_addr_mark=MarkPair.is_addrletis_data_mark=MarkPair.is_dataletmerge_marks=MarkPair.merge_allletcombine_marks=MarkPair.combineletinter_marks=MarkPair.inter_allletminus_marks=MarkPair.minusletcompare_marks=MarkPair.compareletpretty_mark=MarkPair.prettyletmark_to_string=MarkPair.to_stringletmissing_input_mark=MarkPair.missing_inputletmissing_output_mark=MarkPair.missing_output(** {3 on signatures} *)typesig_marks=SigMarks.tletempty_sig=PdgIndex.Signature.emptyletget_input_mark=SigMarks.get_input_markletget_all_input_marks=SigMarks.get_all_input_marksletget_matching_input_marks=SigMarks.get_matching_input_marksletmerge_inputs_m1_mark=SigMarks.merge_inputs_m1_markletget_input_loc_under_mark=SigMarks.get_input_loc_under_mark(*let same_output_visibility = SigMarks.same_output_visibility*)letget_in_ctrl_mark=SigMarks.get_in_ctrl_markletsomething_visible=SigMarks.something_visibleletsome_visible_out=SigMarks.some_visible_outletis_topin_visible=SigMarks.is_topin_visibleletget_marked_out_zone=SigMarks.get_marked_out_zoneletpretty_sig=SigMarks.pretty(*
Local Variables:
compile-command: "make -C ../../.."
End:
*)