123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145(* 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_visitormoduleVarMap=Dataflow.VarMap(*****************************************************************************)(* Prelude *)(*****************************************************************************)(* Liveness dataflow analysis.
*
* A variable is *live* if it holds a value that may be needed in the future.
* So a variable is "dead" if it holds a value that is not used later.
*)(*****************************************************************************)(* Types *)(*****************************************************************************)(* For a liveness analysis, the dataflow result is
* a map from each program point (as usual), to a map from each
* variable (as usual), to whether the variable is live at that point.
*
* For instance on:
*
* 1: a = 1;
* : do {
* 2: b = a + 1;
* 3: c = c + b;
* 4: a = b * 2;
* 5: } while (a < N)
* 6: return c
*
* TODO?? what is live?
*)typemapping=unitDataflow.mapping(*****************************************************************************)(* Gen/Kill *)(*****************************************************************************)(* "Any use of a variable generates liveness".
* note that unit Dataflow.env is really simple a VarSet.t but
* it's convenient to still use a VarMap (Dataflow.env) so we can
* reuse Dataflow.varmap_union and Dataflow.varmap_diff.
*)let(gens:F.flow->(unitDataflow.env)array)=funflow->letarr=Dataflow.new_node_arrayflowVarMap.emptyinV.fold_on_node_and_expr(fun(ni,_nd)e()->(* rvalues here, to get the use of variables *)letrvals=Lrvalue.rvalues_of_exprein(* note that Appel's book p385 says gen(x) is
* something - kill(x) but this is wrong, as shown
* p214 which contradicts p385.
*)letrvars=rvals|>List.map(fun((s,_tok),_idinfo)->s)inrvars|>List.iter(funvar->arr.(ni)<-VarMap.addvar()arr.(ni);))flow();arr(* "Any definition kills liveness". Indeed, if you assign a new value
* in a variable b, and you don't use the previous value of b in this
* assignment, then the previous value of b is indeed not needed just before
* this assignment.
*)let(kills:F.flow->(unitDataflow.env)array)=funflow->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->arr.(ni)<-VarMap.addvar()arr.(ni);))flow();arr(*****************************************************************************)(* Transfer *)(*****************************************************************************)letunion=Dataflow.varmap_union(fun()()->())letdiff=Dataflow.varmap_diff(fun()()->())(fun()->true)(*
* This algorithm is taken from Modern Compiler Implementation in ML, Appel,
* 1998, pp. 385
*
* The transfer is setting:
* - in[n] = gen[n] U (out[n] - kill[n])
* - out[n] = U_{s in succ[n]} in[s]
*)let(transfer:gen:(unitDataflow.env)array->kill:(unitDataflow.env)array->flow:F.flow->unitDataflow.transfn)=fun~gen~kill~flow->(* the transfer function to update the mapping at node index ni *)funmappingni->letout'=(flow#successorsni)#fold(funacc(ni_succ,_)->unionaccmapping.(ni_succ).D.in_env)VarMap.emptyinletout_minus_kill=diffout'kill.(ni)inletin'=uniongen.(ni)out_minus_killin{D.in_env=in';out_env=out'}(*****************************************************************************)(* Entry point *)(*****************************************************************************)let(fixpoint:F.flow->mapping)=funflow->letgen=gensflowinletkill=killsflowinDataflow.fixpoint~eq:(fun()()->true)~init:(Dataflow.new_node_arrayflow(Dataflow.empty_inout()))~trans:(transfer~gen~kill~flow)(* liveness is a backward analysis! *)~forward:false~flow