123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* 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 licenses/LGPLv2.1). *)(* *)(**************************************************************************)openCil_typesopenCil_datatypeincludePlugin.Register(structletname="dominators"letshortname="dominators"lethelp="Compute postdominators of statements"end)moduleDomSet=structtypedomset=ValueofStmt.Hptset.t|Topletinterab=matcha,bwith|Top,Top->Top|Valuev,Top|Top,Valuev->Valuev|Valuev,Valuev'->Value(Stmt.Hptset.intervv')letaddvd=matchdwith|Top->Top|Valued->Value(Stmt.Hptset.addvd)letmemv=function|Top->true|Valued->Stmt.Hptset.memvdletmapf=function|Top->Top|Valueset->Value(fset)includeDatatype.Make(structincludeDatatype.Serializable_undefinedtypet=domsetletname="dominator_set"letreprs=Top::List.map(funs->Values)Stmt.Hptset.reprsletstructural_descr=Structural_descr.t_sum[|[|Stmt.Hptset.packed_descr|]|]letprettyfmt=function|Top->Format.fprintffmt"Top"|Valued->Pretty_utils.pp_iter~pre:"@[{"~sep:",@,"~suf:"}@]"Stmt.Hptset.iter(funfmts->Format.fprintffmt"%d"s.sid)fmtdletequalab=matcha,bwith|Top,Top->true|Value_v,Top|Top,Value_v->false|Valuev,Valuev'->Stmt.Hptset.equalvv'letcopy=mapCil_datatype.Stmt.Hptset.copyletmem_project=Datatype.never_any_projectend)end(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)moduletypeMakePostDomArg=sigvalis_accessible:stmt->bool(* Evaluation of an expression which is supposed to be the condition of an
'if'. The first boolean (resp. second) represents the possibility that
the expression can be non-zero (resp. zero), ie. true (resp. false). *)valeval_cond:stmt->exp->bool*boolvaldependencies:State.tlistvalname:stringendmoduleMakePostDom(X:MakePostDomArg)=structmodulePostDom=Cil_state_builder.Stmt_hashtbl(DomSet)(structletname="postdominator."^X.nameletdependencies=Ast.self::X.dependenciesletsize=503end)modulePostComputer=structletname="postdominator"letdebug=falsetypet=DomSet.tmoduleStmtStartData=PostDomletpretty=DomSet.prettyletcombineStmtStartData_stmt~oldnew_=ifDomSet.equaloldnew_thenNoneelseSomenew_letcombineSuccessors=DomSet.interletdoStmtstmt=Db.yield();Postdominators_parameters.debug~level:2"doStmt: %d"stmt.sid;matchstmt.skindwith|Return_->Dataflow2.Done(DomSet.Value(Stmt.Hptset.singletonstmt))|_->Dataflow2.Post(fundata->DomSet.addstmtdata)letdoInstr___=Dataflow2.Default(* We make special tests for 'if' statements without a 'then' or
'else' branch. It can lead to better precision if we can evaluate
the condition of the 'if' with always the same truth value *)letfilterIfifstmtnext=matchifstmt.skindwith|If(e,{bstmts=sthen::_},{bstmts=[]},_)whennot(Stmt.equalsthennext)->(* [next] is the syntactic successor of the 'if', ie the
'else' branch. If the condition is never false, then
[sthen] postdominates [next]. We must not follow the edge
from [ifstmt] to [next] *)snd(X.eval_condifstmte)|If(e,{bstmts=[]},{bstmts=selse::_},_)whennot(Stmt.equalselsenext)->(* dual case *)fst(X.eval_condifstmte)|_->trueletfilterStmtprednext=X.is_accessiblepred&&filterIfprednextletfuncExitData=DomSet.ValueStmt.Hptset.emptyendmodulePostCompute=Dataflow2.Backwards(PostComputer)letcompute_postdomkf=letreturn=tryKernel_function.find_returnkfwithKernel_function.No_Statement->Postdominators_parameters.abort"No return statement for a function with body %a"Kernel_function.prettykfintrylet_=PostDom.findreturninPostdominators_parameters.feedback~level:2"computed for function %a"Kernel_function.prettykfwithNot_found->Postdominators_parameters.feedback~level:2"computing for function %a"Kernel_function.prettykf;letf=kf.fundecinmatchfwith|Definition(f,_)->letstmts=f.sallstmtsinList.iter(funs->PostDom.addsDomSet.Top)stmts;PostCompute.compute[return];Postdominators_parameters.feedback~level:2"done for function %a"Kernel_function.prettykf|Declaration_->()letget_stmt_postdominatorsfstmt=letdo_it()=PostDom.findstmtintrydo_it()withNot_found->compute_postdomf;do_it()(** @raise Db.PostdominatorsTypes.Top when the statement postdominators
* have not been computed ie neither the return statement is reachable,
* nor the statement is in a natural loop. *)letstmt_postdominatorsfstmt=matchget_stmt_postdominatorsfstmtwith|DomSet.Values->Postdominators_parameters.debug~level:1"Postdom for %d are %a"stmt.sidStmt.Hptset.prettys;s|DomSet.Top->raiseDb.PostdominatorsTypes.Topletis_postdominatorf~opening~closing=letopen_postdominators=get_stmt_postdominatorsfopeninginDomSet.memclosingopen_postdominatorsletdisplay_postdom()=letdisp_allfmt=PostDom.iter(funkv->Format.fprintffmt"Stmt:%d -> @[%a@]\n"k.sidPostComputer.prettyv)inPostdominators_parameters.result"%t"disp_allletprint_dot_postdombasenamekf=letfilename=basename^"."^Kernel_function.get_namekf^".dot"inPrint.build_dotfilenamekf;Postdominators_parameters.result"dot file generated in %s"filenameendmodulePostDomDb(X:MakePostDomArg)(DbPostDom:Db.PostdominatorsTypes.Sig)=structincludeMakePostDom(X)let()=DbPostDom.compute:=compute_postdomlet()=DbPostDom.is_postdominator:=is_postdominatorlet()=DbPostDom.stmt_postdominators:=stmt_postdominatorslet()=DbPostDom.display:=display_postdomlet()=DbPostDom.print_dot:=print_dot_postdomendmodulePostDomBasic=PostDomDb(structletis_accessible_=trueletdependencies=[]letname="basic"leteval_cond__=true,trueend)(Db.Postdominators)letoutput()=letdot_postdom=Postdominators_parameters.DotPostdomBasename.get()inifdot_postdom<>""then(Ast.compute();Globals.Functions.iter(funkf->ifKernel_function.is_definitionkfthen!Db.Postdominators.print_dotdot_postdomkf))letoutput,_=State_builder.apply_once"Postdominators.Compute.output"[PostDomBasic.PostDom.self]outputlet()=Db.Main.extendoutputincludePostDomDb(structletis_accessible=Eva.Results.is_reachableletdependencies=[Eva.Analysis.self]letname="value"leteval_condstmt_e=Eva.Results.condition_truth_valuestmtend)(Db.PostdominatorsValue)(*
Local Variables:
compile-command: "make -C ../../.."
End:
*)