Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file deadcodeelim.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408(* Eliminate assignment instructions whose results are not
used *)openGoblintCilopenExpcompareopenLivenessmoduleE=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,el)->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,eloc)->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