123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246(* Js_of_ocaml compiler
* http://www.ocsigen.org/js_of_ocaml/
* Copyright (C) 2010 Jérôme Vouillon
* Laboratoire PPS - CNRS Université Paris Diderot
*
* This program is free software; 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, with linking exception;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)open!Stdlibletdebug=Debug.find"deadcode"lettimes=Debug.find"times"openCodetypedef=|Exprofexpr|VarofVar.t|Field_updateofVar.tletadd_defdefsxi=letidx=Var.idxxindefs.(idx)<-i::defs.(idx)typevariable_uses=intarraytypet={blocks:blockAddr.Map.t;live:variable_uses;defs:deflistarray;mutablereachable_blocks:Addr.Set.t;pure_funs:Var.Set.t}(****)letpure_exprpure_funse=Pure_fun.pure_exprpure_funse&&Config.Flag.deadcode()(****)letrecmark_varstx=letx=Var.idxxinst.live.(x)<-st.live.(x)+1;ifst.live.(x)=1thenList.iterst.defs.(x)~f:(fune->mark_defstxe)andmark_defstxd=matchdwith|Vary->mark_varsty|Field_updatey->(* A [Set_field (x, _, y)] becomes live *)st.live.(x)<-st.live.(x)+1;mark_varsty|Expre->ifpure_exprst.pure_funsethenmark_exprsteandmark_exprste=matchewith|Constant_->()|Apply{f;args;_}->mark_varstf;List.iterargs~f:(funx->mark_varstx)|Block(_,a,_,_)->Array.itera~f:(funx->mark_varstx)|Field(x,_,_)->mark_varstx|Closure(_,(pc,_))->mark_reachablestpc|Special_->()|Prim(_,l)->List.iterl~f:(funx->matchxwith|Pvx->mark_varstx|_->())andmark_cont_reachablest(pc,_param)=mark_reachablestpcandmark_reachablestpc=ifnot(Addr.Set.mempcst.reachable_blocks)then(st.reachable_blocks<-Addr.Set.addpcst.reachable_blocks;letblock=Addr.Map.findpcst.blocksinList.iterblock.body~f:(funi->matchiwith|Let(_,e)->ifnot(pure_exprst.pure_funse)thenmark_exprste|Event_|Assign_->()|Set_field(x,_,_,y)->(matchst.defs.(Var.idxx)with|[Expr(Block_)]whenst.live.(Var.idxx)=0->(* We will keep this instruction only if x is live *)add_defst.defsx(Field_updatey)|_->mark_varstx;mark_varsty)|Array_set(x,y,z)->mark_varstx;mark_varsty;mark_varstz|Offset_ref(x,_)->mark_varstx);matchblock.branchwith|Returnx|Raise(x,_)->mark_varstx|Stop->()|Branchcont|Poptrapcont->mark_cont_reachablestcont|Cond(x,cont1,cont2)->mark_varstx;mark_cont_reachablestcont1;mark_cont_reachablestcont2|Switch(x,a1)->mark_varstx;Array.itera1~f:(funcont->mark_cont_reachablestcont)|Pushtrap(cont1,_,cont2)->mark_cont_reachablestcont1;mark_cont_reachablestcont2)(****)letlive_instrsti=matchiwith|Let(x,e)->st.live.(Var.idxx)>0||not(pure_exprst.pure_funse)|Assign(x,_)|Set_field(x,_,_,_)->st.live.(Var.idxx)>0|Event_|Offset_ref_|Array_set_->trueletrecfilter_argsstplal=matchpl,alwith|x::pl,y::al->ifst.live.(Var.idxx)>0theny::filter_argsstplalelsefilter_argsstplal|[],[]->[]|_->assertfalseletfilter_contblocksst(pc,args)=letparams=(Addr.Map.findpcblocks).paramsinpc,filter_argsstparamsargsletfilter_closureblockssti=matchiwith|Let(x,Closure(l,cont))->Let(x,Closure(l,filter_contblocksstcont))|_->iletfilter_live_lastblocksstl=matchlwith|Return_|Raise_|Stop->l|Branchcont->Branch(filter_contblocksstcont)|Cond(x,cont1,cont2)->Cond(x,filter_contblocksstcont1,filter_contblocksstcont2)|Switch(x,a1)->Switch(x,Array.mapa1~f:(funcont->filter_contblocksstcont))|Pushtrap(cont1,x,cont2)->Pushtrap(filter_contblocksstcont1,x,filter_contblocksstcont2)|Poptrapcont->Poptrap(filter_contblocksstcont)(****)letref_countsti=matchiwith|Let(x,_)->st.live.(Var.idxx)|_->0letannotstpcxi=ifnot(Addr.Set.mempcst.reachable_blocks)then"x"elsematch(xi:Code.Print.xinstr)with|Last_->" "|Instri->letc=ref_countstiinifc>0thenFormat.sprintf"%d"celseiflive_instrstithen" "else"x"(****)letrecadd_arg_depdefsparamsargs=matchparams,argswith|x::params,y::args->add_defdefsx(Vary);add_arg_depdefsparamsargs|[],[]->()|_->assertfalseletadd_cont_depblocksdefs(pc,args)=matchtrySome(Addr.Map.findpcblocks)withNot_found->Nonewith|Someblock->add_arg_depdefsblock.paramsargs|None->()(* Dead continuation *)letf({blocks;_}asp:Code.program)=lett=Timer.make()inletnv=Var.count()inletdefs=Array.makenv[]inletlive=Array.makenv0inletpure_funs=Pure_fun.fpinAddr.Map.iter(fun_block->List.iterblock.body~f:(funi->matchiwith|Let(x,e)->add_defdefsx(Expre)|Assign(x,y)->add_defdefsx(Vary)|Event_|Set_field(_,_,_,_)|Array_set(_,_,_)|Offset_ref(_,_)->());matchblock.branchwith|Return_|Raise_|Stop->()|Branchcont->add_cont_depblocksdefscont|Cond(_,cont1,cont2)->add_cont_depblocksdefscont1;add_cont_depblocksdefscont2|Switch(_,a1)->Array.itera1~f:(funcont->add_cont_depblocksdefscont)|Pushtrap(cont,_,cont_h)->add_cont_depblocksdefscont_h;add_cont_depblocksdefscont|Poptrapcont->add_cont_depblocksdefscont)blocks;letst={live;defs;blocks;reachable_blocks=Addr.Set.empty;pure_funs}inmark_reachablestp.start;ifdebug()thenPrint.program(funpcxi->annotstpcxi)p;letall_blocks=blocksinletblocks=Addr.Map.fold(funpcblockblocks->ifnot(Addr.Set.mempcst.reachable_blocks)thenblockselseAddr.Map.addpc{params=List.filterblock.params~f:(funx->st.live.(Var.idxx)>0);body=List.fold_leftblock.body~init:[]~f:(funacci->matchi,accwith|Event_,Event_::prev->(* Avoid consecutive events (keep just the last one) *)i::prev|_->iflive_instrstithenfilter_closureall_blockssti::accelseacc)|>List.rev;branch=filter_live_lastall_blocksstblock.branch}blocks)blocksAddr.Map.emptyiniftimes()thenFormat.eprintf" dead code elim.: %a@."Timer.printt;{pwithblocks},st.live