123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284(****************************************************************************)(* *)(* This file is part of MOPSA, a Modular Open Platform for Static Analysis. *)(* *)(* Copyright (C) 2017-2019 The MOPSA Project. *)(* *)(* This program is free software: 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, either version 3 of the License, or *)(* (at your option) any later version. *)(* *)(* This program 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. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this program. If not, see <http://www.gnu.org/licenses/>. *)(* *)(****************************************************************************)(** Interval abstraction of float values. *)openMopsaopenSig.Abstraction.Simplified_valueopenAstopenBotopenCommonmoduleI=ItvUtils.FloatItvNanmoduleFI=ItvUtils.FloatItvmoduleII=ItvUtils.IntItvletprec_of_type=function|T_floatp->p|_->assertfalse(* We first use the simplified signature to handle float operations *)moduleSimplifiedValue=struct(** Types *)typet=I.tincludeGenValueId(structtypenonrect=tletname="universal.numeric.values.intervals.float"letdisplay="float-itv"end)let()=import_shared_optionrounding_option_namenameletaccept_type=function|T_float_->true|_->false(** Lattice operations *)letbottom=I.botlettop_of_prec=function|F_SINGLE->I.single_special|F_DOUBLE->I.double_special|F_LONG_DOUBLE->I.extra|F_FLOAT128->I.extra|F_REAL->I.real(* Relative precision of float types.
If prec_level t1 >= prec_level t2, then t1 can represent all values
that t2 can, and there is no rounding error.
*)letprec_level=function|F_SINGLE->1|F_DOUBLE->2|F_LONG_DOUBLE->3|F_FLOAT128->4|F_REAL->5lettop=top_of_precF_LONG_DOUBLEletis_bottom=I.is_botletsubset(a1:t)(a2:t):bool=I.includeda1a2letjoin(a1:t)(a2:t):t=I.joina1a2letmeet(a1:t)(a2:t):t=I.meeta1a2letwidenctx(a1:t)(a2:t):t=I.widena1a2letprintprinter(a:t)=unformat(I.fprintI.dfl_fmt)printeraletfilter_classitvc={I.itv=ifc.float_validthenitv.I.itvelseBOT;I.pinf=c.float_inf&&itv.I.pinf;I.minf=c.float_inf&&itv.I.minf;I.nan=c.float_nan&&itv.I.nan;}(** Arithmetic operators *)letconstantctr=letp=prec_of_typetrinmatchcwith|C_floati->I.of_float_prec(precp)(round())ii|C_float_interval(lo,up)->I.of_float_prec(precp)(round())loup|C_avalue(V_float_interval_,itv)->(itv:t)|C_top(T_floatp)->top_of_precp|_->top_of_precpletunopoptatr=letp=prec_of_typetrinmatchopwith|O_minus->I.nega|O_plus->a|O_sqrt->I.sqrt(precp)(round())a|O_cast->ifprec_levelp>=prec_level(prec_of_typet)thenaelseI.round(precp)(round())a|O_filter_float_classc->filter_classac|_->top_of_precpletbinopopt1a1t2a2tr=letp=prec_of_typetrinmatchopwith|O_plus->I.add(precp)(round())a1a2|O_minus->I.sub(precp)(round())a1a2|O_mult->I.mul(precp)(round())a1a2|O_div->I.div(precp)(round())a1a2|O_mod->I.fmod(precp)(round())a1a2|_->top_of_precpletfilterbta=letp=prec_of_typetinifbthenI.filter_nonzero(precp)aelseI.filter_nonzero_false(precp)aletbackward_unopoptatrr=letp=prec_of_typetrinmatchopwith|O_minus->I.bwd_negar|O_plus->I.meetar|O_sqrt->I.bwd_sqrt(precp)(round())ar|O_cast->ifprec_levelp>=prec_level(prec_of_typet)thenI.meetarelseI.bwd_round(precp)(round())ar|_->aletbackward_binopopt1a1t2a2trr=letp=prec_of_typetrinmatchopwith|O_plus->I.bwd_add(precp)(round())a1a2r|O_minus->I.bwd_sub(precp)(round())a1a2r|O_mult->I.bwd_mul(precp)(round())a1a2r|O_div->I.bwd_div(precp)(round())a1a2r|O_mod->I.bwd_fmod(precp)(round())a1a2r|_->default_backward_binopopt1a1t2a2trrletcompareopbt1a1t2a2=letp=prec_of_typet1inmatchb,opwith|true,O_eq|false,O_ne->I.filter_eq(precp)a1a2|true,O_ne|false,O_eq->I.filter_neq(precp)a1a2|true,O_lt->I.filter_lt(precp)a1a2|true,O_le->I.filter_leq(precp)a1a2|true,O_gt->I.filter_gt(precp)a1a2|true,O_ge->I.filter_geq(precp)a1a2|false,O_le->I.filter_leq_false(precp)a1a2|false,O_lt->I.filter_lt_false(precp)a1a2|false,O_ge->I.filter_geq_false(precp)a1a2|false,O_gt->I.filter_gt_false(precp)a1a2|_->a1,a2letavalue:typer.ravalue_kind->t->roption=funavala->matchavalwith|V_float_interval_->Somea|V_float_maybenan_->Somea.nan|_->Noneend(* We lift now to the advanced signature to handle mixed operations with integers *)openSig.Abstraction.ValuemoduleValue=structmoduleV=MakeValue(SimplifiedValue)includeSimplifiedValueincludeV(** Casts of integers to floats *)letcast_from_intmanpe=matche.etypwith|T_int|T_bool->(* Get the value of the intger *)letv=man.evalein(* Convert it to an interval *)letint_itv=man.avalueV_int_intervalvin(* Cast it to a float *)I.of_int_itv_bot(precp)(round())int_itv|_->top_of_precp(** Evaluation of float expressions *)letevalmane=matchekindewith|E_unop(O_cast,ee)whenis_int_type(etypee)->cast_from_intman(prec_of_typee.etyp)ee|_->V.evalmane(** Backward evaluation of class predicates *)letbackward_float_classmanceve(r:int_itv)=matchrwith(* Refine only when the truth value of the predicate is a constant *)|Bot.Nb(Finitelo,Finitehi)whenZ.(lo=hi)->letb=Z.(lo<>zero)in(* Get the float value *)leta,_=find_vexpreveinletc=ifbthencelseinv_float_classcin(* Refine [a] depending on the class *)leta'=filter_classacin(* Refine [e] with the new value *)refine_vexpre(meetaa')ve|_->ve(* Backward evaluations of float expressions *)letbackwardmanever=matchekindewith|E_unop(O_float_classcls,ee)->backward_float_classmanclseeve(man.avalueV_int_intervalr)|_->backwardmanever(* Extended backward evaluation of casts of integers *)letbackward_ext_castmanpever=matche.etypwith|T_int|T_bool->(* Get the intger value *)letv,_=find_vexprevein(* Convert to an interval *)letiitv=man.avalueV_int_intervalvinbeginmatchiitvwith|BOT->None|Nbitv->(* Refine it knowing that the result of the cast is [r] *)letiitv'=ItvUtils.FloatItvNan.bwd_of_int_itv(precp)(round())itvrin(* Evaluate the new float value *)letv'=man.eval(mk_avalue_exprV_int_intervaliitv'e.erange)in(* Put it in the evaluation tree *)refine_vexpre(man.meetvv')ve|>OptionExt.returnend|_->None(** Extended backward evaluation of mixed-types expressions *)letbackward_extmanever=matchekindewith|E_unop(O_cast,ee)->backward_ext_castman(prec_of_typee.etyp)eeve(man.getr)|_->V.backward_extmaneverendlet()=register_value_abstraction(moduleValue)