123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580(**************************************************************************)(* 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). *)(* *)(**************************************************************************)moduleLog=Tracelog.Make(structletcategory="Domains.Loop"end);;moduleTC=Operator.Function_symbolmoduleIn_bits=Units.In_bits(* let index_size = 64 ;; *)letindex_size=In_bits.of_int32moduleMake(Terms:Terms.Sig.TERMS)(Sub:Sig.BASEwithtypebinary=TC.binaryTerms.tandtypeboolean=TC.booleanTerms.tandtypeenum=TC.enumTerms.t):Sig.BASE=structletname()="Loop_Domain("^Sub.name()^")";;letunique_id()=Sig.Fresh_id.fresh@@name();;moduleTypes=structtypebinary=Sub.binarytypeboolean=Sub.booleantypeenum=Sub.enumendincludeTypesmoduleBinary=Sub.BinarymoduleBoolean=Sub.BooleanmoduleEnum=Sub.Enumtypecontext={subcontext:Sub.Context.t;index:binaryoption};;moduleContext=structtypet=contextletcopyx={xwithsubcontext=Sub.Context.copyx.subcontext}letassignctx1ctx2=Sub.Context.assignctx1.subcontextctx2.subcontextletlevelctx=Sub.Context.levelctx.subcontexttype'ain_tuple='aSub.Context.in_tupletype'ain_acc=bool*'aSub.Context.in_tuple(* We reconstruct the identifiers on-demand. MAYBE: have the bottom case. *)type'aout_tuple='aSub.Context.out_tupletype('a,'b)result=Result:bool*'somein_tuple*(t->'someout_tuple->'a*'bout_tuple)->('a,'b)resulttypeempty_tuple=Sub.Context.empty_tupleletempty_tuple()=Sub.Context.empty_tuple()endopenContextletroot_context()={subcontext=Sub.root_context();index=None};;letcontext_prettyfmtctx=matchctx.indexwith|None->Format.fprintffmt"Context{sub=%a}"Sub.context_prettyctx.subcontext|Someidx->Format.fprintffmt"Context{sub=%a,index=%a}"Sub.context_prettyctx.subcontext(Sub.binary_pretty~size:index_sizectx.subcontext)idx(* include Operator.Builtin.Make(Types)(Context) *)letassumectxcond=Option.map(funsubctx->{ctxwithsubcontext=subctx})(Sub.assumectx.subcontextcond)moduleBoolean_Forward=structlet(||)ctx=Sub.Boolean_Forward.(||)ctx.subcontextlet(&&)ctx=Sub.Boolean_Forward.(&&)ctx.subcontextletnotctx=Sub.Boolean_Forward.notctx.subcontext(* Note: we avoid creating those every time. *)lettrue_ctx=Sub.Boolean_Forward.true_ctx.subcontextletfalse_ctx=Sub.Boolean_Forward.false_ctx.subcontextendmoduleBinary_Forward=structletbiadd~size~flagsctx=Sub.Binary_Forward.biadd~size~flagsctx.subcontextletbisub~size~flagsctx=Sub.Binary_Forward.bisub~size~flagsctx.subcontextletbimul~size~flagsctx=Sub.Binary_Forward.bimul~size~flagsctx.subcontextletbxor~sizectx=Sub.Binary_Forward.bxor~sizectx.subcontextletband~sizectx=Sub.Binary_Forward.band~sizectx.subcontextletbor~sizectx=Sub.Binary_Forward.bor~sizectx.subcontextletbashr~sizectx=Sub.Binary_Forward.bashr~sizectx.subcontextletblshr~sizectx=Sub.Binary_Forward.blshr~sizectx.subcontextletbshl~size~flagsctx=Sub.Binary_Forward.bshl~size~flagsctx.subcontextletbisdiv~sizectx=Sub.Binary_Forward.bisdiv~sizectx.subcontextletbiudiv~sizectx=Sub.Binary_Forward.biudiv~sizectx.subcontextletbismod~sizectx=Sub.Binary_Forward.bismod~sizectx.subcontextletbiumod~sizectx=Sub.Binary_Forward.biumod~sizectx.subcontextletbeq~sizectx=Sub.Binary_Forward.beq~sizectx.subcontextletbiule~sizectx=Sub.Binary_Forward.biule~sizectx.subcontextletbisle~sizectx=Sub.Binary_Forward.bisle~sizectx.subcontextletbsext~size~oldsizectx=Sub.Binary_Forward.bsext~size~oldsizectx.subcontextletbuext~size~oldsizectx=Sub.Binary_Forward.buext~size~oldsizectx.subcontextletbchoose~sizecondctx=Sub.Binary_Forward.bchoose~sizecondctx.subcontextletbofbool~sizectx=Sub.Binary_Forward.bofbool~sizectx.subcontextletbconcat~size1~size2ctx=Sub.Binary_Forward.bconcat~size1~size2ctx.subcontextletbextract~size~index~oldsizectx=Sub.Binary_Forward.bextract~size~index~oldsizectx.subcontextletbiconst~sizekctx=Sub.Binary_Forward.biconst~sizekctx.subcontextletbuninit~size=assertfalseletbshift~size~offset~max_=assertfalseletbindex~size_=assertfalseletvalid~size_=assertfalseletvalid_ptr_arith~size_=assertfalseendmoduleEnum_Forward=structletcaseof~casectx=Sub.Enum_Forward.caseof~casectx.subcontextletenum_const~casectx=Sub.Enum_Forward.enum_const~casectx.subcontextendletboolean_emptyctx=Sub.boolean_emptyctx.subcontextletbinary_empty~sizectx=Sub.binary_empty~sizectx.subcontextletenum_emptyctx=Sub.enum_emptyctx.subcontextletboolean_unknownctx=Sub.boolean_unknownctx.subcontextletbinary_unknown~sizectx=Sub.binary_unknown~sizectx.subcontextletenum_unknown~enumsizectx=Sub.enum_unknown~enumsizectx.subcontextletboolean_prettyctxfmtx=Sub.boolean_prettyctx.subcontextfmtxletbinary_pretty~sizectxfmtx=Sub.binary_pretty~sizectx.subcontextfmtxletenum_prettyctxfmtx=Sub.enum_prettyctx.subcontextfmtxletserialize_binary~widens~sizectxaactxbbacc=letSub.Context.Result(included,in_tup,deserialize)=Sub.serialize_binary~widens~sizectxa.subcontextactxb.subcontextbaccinContext.Result(included,in_tup,(functxout_tup->deserializectx.subcontextout_tup))letpretty_indexfmtctx=matchctx.indexwith|None->Format.fprintffmt"None"|Somev->binary_pretty~size:index_sizectxfmtv(* TODO : look at the way arithmetic flags are used to unsure the absence of unsoundness *)letserialize_binary~widens~(size:In_bits.t)ctxaactxbb((inc,tup)asacc)=Log.debug(funp->p"Loop_domain.serialize_binary ~widens:%b ~size:%d %a %a with index = %a"widens(size:>int)(binary_pretty~sizectxa)a(binary_pretty~sizectxb)b(funfmtindex->matchindexwithNone->Format.fprintffmt"None"|Someidx->(binary_pretty~sizectxafmt)idx)ctxa.index);ifsize<>index_sizethenserialize_binary~widens~sizectxaactxbbaccelseifnotwidensthenserialize_binary~widens~sizectxaactxbbaccelseletcur_level=Context.levelctxainmatchctxa.indexwith(* Case 1 : First iteration of the loop *)|Some(Terms.Binary{term=T0{tag=TC.Biconst(_size,k)}})when(* Z.equal Z.one k *)Z.equalZ.zerok->beginmatcha,bwith(* case 1 : with prev_index = 0, base \cup (offset + base) = ((offset * index) + base) *)|Terms.(Binary_asx),Terms.(Binary{term=T2{tag=TC.Biadd{size=size';flags};a=Binary{term=T0{tag=TC.Biconst(_size2,k)}};b=Binary_asy}})whenTerms.equalxy&&(Terms.levelx)<cur_level->Log.debug(funp->p"in Loop_domain.serialize, applying substitution 1");Result(inc,tup,(functxout->matchctx.indexwith|Someidx->letoffset=Binary_Forward.biconst~size:index_sizekctxinletoffset=Binary_Forward.bimul~size:index_size~flags:(Operator.Flags.Bimul.pack~nsw:false~nuw:false)ctxoffsetidxinletres=Binary_Forward.biadd~size:index_size~flagsctxoffsetxinres,out|_->assertfalse))(* case 2 : with prev_index = 0, base \cup (base - offset) = base - (offset * index) *)|Terms.(Binary_asx),Terms.(Binary{term=T2{tag=TC.Bisub{size=size';flags=flagssub};a=Binary_asy;b=Binary{term=T0{tag=TC.Biconst(_size2,k)}}}})whenTerms.equalxy&&(Terms.levelx)<cur_level->Log.debug(funp->p"in Loop_domain.serialize, applying substitution 2");Result(inc,tup,(functxout->matchctx.indexwith|Someidx->Log.debug(funp->p"while, applying substitution 2, index = %a"(binary_pretty~sizectx)idx);letflags=Operator.Flags.Bimul.pack~nsw:false~nuw:falseinletoffset=Binary_Forward.biconst~size:index_sizekctxinletoffset=Binary_Forward.bimul~size:index_size~flagsctxoffsetidxinletres=Binary_Forward.bisub~size:index_size~flags:flagssubctxxoffsetinLog.debug(funp->p"Loop_domain.serialize_binary, returning %a"Binary.prettyres);res,out|_->assertfalse))(* case 7 & 8 : with constant values *)|Terms.(Binary{term=T0{tag=TC.Biconst(_size1,k)}}),Terms.(Binary{term=T0{tag=TC.Biconst(_size2,l)}})whennot@@Z.equalkl->letl=Z.signed_extractl0(index_size:>int)inifZ.leqklthen(Log.debug(funp->p"in Loop_domain.serialize, applying substitution 7");Result(inc,tup,(functxout->matchctx.indexwith|Someidx->letbase=Binary_Forward.biconst~size:index_sizekctxinletoffset=Binary_Forward.biconst~size:index_size(Z.sublk)ctxinletoffset=Binary_Forward.bimul~size:index_size~flags:(Operator.Flags.Bimul.pack~nsw:false~nuw:false)ctxidxoffsetinletres=Binary_Forward.biadd~size:index_size~flags:(Operator.Flags.Biadd.pack~nsw:false~nuw:false~nusw:false)ctxbaseoffsetinres,out|_->assertfalse)))else(Log.debug(funp->p"in Loop_domain.serialize, applying substitution 8");Result(inc,tup,(functxout->matchctx.indexwith|Someidx->letbase=Binary_Forward.biconst~size:index_sizekctxinletoffset=Binary_Forward.biconst~size:index_size(Z.subkl)ctxinletoffset=Binary_Forward.bimul~size:index_size~flags:(Operator.Flags.Bimul.pack~nsw:false~nuw:false)ctxoffsetidxinletres=Binary_Forward.bisub~size:index_size~flags:(Operator.Flags.Bisub.pack~nsw:false~nuw:false~nusw:false)ctxbaseoffsetinres,out|_->assertfalse)))|_->Log.debug(funp->p"in Loop_domain.serialize, applying no substituation");serialize_binary~widens~sizectxaactxbbaccend(* Case 2 : Subsequent iteration of the loop *)|Someprevidx->beginmatcha,bwith(* case 3 : ((offset * prev_index) + base) \cup (offset + ((offset * prev_index) + base) = ((offset * index) + base) *)|Terms.(Binary{term=T2{tag=TC.Biadd{size=_size1;flags=flags1};a=Binary{term=T2{tag=TC.Bimul_size2;a=Binary{term=T0{tag=TC.Biconst(_size3,i)}};b=Binary_asu}};b=Binary_asx;}}),Terms.(Binary{term=T2{tag=TC.Biadd{size=_size4;flags=flags4};a=Binary{term=T0{tag=TC.Biconst(_size5,k)}};b=Binary{term=T2{tag=TC.Biadd{size=_size6;flags=flags6};a=Binary{term=T2{tag=TC.Bimul{size=_size7;flags=flags7};a=Binary{term=T0{tag=TC.Biconst(_size8,j)}};b=Binary_asv}};b=Binary_asy}};}})whenZ.equalij&&Z.equalik&&Terms.equalxy&&Terms.equaluv&&Terms.equaluprevidx&&(Terms.levelx)<cur_level&&flags1=flags4->Log.debug(funp->p"in Loop_domain.serialize, applying substitution 3");Result(inc,tup,(functxout->matchctx.indexwith|Someidx->letoffset=Binary_Forward.biconst~size:index_sizeictxinletoffset=Binary_Forward.bimul~size:index_size~flags:flags7ctxoffsetidxinletres=Binary_Forward.biadd~size:index_size~flags:flags1ctxoffsetxinres,out|_->assertfalse))(* case 4 : (base - (offset * prev_index)) \cup ((base - (offset * prev_index)) - offset) = (base - (offset * index)) *)|Terms.(Binary{term=T2{tag=TC.Bisub{size=_size1;flags=flags1};a=Binary_asx;b=Binary{term=T2{tag=TC.Bimul{size=_size2;flags=flags2};a=Binary{term=T0{tag=TC.Biconst(_size3,i)}};b=Binary_asu}}}}),Terms.(Binary{term=T2{tag=TC.Bisub{size=_size4;flags=flags4};a=Binary{term=T2{tag=TC.Bisub{size=_size5;flags=flags5};a=Binary_asy;b=Binary{term=T2{tag=TC.Bimul{size=_size6;flags=flags6};a=Binary{term=T0{tag=TC.Biconst(_size7,j)}};b=Binary_asv}}}};b=Binary{term=T0{tag=TC.Biconst(_size8,k)}}}})whenZ.equalij&&Z.equalik&&Terms.equalxy&&Terms.equaluv&&Terms.equaluprevidx&&(Terms.levelx)<cur_level&&flags1=flags4&&flags2=flags6->Log.debug(funp->p"in Loop_domain.serialize, applying substitution 4");Result(inc,tup,(functxout->matchctx.indexwith|Someidx->letoffset=Binary_Forward.biconst~size:index_sizeictxinletoffset=Binary_Forward.bimul~size:index_size~flags:flags2ctxoffsetidxinletres=Binary_Forward.bisub~size:index_size~flags:flags1ctxxoffsetinres,out|_->assertfalse))(* case 5 : (prev_index + base) \cup (1 + (prev_index + base)) = (index + base) *)|Terms.(Binary{term=T2{tag=TC.Biadd{size=_size1;flags=flags1};a=Binary_asu;b=Binary_asx}}),Terms.(Binary{term=T2{tag=TC.Biadd{size=_size2;flags=flags2};a=Binary{term=T0{tag=TC.Biconst(_size3,k)}};b=Binary{term=T2{tag=TC.Biadd{size=_size4;flags=flags4};a=Binary_asv;b=Binary_asy}}}})whenZ.equalkZ.one&&Terms.equalxy&&Terms.equaluv&&Terms.equaluprevidx&&(Terms.levelx)<cur_level&&flags1=flags2&&flags1=flags4->Log.debug(funp->p"in Loop_domain.serialize, applying substitution 5");Result(inc,tup,(functxout->matchctx.indexwith|Someidx->letres=Binary_Forward.biadd~size:index_size~flags:flags1ctxidxxinres,out|_->assertfalse))(* case 6 : (base - prev_index) \cup (base - prev_index - 1) = (base - index) *)|Terms.(Binary{term=T2{tag=TC.Bisub{size=_size1;flags=flags1};a=Binary_asx;b=Binary_asu}}),Terms.(Binary{term=T2{tag=TC.Bisub{size=_size2;flags=flags2};a=Binary{term=T2{tag=TC.Bisub{size=_size3;flags=flags3};a=Binary_asy;b=Binary_asv}};b=Binary{term=T0{tag=TC.Biconst(_size4,k)}}}})whenZ.equalkZ.one&&Terms.equalxy&&Terms.equaluv&&Terms.equaluprevidx&&(Terms.levelx)<cur_level&&flags1=flags2&&flags1=flags3->Log.debug(funp->p"in Loop_domain.serialize, applying substitution 6");Result(inc,tup,(functxout->matchctx.indexwith|Someidx->letres=Binary_Forward.bisub~size:index_size~flags:flags1ctxxidxinres,out|_->assertfalse))(* case 9 : (offset * prev_index) \cup (offset + (offset * prev_index)) = (offset * index) (with base = 0) *)|Terms.(Binary{term=T2{tag=TC.Bimul{size=_size1;flags=flags1};a=Binary{term=T0{tag=TC.Biconst(_size2,i)}};b=Binary_asx}}),Terms.(Binary{term=T2{tag=TC.Biadd{size=_size3;flags=flags3};a=Binary{term=T0{tag=TC.Biconst(_size4,j)}};b=Binary{term=T2{tag=TC.Bimul{size=_size5;flags=flags5};a=Binary{term=T0{tag=TC.Biconst(_size6,k)}};b=Binary_asy}};}})whenTerms.equalxy&&Terms.equalxprevidx&&Z.equalij&&Z.equalik&&flags1=flags5->Log.debug(funp->p"in Loop_domain.serialize, applying substitution 9");Result(inc,tup,(functxout->matchctx.indexwith|Someidx->letoffset=Binary_Forward.biconst~size:index_sizeictxinletres=Binary_Forward.bimul~size:index_size~flags:flags5ctxoffsetidxinres,out|_->assertfalse))(* case 10 : 0 - (prev_index * offset) \cup 0 - (prev_index * offset) - offset = 0 - (index * offset) *)(* TODO : check if it is necessary *)(* case 11 : prev_index \cup 1 + prev_index = index (when offset = 1 & base = 0) *)|Terms.(Binary_asx),Terms.(Binary{term=T2{tag=TC.Biadd{size=_size;flags};a=Binary{term=T0{tag=TC.Biconst(_size2,k)}};b=Binary_asy}})whenZ.equalkZ.one&&Terms.equalxy&&Terms.equalxprevidx->Log.debug(funp->p"in Loop_domain.serialize, applying substitution 11");Result(inc,tup,(functxout->matchctx.indexwith|Someidx->idx,out|_->assertfalse))(* case 12 : 0 - prev_index \cup 0 - prev_index - 1 = 0 - index *)(* TODO : check if it is necessary *)(* generally for constant value bases *)(* case 13 : (base + (offset * prev_index)) \cup (offset + (base + (offset + base))) = ((offset * index) + base) *)|Terms.(Binary{term=T2{tag=TC.Biadd{size=_size1;flags=flags1};a=Binary_asx;b=Binary{term=T2{tag=TC.Bimul{size=_size2;flags=flags2};a=Binary{term=T0{tag=TC.Biconst(_size3,i)}};b=Binary_asu}}}}),Terms.(Binary{term=T2{tag=TC.Biadd{size=_size4;flags=flags4};a=Binary{term=T0{tag=TC.Biconst(_size5,k)}};b=Binary{term=T2{tag=TC.Biadd{size=_size6;flags=flags6};a=Binary_asy;b=Binary{term=T2{tag=TC.Bimul{size=_size7;flags=flags7};a=Binary{term=T0{tag=TC.Biconst(_size8,j)}};b=Binary_asv}}}};}})whenZ.equalij&&Z.equalik&&Terms.equalxy&&Terms.equaluv&&Terms.equaluprevidx&&(Terms.levelx)<cur_level&&flags1=flags4&&flags1=flags6&&flags2=flags7->Log.debug(funp->p"in Loop_domain.serialize, applying substitution 13");Result(inc,tup,(functxout->matchctx.indexwith|Someidx->letoffset=Binary_Forward.biconst~size:index_sizeictxinletoffset=Binary_Forward.bimul~size:index_size~flags:flags2ctxoffsetidxinletres=Binary_Forward.biadd~size:index_size~flags:flags1ctxoffsetxinres,out|_->assertfalse))(* case 14 : (base + prev_index) \cup (1 + (base + prev_index)) = (base + index) *)|Terms.(Binary{term=T2{tag=TC.Biadd{size=_size1;flags=flags1};a=Binary_asx;b=Binary_asu}}),Terms.(Binary{term=T2{tag=TC.Biadd{size=_size2;flags=flags2};a=Binary{term=T0{tag=TC.Biconst(_size3,k)}};b=Binary{term=T2{tag=TC.Biadd{size=_size4;flags=flags4};a=Binary_asy;b=Binary_asv}}}})whenZ.equalkZ.one&&Terms.equalxy&&Terms.equaluv&&Terms.equaluprevidx&&(Terms.levelx)<cur_level&&flags1=flags2&&flags1=flags4->Log.debug(funp->p"in Loop_domain.serialize, applying substitution 14");Result(inc,tup,(functxout->matchctx.indexwith|Someidx->letres=Binary_Forward.biadd~size:index_size~flags:(Operator.Flags.Biadd.pack~nsw:false~nuw:false~nusw:false)ctxxidxinres,out|_->assertfalse))|_->Log.debug(funp->p"in Loop_domain.serialize, applying no substituation");serialize_binary~widens~sizectxaactxbbaccend|_->Log.debug(funp->p"in Loop_domain.serialize, unable to substitute without an adequate loop index");serialize_binary~widens~sizectxaactxbbaccletserialize_booleanctxaactxbbacc=letSub.Context.Result(included,in_tup,deserialize)=Sub.serialize_booleanctxa.subcontextactxb.subcontextbaccinContext.Result(included,in_tup,(functxout_tup->deserializectx.subcontextout_tup))letserialize_enumctxaactxbbacc=letSub.Context.Result(included,in_tup,deserialize)=Sub.serialize_enumctxa.subcontextactxb.subcontextbaccinContext.Result(included,in_tup,(functxout_tup->deserializectx.subcontextout_tup))(**************** Nondet and union. ****************)letnondet_same_contextctxin_tup=Sub.nondet_same_contextctx.subcontextin_tupletunioncondctxin_tup=Sub.unioncondctx.subcontextin_tuplettyped_nondet2ctxactxbin_tup=matchctxa.index,ctxb.indexwith|Someia,SomeibwhenTerms.equaliaib->letsubctx,out=Sub.typed_nondet2ctxa.subcontextctxb.subcontextin_tupin{subcontext=subctx;index=Someia},out|_->letsubctx,out=Sub.typed_nondet2ctxa.subcontextctxb.subcontextin_tupin{subcontext=subctx;index=None},outlettyped_fixpoint_step~iteration~init~arg~body(inc,tup)=letbool,continuef=Sub.typed_fixpoint_step~iteration~init:init.subcontext~arg:arg.subcontext~body:body.subcontext(inc,tup)inletcontinuef~close=letout,ctx=continuef~closeinout,{subcontext=ctx;index=None}inbool,continueflettyped_fixpoint_step~iteration~init~arg~body((inc,tup):bool*'ain_tuple):bool*(close:bool->'aout_tuple*Context.t)=matcharg.indexwith|Someidx->letone=Sub.Binary_Forward.biconst~size:index_sizeZ.oneinit.subcontextinletnext_idx=Sub.Binary_Forward.biadd~size:index_size~flags:(Operator.Flags.Biadd.pack~nsw:false~nuw:false~nusw:false)body.subcontextidxonein(* TODO : we should probably use flag "nuw" *)letSub.Context.Result(inc,tup,deserialize)=Sub.serialize_binary~widens:true~size:index_sizearg.subcontextidxbody.subcontextnext_idx(inc,tup)inletbool,continuef=Sub.typed_fixpoint_step~iteration~init:init.subcontext~arg:arg.subcontext~body:body.subcontext(inc,tup)inletcontinuef~close=letout,ctx=continuef~closeinletnew_index,out=deserializectxoutinout,{subcontext=ctx;index=Somenew_index}inbool,continuef|_->typed_fixpoint_step~iteration~init~arg~body(inc,tup)letwidened_fixpoint_step~widening_id~previous~next=assertfalseletmu_context_openparent_ctx=letsubctx=Sub.mu_context_openparent_ctx.subcontextinletzero=Sub.Binary_Forward.biconst~size:index_sizeZ.zeroparent_ctx.subcontextin{subcontext=subctx;index=Somezero}moduleQuery=structincludeSub.Queryletbinary~sizectx=Sub.Query.binary~sizectx.subcontextletenumctx=Sub.Query.enumctx.subcontextendletquery_booleanctxb=Sub.query_booleanctx.subcontextbletassume_binary~size=assertfalseletsatisfiablectxcond=Sub.satisfiablectx.subcontextcondletbinary_unknown_typed~sizectxtyp=Sub.binary_unknown_typed~sizectx.subcontexttypend