123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134(**************************************************************************)(* This file is part of the Codex semantics library. *)(* *)(* Copyright (C) 2013-2025 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* 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, version 2.1. *)(* *)(* It 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. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file LICENSE). *)(* *)(**************************************************************************)moduleLog=Tracelog.Make(structletcategory="Fixpoint.MakeGraph"end);;type'transitionnode={mutableid:int;mutablepreds_with_transition:('transitionnode*'transition)list;(* We do not need the list successors for the fixpoint iteration,
but it needed to traverse the graph from the initial node, and
thus e.g. for printing, and for Wto computation. So, we keep
it. *)mutablesuccs:'transitionnodelist;}moduletypeGraph=sigmoduleVertex:Hashtbl.HashedTypetypetransitionvaltransition_to_string:transition->string(* For debugging purposes. *)valskip:transitionendmoduleMake(G:Graph)=structtypetransition=G.transitionmoduleControlLocation=structtypet=transitionnodeletto_intx=x.idletequalab=a==blethash=to_intletprettyfmtx=Format.fprintffmt"%d"x.idendletpreds_with_transitionx=x.preds_with_transitionletsuccsx=x.succsmoduleH=Hashtbl.Make(G.Vertex)(* Generate a digraph representation that can be outputed by xdot.
TODO: A tracelog button to display digraphs. *)letdump_graphfmtinit=letmoduleH'=Hashtbl.Make(structtypet=transitionnodelethashx=x.idletequal=(==)end)inlethashtbl=H'.create30inletrecloopcur=matchH'.findhashtblcurwith|exceptionNot_found->beginH'.replacehashtblcur();cur.preds_with_transition|>List.iter(fun(pred,trans)->Format.fprintffmt"%d -> %d [label=\"%s\"] "pred.idcur.id(G.transition_to_stringtrans));cur.succs|>List.iterloopend|()->()inFormat.fprintffmt"digraph {@[<v>";loopinit;Format.fprintffmt"@]}";;letmakeinitsuccs=(* Mapping from original node to the new nodes. *)lethashtbl=H.create17in(* To avoid conversions, parent is a list with 0 or 1 element. *)letrecloopparentcurcount=matchH.findhashtblcurwith|exceptionNot_found->begin(* We label in post-order, which should be close to the
iteration order. This shoud allow better locality if we
store the value in an array. *)letnode={preds_with_transition=parent;succs=[];id=-1}inH.replacehashtblcurnode;(* Fold on successors. *)letf(acc,count)(transition,child)=letchildnode,count=loop[(node,transition)]childcountinchildnode::acc,countinletchildren,count=List.fold_leftf([],count)(succscur)innode.succs<-children;node.id<-count;Log.debug(funp->p"Creating node %d"count);node,count+1end|curnode->begin(* Already visited. Just add the parent to the list of predecessors. *)letparent=matchparentwith|[parent]->parent|_->assertfalse(* impossible. *)incurnode.preds_with_transition<-parent::curnode.preds_with_transition;curnode,countendinletfirst_node,total_nodes=loop[]init0inletinput_node={preds_with_transition=[];succs=[first_node];id=total_nodes;}infirst_node.preds_with_transition<-(input_node,G.skip)::first_node.preds_with_transition;Log.debug(funp->p"Made graph: %a"dump_graphinput_node);input_node,first_node,total_nodes+1;;end