123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709(**************************************************************************)(* 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). *)(* *)(**************************************************************************)moduleIn_bits=Units.In_bits(* One issue with my tests is that whenever I get through the memory,
it does not work. So, the bitwise domain should be beneath
memory_domain, but above the pointers.
This raises the questions: why these operable values are not true
domains?
Answer: they should. Region separation should just be 2 functor
domains, one for the binary, one for the memory.
Or at least, memory_domain should be split into two domains, two
allow intermediate domains like this one. *)letpretty_detailed=truemoduleQuadrivalent=Lattices.QuadrivalentmoduleMake(Sub:Sig.BASE)=structletname()="Bitwise("^(Sub.name())^")";;letunique_id()=Sig.Fresh_id.fresh@@name();;(** To represent values, we could use an array where each bit would
be a bit in another variable, but this would be slow for most
operation. So, we use a list of "parts" that group these bits,
and the information is complemented with the known 0 bits and
known 1 bits informat that we query from Sub. *)typebinary_part={size:In_bits.t;index:In_bits.t;oldsize:In_bits.t;value:Sub.binary}(* We call this extract even when there is no extraction, in which case index == 0 and size == oldsize. *)modulePart=structletprettyctxfmt{size;index;oldsize;value}=ifindex==In_bits.zero&&size==oldsizethenFormat.fprintffmt"(%a)<%d>"(Sub.binary_pretty~sizectx)value(size:>int)elseFormat.fprintffmt"(%a)[%d..+%d]"(Sub.binary_pretty~sizectx)value(index:>int)(size:>int)letzeroctx~size={size;index=In_bits.zero;oldsize=size;value=Sub.Binary_Forward.biconst~sizeZ.zeroctx}letonesctx~size={size;index=In_bits.zero;oldsize=size;value=Sub.Binary_Forward.biconst~size(Z.extractZ.minus_one0(size:>int))ctx}letdo_extractctx{size;index;oldsize;value}=ifsize=oldsizethenvalueelseSub.Binary_Forward.bextract~size~index~oldsizectxvalueletto_singletonctx{size;index;oldsize;value}=letbin=Sub.Binary_Forward.bextract~size~index~oldsizectxvalueinSub.Query.binary~sizectxbin|>Sub.Query.Binary_Lattice.is_singleton~sizeletfrom_value~sizevalue={size;index=In_bits.zero;oldsize=size;value}endmoduleParts=struct(* A binary is represented as a list where head is the least significant binary_part
(this allows for efficient additions, etc). *)typet=binary_partlist;;(* Remove the first ~index bits from the start. *)letcut_start~indexp=(* Invariant: i <= index. *)letrecloopi=function|[]->assertfalse(* Index is larger than the size. *)|{size;_}::restwhenIn_bits.(i+size<=index)->loopIn_bits.(i+size)rest|{size=sizee;index=indexe;oldsize;value}::restasl->ifi==indexthenlelseletremoved_size=In_bits.(index-i)in{size=In_bits.(sizee-removed_size);index=In_bits.(indexe+removed_size);oldsize;value}::restinloopIn_bits.zerop;;(* Cut the part so that its size becomes size, which must be smaller than the original size. *)letcut_end~sizep=letrecloopi=function(* | [] when i == size -> [] *)|[]->assertfalse(* The parts is too small, cannot cut. *)|hd::tlwhenIn_bits.(i+hd.size<size)->hd::(loopIn_bits.(i+hd.size)tl)|hd::_whenIn_bits.(i+hd.size)=size->[hd]|{size=sizee;index;oldsize;value}::_->letremoved_size=In_bits.(i+sizee-size)in[{size=In_bits.(sizee-removed_size);index;oldsize;value}]inloopIn_bits.zerop;;letextract~index~size~oldsizep=(* cut the first bits up to index. *)letp=ifindex==In_bits.zerothenpelsecut_start~indexpin(* cut the size firts bits of p. *)letp=ifIn_bits.(index+size)==oldsizethenpelsecut_end~sizepinp;;letappendab=List.appendab;;letappendctxab=matchbwith|[]->assertfalse|hdb::tlb->beginletrecloop=function|[]->b|[lasta]->begin(*Codex_log.feedback "lasta = %a" (Part.pretty ctx) lasta;
Codex_log.feedback "hdb = %a" (Part.pretty ctx) hdb;*)(*let b1 = lasta'.index + lasta'.size == hdb'.index in
let b2 = Sub.Binary.equal lasta'.value hdb'.value in
Codex_log.feedback "b1 = %B" b1;
Codex_log.feedback "b2 = %B" b2;*)matchlasta,hdbwith|{size=sizea;index=indexa;oldsize=oldsizea;value=valuea},{size=sizeb;index=indexb;oldsize=oldsizeb;value=valueb}whenIn_bits.(indexa+sizea==indexb)&&Sub.Binary.equalvalueavalueb->(* Stitch together contiguous extractions. *)assert(oldsizea==oldsizeb);{size=In_bits.(sizea+sizeb);index=indexa;oldsize=oldsizea;value=valuea}::tlb|{size=sizea;_},{size=sizeb;_}->beginmatchPart.to_singletonctxlasta,Part.to_singletonctxhdbwith|Somecsta,Somecstb->letsize=In_bits.(sizea+sizeb)inletzvalue=Operator.Concrete.Bitvector_Interp.bconcat~size1:sizeb~size2:sizeacstbcstainletvalue=Sub.Binary_Forward.biconst~sizezvaluectxin(Part.from_value~sizevalue)::tlb|_->lasta::hdb::tlbendend|hd::tl->hd::(looptl)inloopaend;;(* Preprend (i.e. put in least significant positions) size bits of value 0. *)letprepend_zero~sizectxp=appendctx[(Part.zero~sizectx)]p;;(* Append (i.e. put in most significant positions) size bits of value 0. *)letappend_zero~sizectxp=appendctxp[(Part.zero~sizectx)];;letchop_lastl=letrecloopacc=function|[]->assertfalse|[x]->List.revacc,x|hd::tl->loop(hd::acc)tlinloop[]l(* Append (i.e. put in most significant positions) size times the most
* significant bit. If the most significant bit is unknown, use the
* subdomain to extend the last part. *)letsigned_extend~size~oldsizectxp=letbeginning,{size=s_last;value;_}=chop_lastpinletzeroes,ones=Sub.Query.(binary~size:s_lastctxvalue|>Binary_Lattice.to_known_bits~size:s_last)inifnot(Z.testbitzeroes((s_last:>int)-1))thenappend_zero~size:In_bits.(size-oldsize)ctxpelseifZ.testbitones((s_last:>int)-1)thenappendctxp[Part.ones~size:In_bits.(size-oldsize)ctx]elselets=In_bits.(size-oldsize+s_last)inappendctxbeginning[Part.from_value~size:s(Sub.Binary_Forward.bsext~size:s~oldsize:s_lastctxvalue)]letfold2ctxfaccpapb=letrecloopaccpapb=matchpa,pbwith|[],[]->acc|[],_|_,[]->acc(* assert false *)(* Different lengths. *)|({size=sizea;index=indexa;oldsize=oldsizea;value=valuea}aspa)::tla,({size=sizeb;index=indexb;oldsize=oldsizeb;value=valueb}aspb)::tlb->(*Codex_log.feedback "fold2 sizea:%d sizeb:%d oldsizea:%d oldsizeb:%d" sizea sizeb oldsizea oldsizeb;*)if(sizea==sizeb)thenletacc=f~size:sizeaaccpapbinloopacctlatlbelseif(sizea<sizeb)thenletbb={size=sizea;index=indexb;oldsize=oldsizeb;value=valueb}inletacc=f~size:sizeaaccpabbinloopacctla({size=In_bits.(sizeb-sizea);index=In_bits.(indexb+sizea);oldsize=oldsizeb;value=valueb}::tlb)elseletba={size=sizeb;index=indexa;oldsize=oldsizea;value=valuea}inletacc=f~size:sizebaccbapbinloopacc({size=In_bits.(sizea-sizeb);index=In_bits.(indexa+sizeb);oldsize=oldsizea;value=valuea}::tla)tlbinloopaccpapbtypebits=|ZeroesofIn_bits.t(** size. *)|OnesofIn_bits.t(** size. *)|Unknownofbinary_partletpretty_bitsctxfmt=letopenFormatinfunction|Zeroess->fprintffmt"00..0<%d>"(s:>int)|Oness->fprintffmt"11..1<%d>"(s:>int)|Unknownp->Part.prettyctxfmtpletdecompose_using_known_bits~sizectxpart=let{size;index;oldsize;value}=partinletsub=Part.do_extractctxpartin(* Identify groups of known bits *)letzeroes,ones=Sub.Query.Binary_Lattice.to_known_bits~size@@Sub.Query.binary~sizectxsubinletrecloopacccur(i:int)=ifi>=(size:>int)thenList.rev(cur::acc)elsematchZ.testbitzeroesi,Z.testbitonesi,curwith|false,true,_->raiseSig.Bottom|false,_,Zeroess->loopacc(ZeroesIn_bits.(s+one))(i+1)|false,_,_->loop(cur::acc)(ZeroesIn_bits.one)(i+1)|_,true,Oness->loopacc(OnesIn_bits.(s+one))(i+1)|_,true,_->loop(cur::acc)(OnesIn_bits.one)(i+1)|true,false,Unknowne->loopacc(Unknown{ewithsize=In_bits.(e.size+one)})(i+1)|true,false,_->loop(cur::acc)(Unknown{size=In_bits.one;index=In_bits.(index+of_inti);oldsize;value})(i+1)inloop[](ifnot(Z.testbitzeroes0)thenZeroesIn_bits.oneelseifZ.testbitones0thenOnesIn_bits.oneelseUnknown{size=In_bits.one;index;oldsize;value})1letfold2_bitsctxfaccpapb=letsplitsize_fst=function|Zeroessize->Zeroessize_fst,ZeroesIn_bits.(size-size_fst)|Onessize->Onessize_fst,OnesIn_bits.(size-size_fst)|Unknown{size;index;oldsize;value}->Unknown{size=size_fst;index;oldsize;value},Unknown{size=In_bits.(size-size_fst);index=In_bits.(index+size_fst);oldsize;value}inletrecloopaccpapb=matchpa,pbwith|[],[]->acc|[],_|_,[]->assertfalse(* Should not happen (invariant of this function) *)|((Unknown{size=sizea;_}|Zeroessizea|Onessizea)aspa)::tla,((Unknown{size=sizeb;_}|Zeroessizeb|Onessizeb)aspb)::tlb->ifsizea=sizebthenletacc=fctx~size:sizeaaccpapbinloopacctlatlbelseifsizea<sizebthenletfst_pb,rest_pb=splitsizeapbinletacc=fctx~size:sizeaaccpafst_pbinloopacctla(rest_pb::tlb)elseletfst_pa,rest_pa=splitsizebpainletacc=fctx~size:sizebaccfst_papbinloopacc(rest_pa::tla)tlbinloopaccpapb(* Note: can raise Bottom if it discovers bottom. *)letfold2_known_bitsctxfaccpapb=fold2ctx(fun~sizeaccpapb->letbitsa=decompose_using_known_bits~sizectxpainletbitsb=decompose_using_known_bits~sizectxpbinfold2_bitsctxfaccbitsabitsb)accpapbendtypebinary_={complete:Sub.binary;parts:Parts.t}moduleBinary=structtypet=binary_;;(* We could check for equality of the parts too. *)letequalxy=Sub.Binary.equalx.completey.completeletcomparexy=Sub.Binary.comparex.completey.completelethash_=assertfalseletprettyppx=Sub.Binary.prettyppx.complete(* Lift a constant. *)letlift0~sizex={complete=x;parts=[{size;oldsize=size;index=In_bits.zero;value=x}]}(* Lifts a (bitwise) function over binaries. *)letlift1~sizefx={complete=f~sizex.complete;parts=List.map(function|x->{xwithvalue=f~size:x.oldsizex.value}(* | Repeat{repeat;value} -> Repeat{repeat;value=f ~size:1 value} *))x.parts}(* Lift a (non-necessarily bitwise) binary operator. *)letlift2~sizectxfxy=(* If an operand consists in a single part, use it, as it should usually
* (always?) be more precise than x.complete. *)letx=matchx.partswith|[p]->Part.do_extractctxp|_->x.completeinlety=matchy.partswith|[p]->Part.do_extractctxp|_->y.completeinf~sizectxxy(* TODO: improve this. *)letlift2_pred~sizectxfxy=letwith_parts=lift2~sizectxfxyinmatchSub.query_booleanctxwith_partswith|Quadrivalent.True|Quadrivalent.False|Quadrivalent.Bottom->with_parts|_->f~sizectxx.completey.complete;;endmoduleTypes=structtypebinary=Binary.ttypeenum=Sub.enumtypeboolean=Sub.booleanendincludeTypesmoduleBoolean=Sub.BooleanmoduleEnum=Sub.EnummoduleContext=Sub.ContextopenContextletroot_context=Sub.root_contextletcontext_pretty=Sub.context_pretty(* include Operator.Builtin.Make(Types)(Context) *)letmu_context_open=Sub.mu_context_openletassume=Sub.assumeletbinary_empty~sizectx={parts=[];complete=Sub.binary_empty~sizectx}letboolean_empty=Sub.boolean_emptyletenum_empty=Sub.enum_emptymoduleBoolean_Forward=Sub.Boolean_ForwardmoduleEnum_Forward=Sub.Enum_Forward(* let [@inline always] ar0 ~size f = fun ctx ->
* Binary.of_sub ~size @@ f ctx
* let [@inline always] ar1 ~size f = fun ctx a ->
* Binary.of_sub ~size @@ f ctx @@ Binary.to_sub ~size ctx a
* let [@inline always] ar2 ~size f = fun ctx a b ->
* Binary.of_sub ~size @@ f ctx
* (Binary.to_sub ~size ctx a) (Binary.to_sub ~size ctx b)
* let [@inline always] pred2 ~size f = fun ctx a b ->
* f ctx (Binary.to_sub ~size ctx a) (Binary.to_sub ~size ctx b)
* let [@inline always] ar3 f = fun ctx a b c -> match a,b,c with
* | Some a, Some b, Some c -> Some (f ctx a b c)
* | _ -> None
*
* let to_ival ~signed ~size ctx x =
* Binary.to_sub ~size ctx x |> Sub.Query.binary ~size ctx
* |> Sub.Query.binary_to_ival ~signed ~size
*
* let to_integer ~signed ~size ctx x =
* to_ival ~signed ~size ctx x |> Framac_ival.Ival.project_int *)letbinary_pretty~sizectxfmt(x:binary)=(* match List.rev x.parts with
| [] -> assert false
| hd::tl ->
Sub.binary_pretty ~size ctx fmt x.complete;
(*
Format.pp_print_string fmt "(= [";
Part.pretty ctx fmt hd;
List.iter (fun p -> Format.fprintf fmt "::%a" (Part.pretty ctx) p) tl;
Format.pp_print_string fmt "])";
*)
*)Sub.binary_pretty~sizectxfmtx.completemoduleBinary_Forward=structmoduleSBF=Sub.Binary_Forward;;letbofbool~sizectxb=SBF.bofbool~sizectxb|>Binary.lift0~sizeletbchoose~sizechoicectxx=SBF.bchoose~sizechoicectxx.complete|>Binary.lift0~sizeletvalid~size_=assertfalse(* let valid_ptr_arith ~size _ = assert false
* let bunknown ~size _ = assert false
* let baddr ~size _ = assert false
* let biconst ~size _ = assert false
* let buninit ~size _ = assert false *)letbindex~size_=assertfalseletvalid_ptr_arith~sizearithctxab=Sub.Binary_Forward.valid_ptr_arith~sizearithctxa.completeb.completeletbiconst~sizectxk=Binary.lift0~size@@SBF.biconst~sizectxk;;letbuninit~sizectx=Binary.lift0~size@@SBF.buninit~sizectx;;letbisle~sizectxab=Binary.lift2_pred~sizectxSBF.bisleabletbiule~sizectxab=Binary.lift2_pred~sizectxSBF.biuleabletbisub~size~flagsctxab=Binary.lift0~size@@SBF.bisub~size~flagsctxa.completeb.completeletbimul~size~flagsctxab=Binary.lift0~size@@SBF.bimul~size~flagsctxa.completeb.completeletbisdiv~sizectxab=Binary.lift0~size@@SBF.bisdiv~sizectxa.completeb.completeletbiudiv~sizectxab=Binary.lift0~size@@SBF.biudiv~sizectxa.completeb.completeletbismod~sizectxab=Binary.lift0~size@@SBF.bismod~sizectxa.completeb.completeletbiumod~sizectxab=Binary.lift0~size@@SBF.biumod~sizectxa.completeb.completeletbconcat~size1~size2ctxb1b2=(*Codex_log.feedback "@[<v 2>BW.bconcat ~size1:%d ~size2:%d@.%a@.%a@]" size1 size2 (binary_pretty ~size:size1 ctx) b1 (binary_pretty ~size:size2 ctx) b2;*)letcomplete=SBF.bconcat~size1~size2ctxb1.completeb2.completein(* Order of arguments reversed, since b1 should become the most
* significant part. *)letparts=Parts.appendctxb2.partsb1.partsinletres={complete;parts;}in(*Codex_log.feedback "result = %a" (binary_pretty ~size:(size1+size2) ctx) res;*)resletbuext~size~oldsizectxx={complete=SBF.buext~size~oldsizectxx.complete;(* parts = Parts.append x.parts [Part.zero ~size:(size-oldsize) ctx]; *)parts=Parts.append_zero~size:In_bits.(size-oldsize)ctxx.parts;};;letbsext~size~oldsizectxx={complete=SBF.bsext~size~oldsizectxx.complete;parts=Parts.signed_extend~size~oldsizectxx.parts}letbextract~size~index~oldsizectxx=(*Codex_log.feedback "bextract ~size:%d ~index:%d ~oldsize:%d %a" size index oldsize (binary_pretty ~size:oldsize ctx) x;*)letres={parts=Parts.extract~index~size~oldsizex.parts;complete=SBF.bextract~size~index~oldsizectxx.complete}in(*Codex_log.feedback "result = %a" (binary_pretty ~size:oldsize ctx) res;*)resletbshl~size~flagsctxxy=letcomplete=SBF.bshl~size~flagsctxx.completey.completeinmatchSub.Query.Binary_Lattice.is_singleton~size@@Sub.Query.binary~sizectxy.completewith|None->Binary.lift0~sizecomplete|Somey->letparts=Parts.prepend_zero~size:In_bits.(of_int@@Z.to_inty)ctxx.partsinletparts=Parts.cut_end~sizepartsin{complete;parts};;letblshr~sizectxxy=letcomplete=SBF.blshr~sizectxx.completey.completeinmatchSub.Query.Binary_Lattice.is_singleton~size@@Sub.Query.binary~sizectxy.completewith|None->Binary.lift0~sizecomplete|Somey->letyi=Z.to_inty|>In_bits.of_intinassertIn_bits.(zero<=yi);ifyi==In_bits.zerothenxelseletparts=Parts.append_zero~size:yictxx.partsinletparts=Parts.cut_start~index:yipartsin{complete;parts}letbashr~sizectxxy=letcomplete=SBF.bashr~sizectxx.completey.completeinmatchSub.Query.(Binary_Lattice.is_singleton~size@@binary~sizectxy.complete)with|None->Binary.lift0~sizecomplete|Somey->letyi=Z.to_inty|>In_bits.of_intinletbeginning,{size=s_last;value;_}=Parts.chop_lastx.partsinletzeroes,ones=Sub.Query.(Binary_Lattice.to_known_bits~size:s_last@@binary~size:s_lastctxvalue)inletparts=ifnot(Z.testbitzeroes((s_last:>int)-1))thenletparts=Parts.append_zero~size:yictxx.partsinParts.cut_start~index:yipartselseifZ.testbitones((s_last:>int)-1)thenletparts=Parts.appendctxx.parts[Part.onesctx~size:yi]inParts.cut_start~index:yipartselseletnew_sz_last=In_bits.(s_last+yi)inletto_append=SBF.bsext~size:new_sz_last~oldsize:s_lastctxvalueinletparts=Parts.appendctxbeginning[Part.from_value~size:new_sz_lastto_append]inParts.cut_start~index:yipartsin{complete;parts}(* TODO: ici, on voudrait faire l'intersection des deux modes de calcul. *)letbeq~sizectxab=(*Codex_log.feedback "@[<v 2>beq ~size:%d@.a = %a@.b = %a@]"
size (binary_pretty ~size ctx) a (binary_pretty ~size ctx) b;*)Parts.fold2ctx(fun~sizeaccab->(*Codex_log.feedback "beq folding: acc = %a, a = %a, b = %a"
Sub.Boolean.pretty acc (Part.pretty ctx) a (Part.pretty ctx) b;*)Sub.Boolean_Forward.(&&)ctxacc@@Sub.Binary_Forward.beq~sizectx(Part.do_extractctxa)(Part.do_extractctxb))(Sub.Boolean_Forward.true_ctx)a.partsb.parts;;(* TODO: Use the other beq only if better. *)letbeq~sizectxab=letwith_parts=beq~sizectxabinmatchSub.query_booleanctxwith_partswith|Quadrivalent.True|Quadrivalent.False|Quadrivalent.Bottom->with_parts|_->Sub.Binary_Forward.beq~sizectxa.completeb.complete;;letof_bitsctx=function|Parts.Zeroessize->Part.from_value~size@@SBF.biconst~sizeZ.zeroctx|Parts.Onessize->Part.from_value~size@@SBF.biconst~size(Z.extractZ.minus_one0(size:>int))ctx|Parts.Unknownpart->partletor_bits~sizectxab=matcha,bwith|Parts.Zeroes_,_->of_bitsctxb|_,Parts.Zeroes_->of_bitsctxa|Parts.Ones_,_->of_bitsctxa|_,Parts.Ones_->of_bitsctxb|Parts.(Unknownpa,Unknownpb)->Part.from_value~size@@SBF.bor~sizectx(Part.do_extractctxpa)(Part.do_extractctxpb)(* The parts is also used by addition in some cases. *)letbor'complete~sizectxab=(*Codex_log.feedback "@[<v 2>BW.bor ~size:%d@.%a@.%a@]" size (binary_pretty ~size:size ctx) a (binary_pretty ~size:size ctx) b;*)letres=tryletparts=Parts.fold2_known_bitsctx(functx~sizeaccbabb->(*Codex_log.feedback "ba = %a, bb = %a" (Parts.pretty_bits ctx) ba (Parts.pretty_bits ctx) bb;*)letslice=or_bits~sizectxbabbinParts.appendctxacc[slice])[]a.partsb.partsin{parts;complete}withSig.Bottom->binary_empty~sizectxin(*Codex_log.feedback "result = %a" (binary_pretty ~size ctx) res;*)resletbor~sizectxab=letcomplete=SBF.bor~sizectxa.completeb.completeinbor'complete~sizectxab;;letand_bits~sizectxab=matcha,bwith|Parts.Zeroes_,_->of_bitsctxa|_,Parts.Zeroes_->of_bitsctxb|Parts.Ones_,_->of_bitsctxb|_,Parts.Ones_->of_bitsctxa|Parts.(Unknownpa,Unknownpb)->Part.from_value~size@@SBF.band~sizectx(Part.do_extractctxpa)(Part.do_extractctxpb)letband~sizectxab=tryletparts=Parts.fold2_known_bitsctx(functx~sizeaccbabb->letslice=and_bits~sizectxbabbinParts.appendctxacc[slice])[]a.partsb.partsin{parts;complete=SBF.band~sizectxa.completeb.complete}withSig.Bottom->binary_empty~sizectxletxor_bits~sizectxab=matcha,bwith|Parts.Zeroes_,_->of_bitsctxb|_,Parts.Zeroes_->of_bitsctxa|Parts.Ones_,Parts.Ones_->Part.zeroctx~size|Parts.(Unknownp,Ones_)|Parts.(Ones_,Unknownp)->letpb=Part.onesctx~sizeinPart.from_value~size@@SBF.bxor~sizectx(Part.do_extractctxp)(Part.do_extractctxpb)|Parts.(Unknownpa,Unknownpb)->Part.from_value~size@@SBF.bxor~sizectx(Part.do_extractctxpa)(Part.do_extractctxpb)letbxor~sizectxab=tryletparts=Parts.fold2_known_bitsctx(functx~sizeaccbabb->letslice=xor_bits~sizectxbabbinParts.appendctxacc[slice])[]a.partsb.partsin{parts;complete=SBF.bxor~sizectxa.completeb.complete}withSig.Bottom->binary_empty~sizectxletbiadd~size~flagsctxab=(* Codex_log.feedback "@[<v 2>biadd ~size:%d %a %a@]" size (binary_pretty ~size ctx) a (binary_pretty ~size ctx) b; *)(* If no face-to-face bits are simultaneously 1, then addition is an OR. *)letexceptionExitinletorable=tryParts.fold2ctx(fun~sizeaccpapb->letza,oa=Sub.Query.(binary~sizectx(Part.do_extractctxpa)|>Binary_Lattice.to_known_bits~size)inletzb,ob=Sub.Query.(binary~sizectx(Part.do_extractctxpb)|>Binary_Lattice.to_known_bits~size)inif(Z.equalZ.zero@@Z.(land)zazb)(* If simultaneously at 0 everywhere *)thentrueelseraiseExit)truea.partsb.partswithExit->falseiniforablethenletcomplete=SBF.biadd~size~flagsctxa.completeb.completeinbor'complete~sizectxabelseBinary.lift0~size@@SBF.biadd~size~flagsctxa.completeb.completeletbshift~size~offset~maxctxx=letoffset=biconst~size(Z.of_intoffset)ctxinbiadd~size~flags:(Operator.Flags.Biadd.pack~nsw:false~nuw:false~nusw:false)ctxxoffsetendletbinary_unknown~sizectx=Binary.lift0~size@@Sub.binary_unknown~sizectx;;letbinary_unknown_typed~sizectxtyp=Binary.lift0~size@@Sub.binary_unknown_typed~sizectxtyp;;letboolean_unknown=Sub.boolean_unknownletenum_unknown=Sub.enum_unknownletunion=Sub.union(**************** Serialization, fixpoind and nondet. ****************)(* The resulting computation: have we computed something, or should
we juste take one of the arguments (or none). *)(* Higher-ranked polymorphism is required here, and we need a record for that. *)type'elthigher={subf:'tl.Sub.Context.t->'elt->Sub.Context.t->'elt->'tlSub.Context.in_acc->('elt,'tl)Sub.Context.result}[@@unboxed](* Note: OCaml infers the wrong type (no principal type), we have to help it here. *)letserialize(typeelt)(typec){subf}ctxaactxbb(included,(acc:cin_tuple)):(elt,c)result=letResult(included,in_tup,deserialize)=subfctxaactxbb(included,acc)inResult(included,in_tup,deserialize)letserialize_booleanctxaactxbbacc=serialize{subf=Sub.serialize_boolean}ctxaactxbbaccletserialize_enumctxaactxbbacc=serialize{subf=Sub.serialize_enum}ctxaactxbbacc(* For now we loose everything upon serialization. *)letserialize_binary~widens~sizectxaactxbb(included,acc)=letResult(included,in_tup,deserialize)=Sub.serialize_binary~widens~sizectxaa.completectxbb.complete(included,acc)inResult(included,in_tup,(functxout_tup->letres,out_tup=deserializectxout_tupinBinary.lift0~sizeres,out_tup));;(* Note: OCaml infers the wrong type (no principal type), we have to help it here. *)lettyped_nondet2(typec)ctxactxb(acc:cin_tuple)=Sub.typed_nondet2ctxactxbaccletnondet_same_context=Sub.nondet_same_context(* Note: OCaml infers the wrong type (no principal type), we have to help it here. *)lettyped_fixpoint_step(typec)~iteration~init~arg~body(included,(acc:cin_tuple)):bool*(close:bool->(cout_tuple*Context.t))=letbool,continuef=Sub.typed_fixpoint_step~iteration~init~arg~body(included,acc)inbool,fun~close->continuef~closeletwidened_fixpoint_step=Sub.widened_fixpoint_step(**************** Queries ****************)moduleQuery=structincludeSub.Queryletbinary~sizectxx=binary~sizectxx.completeendletquery_boolean=Sub.query_boolean(**************** Pretty printing ****************)(* let basis = Query.binary ~size ctx x in
* Query.Binary_Lattice.pretty ~size pp basis;
* if pretty_detailed then begin
* Format.pp_print_string pp "(= [";
* match Imap.to_list ~size ctx x with
* | [] -> ()
* | (size_fst, fst) :: tl ->
* pretty_bits ~size:size_fst ctx pp fst;
* List.iter (fun (size,bits) ->
* Format.fprintf pp ":%a" (pretty_bits ~size ctx) bits
* ) tl;
* Format.pp_print_string pp "]"; *)letboolean_pretty=Sub.boolean_prettyletenum_pretty=Sub.enum_prettyletbinary_is_empty~sizectxx=x.parts=[]letinteger_is_empty_=assertfalseletboolean_is_empty_=assertfalseletsatisfiable=Sub.satisfiableend