123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)(** Reduction rule for numeric evaluations *)openMopsaopenAstopenSig.Reduction.EvalmoduleReduction=structletname="universal.numeric.reductions.numeric_eval"letreduceexpmanrmanpreresultsflow=(* No reduction if no numeric expression found *)ifnot@@List.exists(fune->letn=get_expr_translation"Universal"einis_numeric_typen.etyp)resultsthenNoneelse(* Simplify constant expressions *)letresults'=results|>List.map(fune->letn=get_expr_translation"Universal"einmatchexpr_to_constnwith|Somec->add_expr_translation"Universal"{nwithekind=E_constantc}e|None->e)(* Convert boolean values to numeric values to simplify reduction *)|>List.map(fune->letn=get_expr_translation"Universal"einmatchekindnwith|E_constant(C_booltrue)->add_expr_translation"Universal"{nwithekind=E_constant(C_intZ.one);etyp=T_int}e|E_constant(C_boolfalse)->add_expr_translation"Universal"{nwithekind=E_constant(C_intZ.zero);etyp=T_int}e|_->e)inmatchresults'with|[]->Some(Eval.emptyflow)|[e]->Some(Eval.singletoneflow)|hd::tl->(* Iterate over the list of result expressions and accumulate the most precise one *)letreciteraccflow=function|[]->Eval.singletonaccflow|hd::tl->letnacc=get_expr_translation"Universal"accinletnhd=get_expr_translation"Universal"hdinmatchekindnacc,ekindnhdwith(* Top rules *)|_,E_constant(C_top_)->iteraccflowtl|E_constant(C_top_),_->iterhdflowtl(* Integer expressions *)|E_constant(C_inta),E_constant(C_intb)->ifZ.(a=b)theniteraccflowtlelseEval.emptyflow|E_constant(C_int_interval(a,b)),E_constant(C_intc)->letc=ItvUtils.IntBound.FinitecinifItvUtils.IntBound.leqac&&ItvUtils.IntBound.leqcbtheniterhdflowtlelseEval.emptyflow|E_constant(C_intc),E_constant(C_int_interval(a,b))->letc=ItvUtils.IntBound.FinitecinifItvUtils.IntBound.leqac&&ItvUtils.IntBound.leqcbtheniteraccflowtlelseEval.emptyflow|E_constant(C_int_interval(a,b)),E_constant(C_int_interval(c,d))->letlo=ItvUtils.IntBound.maxacandhi=ItvUtils.IntBound.minbdinifItvUtils.IntBound.leqlohithenletacc=add_expr_translation"Universal"(mk_int_general_intervallohiexp.erange)acciniteraccflowtlelseEval.emptyflow(* Variables *)|E_var(v1,mode1),E_var(v2,mode2)->(* Ensure that both variables are equal *)man.exec(mk_assume(eqacchdexp.erange)exp.erange)flow>>%funflow'->(* Keep the strong variable as the most precise expression *)letprecise=ifvar_modev1mode1=STRONGthenaccelsehdiniterpreciseflow'tl|E_var_,_|_,E_var_->(* Ensure that variable is equal the other expression *)man.exec(mk_assume(eqacchdexp.erange)exp.erange)flow>>%funflow'->(* Keep the variable as the most precise expression *)letprecise=matchekindnhdwith|E_var(v,_)->hd|_->acciniterpreciseflow'tl(* Logic expressions *)|E_binop(op1,_,_),E_binop(op2,_,_)when(is_comparison_opop1||is_logic_opop1)&&(is_comparison_opop2||is_logic_opop2)->(* Transform as a conjunction *)letacc'=add_expr_translation"Universal"(mk_log_andacchdexp.erange)acciniteracc'flowtl(* constant AND compare : keep compare *)|E_constant(C_intn),E_binop(op,_,_)|E_binop(op,_,_),E_constant(C_intn)when(is_comparison_opop||is_logic_opop)->letprecise=matchekindnhdwithE_binop_->hd|_->acciniterpreciseflowtl(* Keep other constants *)|E_constant_,_->iterhdflowtl|_,E_constant_->iteraccflowtl|_->iteraccflowtlinSome(iterhdflowtl)endlet()=register_eval_reduction(moduleReduction)