Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file deadcodeelim.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408(* Eliminate assignment instructions whose results are not
used *)openCilopenExpcomparemoduleE=ErrormsgmoduleRD=ReachingdefsmoduleUD=UsedefmoduleIH=InthashmoduleS=StatsmoduleIS=Set.Make(structtypet=intletcompare=compareend)letdebug=RD.debugletdoTime=reffalselettimesfa=if!doTimethenS.timesfaelsefa(* This function should be set by the client if it
* knows of functions returning a result that have
* no side effects. If the result is not used, then
* the call will be eliminated. *)letcallHasNoSideEffects:(instr->bool)ref=ref(fun_->false)(* the set of used definition ids *)letusedDefsSet=refIS.empty(* a mapping d -> {u_1,...,u_n} where d is a
* definition id, and the u's are definition
* ids corresponding to definitions in which
* d was used *)letdefUseSetHash=IH.create100(* a mapping d -> {sid_1,...,sid_n} where d is
* a definition id and the sids are statement ids
* corresponding to non-Instr statements where d
* was used *)letsidUseSetHash=IH.create100(* put used def ids into usedDefsSet *)(* assumes reaching definitions have already been computed *)classusedDefsCollectorClass=object(self)inheritRD.rdVisitorClassassupermethodadd_defidsiosheu=UD.VS.iter(funvi->ifIH.memioshvi.vidthenletios=IH.findioshvi.vidinif!debugthenignore(E.log"DCE: IOS size for vname=%s at stmt=%d: %d\n"vi.vnamesid(RD.IOS.cardinalios));RD.IOS.iter(functionSome(i)->if!debugthenignore(E.log"DCE: def %d used: %a\n"id_expe);usedDefsSet:=IS.addi(!usedDefsSet)|None->())ioselseif!debugthenignore(E.log"DCE: vid %d:%s not in stm:%d iosh at %a\n"vi.vidvi.vnamesidd_plainexpe))umethod!vexpre=letu=UD.computeUseExpeinmatchself#get_cur_iosh()withSome(iosh)->self#add_defidsiosheu;DoChildren|None->if!debugthenignore(E.log"DCE: use but no rd data: %a\n"d_plainexpe);DoChildrenmethod!vstmts=ignore(super#vstmts);matchs.skindwith|Instr_->DoChildren|_->beginletu,d=UD.computeUseDefStmtKinds.skindinmatchself#get_cur_iosh()with|Someiosh->UD.VS.iter(funvi->ifIH.memioshvi.vidthenletios=IH.findioshvi.vidinRD.IOS.iter(function|Somei->begin(* add s.sid to set for i *)tryletset=IH.findsidUseSetHashiinIH.replacesidUseSetHashi(IS.adds.sidset)withNot_found->IH.addsidUseSetHashi(IS.singletons.sid)end|None->())ios)u;DoChildren|None->DoChildrenendmethod!vinsti=lethandle_instioshi=matchiwith|Asm(_,_,slvl,_,_,_)->List.iter(fun(_,s,lv)->matchlvwith(Varv,off)->ifs.[0]='+'thenself#add_defidsiosh(Lval(Varv,off))(UD.VS.singletonv)|_->())slvl|Call(_,ce,el,_)whennot(!callHasNoSideEffectsi)->List.iter(fune->letu=UD.computeUseExpeinUD.VS.iter(funvi->ifIH.memioshvi.vidthenletios=IH.findioshvi.vidinRD.IOS.iter(function|Somei->begin(* add sid to set for i *)tryletset=IH.findsidUseSetHashiinIH.replacesidUseSetHashi(IS.addsidset)withNot_found->IH.addsidUseSetHashi(IS.singletonsid)end|None->())ios)u)(ce::el)|Set((Mem_,_)aslh,rhs,l)->List.iter(fune->letu=UD.computeUseExpeinUD.VS.iter(funvi->ifIH.memioshvi.vidthenletios=IH.findioshvi.vidinRD.IOS.iter(function|Somei->begin(* add sid to set for i *)tryletset=IH.findsidUseSetHashiinIH.replacesidUseSetHashi(IS.addsidset)withNot_found->IH.addsidUseSetHashi(IS.singletonsid)end|None->())ios)u)([Lval(lh);rhs])|_->()inignore(super#vinsti);matchcur_rd_datwith|None->beginif!debugthenignore(E.log"DCE: instr with no cur_rd_dat\n");(* handle_inst *)DoChildrenend|Some(_,s,iosh)->beginletu,d=UD.computeUseDefInstriin(* add things in d to the U sets for things in u *)letrecloopn=ifn<0then()elsebeginUD.VS.iter(funvi->ifIH.memioshvi.vidthenletios=IH.findioshvi.vidinRD.IOS.iter(function|Somei->begin(* add n + s to set for i *)tryletset=IH.finddefUseSetHashiinIH.replacedefUseSetHashi(IS.add(n+s)set)withNot_found->IH.adddefUseSetHashi(IS.singleton(n+s))end|None->())ioselse())u;loop(n-1)endinloop(UD.VS.cardinald-1);handle_instioshi;DoChildrenendend(***************************************************
* Also need to find reads from volatiles
* uses two functions I've put in ciltools which
* are basically what Zach wrote, except one is for
* types and one is for vars. Another difference is
* they filter out pointers to volatiles. This
* handles DMA
***************************************************)classhasVolatileflag=object(self)inheritnopCilVisitormethod!vlvall=lettp=typeOfLvallinif(Ciltools.is_volatile_tptp)thenflag:=true;DoChildrenmethod!vexpre=DoChildrenendletexp_has_volatilee=letflag=reffalseinignore(visitCilExpr(newhasVolatileflag)e);!flagletel_has_volatile=List.fold_left(funbe->b||(exp_has_volatilee))false(***************************************************)(*
let rec compareExp (e1: exp) (e2: exp) : bool =
(* log "CompareExp %a and %a.\n" d_plainexp e1 d_plainexp e2; *)
e1 == e2 ||
match e1, e2 with
| Lval lv1, Lval lv2
| StartOf lv1, StartOf lv2
| AddrOf lv1, AddrOf lv2 -> compareLval lv1 lv2
| BinOp(bop1, l1, r1, _), BinOp(bop2, l2, r2, _) ->
bop1 = bop2 && compareExp l1 l2 && compareExp r1 r2
| _ -> begin
match getInteger (constFold true e1), getInteger (constFold true e2) with
Some i1, Some i2 -> compare_cilint i1 i2 = 0
| _ -> false
end
and compareLval (lv1: lval) (lv2: lval) : bool =
let rec compareOffset (off1: offset) (off2: offset) : bool =
match off1, off2 with
| Field (fld1, off1'), Field (fld2, off2') ->
fld1 == fld2 && compareOffset off1' off2'
| Index (e1, off1'), Index (e2, off2') ->
compareExp e1 e2 && compareOffset off1' off2'
| NoOffset, NoOffset -> true
| _ -> false
in
lv1 == lv2 ||
match lv1, lv2 with
| (Var vi1, off1), (Var vi2, off2) ->
vi1 == vi2 && compareOffset off1 off2
| (Mem e1, off1), (Mem e2, off2) ->
compareExp e1 e2 && compareOffset off1 off2
| _ -> false
let rec stripNopCasts (e:exp): exp =
match e with
CastE(t, e') -> begin
match unrollType (typeOf e'), unrollType t with
TPtr _, TPtr _ -> (* okay to strip *)
stripNopCasts e'
(* strip casts from pointers to unsigned int/long*)
| (TPtr _ as t1), (TInt(ik,_) as t2)
when bitsSizeOf t1 = bitsSizeOf t2
&& not (isSigned ik) ->
stripNopCasts e'
| (TInt _ as t1), (TInt _ as t2)
when bitsSizeOf t1 = bitsSizeOf t2 -> (* Okay to strip.*)
stripNopCasts e'
| _ -> e
end
| _ -> e
let compareExpStripCasts (e1: exp) (e2: exp) : bool =
compareExp (stripNopCasts e1) (stripNopCasts e2)
*)letremovedCount=ref0(* Filter out instructions whose definition ids are not
in usedDefsSet *)classuselessInstrElim:cilVisitor=object(self)inheritnopCilVisitormethod!vstmtstm=(* give a set of varinfos and an iosh and get
* the set of definition ids definining the vars *)letviSetToDefIdSetioshvis=UD.VS.fold(funvis->ifIH.memioshvi.vidthenletios=IH.findioshvi.vidinRD.IOS.fold(funios->matchiowithNone->s|Somei->IS.addis)iosselses)visIS.emptyin(* false when U(defid)\subeq instruses and SU(d) = empty *)letcheck_defidiinstrusesioshdefid=IS.memdefid(!usedDefsSet)&&tryletdefuses=IH.finddefUseSetHashdefidin(*let siduses = IH.find sidUseSetHash defid in*)ifIH.memsidUseSetHashdefidthenbeginif!debugthenignore(E.log"siduses not empty: %a\n"d_instri);trueendelsebegin(* true if there is something in defuses not in instruses or when
* something from defuses is in instruses and is also used somewhere else *)ifUD.VS.exists(funvi->vi.vglob)instrusesthentrueelseletinstruses=viSetToDefIdSetioshinstrusesinIS.fold(funi'b->ifnot(IS.memi'instruses)thenbeginif!debugthenignore(E.log"i not in instruses: %a\n"d_instri);trueendelse(* can only use the definition i' at the definition defid *)leti'_uses=IH.finddefUseSetHashi'inIH.memsidUseSetHashi'||ifnot(IS.equali'_uses(IS.singletondefid))thenbeginIS.iter(funiu->matchRD.getSimpRhsiuwith|Some(RD.RDExpe)->if!debugthenignore(E.log"i' had other than one use: %d: %a\n"(IS.cardinali'_uses)d_expe)|Some(RD.RDCalli)->if!debugthenignore(E.log"i' had other than one use: %d: %a\n"(IS.cardinali'_uses)d_instri)|None->())i'_uses;trueendelseb)defusesfalseendwithNot_found->trueinlettest(i,(_,s,iosh))=matchiwith|Call(Some(Varvi,NoOffset),Lval(Varvf,NoOffset),el,l)->ifnot(!callHasNoSideEffectsi)thenbeginif!debugthenignore(E.log"found call w/ side effects: %a\n"d_instri);trueendelsebeginif!debugthenignore(E.log"found call w/o side effects: %a\n"d_instri);(vi.vglob||(Ciltools.is_volatile_vivi)||(el_has_volatileel)||letuses,defd=UD.computeUseDefInstriinletrecloopn=n>=0&&(check_defidiusesiosh(n+s)||loop(n-1))inloop(UD.VS.cardinaldefd-1)||(incrremovedCount;false))end|Call_->true|Set(lh,e,_)whencompareExpStripCasts(Lvallh)e->false(* filter x = x *)|Set((Varvi,NoOffset),e,_)->vi.vglob||(Ciltools.is_volatile_vivi)||(exp_has_volatilee)||letuses,defd=UD.computeUseDefInstriinletrecloopn=n>=0&&(check_defidiusesiosh(n+s)||loop(n-1))inloop(UD.VS.cardinaldefd-1)||(incrremovedCount;false)|_->trueinletfilterilstmdat=letrd_dat_lst=RD.instrRDsilstm.sidstmdatfalseinletildatlst=List.combineilrd_dat_lstinletildatlst'=List.filtertestildatlstinlet(newil,_)=List.splitildatlst'innewilinmatchRD.getRDsstm.sidwithNone->DoChildren|Some(_,s,iosh)->matchstm.skindwithInstril->stm.skind<-Instr(filteril((),s,iosh));SkipChildren|_->DoChildrenend(* until fixed point is reached *)letelim_dead_code_fp(fd:fundec):fundec=(* fundec -> fundec *)letrecloopfd=usedDefsSet:=IS.empty;IH.cleardefUseSetHash;IH.clearsidUseSetHash;removedCount:=0;time"reaching definitions"RD.computeRDsfd;ignore(time"ud-collector"(visitCilFunction(newusedDefsCollectorClass:>cilVisitor))fd);letfd'=time"useless-elim"(visitCilFunction(newuselessInstrElim))fdinif!removedCount=0thenfd'elseloopfd'inloopfd(* just once *)letelim_dead_code(fd:fundec):fundec=(* fundec -> fundec *)usedDefsSet:=IS.empty;IH.cleardefUseSetHash;IH.clearsidUseSetHash;removedCount:=0;time"reaching definitions"RD.computeRDsfd;if!debugthenignore(E.log"DCE: collecting used definitions\n");ignore(time"ud-collector"(visitCilFunction(newusedDefsCollectorClass:>cilVisitor))fd);if!debugthenignore(E.log"DCE: eliminating useless instructions\n");letfd'=time"useless-elim"(visitCilFunction(newuselessInstrElim))fdinfd'classdeadCodeElimClass:cilVisitor=object(self)inheritnopCilVisitormethod!vfuncfd=letfd'=elim_dead_code(*_fp*)fdinChangeTo(fd')endletdcef=if!debugthenignore(E.log"DCE: starting dead code elimination\n");visitCilFile(newdeadCodeElimClass)f