123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297(**************************************************************************)(* *)(* This file is part of WP plug-in of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* CEA (Commissariat a l'energie atomique et aux energies *)(* 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). *)(* *)(**************************************************************************)openLang(* Helpers *)letis_positivee=F.p_leqF.e_zeroe(* 0 <= n *)letis_negativee=F.p_lteF.e_zero(* n < 0 *)(* Requires 2^i < n && 0 <= i < j *)letreclog2mijn=letb=Integer.two_power_of_intjinifInteger.ltbnthenlog2mj(2*j)nelse(* 2^i < n <= 2^j *)ifInteger.equalbnthenjelse(* 2^i < n < 2^j *)log2dijn(* Requires 2^i < n < 2 ^j && 0 <= i < j *)andlog2dijn=ifsucci=jthenielseletk=(i+j)/2inleta=Integer.two_power_of_intkinletc=Integer.compareaninifc>0thenlog2diknelse(* a=2^k > n *)ifc<0thenlog2dkjnelse(* a=2^k < n *)k(* Theorem LAND-1: derived from Cbits.uint_land_range
exists i, 0 <= e_i <= n
-----------------------------
0 <= land(e_1,...,e_n) <= n
Theorem LAND-2: partially derived from Cbits.sint_land_inf
forall i, -2^p <= e_i <= n < 0
-------------------------------------------
-2^p <= land(e_1,...,e_n) <= e_i <= n < 0
*)letland_leq~positiveesn=(* land(e_1,...,e_n) <= n *)ifInteger.(lezeron)then(* From theorem LAND-1 when 0<=n:
(exist i, 0 <= e_i <= n) |- 0 <= land(e_1,...,e_n) <= n *)leta=F.e_zintninletcase1=F.p_any(fune->F.p_and(is_positivee)(F.p_leqea))esinifpositivethencase1else(* From theorem LAND-2: when 0 <= n
(forall i, e_i < 0) && -1 <= 0 <= n |- land(e_1,...e_n) <= -1 <= 0 <= n *)letcase2=F.p_anyis_negativeesinF.p_orcase1case2elseifpositivethenraiseNot_foundelse(* From theorem LAND-2 when n<0:
(forall i, e_i <= n < 0) |- land(e_1,...,e_n) <= n < 0*)leta=F.e_zintninletcase1=F.p_any(fune->F.p_leqea)esinifInteger.(ltnminus_one)thencase1else(* From theorem LAND-2: when -1 == n
(forall i, e_i < 0) && -1 <= 0 <= n |- land(e_1,...e_n) <= -1 <= 0 <= n *)letcase2=F.p_anyis_negativeesinF.p_orcase1case2letleq_land~positivenes=(* n <= land(e_1,...,e_n) *)ifInteger.(lenzero)then(* From theorem LAND-1 when n<=0:
(exist i, n <= 0 <= e_i) |- n <= 0 <= land(e_1,...,e_n) *)F.p_anyis_positiveeselseifpositivethenraiseNot_foundelseletp=log2m01(Integer.negn)in(* Have n <= -2^p < 0
From theorem LAND-2: when n <= -2^p < 0
(forall i, n <= -2^p <= e_i < 0) |- n <= land(e_1,...e_n) < 0 *)leta=F.e_zintInteger.(neg(two_power_of_intp))inF.p_all(fune->F.p_and(is_negativee)(F.p_ltae))es(* Theorem LOR-1: partially derived from Cbits.uint_lor_inf
forall i, 0 <= e_i <= 2^p-1
-----------------------------
forall i, 0 <= e_i <= lor(e_1,...,e_n) <= 2^p-1
Theorem LOR-2: derived from Cbits.sint_lor_range
exist i, e_i <= n < 0
-----------------------------
n <= lor(e_1,...,e_n) < 0
*)letlor_leq~positiveesn=(* lor(e_1,...,e_n) <= n *)ifInteger.(lezeron)thenletp=log2m01(Integer.succn)in(* Have 0 <= 2^p <= n+1, hence 0 <= 2^p-1 <= n.
From theorem LOR-1 when 0 <= 2^p-1 <= n
(forall i, 0<= e_i <= 2^p-1 <=n) ==> 0<=lor(e_1,...,e_n) <= 2^p-1 <=n *)leta=F.e_zint(Integer.two_power_of_intp)inletcase1=F.p_all(fune->F.p_and(is_positivee)(F.p_ltea))esinifpositivethencase1else(* From theorem LOR-2 when 0<=n:
(exist i, e_i < 0 <= n) |- lor(e_1,...,e_n) < 0 <= n*)letcase2=F.p_anyis_negativeesinF.p_orcase1case2elseraiseNot_foundletleq_lor~positivenes=(* n <= lor(e_1,...,e_n) *)ifInteger.(lezeron)then(* From theorem LOR-1 when 0<=n:
(forall i, 0 <= n <= e_i) |- 0 <= n <= lor(e_1,...,e_n) *)leta=F.e_zintninF.p_all(fune->F.p_leqae)eselseifpositivethenraiseNot_foundelse(* From theorem LOR-1 when n<0:
(forall i, n < 0 <= e_i) |- n < 0 <= lor(e_1,...,e_n) *)letcase1=F.p_allis_positiveesin(* From theorem LOR-2 when n<0:
(exist i, n <= e_i < 0) |- n <= lor(e_1,...,e_n) < 0 *)leta=F.e_zintninletcase2=F.p_any(fune->F.p_and(F.p_leqae)(is_negativee))esinF.p_orcase1case2(* -------------------------------------------------------------------------- *)(* --- Patterns --- *)(* -------------------------------------------------------------------------- *)typepattern=|LEQofpattern*pattern|LTofpattern*pattern|INT|LAND|LORtypesigma={plor:bool;pland:bool;mutablebound:Integer.t;mutableterms:F.termlist;}letrecpmatchspe=letopenQed.Logicinmatchp,F.reprewith|LEQ(p,q),Leq(a,b)|LT(p,q),Lt(a,b)->pmatchspa;pmatchsqb|INT,Kintn->s.bound<-n|LAND,Fun(f,es)whenf==Cint.f_land->s.terms<-es|LOR,Fun(f,es)whenf==Cint.f_lor->s.terms<-es|_->raiseExitletmatchesspe=trypmatchspe;truewithExit->falseletpatterns:(pattern*(sigma->F.pred))list=[LEQ(INT,LAND),(funs->leq_land~positive:s.plands.bounds.terms);LT(INT,LAND),(funs->leq_land~positive:s.pland(Integer.succs.bound)s.terms);LEQ(LAND,INT),(funs->land_leq~positive:s.plands.termss.bound);LT(LAND,INT),(funs->land_leq~positive:s.plands.terms(Integer.preds.bound));LEQ(INT,LOR),(funs->leq_lor~positive:s.plors.bounds.terms);LT(INT,LOR),(funs->leq_lor~positive:s.plor(Integer.succs.bound)s.terms);LEQ(LOR,INT),(funs->lor_leq~positive:s.plors.termss.bound);LT(LOR,INT),(funs->lor_leq~positive:s.plors.terms(Integer.preds.bound));]letselect_goal~pland~plorg=trylets={pland;plor;bound=Integer.zero;terms=[]}inlet(_,f)=List.find(fun(p,_)->matchesspg)patternsinSome(fs)withNot_found->Noneletrecsplit_goals~pland~plorothersranges=function|[]->List.revothers,List.revranges|g::gs->beginmatchselect_goal~pland~plorgwith|None->split_goals~pland~plor(F.p_boolg::others)rangesgs|Someg'->split_goals~pland~plorothers(g'::ranges)gsendletrange_goalg'(hs,_)=["bit-range",(hs,g')]letrange_goalsgs'(hs,_)=List.map(fung'->"bit-range",(hs,g'))gs'letother_goalsps(hs,_)=List.map(funp->"split",(hs,p))psopenTacticalletpositive_land=Tactical.checkbox~id:"positive-land"~title:"Force positive logical-and"~descr:"Requires to obtain a result from (at least one) positive operands"~default:true()letpositive_lor=Tactical.checkbox~id:"positive-lor"~title:"Force negative logical-or"~descr:"Restrict to obtain a positive result from (all) positive operands"~default:true()classbitrange=object(self)inheritTactical.make~id:"Wp.bitrange"~title:"Bit Range"~descr:"Bounds of Bitwise Operators"~params:[sndpositive_land;sndpositive_lor]methodselectfeedback=function|Clause(Goalp)->beginletgoals=lete=F.e_proppinmatchF.reprewith|Qed.Logic.Andes->es|Qed.Logic.Leq_|Qed.Logic.Lt_->[e]|_->raiseNot_foundinletpland=self#get_field(fstpositive_land)inletplor=self#get_field(fstpositive_lor)inletothers,ranges=split_goals~pland~plor[][]goalsinifranges=[]thenTactical.Not_applicableelsebeginifothers=[]thenfeedback#set_title"Split & Bit Range(s)"elsefeedback#set_title"Bit Range(s)";Tactical.Applicable(funseq->other_goalsothersseq@range_goalsrangesseq)endend|Inside(Goalp,e)->beginletg=F.e_proppinmatchF.reprgwith|Qed.Logic.AndeswhenList.memqees->beginletpland=self#get_field(fstpositive_land)inletplor=self#get_field(fstpositive_lor)inmatchselect_goal~pland~plorgwith|Someg'->Tactical.Applicable(range_goalg')|None->Tactical.Not_applicableend|_->Tactical.Not_applicableend|_->Tactical.Not_applicableendlettactical=Tactical.export(newbitrange)letstrategy=Strategy.maketactical~arguments:[](* -------------------------------------------------------------------------- *)(* --- Auto Bitrange --- *)(* -------------------------------------------------------------------------- *)letis_bitwisede=letopenQed.LogicinmatchF.reprewith|Fun(f,_)->List.memqfCint.f_bitwised|_->falseclassautobitrange=objectmethodid="wp:bitrange"methodtitle="Auto Bit-Range"methoddescr="Apply Bit-Range on comparison with bitwised operations"methodsearchpush(seq:Conditions.sequent)=letgoal=sndseqinletopenQed.LogicinmatchF.e_exprgoalwith|Lt(x,y)|Leq(x,y)whenis_bitwisedx||is_bitwisedy->push(strategyTactical.(Clause(Goalgoal)))|_->()endlet()=Strategy.register(newautobitrange)