123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265openStdlibopenCodeletget_edgesgsrc=tryHashtbl.findgsrcwithNot_found->Addr.Set.emptyletadd_edgegsrcdst=Hashtbl.replacegsrc(Addr.Set.adddst(get_edgesgsrc))letreverse_treet=letg=Hashtbl.create16inHashtbl.iter(funchildparent->add_edgegparentchild)t;gletreverse_graphg=letg'=Hashtbl.create16inHashtbl.iter(funchildparents->Addr.Set.iter(funparent->add_edgeg'parentchild)parents)g;g'typegraph=(Addr.t,Addr.Set.t)Hashtbl.ttypet={succs:(Addr.t,Addr.Set.t)Hashtbl.t;preds:(Addr.t,Addr.Set.t)Hashtbl.t;reverse_post_order:Addr.tlist;block_order:(Addr.t,int)Hashtbl.t}letget_nodesg=List.fold_left~init:Addr.Set.empty~f:(funspc->Addr.Set.addpcs)g.reverse_post_orderletblock_ordergpc=Hashtbl.findg.block_orderpcletis_backwardgpcpc'=Hashtbl.findg.block_orderpc>=Hashtbl.findg.block_orderpc'letis_forwardgpcpc'=Hashtbl.findg.block_orderpc<Hashtbl.findg.block_orderpc'(* pc has at least two forward edges moving into it *)letis_merge_node'block_orderpredspc=lets=tryHashtbl.findpredspcwithNot_found->Addr.Set.emptyinleto=Hashtbl.findblock_orderpcinletn=Addr.Set.fold(funpc'n->ifHashtbl.findblock_orderpc'<othenn+1elsen)s0inn>1letempty_bodybody=List.for_all~f:(funi->matchiwith|Event_->true|_->false)bodyletrecleave_try_bodyblock_orderpredsblockspc=ifis_merge_node'block_orderpredspcthenfalseelsematchAddr.Map.findpcblockswith|{body;branch=Return_|Stop;_}whenempty_bodybody->false|{body;branch=Branch(pc',_);_}whenempty_bodybody->leave_try_bodyblock_orderpredsblockspc'|_->trueletbuild_graphblockspc=letsuccs=Hashtbl.create16inletl=ref[]inletvisited=Hashtbl.create16inletpoptraps=ref[]inletrectraverse~englobing_exn_handlerspc=ifnot(Hashtbl.memvisitedpc)then(Hashtbl.addvisitedpc();letsuccessors=Code.fold_childrenblockspcAddr.Set.addAddr.Set.emptyinHashtbl.addsuccspcsuccessors;letblock=Addr.Map.findpcblocksinAddr.Set.iter(funpc'->letenglobing_exn_handlers=matchblock.branchwith|Pushtrap((body_pc,_),_,_)whenpc'=body_pc->pc::englobing_exn_handlers|Poptrap(leave_pc,_)->(matchenglobing_exn_handlerswith|[]->assertfalse|enter_pc::rem->poptraps:=(enter_pc,leave_pc)::!poptraps;rem)|_->englobing_exn_handlersintraverse~englobing_exn_handlerspc')successors;l:=pc::!l)intraverse~englobing_exn_handlers:[]pc;letblock_order=Hashtbl.create16inList.iteri!l~f:(funipc->Hashtbl.addblock_orderpci);letpreds=reverse_graphsuccsinList.iter!poptraps~f:(fun(enter_pc,leave_pc)->ifleave_try_bodyblock_orderpredsblocksleave_pcthen((* Add an edge to limit the [try] body *)Hashtbl.replacesuccsenter_pc(Addr.Set.addleave_pc(Hashtbl.findsuccsenter_pc));Hashtbl.replacepredsleave_pc(Addr.Set.addenter_pc(Hashtbl.findpredsleave_pc))));{succs;preds;reverse_post_order=!l;block_order}letdominator_treeg=(* A Simple, Fast Dominance Algorithm
Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy *)letdom=Hashtbl.create16inletrecinterpcpc'=(* Compute closest common ancestor *)ifpc=pc'thenpcelseifis_forwardgpcpc'theninterpc(Hashtbl.finddompc')elseinter(Hashtbl.finddompc)pc'inList.iterg.reverse_post_order~f:(funpc->letl=Hashtbl.findg.succspcinAddr.Set.iter(funpc'->ifis_forwardgpcpc'thenletd=tryinterpc(Hashtbl.finddompc')withNot_found->pcinHashtbl.replacedompc'd)l);(* Check we have reached a fixed point (reducible graph) *)List.iterg.reverse_post_order~f:(funpc->letl=Hashtbl.findg.succspcinAddr.Set.iter(funpc'->ifis_forwardgpcpc'thenletd=Hashtbl.finddompc'inassert(interpcd=d))l);reverse_treedom(* pc has at least two forward edges moving into it *)letis_merge_nodegpc=is_merge_node'g.block_orderg.predspcletis_loop_headergpc=lets=tryHashtbl.findg.predspcwithNot_found->Addr.Set.emptyinleto=Hashtbl.findg.block_orderpcinAddr.Set.exists(funpc'->Hashtbl.findg.block_orderpc'>=o)sletsort_in_post_ordertl=List.sort~cmp:(funab->compare(block_ordertb)(block_orderta))l(*
(* pc dominates pc' *)
let rec dominates g idom pc pc' =
pc = pc' || (is_forward g pc pc' && dominates g idom pc (Hashtbl.find idom pc'))
let dominance_frontier g idom =
let frontiers = Hashtbl.create 16 in
Hashtbl.iter
(fun pc preds ->
if Addr.Set.cardinal preds > 1
then
let dom = Hashtbl.find idom pc in
let rec loop runner =
if runner <> dom
then (
add_edge frontiers runner pc;
loop (Hashtbl.find idom runner))
in
Addr.Set.iter loop preds)
g.preds;
frontiers
*)(* Compute a map from each block to the set of loops it belongs to *)letmark_loopsg=letin_loop=Hashtbl.create16inHashtbl.iter(funpcpreds->letrecmark_looppc'=ifnot(Addr.Set.mempc(get_edgesin_looppc'))then(add_edgein_looppc'pc;ifpc'<>pcthenAddr.Set.itermark_loop(Hashtbl.findg.predspc'))inAddr.Set.iter(funpc'->ifis_backwardgpc'pcthenmark_looppc')preds)g.preds;in_loopletrecmeasureblocksgpclimit=ifis_loop_headergpcthen-1elseletb=Addr.Map.findpcblocksinletlimit=List.fold_leftb.body~init:limit~f:(funaccx->matchxwith(* A closure is never small *)|Let(_,Closure_)->-1|Event_->acc|_->acc-1)iniflimit<0thenlimitelseAddr.Set.fold(funpclimit->iflimit<0thenlimitelsemeasureblocksgpclimit)(get_edgesg.succspc)limitletis_smallblocksgpc=measureblocksgpc20>=0letshrink_loopsblocks({succs;preds;reverse_post_order;_}asg)=letadd_edgepredsucc=Hashtbl.replacesuccspred(Addr.Set.addsucc(Hashtbl.findsuccspred));Hashtbl.replacepredssucc(Addr.Set.addpred(Hashtbl.findpredssucc))inletin_loop=mark_loopsginletdom=dominator_treeginletroot=List.hdreverse_post_orderinletrectraverseignoredpc=letsuccs=get_edgesdompcinletloops=get_edgesin_looppcinletblock=Addr.Map.findpcblocksinAddr.Set.iter(funpc'->(* Whatever is in the scope of an exception handler should not be
moved outside *)letignored=matchblock.branchwith|Pushtrap((body_pc,_),_,_)whenpc'=body_pc->Addr.Set.unionignoredloops|_->ignoredinletloops'=get_edgesin_looppc'inletleft_loops=Addr.Set.diff(Addr.Set.diffloopsloops')ignoredin(* If we leave a loop, we add an edge from predecessors of
the loop header to the current block, so that it is
considered outside of the loop. *)ifnot(Addr.Set.is_emptyleft_loops||is_smallblocksgpc')thenAddr.Set.iter(funpc0->Addr.Set.iter(funpc->ifis_forwardgpcpc0thenadd_edgepcpc')(get_edgesg.predspc0))left_loops;traverseignoredpc')succsintraverseAddr.Set.emptyrootletbuild_graphblockspc=letg=build_graphblockspcinshrink_loopsblocksg;g