123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360(*
*
* Copyright (c) 2001-2002,
* George C. Necula <necula@cs.berkeley.edu>
* Scott McPeak <smcpeak@cs.berkeley.edu>
* Wes Weimer <weimer@cs.berkeley.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*)(** Compute dominator information for the statements in a function *)openCilopenPrettymoduleE=ErrormsgmoduleH=HashtblmoduleU=UtilmoduleIH=InthashmoduleDF=Dataflowletdebug=false(* For each statement we maintain a set of statements that dominate it *)moduleBS=Set.Make(structtypet=Cil.stmtletcomparev1v2=Stdlib.comparev1.sidv2.sidend)(** Customization module for dominators *)moduleDT=structletname="dom"letdebug=refdebugtypet=BS.t(** For each statement in a function we keep the set of dominator blocks.
* Indexed by statement id *)letstmtStartData:tIH.t=IH.create17letcopy(d:t)=dletpretty()(d:t)=dprintf"{%a}"(docList(funs->dprintf"%d"s.sid))(BS.elementsd)letcomputeFirstPredecessor(s:stmt)(d:BS.t):BS.t=(* Make sure we add this block to the set *)BS.addsdletcombinePredecessors(s:stmt)~(old:BS.t)(d:BS.t):BS.toption=(* First, add this block to the data from the predecessor *)letd'=BS.addsdinifBS.subsetoldd'thenNoneelseSome(BS.interoldd')letdoInstr(i:instr)(d:t)=DF.DefaultletdoStmt(s:stmt)(d:t)=DF.SDefaultletdoGuardcondition_=DF.GDefaultletfilterStmt_=trueendmoduleDom=DF.ForwardsDataFlow(DT)letgetStmtDominators(data:BS.tIH.t)(s:stmt):BS.t=tryIH.finddatas.sidwithNot_found->BS.empty(* Not reachable *)letgetIdom(idomInfo:stmtoptionIH.t)(s:stmt)=tryIH.findidomInfos.sidwithNot_found->E.s(E.bug"Immediate dominator information not set for statement %d"s.sid)(** Check whether one block dominates another. This assumes that the "idom"
* field has been computed. *)letrecdominates(idomInfo:stmtoptionIH.t)(s1:stmt)(s2:stmt)=s1==s2||(lets2idom=getIdomidomInfos2inmatchs2idomwithNone->false|Somes2idom->dominatesidomInfos1s2idom)letcomputeIDom?(doCFG:bool=true)(f:fundec):stmtoptionIH.t=(* We must prepare the CFG info first *)ifdoCFGthenbeginprepareCFGf;computeCFGInfoffalseend;IH.clearDT.stmtStartData;letidomData:stmtoptionIH.t=IH.create13inlet_=matchf.sbody.bstmtswith[]->()(* function has no body *)|start::_->begin(* We start with only the start block *)IH.addDT.stmtStartDatastart.sid(BS.singletonstart);Dom.compute[start];(* Dump the dominators information *)ifdebugthenList.iter(funs->letsdoms=getStmtDominatorsDT.stmtStartDatasinifnot(BS.memssdoms)thenbegin(* It can be that the block is not reachable *)ifs.preds<>[]thenE.s(E.bug"Statement %d is not in its list of dominators"s.sid);end;ignore(E.log"Dominators for %d: %a\n"s.sidDT.pretty(BS.removessdoms)))f.sallstmts;(* Now fill the immediate dominators for all nodes *)letrecfillOneIdom(s:stmt)=tryignore(IH.findidomDatas.sid)(* Already set *)withNot_found->begin(* Get the dominators *)letsdoms=getStmtDominatorsDT.stmtStartDatasin(* Fill the idom for the dominators first *)letidom=BS.fold(fund(sofar:stmtoption)->ifd.sid=s.sidthensofar(* Ignore the block itself *)elsebegin(* fill the idom information recursively *)fillOneIdomd;matchsofarwithNone->Somed|Somesofar'->(* See if d is dominated by sofar. We know that the
* idom information has been computed for both sofar
* and for d*)ifdominatesidomDatasofar'dthenSomedelsesofarend)sdomsNoneinIH.replaceidomDatas.sididomendin(* Scan all blocks and compute the idom *)List.iterfillOneIdomf.sallstmtsendinidomDatatypetree=stmtoption*BS.tIH.t(* returns the IDoms and a map from statement ids to
the set of statements that are dominated *)letcomputeDomTree?(doCFG:bool=true)(f:fundec):stmtoptionIH.t*tree=(* We must prepare the CFG info first *)ifdoCFGthenbeginprepareCFGf;computeCFGInfoffalseend;IH.clearDT.stmtStartData;lettreeData:BS.tIH.t=IH.create64inletidomData:stmtoptionIH.t=IH.create64inlet_=matchf.sbody.bstmtswith[]->()(* function has no body *)|start::_->begin(* We start with only the start block *)IH.addDT.stmtStartDatastart.sid(BS.singletonstart);Dom.compute[start];(* Dump the dominators information *)ifdebugthenList.iter(funs->letsdoms=getStmtDominatorsDT.stmtStartDatasinifnot(BS.memssdoms)thenbegin(* It can be that the block is not reachable *)ifs.preds<>[]thenE.s(E.bug"Statement %d is not in its list of dominators"s.sid);end;ignore(E.log"Dominators for %d: %a\n"s.sidDT.pretty(BS.removessdoms)))f.sallstmts;(* Now fill the immediate dominators for all nodes *)letrecfillOneIdom(s:stmt)=tryignore(IH.findidomDatas.sid)(* Already set *)withNot_found->begin(* Get the dominators *)letsdoms=getStmtDominatorsDT.stmtStartDatasin(* Fill the idom for the dominators first *)letidom=BS.fold(fund(sofar:stmtoption)->ifd.sid=s.sidthensofar(* Ignore the block itself *)elsebegin(* fill the idom information recursively *)fillOneIdomd;matchsofarwithNone->Somed|Somesofar'->(* See if d is dominated by sofar. We know that the
* idom information has been computed for both sofar
* and for d*)ifdominatesidomDatasofar'dthenSomedelsesofarend)sdomsNoneinIH.replaceidomDatas.sididom;matchidomwith|None->()|Somed->beginmatchIH.tryfindtreeDatad.sidwith|None->IH.addtreeDatad.sid(BS.singletons)|Somebs->IH.replacetreeDatad.sid(BS.addsbs)endendin(* Scan all blocks and compute the idom *)List.iterfillOneIdomf.sallstmtsendintryidomData,(Some(List.hdf.sbody.bstmts),treeData)withFailure_->idomData,(None,treeData)typeorder=PreOrder|PostOrderletrecdomTreeIter(f:stmt->unit)(o:order)(t:tree):unit=letdoChildrens=matchIH.tryfind(sndt)s.sidwith|None->()(* No children *)|Somebs->beginBS.iter(funs->domTreeIterfo(Somes,sndt))bsendinmatchfsttwith|None->()|Somes->begin(* s is the current root *)matchowith|PreOrder->begin(* do s first *)fs;doChildrensend|PostOrder->begin(* do s's children first *)doChildrens;fsendendletchildren(t:tree)(s:stmt):stmtlist=matchIH.tryfind(sndt)s.sidwith|None->[]|Somebs->BS.elementsbs(** Compute the start of the natural loops. For each start, keep a list of
* origin of a back edge. The loop consists of the loop start and all
* predecessors of the origins of back edges, up to and including the loop
* start *)letfindNaturalLoops(f:fundec)(idomData:stmtoptionIH.t):(stmt*stmtlist)list=letloops=List.fold_left(funaccb->(* Iterate over all successors, and see if they are among the
* dominators for this block *)List.fold_left(funaccs->ifdominatesidomDatasbthen(* s is the start of a natural loop *)letrecaddNaturalLoop=function[]->[(s,[b])]|(s',backs)::restwhens'.sid=s.sid->(s',b::backs)::rest|l::rest->l::addNaturalLooprestinaddNaturalLoopaccelseacc)accb.succs)[]f.sallstmtsinifdebugthenignore(E.log"Natural loops:\n%a\n"(docList~sep:line(fun(s,backs)->dprintf" Start: %d, backs:%a"s.sid(docList(funb->numb.sid))backs))loops);loops