123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146(* Iain Proctor, Yoann Padioleau, Jiao Li
*
* Copyright (C) 2009-2010 Facebook
* Copyright (C) 2019 r2c
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation, with the
* special exception on linking described in file license.txt.
*
* This library 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 file
* license.txt for more details.
*)moduleF=ControlflowmoduleD=DataflowmoduleV=Controlflow_visitormoduleNodeiSet=Dataflow.NodeiSetmoduleVarMap=Dataflow.VarMapmoduleVarSet=Dataflow.VarSet(*****************************************************************************)(* Prelude *)(*****************************************************************************)(* Reaching definitions dataflow analysis.
*
* A definition will "reach" another program point if there is no
* intermediate assignment between this definition and this program point.
*)(*****************************************************************************)(* Types *)(*****************************************************************************)(* For a reaching definitions analysis, the dataflow result is
* a map from each program point (as usual), to a map from each
* variable (as usual), to a set of nodes that define this variable
* that are visible at this program point.
*
* For instance on:
*
* 1: $a = 1;
* 2: if(...) {
* 3: $a = 2;
* 4: } else {
* 5: $a = 3;
* 6: }
* 7: echo $a;
*
* then at the program point (node index) 7, then for $a the nodei set
* is {3, 5}, but not '1'.
*)typemapping=Dataflow.NodeiSet.tDataflow.mapping(*****************************************************************************)(* Gen/Kill *)(*****************************************************************************)let(defs:F.flow->NodeiSet.tDataflow.env)=funflow->(* the long version, could use F.fold_on_expr *)flow#nodes#fold(funenv(ni,node)->letxs=V.exprs_of_nodenodeinxs|>List.fold_left(funenve->letlvals=Lrvalue.lvalues_of_expreinletvars=lvals|>List.map(fun((s,_tok),_idinfo)->s)invars|>List.fold_left(funenvvar->Dataflow.add_var_and_nodei_to_envvarnienv)env)env)VarMap.emptylet(gens:F.flow->VarSet.tarray)=funflow->letarr=Dataflow.new_node_arrayflowVarSet.emptyinV.fold_on_node_and_expr(fun(ni,_nd)earr->letlvals=Lrvalue.lvalues_of_expreinletvars=lvals|>List.map(fun((s,_tok),_idinfo)->s)invars|>List.iter(funvar->arr.(ni)<-VarSet.addvararr.(ni););arr)flowarrlet(kills:NodeiSet.tDataflow.env->F.flow->(NodeiSet.tDataflow.env)array)=fundefsflow->letarr=Dataflow.new_node_arrayflow(Dataflow.empty_env())inV.fold_on_node_and_expr(fun(ni,_nd)e()->letlvals=Lrvalue.lvalues_of_expreinletvars=lvals|>List.map(fun((s,_tok),_idinfo)->s)invars|>List.iter(funvar->letset=NodeiSet.removeni(VarMap.findvardefs)inarr.(ni)<-VarMap.addvarsetarr.(ni);))flow();arr(*****************************************************************************)(* Transfer *)(*****************************************************************************)letunion=Dataflow.union_envletdiff=Dataflow.diff_env(*
* This algorithm is taken from Modern Compiler Implementation in ML, Appel,
* 1998, pp. 382.
*
* The transfer is setting:
* - in'[n] = U_{p in pred[n]} out[p]
* - out'[n] = gen[n] U (in[n] - kill[n])
*)let(transfer:gen:VarSet.tarray->kill:(NodeiSet.tDataflow.env)array->flow:F.flow->NodeiSet.tDataflow.transfn)=fun~gen~kill~flow->(* the transfer function to update the mapping at node index ni *)funmappingni->letin'=(flow#predecessorsni)#fold(funacc(ni_pred,_)->unionaccmapping.(ni_pred).D.out_env)VarMap.emptyinletin_minus_kill=diffin'kill.(ni)inletout'=Dataflow.add_vars_and_nodei_to_envgen.(ni)niin_minus_killin{D.in_env=in';out_env=out'}(*****************************************************************************)(* Entry point *)(*****************************************************************************)let(fixpoint:F.flow->mapping)=funflow->letgen=gensflowinletkill=kills(defsflow)flowinDataflow.fixpoint~eq:NodeiSet.equal~init:(Dataflow.new_node_arrayflow(Dataflow.empty_inout()))~trans:(transfer~gen~kill~flow)~forward:true~flow