1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864(**************************************************************************)(* This file is part of the Codex semantics library. *)(* *)(* Copyright (C) 2013-2025 *)(* 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 LICENSE). *)(* *)(**************************************************************************)[@@@ocaml.warning"-32"]moduleLog=Tracelog.Make(structletcategory="Single_value_abstraction.Ival"end);;moduleIval=Framac_ival.IvalmoduleAbstract_interp=Framac_ival.Abstract_interpmoduleIn_bits=Units.In_bitsopenIvalletname="Ival"moduleQuadrivalent_Lattice=Lattices.Quadrivalent;;moduleB=Sva_quadrivalenttypeinteger=tlet_is_topx=matchxwith|Top(None,None,r,m)whenZ.equalrZ.zero&&Z.equalmZ.one->true|_->falseletpp_optffmt=function|None->Format.fprintffmt"None"|Somex->Format.fprintffmt"Some(%a)"fx;;moduleInteger_Forward=struct(* Predicates. *)letieq0a=letopenIvalinmatchawith|Set[||]->Quadrivalent_Lattice.Bottom|Set[|a|]whenZ.equalaZ.zero->B.Boolean_Forward.true_|_whennot(Ival.contains_zeroa)->B.Boolean_Forward.false_|_->B.Topletieqab=letopenIvalinmatcha,bwith|Set[||],_|_,Set[||]->Quadrivalent_Lattice.Bottom|Set[|a|],Set[|b|]whenZ.equalab->B.Boolean_Forward.true_|_whennot(Ival.intersectsab)->B.Boolean_Forward.false_|_->B.Top;;letige0a=ifIval.is_bottomathenB.Bottomelseletmin_a,max_a=Ival.min_and_maxainletmay_be_false =match min_a with|None->true|SomexwhenZ.ltxZ.zero->true|_->falseinletmay_be_true=matchmax_awith|None->true|SomexwhenZ.geqxZ.zero->true|_->falseinB.of_bools~may_be_false~may_be_true;;leticmpop1op2ab=ifIval.is_bottoma||Ival.is_bottombthenB.Bottomelseletmin_a,max_a=Ival.min_and_maxainletmin_b,max_b=Ival.min_and_maxbinletmay_be_false=matchmax_a,min_bwith|None,_->true|_,None->true|Someia,Someib->op1iaibinletmay_be_true=matchmin_a,max_bwith|None,_->true|_,None->true|Someia,Someib->op2iaibinB.of_bools~may_be_false~may_be_true;;letile=icmpZ.gtZ.leq;;letilt=icmpZ.geqZ.lt;;letidiv=Ival.divletimul=Ival.mulletimod=Ival.c_remletiand=Ival.bitwise_andletior=Ival.bitwise_orletixor=Ival.bitwise_xorletiadd=Ival.add_intletisub=Ival.sub_intletitimeskx=ifZ.equalkZ.minus_onethenIval.neg_intxelseIval.scalekxleticonstk=Ival.inject_singletonkletzero=Ival.zeroletone=Ival.oneletiunknown_=Ival.topletassumecondx=matchcondwith|B.False|B.Bottom->Ival.bottom|_->xletishr=Ival.shift_rightletishl=Ival.shift_leftletishrab=ifIval.is_zeroathenaelseifIval.is_singleton_inta&&Ival.is_singleton_intbthenIval.inject_singleton@@Z.shift_right(Ival.project_inta)(Z.to_int(Ival.project_intb))elseletres=ishrabin(* Codex_log.feedback "ishr %a %a %a" Ival.pretty a Ival.pretty b Ival.pretty res; *)res;;(* let imod a b =
* let res = imod a b in
* Codex_log.feedback "imod %a %a %a" Ival.pretty a Ival.pretty b Ival.pretty res;
* res *)endletinter=narrowletinteger_is_bottom=function|Set[||]->true|_->falseletinteger_bottom=bottomletinteger_is_singletonx=trySome(Ival.project_intx)withIval.Not_Singleton_Int->NonemoduleInteger_Backward'=struct(* XXX: really do it. *)letcheck_improvementoldnew_=Somenew_(* a-A <= b-B ==> a <= b et A <= B (grandir b et baisser A) *)letilev1v2=tryletmin_v1=Ival.min_intv1inletmax_v2=Ival.max_intv2in(Ival.narrowv1(Ival.inject_rangeNonemax_v2),Ival.narrowv2(Ival.inject_rangemin_v1None))withFramac_ival.Abstract_interp.Error_Bottom->v1,v2(* TODO: unchanged. *);;letopt1fm=matchmwithNone->None|Somem->Some(fm)letiltv1v2=tryletmin_v1=Ival.min_intv1inletmax_v2=Ival.max_intv2in(Ival.narrowv1(Ival.inject_rangeNone(opt1Z.predmax_v2))),(Ival.narrowv2(Ival.inject_range(opt1Z.succmin_v1)None))withFramac_ival.Abstract_interp.Error_Bottom->v1,v2(* TODO: unchanged. *);;end(* Computes an over-approximation of old and new, and check whether
the result improves the precision. *)letinter_refinesoldnew_=letinter=Ival.narrowoldnew_in(* Codex_log.feedback "inter a %a b %a res %a"
Ival.pretty old Ival.pretty new_ Ival.pretty inter; *)assert(Ival.is_includedinterold);assert(Ival.is_includedinternew_);(* Note: we suppose that the result of narrow is always better
than old. *)ifIval.equalinteroldthenNoneelseSomeintermoduleInteger_Backward=structincludeSva_noop_transfer_functions.Integer_BackwardmoduleIF=Integer_Forward;;(* TODO: Ideally, should be done in the Ival lattice; would be faster. *)letieq0abool=matchboolwith|B.True->inter_refinesaIval.zero|B.False->inter_refinesa@@Ival.diff_if_oneaIval.zero|B.Bottom->inter_refinesa@@Ival.bottom|B.Top->None;;letieqabbool=matchboolwith|B.True->inter_refinesab,inter_refinesba|B.False->inter_refinesa@@Ival.diff_if_oneab,inter_refinesb@@Ival.diff_if_oneba|B.Bottom->inter_refinesaIval.bottom,inter_refinesbIval.bottom|B.Top->None,None;;letiaddi1i2res=inter_refinesi1(Ival.sub_intresi2),inter_refinesi2(Ival.sub_intresi1);;letisubi1i2res=inter_refinesi1(Ival.add_intresi2),inter_refinesi2(Ival.sub_inti1res);;(* More precise, but does not show up in practice and slower. *)let_ishri1i2res=(* if Ival.is_bottom i2 then *)letni1=ifIval.is_singleton_inti2thenletv=Ival.project_inti2inletv=Z.(lsl)Z.one(Z.to_intv)inletretrieve_i1=lethigh_bits=Ival.scalevresinletlow_bits=Ival.inject_range(SomeZ.zero)(Some(Z.predv))inIval.bitwise_orhigh_bitslow_bitsininter_refinesi1retrieve_i1elseNoneinni1,None(* MAYBE: refine with the size of the operation. *);;letileabbool=matchboolwith|B.True->inter_refinesa(Ival.backward_comp_int_leftAbstract_interp.Comp.Leab),inter_refinesb(Ival.backward_comp_int_leftAbstract_interp.Comp.Geba)|B.False->inter_refinesa(Ival.backward_comp_int_leftAbstract_interp.Comp.Gtab),inter_refinesb(Ival.backward_comp_int_leftAbstract_interp.Comp.Ltba)|B.Bottom->inter_refinesaIval.bottom,inter_refinesbIval.bottom|B.Top->None,None;;(* Note: incorrect when overflows, and Value has better backward multipliers. *)letimuli1i2res=matchIval.project_inti1with|exceptionIval.Not_Singleton_Int->beginmatchIval.project_inti2with|exceptionIval.Not_Singleton_Int->(None,None)|k->(inter_refinesi1(Ival.scale_div~pos:falsekres),None)end|k->(None,inter_refinesi2(Ival.scale_div~pos:falsekres));;letitimeskares=inter_refinesa@@Ival.scale_div~pos:truekres(* Note: Ival does not handle itimes minus one very well. *)letitimeskares=ifZ.equalk(Z.minus_one)theninter_refinesa@@Ival.neg_intreselseitimeskaresletimodadivres=(* Log.trace (fun p -> p "imod %a %a %a" Ival.pretty a Ival.pretty div Ival.pretty res) @@ fun () -> *)(* Note that we cannot just conclude that we can intersect [a]
with inject_top (None,None,res,div), because those may be
negative, and this operation is truncated modulo, not
euclidian modulo.
Instead, we use the following equality, which holds only
when v1 does not change sign, which is why we split its range:
res == (res / div) * div + res *)leta_pos=Ival.narrowaIval.positive_integersinleta_neg=Ival.narrowaIval.negative_integersinletres_pos=Ival.narrowresIval.positive_integersinletres_neg=Ival.narrowresIval.negative_integersinletnew_aares=ifIval.is_bottomathenIval.bottomelseIval.add_int(Ival.mul(Ival.divadiv)div)resinletnew_a=Ival.join(new_aa_posres_pos)(new_aa_negres_neg)in(* Codex_log.feedback "new_a %a %a" Ival.pretty new_a Ival.pretty a; *)letnew_div=ifIval.intersectsaresthenNoneelseletnew_div=ifIval.is_bottoma||Ival.is_bottomresthenIval.bottomelseIval.div(Ival.sub_intares)(Ival.divadiv)ininter_refinesdivnew_divininter_refinesanew_a,new_div;;moduleDebug=structletiaddi1i2res=let(newi1,newi2)=iaddi1i2resinletaffnewi1=matchnewi1withNone->i1|Somev->vinletaffnewi2=matchnewi2withNone->i2|Somev->vinLog.debug(funp->p"iadd: i1 %a i2 %a res %a newi1 %a newi2 %a"Ival.prettyi1Ival.prettyi2Ival.prettyresIval.prettyaffnewi1Ival.prettyaffnewi2);(newi1,newi2);;letitimeskares=let(newa)=itimeskaresinletaffnewa=matchnewawithNone->a|Somev->vinLog.debug(funp->p"itimes: k %s a %a res %a newa %a"(Z.to_stringk)Ival.prettyaIval.prettyresIval.prettyaffnewa);newa;;letimodadivres=Log.debug(funp->p"imod start");letres=imodadivresinLog.debug(funp->p"imod end");res;;end(* include Debug *)endmoduleInteger_Lattice=structincludeIvalletwiden_hints=Widen_Hints.default_widen_hints(* let widen_hints = Ival.Widen_Hints.of_list [] *)letthirtytwo=Z.of_int32(* Note: not having these widen hints greatly improves performance. *)letsize_hint=thirtytwo(* Z.zero *)letwiden~previousnext=widen(size_hint,widen_hints)previousnextletincludes_or_widen~previousnext=ifis_includednextpreviousthen(true,next)else(false,widen~previousnext)letincludes_or_widen'~previousnext=let(bool,res)=includes_or_widen~previousnextin(* Codex_log.debug "ival widens %a %a %b %a" Ival.pretty previous Ival.pretty next bool Ival.pretty res; *)(bool,res);;letincludesab=is_includedbaletinter=narrowletsingleton=Ival.inject_singletonletis_singletonx=trySome(Ival.project_intx)withIval.Not_Singleton_Int->Nonelettop()=topletbottom()=bottomletfold_cropt~inf~supfacc=ifZ.ltsupinfthenaccelse(* Also allow [0,negative] to represent the empty interval. *)(* Codex_log.feedback "inf %s sup %s" (Z.to_string inf) (Z.to_string sup); *)(* assert (Z.leq inf sup || (Z.equal inf Z.zero && Z.equal sup Z.minus_one)); *)(* assert (Z.leq inf sup || (Z.equal inf Z.zero && Z.lt sup Z.zero)); *)matchtwith|Sets->Array.fold_left(funaccx->ifZ.leqinfx&&Z.leqxsupthenfxaccelseacc)accs|Float_->assertfalse|Top(mn,mx,_,step)->letinf=matchmnwith|None->inf|Somemn->Z.maxmninfinletsup=matchmxwith|None->sup|Somemx->Z.minmxsupinAbstract_interp.Int.foldf~inf~sup~stepaccend(**************** Binary. ****************)(* MAYBE: Do nothing if already good. Not sure about what Ival.cast does.*)letunsigned_bound=(* precompute common values *)letub7=Abstract_interp.Int.two_power_of_int7inletub8=Abstract_interp.Int.two_power_of_int8inletub31=Abstract_interp.Int.two_power_of_int31inletub63=Abstract_interp.Int.two_power_of_int63infunction|7->ub7|8->ub8|31->ub31|32->Abstract_interp.Int.two_power_32|63->ub63|64->Abstract_interp.Int.two_power_64|n->Abstract_interp.Int.two_power_of_intnletwrapped_u~(size:In_bits.t)value=trymatchIval.min_and_maxvaluewith|None,_|_,None->false|Somemin,Somemax->Z.geqminZ.zero&&Z.equalZ.zero@@Z.shift_right_truncmax(size:>int)withFramac_ival.Abstract_interp.Error_Bottom->true(* Slower than above. *)(* let _wrapped_u ~size value =
try
(match Ival.min_int value with
| None -> false
| Some x -> Z.geq x Z.zero) &&
(match Ival.max_int value with
| None -> false
| Some x -> Z.numbits x <= size)
with Framac_ival.Abstract_interp.Error_Bottom -> true *)(* Seems slower. *)(* let _wrapped_s ~size value =
try
let bound = Z.shift_left Z.one @@ pred size in
(match Ival.min_int value with
| None -> false
| Some x -> Z.geq x (Z.neg bound)) &&
(match Ival.max_int value with
| None -> false
| Some x -> Z.lt x @@ bound)
with Framac_ival.Abstract_interp.Error_Bottom -> true *)letwrapped_s~(size:In_bits.t)value=tryletsizem1=(size:>int)-1in(* let bound = Z.shift_left Z.one @@ pred size in *)(* Cannot use shift_right_trunc here, because of -2^{size-1}. *)matchIval.min_and_maxvaluewith|None,_|_,None->false|Somemin,Somemax->Z.leqZ.minus_one@@Z.shift_rightminsizem1&&Z.geqZ.zero@@Z.shift_rightmaxsizem1withFramac_ival.Abstract_interp.Error_Bottom->true(** [z_fold f x low high] is a fold on the integer interval [low..high]
I.E. [f high (f (high-1) ... (f low acc))] *)letrecz_foldfacclowhigh=letopenZinifgtlowhighthenaccelsez_foldf(flowacc)(low+one)high(** [z_reduce f (++) low high] is [f low ++ ... ++ f high]. *)letz_reducef(++)lowhigh=letopenZinifequallowhighthenflowelsez_fold(funiacc->acc++(fi))(flow)(low+one)highletwrapu~(size:In_bits.t)value=tryletwrapped=ifwrapped_u~sizevaluethenvalueelseIval.cast_int_to_int~size:(Z.of_int(size:>int))~signed:falsevalueinmatchvaluewith|Top(_,_,rem,modu)whennot(Z.equalmoduZ.one||Z.equalremZ.zero)->(* If the value is known to be rem modulo mod, then the unsigned value
must be greater than rem. *)Ival.narrow(inject_interval~min:(Somerem)~max:(Some(Abstract_interp.Int.two_power_of_int(size:>int)))~modu:Z.one~rem:Z.zero)wrapped|_->wrappedwithZ.Overflow->Log.warning(funp->p"Overflow wrapu: TODO");topletthree=Z.of_int3letall_unsigned_8=Ival.create_all_values~signed:false~size:8letall_unsigned_32=Ival.create_all_values~signed:false~size:32letall_unsigned_64=Ival.create_all_values~signed:false~size:64letall_unsigned=function|8->all_unsigned_8|32->all_unsigned_32|64->all_unsigned_64|size->Ival.create_all_values~signed:false~size(** More precise version of [wrapu] when the interval being wrapped is close
in size to the target.
Splits the interval into sections of same remainder modulo {m 2^{size}},
shifts each section individually using addition (exact), the combines all
sections with join. *)letwrapu~(size:In_bits.t)value=letfactor=unsigned_bound(size:>int)inmatchIval.min_and_maxvaluewith|Somemin,Somemax->letk_min=Z.edivminfactorinletk_max=Z.edivmaxfactorinifZ.(leq(k_max-k_min)three)thenletvalid=all_unsigned(size:>int)inz_reduce(funi->letshifted_res=Ival.add_singleton_int(Z.neg(Z.mulifactor))valueinIval.narrowvalidshifted_res)Ival.joink_mink_maxelsewrapu~sizevalue|None,_|_,None|exceptionAbstract_interp.Error_Bottom->wrapu~sizevalue(** Wrapper around [wrapu] to increase sharing of "top" *)letwrapu~sizevalue=letres=wrapu~sizevalueinmatch(size:>int)with|8->ifIval.equalall_unsigned_8resthenall_unsigned_8elseres|32->ifIval.equalall_unsigned_32resthenall_unsigned_32elseres|64->ifIval.equalall_unsigned_64resthenall_unsigned_64elseres|_->resletall_signed_8=Ival.create_all_values~signed:true~size:8letall_signed_32=Ival.create_all_values~signed:true~size:32letall_signed_64=Ival.create_all_values~signed:true~size:64letall_signed=function|8->all_signed_8|32->all_signed_32|64->all_signed_64|size->Ival.create_all_values~signed:true~sizeletwraps~(size:In_bits.t)value=try(* Codex_log.feedback "wraps %a" pretty value; *)ifwrapped_s~sizevaluethenvalueelseIval.cast_int_to_int~size:(Z.of_int(size:>int))~signed:truevaluewithZ.Overflow->Log.warning(funp->p"Overflow wraps: TODO");top(** More precise version of [wraps] when the interval being wrapped is close
in size to the target.
Splits the interval into sections of same remainder modulo {m 2^{size}},
shifts each section individually using addition (exact), the combines all
sections with join. *)letwraps~(size:In_bits.t)value=letfactor=unsigned_bound(size:>int)inletpre_factor=unsigned_bound(pred(size:>int))inmatchIval.min_and_maxvaluewith|Somemin,Somemax->letk_min=Z.ediv(Z.addminpre_factor)factorinletk_max=Z.ediv(Z.addmaxpre_factor)factorinifZ.(leq(k_max-k_min)three)thenletvalid=all_signed(size:>int)inz_reduce(funi->letshifted_res=Ival.add_singleton_int(Z.neg(Z.mulifactor))valueinIval.narrowvalidshifted_res)Ival.joink_mink_maxelsewraps~sizevalue|None,_|_,None|exceptionAbstract_interp.Error_Bottom->wraps~sizevalue(** Wrapper around [wraps] to increase sharing of "top" *)letwraps~sizevalue=letres=wraps~sizevalueinmatch(size:>int)with|8->ifIval.equalall_signed_8resthenall_signed_8elseres|32->ifIval.equalall_signed_32resthenall_signed_32elseres(* | 64 -> if Ival.equal all_signed_64 res then all_signed_64 else res *)|_->res(** [backward_wrapu ~size value res] returns an optional [value'] such that:
- [value'] is included in [value]
- [wrapu ~size value'] is included in [res]. *)letbackward_wrapu~sizevalueres=tryifwrapped_u~sizevaluethenSome(Ival.narrowresvalue)elsematchIval.min_and_maxvaluewith|None,_|_,None->None|Somemin,Somemax->letfactor=unsigned_bound(size:>int)inletk_min=Z.edivminfactorinletk_max=Z.edivmaxfactorinifZ.(leq(k_max-k_min)three)then(* For all possible shift factor, shift res by that amount,
and intersect it with value, the join all the results.
In practice, there should only be one or two possible shift factors. *)Some(z_reduce(funi->letshifted_res=Ival.add_singleton_int(Z.mulifactor)resinIval.narrowvalueshifted_res)Ival.joink_mink_max)elseNonewithZ.Overflow->Log.warning(funp->p"Overflow backward_wrapu: TODO");None(** [backward_wraps ~size value res] returns an optional [value'] such that:
- [value'] is included in [value]
- [wraps ~size value'] is included in [res].*)letbackward_wraps~sizevalueres=tryifwrapped_s~sizevaluethenSome(Ival.narrowresvalue)elsematchIval.min_and_maxvaluewith|None,_|_,None->None|Somemin,Somemax->letfactor=unsigned_bound(size:>int)inletpre_factor=unsigned_bound((size:>int)-1)inletk_min=Z.ediv(Z.addminpre_factor)factorinletk_max=Z.ediv(Z.addmaxpre_factor)factorinifZ.(leq(k_max-k_min)three)thenSome(z_reduce(funi->letshifted_res=Ival.add_singleton_int(Z.mulifactor)resinIval.narrowvalueshifted_res)Ival.joink_mink_max)elseNonewithZ.Overflow->Log.warning(funp->p"Overflow backward_wraps: TODO");Noneletwraps_or_narrow~(size:In_bits.t)~nswvalue=ifnswthenletbound=Z.shift_leftZ.one@@pred(size:>int)inletinterval=Ival.inject_range(Some(Z.negbound))(Some(Z.predbound))inletres=Ival.narrowvalueintervalin(* assert(not @@ Ival.is_bottom res); *)reselsewraps~sizevalueletwrapu_or_narrow~(size:In_bits.t)~nuwvalue=ifnuwthenletbound=Z.pred@@Z.shift_leftZ.one(size:>int)inletinterval=Ival.inject_range(SomeZ.zero)(Somebound)inletres=Ival.narrowvalueintervalin(* assert(not @@ Ival.is_bottom res); *)reselsewrapu~sizevalue(* Note: Ival is not the best fit for this; e.g. we always have a
minimum and a maximum value; the congruence information could be
shared between the signed and unsigned representations, etc. *)moduleUnsigned=struct(* Invariant: arguments and return of every operation is in the [0,2^size[ range. *)moduleBinary_Forward=structletar2op~sizeab=assert(wrapped_u~sizea);assert(wrapped_u~sizeb);letres=wrapu~size@@opabin(* assert (wrapped_u ~size res); *)res;;letbiadd=ar2Ival.add_intletbisub=ar2Ival.sub_intletbimul=ar2Ival.mul(* Signed operation: wrap to signed, to the operation, wrap to unsigned. *)letbisdiv~sizeab=wrapu~size@@Integer_Forward.idiv(wraps~sizea)(wraps~sizeb)letbismod~sizeab=wrapu~size@@Integer_Forward.imod(wraps~sizea)(wraps~sizeb)letbiudiv=ar2Integer_Forward.idivletbiumod=ar2Integer_Forward.imodletband=ar2Ival.bitwise_andletbor=ar2Ival.bitwise_orletbxor=ar2Ival.bitwise_xorletbshl=ar2Ival.shift_leftletbashr=ar2Ival.shift_rightletblshr=ar2Ival.shift_rightletbeq~sizeab=Integer_Forward.ieqabletbiule~sizeab=Integer_Forward.ileabletbisle~sizeab=letres=Integer_Forward.ile(wraps~sizea)(wraps~sizeb)in(* Codex_log.feedback "bisle res %a" Sva_quadrivalent.Boolean_Lattice.pretty res; *)resletbsext~size~oldsizex=wrapu~size@@wraps~size:oldsizexletbuext~size~oldsizex=assert(wrapped_u~sizex);xletbofbool~sizex=assertfalse(* module Debug = struct *)(* let _bisdiv ~size a b = *)(* let res = bisdiv ~size a b in *)(* Codex_log.feedback "bisdiv %d: %a %a %a" size Ival.pretty a Ival.pretty b Ival.pretty res; *)(* res *)(* let _biudiv ~size a b = *)(* let res = biudiv ~size a b in *)(* Codex_log.feedback "biudiv %d: %a %a %a" size Ival.pretty a Ival.pretty b Ival.pretty res; *)(* res *)(* let _bismod ~size a b = *)(* let res = bismod ~size a b in *)(* Codex_log.feedback "bismod %d: %a %a %a" size Ival.pretty a Ival.pretty b Ival.pretty res; *)(* res *)(* let _biumod ~size a b = *)(* let res = biumod ~size a b in *)(* Codex_log.feedback "biumod %d: %a %a %a" size Ival.pretty a Ival.pretty b Ival.pretty res; *)(* res *)(* let _bisle ~size a b = *)(* let res = bisle ~size a b in *)(* Codex_log.feedback "bisle %d: %a %a %a" size Ival.pretty a Ival.pretty b Sva_quadrivalent.Boolean_Lattice.pretty res; *)(* res *)(* let _biule ~size a b = *)(* let res = biule ~size a b in *)(* Codex_log.feedback "biule %d: %a %a %a" size Ival.pretty a Ival.pretty b Sva_quadrivalent.Boolean_Lattice.pretty res; *)(* res *)(* ;; *)(* let _beq ~size a b = *)(* let res = beq ~size a b in *)(* Codex_log.feedback "beq %d: %a %a %a" size Ival.pretty a Ival.pretty b Sva_quadrivalent.Boolean_Lattice.pretty res; *)(* res *)(* ;; *)(* end *)(* include Debug *)letbuninit~size=Ival.bottomletbunknown~size=wrapu~sizeIval.topletbextract~size~index~oldsizex=(* Codex_log.feedback "bextracat %d %d %d %a" size index oldsize Ival.pretty x; *)wrapu~size@@Ival.extract_bits~size:(Z.of_intoldsize)~start:(Z.of_intindex)~stop:(Z.of_int@@index+(size:>int)-1)xletbconcat~size1~size2v1v2=wrapu~size:In_bits.(size1+size2)@@Ival.add_int(Ival.scale(Z.shift_leftZ.one(size2:>int))v1)v2let_bconcat_~size1~size2v1v2=letres=bconcat~size1~size2v1v2inLog.debug(funp->p"bconcat %d %d %a %a res %a"(size1:>int)(size2:>int)Ival.prettyv1Ival.prettyv2Ival.prettyres);resletbitimes~sizekx=wrapu~size@@Ival.scalekxletassume~sizecondx=matchcondwith|B.False|B.Bottom->Ival.bottom|_->xletvalid~size_=assertfalseletbiconst~sizek=wrapu~size@@Ival.inject_singletonkletbshift~size~offset~max_=assertfalseletbindex~size_=assertfalseendmoduleBitvector_Backward=structincludeSva_noop_transfer_functions.Bitvector_Backward(* Invariant: the arguments should have been already wrapped
unsigned, so this should work directly. *)letbeq~size=Integer_Backward.ieqletbiule~size=Integer_Backward.ileletbiumod~size=Integer_Backward.imodletbisle~sizeabbool=letwsa=wraps~sizeaandwsb=wraps~sizebinmatchboolwith|B.True->inter_refinesa(wrapu~size@@Ival.backward_comp_int_leftAbstract_interp.Comp.Lewsawsb),inter_refinesb(wrapu~size@@Ival.backward_comp_int_leftAbstract_interp.Comp.Gewsbwsa)|B.False->inter_refinesa(wrapu~size@@Ival.backward_comp_int_leftAbstract_interp.Comp.Gtwsawsb),inter_refinesb(wrapu~size@@Ival.backward_comp_int_leftAbstract_interp.Comp.Ltwsbwsa)|B.Bottom->inter_refinesaIval.bottom,inter_refinesbIval.bottom|B.Top->None,Nonelet_bisle~sizeabbool=letresa,resb=bisle~sizeabboolinlet_ffmt=Format.fprintffmt"backward bisle %d %a %a %a"(size:>int)Ival.prettyaIval.prettybSva_quadrivalent.Boolean_Lattice.prettybool;(matchresawith|None->Format.fprintffmt" none"|Somea->Format.fprintffmt" %a"Ival.prettya);(matchresbwith|None->Format.fprintffmt" none"|Someb->Format.fprintffmt" %a"Ival.prettyb)inresa,resb;;endend(* NoWrap: unsound version. *)moduleNoWrap=struct(* A version where we assume that nothing wraps. *)moduleBitvector_Forward=structlet_wraps~sizevalue=letres=wraps~sizevalueinLog.debug(funp->p"wraps %d: %a -> %a"(size:>int)Ival.prettyvalueIval.prettyres);res;;let_wrapu~sizevalue=letres=wrapu~sizevalueinLog.debug(funp->p"wrapu %d: %a -> %a"(size:>int)Ival.prettyvalueIval.prettyres);res;;letbiadd~size=Ival.add_intletbisub~size=Ival.sub_intletbimul~size=Ival.mulletbisdiv~sizeab=Integer_Forward.idiv(wraps~sizea)(wraps~sizeb)letbiudiv~sizeab=Integer_Forward.idiv(wrapu~sizea)(wrapu~sizeb)letbismod~sizeab=Integer_Forward.imod(wraps~sizea)(wraps~sizeb)letbiumod~sizeab=Integer_Forward.imod(wrapu~sizea)(wrapu~sizeb)(* let bisdiv ~size = Integer_Forward.idiv
* let biudiv ~size = Integer_Forward.idiv
* let bismod ~size = Integer_Forward.imod
* let biumod ~size = Integer_Forward.imod *)letbsext~size~oldsizex=xletbuext~size~oldsizex=xletbofbool~size=assertfalseletband~size=Ival.bitwise_andletbeq~sizeab=Sva_quadrivalent.Boolean_Lattice.inter(Integer_Forward.ieq(wrapu~sizea)(wrapu~sizeb))(Integer_Forward.ieq(wraps~sizea)(wraps~sizeb))letbiule~sizeab=Integer_Forward.ile(wrapu~sizea)(wrapu~sizeb)letbisle~sizeab=Integer_Forward.ile(wraps~sizea)(wraps~sizeb)(* let beq ~size = Integer_Forward.ieq
* let biule ~size = Integer_Forward.ile
* let bisle ~size = Integer_Forward.ile *)letbor~size=Ival.bitwise_orletbxor~size=Ival.bitwise_xorletbuninit~size=Ival.bottomletbunknown~size=Ival.topletbextract~size~index~oldsizex=(* Log.debug (fun p -> p "bextracat %d %d %d %a" size index oldsize Ival.pretty x; *)Ival.extract_bits~size:(Z.of_intoldsize)~start:(Z.of_intindex)~stop:(Z.of_int@@index+size-1)xletbextract~size~index~oldsizex=letres=bextract~size~index~oldsizexinLog.debug(funp->p"Sva_ival.bextract %d %d %d %a %a"sizeindexoldsizeIval.prettyxIval.prettyres);resletbconcat~size1~size2v1v2=Ival.add_int(Ival.scale(Z.shift_leftZ.onesize2)v1)v2(* let bconcat ~size1 ~size2 v1 v2 =
* wrapu ~size:(size1 + size2) @@ Ival.add_int (Ival.scale (Z.shift_left Z.one size2) v1) v2
* let bconcat_ ~size1 ~size2 v1 v2 =
* let res = bconcat ~size1 ~size2 v1 v2 in
* Log.debug (fun p -> p "bconcat %d %d %a %a res %a" size1 size2 Ival.pretty v1 Ival.pretty v2 Ival.pretty res;
* res *)letbitimes~sizek=Ival.scalekletassume~sizecondx=matchcondwith|B.False|B.Bottom->Ival.bottom|_->xletvalid~size_=assertfalseletbiconst~sizek=Ival.inject_singletonkletbshl~size=Ival.shift_leftletbashr~size=Ival.shift_rightletblshr~size=Ival.shift_rightletbshift~size~offset~max_=assertfalseletbindex~size_=assertfalseendmoduleBitvector_Backward=structincludeSva_noop_transfer_functions.Bitvector_Backwardletbeq~size=Integer_Backward.ieqletbisle~size=Integer_Backward.ileletbiule~size=Integer_Backward.ileletbiadd~size=Integer_Backward.iaddletbisub~size=Integer_Backward.isubletbimul~size=Integer_Backward.imulletbitimes~size=Integer_Backward.itimesletbismod~size=Integer_Backward.imodletbiumod~size=Integer_Backward.imodletbisdiv~size=Integer_Backward.idivletbiudiv~size=Integer_Backward.idivletbshift~size~offset~max_=assertfalseletbindex~size_=assertfalseendletbinary_to_ival~size~signed:_x=xletbinary_is_singleton~size=is_singleton_intmoduleBitvector_Lattice=structincludeLattices.Unimplemented.Bitvector_Lattice(structtypet=Integer_Lattice.tletloc=__LOC__end)includeInteger_Latticeletwiden~size~previousnext=letres1=Ival.widen(Z.of_intsize,widen_hints)previousnextin(* Note: with this wrapu, we sometimes enter an infinite loop. *)(* let res2 = wrapu ~size @@ res1 in *)(* Log.debug (fun p -> p "size %d prev %a next %a res1 %a res2 %a" size Ival.pretty previous Ival.pretty next Ival.pretty res1 Ival.pretty res2; *)res1letincludes_or_widen~size~previousnext=ifis_includednextpreviousthen(true,next)else(false,widen~size~previousnext)letsingleton~size=singletonendend(* include Unsigned *)(* include NoWrap *)moduleBothWrap=struct(* We try to use == whenever possible to avoid consuming too much memory. *)typebitvector={signed:Ival.t;unsigned:Ival.t}(* Reduced product between the signed and unsigned abstraction. Also
tries to share both when possible. *)letreduce~sizex=ifInteger_Lattice.equalx.signedx.unsignedthenxelse(* Fast, common case: we are in the intersection. *)ifwrapped_u~sizex.signed||wrapped_s~sizex.unsignedthenletres=Ival.narrowx.signedx.unsignedin{signed=res;unsigned=res}else(* Sometimes ival can learn things, and it is hard to predict why.
We need to perform the reduction three times, because each reduction may
be beneficial to the other. *)letsigned=Ival.narrowx.signed@@wraps~sizex.unsignedinletunsigned=Ival.narrowx.unsigned@@wrapu~sizesignedinletsigned=Ival.narrowsigned@@wraps~sizeunsignedinifInteger_Lattice.equalsignedunsignedthen{signed;unsigned=signed}else{signed;unsigned};;letreduce~sizex=letres=reduce~sizexinassert(Ival.is_includedres.signedx.signed&&Ival.is_includedres.unsignedx.unsigned);res;;moduleBitvector_Lattice=structincludeLattices.Unimplemented.Bitvector_Lattice(structtypet=bitvectorletloc=__LOC__end)letis_top_signed~sizex=Ival.equalx@@wraps~sizeIval.topletis_top_unsigned~sizex=Ival.equalx@@wrapu~sizeIval.topletival_pretty~size=Ival.pretty;;letpretty~sizefmtx=ifIval.equalx.signedx.unsignedthenival_pretty~sizefmtx.signedelsematchis_top_signed~sizex.signed,is_top_unsigned~sizex.unsignedwith|true,true->Format.fprintffmt"[--..--]"|false,true->ival_pretty~sizefmtx.signed|true,false->ival_pretty~sizefmtx.unsigned|false,false->ifIval.equalx.unsigned@@wrapu~sizex.signed(* unsigned implied by signed *)thenival_pretty~sizefmtx.signedelseifIval.equalx.signed@@wraps~sizex.unsigned(* signed implied by unsigned*)thenival_pretty~sizefmtx.unsignedelseFormat.fprintffmt"{signed: %a; unsigned: %a}"(ival_pretty~size)x.signed(ival_pretty~size)x.unsignedletwiden_hints=Widen_Hints.default_widen_hintsletwiden~(size:In_bits.t)~previous:ab=letsize_=Z.of_int(size:>int)inletsigned=Ival.widen(size_,widen_hints)a.signedb.signedinifa.signed==a.unsigned&&b.signed==b.unsignedthen{signed;unsigned=signed}elsereduce~size{signed;unsigned=Ival.widen(size_,widen_hints)a.unsignedb.unsigned}(* As we have an intersection semantics for signed and unsigned,
we can usr || on the inclusion tests.
EDIT: no we cannot, as the inclusion test is comparing the
abstract values, not the concrete ones. *)letincludesab=Integer_Lattice.includesa.signedb.signed&&Integer_Lattice.includesa.unsignedb.unsignedletincludes_or_widen~size~previousnext=ifincludespreviousnextthen(true,next)else(false,widen~size~previousnext)(* Note: we cannot call reduce in join and inter without size
information; this causes some expressions to be evaluated
without the maximum precision in some cases. Unfortunately,
passing the size information here is hard. *)letjoin~sizeab=(* Important special case. *)ifIval.is_bottoma.signedthenb(* assuming b is already reduced. *)elseletsigned=Integer_Lattice.joina.signedb.signedinifa.signed==a.unsigned&&b.signed==b.unsignedthen{signed;unsigned=signed}elsereduce~size{signed;unsigned=Integer_Lattice.joina.unsignedb.unsigned}let_join~sizeab=letres=join~sizeabinifnot@@Ival.is_bottoma.signedthenLog.debug(funp->p"join %a %a res %a"(pretty~size)a(pretty~size)b(pretty~size)res);res;;letinter~sizeab=letsigned=Integer_Lattice.intera.signedb.signedinifa.signed==a.unsigned&&b.signed==b.unsignedthen{signed;unsigned=signed}elsereduce~size{signed;unsigned=Integer_Lattice.intera.unsignedb.unsigned};;letincludes~sizeab=Integer_Lattice.includesa.signedb.signed&&Integer_Lattice.includesa.unsignedb.unsignedlethash_=assertfalseletcompareab=letx=Stdlib.comparea.signedb.signedinifx==0thenStdlib.comparea.unsignedb.unsignedelsex;;letbottom~size={signed=Ival.bottom;unsigned=Ival.bottom}(* We precompute the value for the most common sizes. *)lettop=letdefault~size={signed=wraps~sizeIval.top;unsigned=wrapu~sizeIval.top;}inlettop64=default~size:(In_bits.of_int64)inlettop32=default~size:(In_bits.of_int32)inlettop16=default~size:(In_bits.of_int16)inlettop8=default~size:(In_bits.of_int8)infun~(size:In_bits.t)->match(size:>int)with|32->top32|64->top64|8->top8|16->top16|_->default~size;;letsingleton~(size:In_bits.t)k=(* This test allows to share the value when feasible. *)letku=Z.extractk0(size:>int)inletks=Z.signed_extractk0(size:>int)inifZ.equalkuksthenletv=Integer_Forward.iconstksin{signed=v;unsigned=v}else{signed=Integer_Forward.iconstks;unsigned=Integer_Forward.iconstku}letis_singleton~size{signed;unsigned}=trySome(Ival.project_intunsigned)withIval.Not_Singleton_Int->Nonetypet=bitvectorletis_bottom~size{signed;unsigned}=Ival.is_bottomsigned||Ival.is_bottomunsignedletis_empty=is_bottomletequalab=Ival.equala.signedb.signed&&Ival.equala.unsignedb.unsignedletto_known_bits~(size:In_bits.t)x=letmoduleKnown_bits=Lattices.Known_BitsinifIval.is_bottomx.unsignedthenKnown_bits.bottom~sizeelsematchIval.project_intx.unsignedwith|x->Known_bits.singleton~sizex(* (x,x) *)|exceptionNot_Singleton_Int->beginmatchIval.min_max_r_modx.unsignedwith|exceptionFramac_ival.Abstract_interp.Error_Bottom->Lattices.Known_Bits.bottom~size|None,_,_,_|_,None,_,_->assertfalse|(Somemin,Somemax,r,modu)->begin(* (min,max) give an information about the common most significant bits. *)letfrom_min_max=(* Find the first bit that differs, and mask the lower bits. *)letxorminmax=Z.(lxor)minmaxinlethighest_bit=Z.log2xorminmaxinletmask=Z.sub(Z.(lsl)Z.one@@1+highest_bit)Z.onein(Z.(lor)minmask,Z.(land)min@@Z.(~!)mask)in(* Congruence gives an information about the least significant bits. *)letfrom_congruence=(* If modu is some n * 2^k *)letk=Z.trailing_zerosmoduinletmask=Z.sub(Z.(lsl)Z.onek)Z.onein(Z.(lor)r@@Z.(~!)mask,Z.(land)r@@mask)inLattices.Known_Bits.inter~sizefrom_min_maxfrom_congruenceendendletto_unsigned_interval~sizex=letmin,max=Ival.min_and_maxx.unsignedinOption.getmin,Option.getmaxletto_signed_interval~sizex=letmin,max=Ival.min_and_maxx.signedinOption.getmin,Option.getmaxletfold_crop_unsigned~sizex~inf~supaccf=Integer_Lattice.fold_cropx.unsigned~inf~supfaccend(* TODO: This should be used as little as possible; at least we
should give an argument when this is used, to say which
representation we need. *)letbinary_to_ival~signed~sizex=ifsignedthenx.signedelsex.unsigned;;(* On the part common to signed and unsigned representation (the
most common one), we narrow. *)letbinary_fold_crop~sizex~inf~supaccf=letacc=ifZ.ltinfZ.zerothenInteger_Lattice.fold_cropx.signed~inf~sup:Z.zerofaccelseaccinletbound=Z.shift_leftZ.one(predsize)inletmax_signed_int=Z.predboundinletival=Ival.inject_range(SomeZ.zero)(Somemax_signed_int)inletival=Ival.narrowivalx.signedinletival=Ival.narrowivalx.unsignedinletacc=Integer_Lattice.fold_cropival~inf~supfaccinletacc=Integer_Lattice.fold_cropx.unsigned~inf:bound~supfaccinacc;;moduleBitvector_Forward=struct(* MAYBE: try specializing for zero and one. *)letbiconst=Bitvector_Lattice.singletonletbeq~sizeab=Sva_quadrivalent.Boolean_Lattice.inter(Integer_Forward.ieqa.signedb.signed)(Integer_Forward.ieqa.unsignedb.unsigned)letbiule~sizeab=Integer_Forward.ilea.unsignedb.unsignedletbisle~sizeab=Integer_Forward.ilea.signedb.signedletbitimes~size~nsw~nuwkb=letsigned=Integer_Forward.itimeskb.signedinifb.signed==b.unsignedthenreduce~size{signed=wraps_or_narrow~nsw~sizesigned;unsigned=wrapu_or_narrow~nuw~sizesigned}elseletunsigned=Integer_Forward.itimeskb.unsignedinreduce~size{signed=wraps_or_narrow~nsw~sizesigned;unsigned=wrapu_or_narrow~nuw~sizeunsigned}letbiadd~size~flagsab=letOperator.Flags.Biadd.{nsw;nuw;nusw}=Operator.Flags.Biadd.unpackflagsinletsigned=Integer_Forward.iadda.signedb.signedinifa.signed==a.unsigned&&b.signed==b.unsignedthenreduce~size{signed=wraps_or_narrow~nsw~sizesigned;unsigned=wrapu_or_narrow~nuw~sizesigned}elseifnuswthen(assert(notnsw&¬nuw);letunsigned=Integer_Forward.iadda.unsignedb.signedinreduce~size{signed=wraps_or_narrow~nsw:false~sizesigned;unsigned=wrapu_or_narrow~nuw:true~sizeunsigned})elseletunsigned=Integer_Forward.iadda.unsignedb.unsignedinreduce~size{signed=wraps_or_narrow~nsw~sizesigned;unsigned=wrapu_or_narrow~nuw~sizeunsigned};;letbisub~size~flagsab=letOperator.Flags.Bisub.{nsw;nuw;nusw}=Operator.Flags.Bisub.unpackflagsinletsigned=Integer_Forward.isuba.signedb.signedinifa.signed==a.unsigned&&b.signed==b.unsignedthenreduce~size{signed=wraps_or_narrow~nsw~sizesigned;unsigned=wrapu_or_narrow~nuw~sizesigned}elseifnuswthen(assert(notnsw&¬nuw);letunsigned=Integer_Forward.isuba.unsignedb.signedinreduce~size{signed=wraps_or_narrow~nsw:false~sizesigned;unsigned=wrapu_or_narrow~nuw:true~sizeunsigned})elseletunsigned=Integer_Forward.isuba.unsignedb.unsignedinreduce~size{signed=wraps_or_narrow~nsw~sizesigned;unsigned=wrapu_or_narrow~nuw~sizeunsigned};;letbimul~size~flagsab=letOperator.Flags.Bimul.{nsw;nuw}=Operator.Flags.Bimul.unpackflagsinletsigned=Integer_Forward.imula.signedb.signedinifa.signed==a.unsigned&&b.signed==b.unsignedthenreduce~size{signed=wraps_or_narrow~nsw~sizesigned;unsigned=wrapu_or_narrow~nuw~sizesigned}elseletunsigned=Integer_Forward.imula.unsignedb.unsignedinreduce~size{signed=wraps_or_narrow~nsw~sizesigned;unsigned=wrapu_or_narrow~nuw~sizeunsigned};;letbimul_add~(size:In_bits.t)~prod~offseta=letprod_s=Z.signed_extractprod0(size:>int)inletoffset=Integer_Lattice.singletonoffsetinletsigned=Integer_Forward.iadd(Integer_Forward.itimesprod_sa.signed)offsetinifa.signed==a.unsigned&&Z.equalprodprod_sthenreduce~size{signed=wraps~sizesigned;unsigned=wrapu~sizesigned}elseletunsigned=Integer_Forward.iadd(Integer_Forward.itimesproda.unsigned)offsetinreduce~size{signed=wraps~sizesigned;unsigned=wrapu~sizeunsigned}letbxor~sizeab=letsigned=Integer_Forward.ixora.signedb.signedinletunsigned=Integer_Forward.ixora.unsignedb.unsignedin(* Ival does not respect this invariant. *)(* assert(wrapped_s ~size signed); *)letsigned=wraps~sizesignedin(* Nor this one. *)(* assert(wrapped_u ~size unsigned); *)letunsigned=wrapu~sizeunsignedinreduce~size{signed;unsigned}letband~sizeab=letsigned=Integer_Forward.ianda.signedb.signedinletunsigned=Integer_Forward.ianda.unsignedb.unsignedin(* Ival does not respect this invariant. *)(* assert(wrapped_s ~size signed); *)letsigned=wraps~sizesignedinassert(wrapped_u~sizeunsigned);reduce~size{signed;unsigned}letbor~sizeab=letsigned=Integer_Forward.iora.signedb.signedinletunsigned=Integer_Forward.iora.unsignedb.unsignedin(* Ival does not respect this invariant. *)(* assert(wrapped_s ~size signed); *)letsigned=wraps~sizesignedin(* Ival does not respect this invariant. *)letunsigned=wrapu~sizeunsignedin(* assert(wrapped_u ~size unsigned); *)reduce~size{signed;unsigned}letassume~size__=assertfalseletbsext~size~oldsizex=letsigned=x.signedinletunsigned=wrapu~sizesignedin{signed;unsigned}letbuext~size~oldsizex=letunsigned=x.unsignedinletsigned=wraps~sizeunsignedin{signed;unsigned}letbashr~sizexy=letorig_signed=Ival.shift_rightx.signedy.signedin(* Log.debug (fun p -> p "bashr %a %a res %a" Ival.pretty x.signed Ival.pretty y.signed Ival.pretty signed; *)(* assert(wrapped_s ~size orig_signed); *)(* Not verified by the implementation in Ival, even if we restrict y to be signed.*)letsigned=wraps~sizeorig_signedinletunsigned=wrapu~sizeorig_signedin{signed;unsigned};;letblshr~(size:In_bits.t)xy=(* when y may be bigger than size, Ival.shift_right returns top *)letmax=Ival.max_inty.unsignedinletmay_be_too_big=matchmaxwith|None->true|Somex->Z.geqx(Z.of_int(size:>int))inletshift=ifmay_be_too_bigthenletsmall=Ival.inject_range(SomeZ.zero)(Some(Z.of_int((size:>int)-1)))inIval.narrowy.unsignedsmallelsey.unsignedinletunsigned=Ival.shift_rightx.unsignedshiftinletunsigned=ifmay_be_too_bigthenIval.joinIval.zerounsignedelseunsignedin(* Log.debug (fun p -> p "blshr %a %a res %a" Ival.pretty x.unsigned Ival.pretty y.unsigned Ival.pretty unsigned; *)assert(wrapped_u~sizeunsigned);letsigned=wraps~sizeunsignedin{signed;unsigned};;letbshl~size~flagsxy=letOperator.Flags.Bshl.{nsw;nuw}=Operator.Flags.Bshl.unpackflagsinletunsigned=wrapu_or_narrow~nuw~size@@Ival.shift_leftx.unsignedy.unsignedinletsigned=wraps_or_narrow~nsw~size@@Ival.shift_leftx.signedy.signedinreduce~size{signed;unsigned};;letbconcat~size1~(size2:In_bits.t)ab=letunsigned=Ival.add_int(Ival.scale(Z.shift_leftZ.one(size2:>int))a.unsigned)b.unsignedinassert(wrapped_u~size:In_bits.(size1+size2)unsigned);letsigned=wraps~size:In_bits.(size1+size2)unsignedin{signed;unsigned;};;letbisdiv~sizeab=letsigned=Ival.diva.signedb.signedin(* assert(wrapped_s ~size signed); *)(* Should be true, but is not. *)letsigned=wraps~sizesignedinletunsigned=wrapu~sizesignedin{signed;unsigned}letbisdiv~(size:In_bits.t)ab=Log.trace(funp->p"bisdiv ~size:%d %a %a"(size:>int)(Bitvector_Lattice.pretty~size)a(Bitvector_Lattice.pretty~size)b)~pp_ret:(Bitvector_Lattice.pretty~size)@@fun()->bisdiv~sizeab;;letbiudiv~sizeab=letunsigned=Ival.diva.unsignedb.unsignedinassert(wrapped_u~sizeunsigned);letsigned=wraps~sizeunsignedin{signed;unsigned}letbismod~sizeab=letsigned=Ival.c_rema.signedb.signedinassert(wrapped_s~sizesigned);letunsigned=wrapu~sizesignedin{signed;unsigned}letbiumod~sizeab=letunsigned=Ival.c_rema.unsignedb.unsignedinassert(wrapped_u~sizeunsigned);letsigned=wraps~sizeunsignedin{signed;unsigned}letbextract~(size:In_bits.t)~(index:In_bits.t)~(oldsize:In_bits.t)x=ifsize==oldsizethenxelseifIn_bits.to_intindex==0then{signed=wraps~sizex.signed;unsigned=wrapu~sizex.unsigned}elseletstop=(Z.of_int@@(index:>int)+(size:>int)-1)inletoldsize=Z.of_int(oldsize:>int)inletstart=Z.of_int(index:>int)inifx.signed==x.unsignedthenletres=Ival.extract_bits~size:oldsize~start~stopx.signedinreduce~size{signed=wraps~sizeres;unsigned=wrapu~sizeres}elseletress=wraps~size@@Ival.extract_bits~size:oldsize~start~stopx.signedinletresu=wrapu~size@@Ival.extract_bits~size:oldsize~start~stopx.unsignedinreduce~size{signed=ress;unsigned=resu};;(* let bextract ~size ~index ~oldsize x =
* let r = bashr ~size:oldsize x (biconst ~size:oldsize @@ Z.of_int index) in
* band ~size:oldsize r (biconst ~size:oldsize @@ Z.pred @@ Z.shift_left Z.one size)
* ;; *)let_bextract~size~index~oldsizex=letres=bextract~size~index~oldsizexinLog.debug(funp->p"bextract %d %d %d %a res %a"(size:>int)(index:>int)(oldsize:>int)(Bitvector_Lattice.pretty~size:oldsize)x(Bitvector_Lattice.pretty~size)res);resletvalid~size_=assertfalseletvalid_ptr_arith~size_=assertfalseletbuninit~size=assertfalseletbaddr~size_=assertfalseletbshift~size~offset~max=assertfalseletbindex~size_=assertfalseletbofbool=letsize=In_bits.of_int1in(* For 1, the signed version of 1 is-1. For all others, it will be 1. *)letzero=biconst~sizeZ.zeroinletone1=biconst~sizeZ.oneinlettop1=Bitvector_Lattice.join~sizezeroone1in(* The representation is independent of the length, which is why this code is correct. *)letsize=In_bits.of_int2inletone_larger=biconst~sizeZ.oneinlettop_larger=Bitvector_Lattice.join~sizezeroone_largerinfun~(size:In_bits.t)x->if(size:>int)==1thenmatchxwith|Sva_quadrivalent.Bottom->Bitvector_Lattice.bottom~size|Sva_quadrivalent.Top->top1|Sva_quadrivalent.True->one1|Sva_quadrivalent.False->zeroelsematchxwith|Sva_quadrivalent.Bottom->Bitvector_Lattice.bottom~size|Sva_quadrivalent.Top->top_larger|Sva_quadrivalent.True->one_larger|Sva_quadrivalent.False->zeroendmoduleBitvector_Backward=structincludeSva_noop_transfer_functions.Bitvector_Backwardletival_inter_refines=inter_refinesletinter_refines~sizeoldnewer=letsigned=Ival.narrowold.signednewer.signedinassert(Ival.is_includedsignedold.signed);assert(Ival.is_includedsignednewer.signed);ifold.signed==old.unsigned&&newer.signed==newer.unsignedthenifIval.equalsignedold.signedthenNoneelseSome{signed;unsigned=signed}elseletunsigned=Ival.narrowold.unsignednewer.unsignedinassert(Ival.is_includedunsignedold.unsigned);assert(Ival.is_includedunsignednewer.unsigned);ifIval.equalsignedold.signed&&Ival.equalunsignedold.unsignedthenNoneelseSome(reduce~size{signed;unsigned});;letbisle~sizeabbool=(* Log.debug (fun p -> p "new bisle"; *)letgcomp1comp2=letsigneda=Ival.backward_comp_int_leftcomp1a.signedb.signedin(* Log.debug (fun p -> p "signeda %a" Ival.pretty signeda; *)letsignedb=Ival.backward_comp_int_leftcomp2b.signeda.signedinletfsignedxx=matchival_inter_refinesx.signedsignedxwith|None->None|Somey->Some(reduce~size{signed=y;unsigned=x.unsigned})infsignedaa,fsignedbbinmatchboolwith|B.True->gAbstract_interp.Comp.LeAbstract_interp.Comp.Ge|B.False->gAbstract_interp.Comp.GtAbstract_interp.Comp.Lt|B.Bottom->(ifBitvector_Lattice.is_bottom~sizeathenNoneelseSome(Bitvector_Lattice.bottom~size)),(ifBitvector_Lattice.is_bottom~sizebthenNoneelseSome(Bitvector_Lattice.bottom~size))|B.Top->None,None;;let_bisle~sizeabbool=letresa,resb=bisle~sizeabboolinLog.debug(funp->p"bisle %a %a %a res %a %a"(Bitvector_Lattice.pretty~size)a(Bitvector_Lattice.pretty~size)bSva_quadrivalent.Boolean_Lattice.prettybool(funfmt->function|None->Format.fprintffmt"None"|Somex->(Bitvector_Lattice.pretty~size)fmtx)resa(funfmt->function|None->Format.fprintffmt"None"|Somex->(Bitvector_Lattice.pretty~size)fmtx)resb);resa,resb;;letbiule~sizeabbool=letgcomp1comp2=letunsigneda=Ival.backward_comp_int_leftcomp1a.unsignedb.unsignedinletunsignedb=Ival.backward_comp_int_leftcomp2b.unsigneda.unsignedinletfunsignedxx=matchival_inter_refinesx.unsignedunsignedxwith|None->None|Somey->Some(reduce~size{unsigned=y;signed=x.signed})infunsignedaa,funsignedbbinmatchboolwith|B.True->gAbstract_interp.Comp.LeAbstract_interp.Comp.Ge|B.False->gAbstract_interp.Comp.GtAbstract_interp.Comp.Lt|B.Bottom->(ifBitvector_Lattice.is_bottom~sizeathenNoneelseSome(Bitvector_Lattice.bottom~size)),(ifBitvector_Lattice.is_bottom~sizebthenNoneelseSome(Bitvector_Lattice.bottom~size))|B.Top->None,None;;let_biule~sizeabres=letnewa,newb=biule~sizeabresinLog.debug(funp->p"biule size %d a %a b %a res %a new_a %a new_b %a"(size:>int)(Bitvector_Lattice.pretty~size)a(Bitvector_Lattice.pretty~size)b(Quadrivalent_Lattice.pretty)res(pp_opt@@Bitvector_Lattice.pretty~size)newa(pp_opt@@Bitvector_Lattice.pretty~size)newb);newa,newb;;letbeq~sizeabres=matchreswith|B.True->inter_refines~sizeab,inter_refines~sizeba|B.False->inter_refines~sizea@@{signed=Ival.diff_if_onea.signedb.signed;unsigned=Ival.diff_if_onea.unsignedb.unsigned},inter_refines~sizeb@@{signed=Ival.diff_if_oneb.signeda.signed;unsigned=Ival.diff_if_oneb.unsigneda.unsigned}|B.Bottom->inter_refines~sizea@@Bitvector_Lattice.bottom~size,inter_refines~sizeb@@Bitvector_Lattice.bottom~size|B.Top->None,None;;letbiadd~size~flagsabres=inter_refines~sizea(Bitvector_Forward.bisub~flags~sizeresb),inter_refines~sizeb(Bitvector_Forward.bisub~flags~sizeresa);;letzero_in_bits=In_bits.of_int0letbiadd~(size:In_bits.t)~flagsabres=letOperator.Flags.Biadd.{nsw;nuw;nusw}=Operator.Flags.Biadd.unpackflagsinifnuswthen(assert(notnsw&¬nuw);letaext=Bitvector_Forward.buext~size:In_bits.(doublesize)~oldsize:sizeainletresext=Bitvector_Forward.buext~size:In_bits.(doublesize)~oldsize:sizeresinletbext=Bitvector_Forward.bisub~size:In_bits.(doublesize)~flags:(Operator.Flags.Bisub.pack~nsw:false~nuw:false~nusw:false)resextaextinletnewb=Bitvector_Forward.bextract~size~index:zero_in_bits~oldsize:(In_bits.doublesize)bextininter_refines~sizea(Bitvector_Forward.bisub~flags~sizeresb),inter_refines~sizebnewb)elsebiadd~size~flagsabreslet_biadd~size~flagsabres=letra,rb=biadd~size~flagsabresinLog.debug(funp->p"Backward biadd %a %a %a res %a %a"(Bitvector_Lattice.pretty~size)a(Bitvector_Lattice.pretty~size)b(Bitvector_Lattice.pretty~size)res(funfmt->function|None->Format.fprintffmt"None"|Somex->(Bitvector_Lattice.pretty~size)fmtx)ra(funfmt->function|None->Format.fprintffmt"None"|Somex->(Bitvector_Lattice.pretty~size)fmtx)rb);ra,rbletbisub~size~flagsabres=inter_refines~sizea(Bitvector_Forward.biadd~flags~sizeresb),inter_refines~sizeb(Bitvector_Forward.bisub~flags~sizeares);;letbisub~size~flagsabres=letOperator.Flags.Bisub.{nsw;nuw;nusw}=Operator.Flags.Bisub.unpackflagsinifnuswthen(assert(notnsw&¬nuw);letaext=Bitvector_Forward.buext~size:(In_bits.doublesize)~oldsize:sizeainletresext=Bitvector_Forward.buext~size:(In_bits.doublesize)~oldsize:sizeresinletbext=Bitvector_Forward.bisub~size:(In_bits.doublesize)~flags:(Operator.Flags.Bisub.pack~nsw:false~nuw:false~nusw:false)aextresextinletnewb=Bitvector_Forward.bextract~size~index:zero_in_bits~oldsize:(In_bits.doublesize)bextininter_refines~sizea(Bitvector_Forward.biadd~flags~sizeresb),inter_refines~sizebnewb)elsebisub~size~flagsabresletbsext~size~oldsizeares=matchival_inter_refinesa.signedres.signedwith|None->None|Somesigned->Some(reduce~size:oldsize{signed;unsigned=a.unsigned})letbuext~size~oldsizeares=matchival_inter_refinesa.unsignedres.unsignedwith|None->None|Someunsigned->Some(reduce~size:oldsize{unsigned;signed=a.signed})(* We assume that we are reduced. *)letbofbool~sizeares=letrev=ifIval.is_bottomres.unsignedthenQuadrivalent_Lattice.BottomelsematchIval.project_intres.unsignedwith|exceptionIval.Not_Singleton_Int->Quadrivalent_Lattice.Top|xwhenZ.equalxZ.zero->Quadrivalent_Lattice.False|xwhenZ.equalxZ.one->Quadrivalent_Lattice.True|_->Quadrivalent_Lattice.BottominSva_quadrivalent.refine~older:a~newer:rev;;let_buext~(size:In_bits.t)~oldsizeares=letnewa=buext~size~oldsizearesinLog.debug(funp->p"buext size %d oldsize %d a %a res %a new_a %a"(size:>int)(oldsize:>int)(Bitvector_Lattice.pretty~size)a(Bitvector_Lattice.pretty~size)res(pp_opt@@Bitvector_Lattice.pretty~size)newa);newa;;(* There are too many references to this one. *)letbextract_once=reftrue;;letbextract~size~index~oldsizexres=if!bextract_oncethenbeginbextract_once:=false;Log.warning(funp->p"No backpropagation for 'bextract'")end;None;;let_bextract~size~index~oldsizexres=(* Special case: bextract is a no-op operation because the most
significant bits are already zero. *)ifindex==0&&wrapped_u~sizex.unsigned&&wrapped_s~sizex.signedtheninter_refines~size:oldsizexreselsebeginif!bextract_oncethenbeginbextract_once:=false;Log.warning(funp->p"No backpropagation for 'bextract'")end;Noneend;;letbconcat~size1~size2abres=letoldsize=In_bits.(size1+size2)inletnewb=Bitvector_Forward.bextract~oldsize~size:size2~index:zero_in_bitsresinletnewa=Bitvector_Forward.bextract~oldsize~size:size1~index:size2resininter_refines~size:size1anewa,inter_refines~size:size2bnewb;;(** [bitimes] refines [a] by inverting a multiplication by constant [k].
- For [k = 0]: if [res] does not contain zero, [a] is refined to bottom; otherwise, no change.
- For nonzero [k]: computes [Some refined_a] if refinement is possible, or no change.
*)letbitimes~size~nsw~nuwkares=letnsw=nsw||wrapped_s~size@@Ival.scaleka.signedinletnuw=nuw||wrapped_u~size@@Ival.scaleka.unsignedinifnot(nsw||nuw)thenNoneelseifZ.equalkZ.zerothenif(Ival.contains_zerores.signed)&&(Ival.contains_zerores.unsigned)thenNoneelseif(Ival.is_bottoma.signed)thenNoneelseSome(Bitvector_Lattice.bottom~size)else(letsigned=ifnswthenIval.scale_div~pos:falsekres.signedelsea.signedinletunsigned=ifnuwthenIval.scale_div~pos:falsekres.unsignedelsea.unsignedininter_refines~sizea{signed;unsigned});;letbimul~size~flagsabres=letOperator.Flags.Bimul.{nsw;nuw}=Operator.Flags.Bimul.unpackflagsin(* Bitimes is faster (which shows on the benchmarks) and more
precise when it applies. *)ifBitvector_Lattice.is_bottom~sizeresthenNone,NoneelseifIval.is_singleton_inta.signedthenNone,bitimes~size~nsw~nuw(Ival.project_inta.signed)breselseifIval.is_singleton_intb.signedthenbitimes~size~nsw~nuw(Ival.project_intb.signed)ares,Noneelse(* backward_mult_int_left cannot be called when wrapping.
Note: meaning that the abstract computation has not wrapped, independently
of the passed ~nsw and ~nuw flags. *)letnsw=(* nsw || *)wrapped_s~size@@Ival.mula.signedb.signedinletnuw=(* nuw || *)wrapped_u~size@@Ival.mula.signedb.signedinifnot(nsw||nuw)thenNone,Noneelseletconvert=function`Bottom->SomeIval.bottom|`Valuex->xinletasigned,bsigned=ifnswthenletasigned=convert@@Ival.backward_mult_int_left~right:b.signed~result:res.signedinletbsigned=convert@@Ival.backward_mult_int_left~right:a.signed~result:res.signedin(* Log.debug (fun p -> p "a.signed %a res.signed %a asigned
%a bsigned %a" Ival.pretty a.signed Ival.pretty
res.signed (pp_opt Ival.pretty) asigned (pp_opt
Ival.pretty) bsigned; *)asigned,bsignedelseNone,Noneinletaunsigned,bunsigned=ifnuwthenletaunsigned=convert@@Ival.backward_mult_int_left~right:b.unsigned~result:res.unsignedinletbunsigned=convert@@Ival.backward_mult_int_left~right:a.unsigned~result:res.unsignedin(* Log.debug (fun p -> p "aunsigned %a bsunigned %a" (pp_opt Ival.pretty) aunsigned (pp_opt Ival.pretty) bunsigned; *)aunsigned,bunsignedelseNone,Noneinletfxxsignedxunsigned=matchxsigned,xunsignedwith|None,None->None|Somesigned,None->inter_refines~sizex@@(* reduce ~size *){signed;unsigned=x.unsigned}|None,Someunsigned->inter_refines~sizex@@(* reduce ~size *){signed=x.signed;unsigned}|Somesigned,Someunsigned->inter_refines~sizex@@(* reduce ~size *){signed;unsigned}infaasignedaunsigned,fbbsignedbunsigned;;let_bimul~size~flagsabres=letra,rb=bimul~size~flagsabresinLog.debug(funp->p"Backward imul %a %a %a res %a %a"(Bitvector_Lattice.pretty~size)a(Bitvector_Lattice.pretty~size)b(Bitvector_Lattice.pretty~size)res(funfmt->function|None->Format.fprintffmt"None"|Somex->(Bitvector_Lattice.pretty~size)fmtx)ra(funfmt->function|None->Format.fprintffmt"None"|Somex->(Bitvector_Lattice.pretty~size)fmtx)rb);ra,rbletbimul_add~(size:In_bits.t)~prod~offsetares=letprod_s=Z.signed_extractprod0(size:>int)inlet(let*)=Option.bindinifBitvector_Lattice.is_bottom~sizeresthenNoneelseletoffset=Integer_Lattice.singletonoffsetinletsigned=letintermediate=Integer_Forward.itimesprod_sa.signedinletintermediate2=Integer_Forward.iaddintermediateoffsetinlet*intermediate2=backward_wraps~sizeintermediate2res.signedinlet*intermediate=Integer_Backward.iaddintermediateoffsetintermediate2|>fstinInteger_Backward.itimesprod_sa.signedintermediateinletunsigned=letintermediate=Integer_Forward.itimesproda.unsignedinletintermediate2=Integer_Forward.iaddintermediateoffsetinlet*intermediate2=backward_wrapu~sizeintermediate2res.unsignedinlet*intermediate=Integer_Backward.iaddintermediateoffsetintermediate2|>fstinInteger_Backward.itimesproda.unsignedintermediateinlet*new_a=matchsigned,unsignedwith|None,None->None|Somesigned,Someunsigned->Some(reduce~size{signed=wraps~sizesigned;unsigned=wrapu~sizeunsigned})|Somesigned,None->Some(reduce~size{awithsigned=wraps~sizesigned})|None,Someunsigned->Some(reduce~size{awithunsigned=wrapu~sizeunsigned})ininter_refines~sizeanew_aletbismod~sizeabres=letnewa,newb=Integer_Backward.imoda.signedb.signedres.signedinletnewa=matchnewawith|None->None|Somesigned->Some(reduce~size{signed;unsigned=a.unsigned})inletnewb=matchnewbwith|None->None|Somesigned->Some(reduce~size{signed;unsigned=b.unsigned})innewa,newbletbisdiv~sizeabres=ifBitvector_Lattice.is_bottom~sizeresthenNone,NoneelseifIval.is_singleton_intb.signedtheninter_refines~sizea(Bitvector_Forward.bitimes~nuw:false~nsw:false~size(Ival.project_intb.signed)a),Noneelsebisdiv~sizeabreslet_bismod~sizeabres=letnewa,newb=bismod~sizeabresinLog.debug(funp->p"bismod size %d a %a b %a res %a new_a %a new_b %a"(size:>int)(Bitvector_Lattice.pretty~size)a(Bitvector_Lattice.pretty~size)b(Bitvector_Lattice.pretty~size)res(pp_opt@@Bitvector_Lattice.pretty~size)newa(pp_opt@@Bitvector_Lattice.pretty~size)newb);newa,newbletbiumod~sizeabres=letnewa,newb=Integer_Backward.imoda.unsignedb.unsignedres.unsignedinletnewa=matchnewawith|None->None|Someunsigned->Some(reduce~size{unsigned;signed=a.signed})inletnewb=matchnewbwith|None->None|Someunsigned->Some(reduce~size{unsigned;signed=b.signed})innewa,newb;;letband~sizeabres=letbnota=Bitvector_Forward.bxor~size(Bitvector_Lattice.singleton~sizeZ.minus_one)ainletrefine_a_from_bab=(* For each bit, if a & _ = 1 then a = 1. [a1] is [a] with all such bits at 1
(for the others, res = 0 and this bitwise_or has no effect on a). *)leta1=Bitvector_Forward.bor~sizeresain(* For each bit, if a & 1 = 0 then a = 0. [a2] is [a] with all such bits at 0
(for the others, (not b or res) = 1 and this bitwise_and has no effect on a). *)(* This could work too. MAYBE: use both? *)(* let a2 = Bitvector_Forward.band ~size a (bnot (Bitvector_Forward.bxor ~size res b)) in *)leta2=Bitvector_Forward.band~sizea@@Bitvector_Forward.bor~size(bnotb)resinleta'=Bitvector_Lattice.inter~sizea1a2ininter_refines~sizeaa'inrefine_a_from_bab,refine_a_from_bbaletbor~sizeabres=letbnota=Bitvector_Forward.bxor~size(Bitvector_Lattice.singleton~sizeZ.minus_one)ainletrefine_a_from_bab=(* For each bit, if a | _ = 0 then a = 0. [a1] is [a] with all such bits at 0
(for the others, res = 1 and this bitwise_and has no effect on a). *)leta1=Bitvector_Forward.band~sizeresain(* For each bit, if a | 0 = 1 then a = 1. [a2] is [a] with all such bits at 1
(for the others, (not b and res) = 0 and this bitwise_or has no effect on a). *)(* This could work too. MAYBE: use both? *)(* let a2 = Bitvector_Forward.bor ~size a (Bitvector_Forward.bxor ~size res b) in *)leta2=Bitvector_Forward.bor~sizea@@Bitvector_Forward.band~size(bnotb)resinleta'=Bitvector_Lattice.inter~sizea1a2ininter_refines~sizeaa'inrefine_a_from_bab,refine_a_from_bbaendendincludeBothWrapletconvert_to_ivalx=xletis_singleton_intx=trySome(Ival.project_intx)withIval.Not_Singleton_Int->NonemoduleInteger:Datatype_sig.Swithtypet=Ival.t=IvalincludeSva_quadrivalent