123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305(**************************************************************************)(* *)(* This file is part of WP plug-in of Frama-C. *)(* *)(* Copyright (C) 2007-2025 *)(* CEA (Commissariat a l'energie atomique et aux energies *)(* 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). *)(* *)(**************************************************************************)moduleF=Lang.F(* -------------------------------------------------------------------------- *)(* --- Generic Chunk Type --- *)(* -------------------------------------------------------------------------- *)moduletypeChunkType=sigtypetvalself:stringvalhash:t->intvalequal:t->t->boolvalcompare:t->t->intvalpretty:Format.formatter->t->unitvaltau_of_chunk:t->F.tauvalbasename_of_chunk:t->stringvalis_init:t->boolvalis_primary:t->boolvalis_framed:t->boolend(* -------------------------------------------------------------------------- *)(* --- Generic Sigma Factory --- *)(* -------------------------------------------------------------------------- *)typeckind=..moduletypeTag=sigvaltag:intincludeChunkTypewithtypet:=ckindend(* memory chunks *)typechunk={tag:(moduleTag);ckind:ckind}letckindc=c.ckindmoduleChunk:ChunkTypewithtypet=chunk=structtypet=chunkletself="Core"lethashc=letmoduleT=(valc.tag)inQed.Hcons.hash_pairT.tag@@T.hashc.ckindletequalab=letmoduleA=(vala.tag)inletmoduleB=(valb.tag)inA.tag=B.tag&&A.equala.ckindb.ckindletcompareab=letmoduleA=(vala.tag)inletmoduleB=(valb.tag)inmatchA.is_primarya.ckind,B.is_primaryb.ckindwith|true,false->(-1)|false,true->(+1)|true,true|false,false->letcmp=Int.compareA.tagB.taginifcmp<>0thencmpelseA.comparea.ckindb.ckindletprettyfmtc=letmoduleT=(valc.tag)inT.prettyfmtc.ckindlettau_of_chunkc=letmoduleT=(valc.tag)inT.tau_of_chunkc.ckindletbasename_of_chunkc=letmoduleT=(valc.tag)inT.basename_of_chunkc.ckindletis_initc=letmoduleT=(valc.tag)inT.is_initc.ckindletis_primaryc=letmoduleT=(valc.tag)inT.is_primaryc.ckindletis_framedc=letmoduleT=(valc.tag)inT.is_framedc.ckindendmoduleHeap=Qed.Collection.Make(Chunk)moduleDomain=Heap.Set(* -------------------------------------------------------------------------- *)(* --- Domain --- *)(* -------------------------------------------------------------------------- *)typedomain=Domain.tletempty=Domain.emptyletunion=Domain.union(* -------------------------------------------------------------------------- *)(* --- State --- *)(* -------------------------------------------------------------------------- *)typestate=chunkF.Tmap.tletapplyf(s:state):state=F.Tmap.fold(funtcs->F.Tmap.add(ft)cs)sF.Tmap.empty(* -------------------------------------------------------------------------- *)(* --- Sigma --- *)(* -------------------------------------------------------------------------- *)typesigma=F.varHeap.Map.trefletcreate()=refHeap.Map.emptyletcopysigma=ref!sigmaletnewchunkc=letmoduleT=(valc.tag)inletbasename=T.basename_of_chunkc.ckindinlettau=T.tau_of_chunkc.ckindinLang.freshvar~basenametauletmem(sigma:sigma)c=Heap.Map.memc!sigmaletdomain(sigma:sigma):domain=Heap.Map.domain!sigmaletstate(sigma:sigma):state=lets=refF.Tmap.emptyinHeap.Map.iter(funcx->s:=F.Tmap.add(F.e_varx)c!s)!sigma;!sletgetsigmac=lets=!sigmaintryHeap.Map.findcswithNot_found->letx=newchunkcinsigma:=Heap.Map.addcxs;xletvaluesigmac=F.e_var@@getsigmacletmergeab=letpa=refPassive.emptyinletpb=refPassive.emptyinletmerge_chunkcxy=ifF.Var.equalxythenxelseletz=newchunkcinpa:=Passive.bind~fresh:z~bound:x!pa;pb:=Passive.bind~fresh:z~bound:y!pb;zinletmerged=Heap.Map.unionmerge_chunk!a!binrefmerged,!pa,!pbletchooseab=letmerge_chunck_xy=ifF.Var.comparexy<=0thenxelseyinref@@Heap.Map.unionmerge_chunck!a!bletjoinab=ifa==bthenPassive.emptyelseletp=refPassive.emptyinHeap.Map.iter2(funchunkxy->matchx,ywith|Somex,Somey->p:=Passive.joinxy!p|Somex,None->b:=Heap.Map.addchunkx!b|None,Somey->a:=Heap.Map.addchunky!a|None,None->())!a!b;!plethavocsigmadomain=letys=Domain.mappingnewchunkdomaininref@@Heap.Map.union(fun_v_oldy->y)!sigmaysletremove_chunkssigmadomain=ref@@Heap.Map.filter(func_->not@@Domain.memcdomain)!sigmalethavoc_chunksigmac=letx=newchunkcinref@@Heap.Map.addcx!sigmaletis_initc=letmoduleT=(valc.tag)inT.is_initc.ckindletis_framedc=letmoduleT=(valc.tag)inT.is_framedc.ckindlethavoc_any~callsigma=letframercx=ifcall&&is_framedcthenxelsenewchunkcinref@@Heap.Map.mapiframer!sigma(* Merge All *)typeusage=UsedofF.var|Unusedletmerge_list(ls:sigmalist):sigma*Passive.tlist=(* Get a map of the chunks (the data is not important) *)letdomain=Heap.Map.map(fun_->[])@@letdunion_c_=cinList.fold_left(funaccs->Heap.Map.mergedunionacc!s)Heap.Map.emptylsin(* Accumulate usage for each c, preserving the order of the list *)letusage=letumerge_ce=matchc,ewith|Somec,Somex->Some(Usedx::c)|Somec,None->Some(Unused::c)|None,_->assertfalseinList.fold_left(funaccs->Heap.Map.mergeumergeacc!s)domain(List.revls)in(* Build the passive for each sigma of the list, and the final sigma *)letpassives=ref@@List.map(fun_->Passive.empty)lsinletchoosecuses=letused=functionUsed_->true|Unused->falseinletcompatiblex=functionUsedy->F.Var.equalxy|Unused->trueinmatchList.filteruseduseswith|[]->assertfalse|Usedx::otherswhenList.for_all(compatiblex)others->x|_->letfresh=newchunkcinletjoinpa=function|Unused->pa|Usedbound->Passive.bind~fresh~boundpainpassives:=List.map2join!passivesuses;freshinref@@Heap.Map.mapichooseusage,!passives(* Effects *)letwrites~(pre:sigma)~(post:sigma):domain=letdomain=refDomain.emptyinHeap.Map.iter2(funcuv->letwritten=matchu,vwith|Somex,Somey->not@@F.Var.equalxy|None,Some_->true|Some_,None->false(* no need to create a new *)|None,None->assertfalseinifwrittenthendomain:=Domain.addc!domain)!pre!post;!domainletassigned~(pre:sigma)~(post:sigma)written=letp=refBag.emptyinHeap.Map.iter2(funchunkxy->ifnot(Domain.memchunkwritten)thenmatchx,ywith|Somex,Someywhenx!=y->p:=Bag.add(F.p_equal(F.e_varx)(F.e_vary))!p|Somex,None->post:=Heap.Map.addchunkx!post|None,Somey->pre:=Heap.Map.addchunky!pre|_->())!pre!post;!pletiterfs=Heap.Map.iterf!sletiter2fab=Heap.Map.iter2f!a!bletprettyfmtsigma=beginFormat.fprintffmt"{@[<hov 2>";Heap.Map.iter(funcx->letmoduleT=(valc.tag)inFormat.fprintffmt"@ %a:%a"T.prettyc.ckindF.Var.prettyx)!sigma;Format.fprintffmt"@]}";end(* -------------------------------------------------------------------------- *)(* --- Chunks --- *)(* -------------------------------------------------------------------------- *)moduleMake(C:ChunkType)=structtypeckind+=MuofC.tmoduleT=structletself=C.selflettag=Obj.Extension_constructor.id[%extension_constructorMu]letmapf=functionMum->fm|_->assertfalseletmap2fab=matcha,bwithMua,Mub->fab|_->assertfalselethash=mapC.hashletequal=map2C.equalletcompare=map2C.compareletis_init=mapC.is_initletis_primary=mapC.is_primaryletis_framed=mapC.is_framedlettau_of_chunk=mapC.tau_of_chunkletbasename_of_chunk=mapC.basename_of_chunkletprettyfmt=map(C.prettyfmt)endlettag=(moduleT:Tag)letchunkc={tag;ckind=Muc}letmemsigmac=memsigma@@chunkcletgetsigmac=getsigma@@chunkcletvaluesigmac=valuesigma@@chunkcletsingletonc=Domain.singleton@@chunkcend(* -------------------------------------------------------------------------- *)