123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137(** Metadata associated to a graph node (of type 'a) *)type'at={node:'a;(** Node the metadata applies to *)mutableindex:int;(** Index of the node in postorder traversal:
[-1] for invalid or unvisited nodes
[max_int] for a marked node during traversal
[n >= 0] for a valid and visited node
*)mutablepredecessors:'atlist;(** List of node predecessors (used temporarily) *)mutabledom:'at;(** Dominator of this node *)}(** Public accessors *)letnodet=t.nodeletdominatort=t.domletpostorder_indext=t.indexletpredecessorst=t.predecessors(* We use [-1] index for identifying invalid or unvisited nodes *)letis_validnode=node.index>=0(* Intersect set of nodes, using the encoding defined in the paper *)letrecmaximize~targetnode=(*Printf.eprintf "maximize(%d,%d)\n" node.index target;*)ifnode.index<targetthenmaximize~targetnode.domelsenodeletrecintersectb1b2=ifb1!=b2thenletb1=maximize~target:b2.indexb1inletb2=maximize~target:b1.indexb2inintersectb1b2elseb1(* Intersect immediate dominators *)letrecupdate_idom=function|[]->None|x::xs->ifis_validx.domthenletisectaccp=ifis_validp.domthenintersectpaccelseaccinSome(List.fold_leftisectxxs)elseupdate_idomxs(* Traverse and update dominators until a fixpoint is reached *)letdominator_fixpointnodescount=letchanged=reftrueinwhile!changeddochanged:=false;fori=count-2downto0doletnode=nodes.(i)inmatchupdate_idomnode.predecessorswith|None->()|Somedom->ifdom!=node.domthen(node.dom<-dom;changed:=true)donedone(** Representation of a graph with nodes of type 'a *)type'agraph={memoize:'b.('a->'b)->('a->'b);(** Memoize a function on nodes *)successors:'b.('b->'a->'b)->'b->'a->'b;(** Fold over successors of a node *)}(* Compute a postorder traversal:
- associate tags to each node of a graph
- number the tags
- return an array of all tags in postorder *)letpostorder(typea)(graph:agraph)(start:a)=(* Sentinel value for undefined nodes *)letrecundefined={node=start;index=-1;predecessors=[];dom=undefined}in(* A function to associate a `'a t` tag to each node of the graph *)lettag_of=letmknode={node;index=-1;predecessors=[];dom=undefined}ingraph.memoizemkin(* A vector to record all the tags *)letbuffer=ref[|undefined;undefined|]inletmarktag=tag.index<-max_intinletrecordtagindex=tag.index<-index;ifindex>=Array.length!bufferthen(letbuffer'=Array.make(index*2)undefinedinArray.blit!buffer0buffer'0(Array.length!buffer);buffer:=buffer';);assert((!buffer).(index)==undefined);(!buffer).(index)<-tag;in(* Visit a node in DFS, record post-order index *)letrecprocess_tagidxtag=iftag.index=-1then(marktag;letidx=graph.successors(process_successortag)idxtag.nodeinrecordtagidx;(idx+1))elseidx(* Record predecessors when visiting successors *)andprocess_successorselfindexsucc=lettag=tag_ofsuccintag.predecessors<-self::tag.predecessors;process_tagindextagin(* Begin post-order visit *)letstart=tag_ofstartinstart.dom<-start;letcount=process_tag0startin(tag_of,Array.sub!buffer0count)(* dominance = postorder traversal & dominators fixpoint *)letdominance(typea)(graph:agraph)(start:a)=lettag_of,postorder=postordergraphstartin(*Printf.eprintf "postorder: %d nodes\n" (Array.length postorder);
Array.iteri (fun i tag ->
Printf.eprintf "postorder[%d]: node=%d index=%d |predecessors|=%d dominator=%d\n" i (Obj.magic tag.node) tag.index
(List.length tag.predecessors) tag.dom.index;
) postorder;*)dominator_fixpointpostorder(Array.lengthpostorder);(postorder,tag_of)letis_reachable=is_valid