123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169(**************************************************************************)(* *)(* Ocamlgraph: a generic graph library for OCaml *)(* Copyright (C) 2004-2010 *)(* Sylvain Conchon, Jean-Christophe Filliatre and Julien Signoles *)(* *)(* This software is free software; you can redistribute it and/or *)(* modify it under the terms of the GNU Library General Public *)(* License version 2.1, with the special exception on linking *)(* described in file LICENSE. *)(* *)(* This software 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. *)(* *)(**************************************************************************)(* Copyright (c) 2010 - 2012 Technische Universitaet Muenchen
* Markus W. Weissmann <markus.weissmann@in.tum.de>
* All rights reserved. *)(* maximum fixpoint point calculation with the work list algorithm;
to implement a concrete analysis, implement a module that satisfies
the Rules signature. Such a module in the Analysis functor gives a
complete analysis/optimization module that works on a CFG.
*)typedirection=Forward|BackwardmoduletypeAnalysis=sigtypedatatypeedgetypevertextypegvaldirection:directionvaljoin:data->data->datavalequal:data->data->boolvalanalyze:edge->data->dataend(** Minimal graph signature for work list algorithm *)moduletypeG=sigtypetmoduleV:Sig.COMPARABLEmoduleE:sigtypetvaldst:t->V.tvalsrc:t->V.tendvalfold_vertex:(V.t->'a->'a)->t->'a->'avalsucc_e:t->V.t->E.tlistvalpred_e:t->V.t->E.tlistvalsucc:t->V.t->V.tlistvalpred:t->V.t->V.tlistendmoduleMake(G:G)(A:Analysiswithtypeg=G.twithtypeedge=G.E.twithtypevertex=G.V.t)=structmoduleM=Map.Make(G.V)moduleN=Set.Make(G.V)letanalyzeinitialg=let(nodes,data)=G.fold_vertex(funvertex(n,m)->(N.addvertexn,M.addvertex(initialvertex)m))g(N.empty,M.empty)in(* generate an associative map to quickly find the incoming
* (outgoing) edges of a node during the anaysis store a pair of
* a partially applied analysis function and the corresponding
* 'partner' node *)letnodemap:((A.data->A.data)*G.V.t)listM.t=letadd=matchA.directionwith|Forward->(funn->letpreds=G.pred_egninList.map(funedge->(A.analyzeedge,G.E.srcedge))preds)|Backward->(funn->letsuccs=G.succ_egninList.map(funedge->(A.analyzeedge,G.E.dstedge))succs)inG.fold_vertex(funvertexm->M.addvertex(addvertex)m)gM.emptyinletrecworklist(data:A.dataM.t)(wl:N.t)=(* 'meet' an arbitrary number of data-sets *)letmeetinitialxs=List.fold_leftA.joininitialxsin(* analyze one node, creating a new data-set and node-worklist
as necessary *)letanalyze_nodeanalysisndwl=matchanalysisdnwith|None->(d,wl)|Somed'->(d',N.addnwl)in(* get some node from the node-set -- this will eventually trigger
an exception *)match(trySome(N.choosewl)withNot_found->None)with|None->data|Somen->(* remove the chosen node from the set *)letwl=N.removenwlinlet(f,ns)=matchA.directionwith(* analyze all INCOMING edges of all SUCCESSOR nodes of the
node to be processed *)|Forward->(* process one node: analyze all it's incoming edges
and merge the resulting data;
if the result is different to the previously stored data
for this node, return a new tuple, else None *)letnew_node_data(data:A.dataM.t)node=letedges=M.findnodenodemapinletanalysis=List.map(fun(f,src)->f(M.findsrcdata))edgesinletnode_data=M.findnodedatainletnode_data'=meet(initialnode)analysisinifA.equalnode_datanode_data'thenNoneelseSome(M.addnodenode_data'data)in(new_node_data,G.succgn)(* analyze all OUTGOING edges of all PREDECESSOR nodes
of the node to be processed *)|Backward->letnew_node_data(data:A.dataM.t)node=letedges=M.findnodenodemapinletanalysis=List.map(fun(f,dst)->f(M.finddstdata))edgesinletnode_data=M.findnodedatainletnode_data'=meet(initialnode)analysisinifA.equalnode_datanode_data'thenNoneelseSome(M.addnodenode_data'data)in(new_node_data,G.predgn)in(* analyze all successor nodes by analyzing all of their
predecessor edges *)let(data,wl)=List.fold_left(fun(d,wl)n->analyze_nodefndwl)(data,wl)nsin(* do a recursive call: the recursion will eventually end with a
* Not_found exception when no nodes are left in the work list *)worklistdatawlinletdata=worklistdatanodesin(funn->M.findndata)end