123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236(* 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.ttypet={blocks:blockAddr.Map.t;live:intarray;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_defste)andmark_defstd=matchdwith|Varx->mark_varstx|Expre->ifpure_exprst.pure_funsethenmark_exprsteandmark_exprste=matchewith|Const_|Constant_->()|Apply(f,l,_)->mark_varstf;List.iterl~f:(funx->mark_varstx)|Block(_,a,_)->Array.itera~f:(funx->mark_varstx)|Field(x,_)->mark_varstx|Closure(_,(pc,_))->mark_reachablestpc|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|Set_field(x,_,y)->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|Poptrap(cont,_)->mark_cont_reachablestcont|Cond(_,x,cont1,cont2)->mark_varstx;mark_cont_reachablestcont1;mark_cont_reachablestcont2|Switch(x,a1,a2)->mark_varstx;Array.itera1~f:(funcont->mark_cont_reachablestcont);Array.itera2~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)|Set_field_|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(c,x,cont1,cont2)->Cond(c,x,filter_contblocksstcont1,filter_contblocksstcont2)|Switch(x,a1,a2)->Switch(x,Array.mapa1~f:(funcont->filter_contblocksstcont),Array.mapa2~f:(funcont->filter_contblocksstcont))|Pushtrap(cont1,x,cont2,pcs)->Pushtrap(filter_contblocksstcont1,x,filter_contblocksstcont2,Addr.Set.interpcsst.reachable_blocks)|Poptrap(cont,addr)->Poptrap(filter_contblocksstcont,addr)(****)letref_countsti=matchiwith|Let(x,_)->st.live.(Var.idxx)|_->0letannotstpcxi=ifnot(Addr.Set.mempcst.reachable_blocks)then"x"elsematchxiwith|Last_->" "|Instri->letc=ref_countstiinifc>0thenFormat.sprintf"%d"celseiflive_instrstithen" "else"x"(****)letadd_defdefsxi=letidx=Var.idxxindefs.(idx)<-i::defs.(idx)letrecadd_arg_depdefsparamsargs=matchparams,argswith|x::params,y::args->add_defdefsx(Vary);add_arg_depdefsparamsargs|_->()letadd_cont_depblocksdefs(pc,args)=matchtrySome(Addr.Map.findpcblocks)withNot_found->Nonewith|Someblock->add_arg_depdefsblock.paramsargs|None->()(* Dead continuation *)letf((pc,blocks,free_pc)asprogram)=lett=Timer.make()inletnv=Var.count()inletdefs=Array.makenv[]inletlive=Array.makenv0inletpure_funs=Pure_fun.fprograminAddr.Map.iter(fun_block->List.iterblock.body~f:(funi->matchiwith|Let(x,e)->add_defdefsx(Expre)|Set_field(_,_,_)|Array_set(_,_,_)|Offset_ref(_,_)->());Option.iterblock.handler~f:(fun(_,cont)->add_cont_depblocksdefscont);matchblock.branchwith|Return_|Raise_|Stop->()|Branchcont->add_cont_depblocksdefscont|Cond(_,_,cont1,cont2)->add_cont_depblocksdefscont1;add_cont_depblocksdefscont2|Switch(_,a1,a2)->Array.itera1~f:(funcont->add_cont_depblocksdefscont);Array.itera2~f:(funcont->add_cont_depblocksdefscont)|Pushtrap(cont,_,_,_)->add_cont_depblocksdefscont|Poptrap(cont,_)->add_cont_depblocksdefscont)blocks;letst={live;defs;blocks;reachable_blocks=Addr.Set.empty;pure_funs}inmark_reachablestpc;ifdebug()thenprint_program(funpcxi->annotstpcxi)(pc,blocks,free_pc);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);handler=Option.mapblock.handler~f:(fun(x,cont)->x,filter_contall_blocksstcont);body=List.map(List.filterblock.body~f:(funi->live_instrsti))~f:(funi->filter_closureall_blockssti);branch=filter_live_lastall_blocksstblock.branch}blocks)blocksAddr.Map.emptyiniftimes()thenFormat.eprintf" dead code elim.: %a@."Timer.printt;(pc,blocks,free_pc),st.live