123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023(* SPDX-License-Identifier: MIT *)(* Copyright (C) 2023-2024 formalsec *)(* Written by the Smtml programmers *)(* Adapted from: *)(* - https://github.com/WebAssembly/spec/blob/main/interpreter/exec/ixx.ml, *)(* - https://github.com/WebAssembly/spec/blob/main/interpreter/exec/fxx.ml, and *)(* - https://github.com/WebAssembly/spec/blob/main/interpreter/exec *)typeop_type=[`UnopofTy.Unop.t|`BinopofTy.Binop.t|`RelopofTy.Relop.t|`TriopofTy.Triop.t|`CvtopofTy.Cvtop.t|`NaryopofTy.Naryop.t][@@derivingshow]typetype_error_info={index:int;value:Value.t;ty:Ty.t;op:op_type;msg:string}[@@derivingshow]typeerror_kind=[`Divide_by_zero|`Conversion_to_integer|`Integer_overflow|`Index_out_of_bounds|`Invalid_format_conversion|`Unsupported_operatorofop_type*Ty.t|`Unsupported_theoryofTy.t|`Type_erroroftype_error_info]letpp_error_kindfmterr=matcherrwith|`Divide_by_zero->Fmt.stringfmt"Division by zero"|`Conversion_to_integer->Fmt.stringfmt"Failed to convert value to integer"|`Integer_overflow->Fmt.stringfmt"Integer overflow: result is outside the representable range"|`Index_out_of_bounds->Fmt.stringfmt"Index out of bounds"|`Invalid_format_conversion->Fmt.stringfmt"Invalid format conversion string"|`Unsupported_operator(op,ty)->Fmt.pffmt"The operator '%a' is not supported for type '%a'"pp_op_typeopTy.ppty|`Unsupported_theoryty->Fmt.pffmt"The theory for type '%a' is not currently supported"Ty.ppty|`Type_error{index;value;ty;op;_}->Fmt.pffmt"@[<h>Type error: Argument %d of operation '%a' expected type '%a', but \
received value '%a' instead.@]"indexpp_op_typeopTy.pptyValue.ppvalueexceptionEval_erroroferror_kindexceptionValueofTy.t(* Exception helpers *)leteval_errorkind=raise(Eval_errorkind)lettype_errornvtyopmsg=eval_error(`Type_error{index=n;value=v;ty;op;msg})leterr_strnopty_expectedty_actual=Fmt.str"Argument %d of %a expected type %a but got %a instead."npp_op_typeopTy.ppty_expectedTy.ppty_actualletraise_type_mismatchnopvexpected_ty=letactual_ty=Value.type_ofvinletmsg=err_strnopexpected_tyactual_tyintype_errornvexpected_tyopmsg(* Coercion helpers *)let[@inline]of_intnopv=matchvwithValue.Intx->x|_->raise_type_mismatchnopvTy_intlet[@inline]to_intx=Value.Intxlet[@inline]of_realnopv=matchvwithValue.Realx->x|_->raise_type_mismatchnopvTy_reallet[@inline]to_realx=Value.Realxlet[@inline]of_boolnopv=matchvwith|Value.True->true|False->false|_->raise_type_mismatchnopvTy_boollet[@inline]to_boolx=ifxthenValue.TrueelseFalselet[@inline]of_strnopv=matchvwithValue.Strx->x|_->raise_type_mismatchnopvTy_strlet[@inline]to_strx=Value.Strxlet[@inline]of_listnopv=matchvwithValue.Listx->x|_->raise_type_mismatchnopvTy_listlet[@inline]of_bitvnopv=matchvwithValue.Bitvx->x|_->raise_type_mismatchnopv(Ty_bitv0)let[@inline]int32_of_bitvnopv=of_bitvnopv|>Bitvector.to_int32let[@inline]int64_of_bitvnopv=of_bitvnopv|>Bitvector.to_int64let[@inline]to_bitvx=Value.Bitvxlet[@inline]bitv_of_int32x=to_bitv(Bitvector.of_int32x)let[@inline]bitv_of_int64x=to_bitv(Bitvector.of_int64x)let[@inline]of_fp32nopv:int32=matchvwith|Value.Num(F32f)->f|_->raise_type_mismatchnopv(Ty_fp32)let[@inline]to_fp32(x:int32)=Value.Num(F32x)let[@inline]fp32_of_float(x:float)=to_fp32(Int32.bits_of_floatx)let[@inline]of_fp64nopv:int64=matchvwith|Value.Num(F64f)->f|_->raise_type_mismatchnopv(Ty_fp64)let[@inline]to_fp64(x:int64)=Value.Num(F64x)let[@inline]fp64_of_float(x:float)=to_fp64(Int64.bits_of_floatx)(* Operator evaluation *)moduleInt=structlet[@inline]unop(op:Ty.Unop.t)(v:Value.t):Value.t=letv=of_int1(`Unopop)vinmatchopwith|Neg->to_int(Int.negv)|Not->to_int(Int.lognotv)|Abs->to_int(Int.absv)|_->eval_error(`Unsupported_operator(`Unopop,Ty_int))letexp_by_squaringxn=letrecexp_by_squaring2yxn=ifn<0thenexp_by_squaring2y(1/x)~-nelseifn=0thenyelseifnmod2=0thenexp_by_squaring2y(x*x)(n/2)elsebeginassert(nmod2=1);exp_by_squaring2(x*y)(x*x)((n-1)/2)endinexp_by_squaring21xnlet[@inline]binop(op:Ty.Binop.t)(v1:Value.t)(v2:Value.t):Value.t=letv1=of_int1(`Binopop)v1inletv2=of_int2(`Binopop)v2inmatchopwith|Add->to_int(Int.addv1v2)|Sub->to_int(Int.subv1v2)|Mul->to_int(Int.mulv1v2)|Div->to_int(Int.divv1v2)|Rem->to_int(Int.remv1v2)|Pow->to_int(exp_by_squaringv1v2)|Min->to_int(Int.minv1v2)|Max->to_int(Int.maxv1v2)|And->to_int(Int.logandv1v2)|Or->to_int(Int.logorv1v2)|Xor->to_int(Int.logxorv1v2)|Shl->to_int(Int.shift_leftv1v2)|ShrL->to_int(Int.shift_right_logicalv1v2)|ShrA->to_int(Int.shift_rightv1v2)|_->eval_error(`Unsupported_operator(`Binopop,Ty_int))let[@inline]relop(op:Ty.Relop.t)(v1:Value.t)(v2:Value.t):bool=leta=of_int1(`Relopop)v1inletb=of_int2(`Relopop)v2inmatchopwith|Lt->a<b|Le->a<=b|Eq->Int.equalab|Ne->not(Int.equalab)|_->eval_error(`Unsupported_operator(`Relopop,Ty_int))let[@inline]int_of_boolv=matchvwithValue.True->1|False->0|_->assertfalselet[@inline]cvtop(op:Ty.Cvtop.t)(v:Value.t):Value.t=matchopwith|OfBool->to_int(int_of_boolv)|Reinterpret_float->Int(Int.of_float(of_real1(`Cvtopop)v))|_->eval_error(`Unsupported_operator(`Cvtopop,Ty_int))endmoduleReal=structlet[@inline]unop(op:Ty.Unop.t)(v:Value.t):Value.t=letv=of_real1(`Unopop)vinmatchopwith|Neg->to_real@@Float.negv|Abs->to_real@@Float.absv|Sqrt->to_real@@Float.sqrtv|Nearest->to_real@@Float.roundv|Ceil->to_real@@Float.ceilv|Floor->to_real@@Float.floorv|Trunc->to_real@@Float.truncv|Is_nan->ifFloat.is_nanvthenValue.TrueelseValue.False|_->eval_error(`Unsupported_operator(`Unopop,Ty_real))let[@inline]binop(op:Ty.Binop.t)(v1:Value.t)(v2:Value.t):Value.t=leta=of_real1(`Binopop)v1inletb=of_real2(`Binopop)v2inmatchopwith|Add->to_real(Float.addab)|Sub->to_real(Float.subab)|Mul->to_real(Float.mulab)|Div->to_real(Float.divab)|Rem->to_real(Float.remab)|Min->to_real(Float.minab)|Max->to_real(Float.maxab)|Pow->to_real(Float.powab)|_->eval_error(`Unsupported_operator(`Binopop,Ty_real))let[@inline]relop(op:Ty.Relop.t)(v1:Value.t)(v2:Value.t):bool=leta=of_real1(`Relopop)v1inletb=of_real2(`Relopop)v2inmatchopwith|Lt->Float.Infix.(a<b)|Le->Float.Infix.(a<=b)|Eq->Float.Infix.(a=b)|Ne->Float.Infix.(a<>b)|_->eval_error(`Unsupported_operator(`Relopop,Ty_real))let[@inline]cvtop(op:Ty.Cvtop.t)(v:Value.t):Value.t=letop'=`Cvtopopinmatchopwith|ToString->Str(Float.to_string(of_real1op'v))|OfString->beginmatchfloat_of_string_opt(of_str1op'v)with|None->eval_error`Invalid_format_conversion|Somev->to_realvend|Reinterpret_int->to_real(float_of_int(of_int1op'v))|Reinterpret_float->to_int(Float.to_int(of_real1op'v))|_->eval_error(`Unsupported_operator(op',Ty_real))endmoduleBool=structlet[@inline]unop(op:Ty.Unop.t)v=letb=of_bool1(`Unopop)vinmatchopwith|Not->to_bool(notb)|_->eval_error(`Unsupported_operator(`Unopop,Ty_bool))letxorb1b2=match(b1,b2)with|true,true->false|true,false->true|false,true->true|false,false->falselet[@inline]binop(op:Ty.Binop.t)v1v2=leta=of_bool1(`Binopop)v1inletb=of_bool2(`Binopop)v2inmatchopwith|And->to_bool(a&&b)|Or->to_bool(a||b)|Xor->to_bool(xorab)|_->eval_error(`Unsupported_operator(`Binopop,Ty_bool))let[@inline]triop(op:Ty.Triop.t)cv1v2=matchopwith|Ite->(matchof_bool1(`Triopop)cwithtrue->v1|false->v2)|_->eval_error(`Unsupported_operator(`Triopop,Ty_bool))let[@inline]relop(op:Ty.Relop.t)v1v2=matchopwith|Eq->Value.equalv1v2|Ne->not(Value.equalv1v2)|_->eval_error(`Unsupported_operator(`Relopop,Ty_bool))let[@inline]naryop(op:Ty.Naryop.t)vs=matchopwith|Logand->letexists_false=leti=ref0inList.find_map(fune->incri;letb=of_bool!i(`Naryopop)einifnotbthenSome()elseNone)vsinifOption.is_someexists_falsethenValue.FalseelseValue.True|Logor->letexists_true=leti=ref0inList.find_map(fune->incri;letb=of_bool!i(`Naryopop)einifbthenSome()elseNone)vsinifOption.is_someexists_truethenValue.TrueelseValue.False|_->eval_error(`Unsupported_operator(`Naryopop,Ty_bool))endmoduleStr=structletreplacestt'=letlen_s=String.lengthsinletlen_t=String.lengthtinletrecloopi=ifi>=len_sthenselseifi+len_t>len_sthenselseifString.equal(String.subsilen_t)tthenlets'=Fmt.str"%s%s"(String.subs0i)t'inlets''=String.subs(i+len_t)(len_s-i-len_t)inFmt.str"%s%s"s's''elseloop(i+1)inloop0letindexofssubstart=letlen_s=String.lengthsinletlen_sub=String.lengthsubinletmax_i=len_s-1inletrecloopi=ifi>max_ithen~-1elseifi+len_sub>len_sthen~-1elseifString.equalsub(String.subsilen_sub)thenielseloop(i+1)inifstart<=0thenloop0elseloopstartletcontainsssub=ifindexofssub0<0thenfalseelsetruelet[@inline]unop(op:Ty.Unop.t)v=letstr=of_str1(`Unopop)vinmatchopwith|Length->to_int(String.lengthstr)|Trim->to_str(String.trimstr)|_->eval_error(`Unsupported_operator(`Unopop,Ty_str))let[@inline]binop(op:Ty.Binop.t)v1v2=letop'=`Binopopinletstr=of_str1op'v1inmatchopwith|At->beginleti=of_int2op'v2intryto_str(Fmt.str"%c"(String.getstri))withInvalid_argument_->eval_error`Index_out_of_boundsend|String_prefix->to_bool(String.starts_with~prefix:str(of_str2op'v2))|String_suffix->to_bool(String.ends_with~suffix:str(of_str2op'v2))|String_contains->to_bool(containsstr(of_str2op'v2))|_->eval_error(`Unsupported_operator(op',Ty_str))let[@inline]triop(op:Ty.Triop.t)v1v2v3=letop'=`Triopopinletstr=of_str1op'v1inmatchopwith|String_extract->beginleti=of_int2op'v2inletlen=of_int3op'v3intryto_str(String.substrilen)withInvalid_argument_->eval_error`Index_out_of_boundsend|String_replace->lett=of_str2op'v2inlett'=of_str2op'v3into_str(replacestrtt')|String_index->lett=of_str2op'v2inleti=of_int3op'v3into_int(indexofstrti)|_->eval_error(`Unsupported_operator(`Triopop,Ty_str))let[@inline]relop(op:Ty.Relop.t)v1v2=leta=of_str1(`Relopop)v1inletb=of_str2(`Relopop)v2inletcmp=String.compareabinmatchopwith|Lt->cmp<0|Le->cmp<=0|Eq->cmp=0|Ne->cmp<>0|_->eval_error(`Unsupported_operator(`Relopop,Ty_str))let[@inline]cvtop(op:Ty.Cvtop.t)v=letop'=`Cvtopopinmatchopwith|String_to_code->letstr=of_str1op'vinto_int(Char.codestr.[0])|String_from_code->letcode=of_int1op'vinto_str(String.make1(Char.chrcode))|String_to_int->beginlets=of_str1op'vinmatchint_of_string_optswith|None->eval_error`Invalid_format_conversion|Somex->to_intxend|String_from_int->to_str(string_of_int(of_int1op'v))|String_to_float->beginlets=of_str1op'vinmatchfloat_of_string_optswith|None->eval_error`Invalid_format_conversion|Somef->to_realfend|_->eval_error(`Unsupported_operator(`Cvtopop,Ty_str))let[@inline]naryop(op:Ty.Naryop.t)vs=letop'=`Naryopopinmatchopwith|Concat->let_,s=List.fold_left(fun(i,acc)v->lets=of_striop'vin(i+1,String.cataccs))(0,"")vsinto_strs|_->eval_error(`Unsupported_operator(`Naryopop,Ty_str))endmoduleLst=structlet[@inline]unop(op:Ty.Unop.t)(v:Value.t):Value.t=letlst=of_list1(`Unopop)vinmatchopwith|Head->begin(* FIXME: Exception handling *)matchlstwith|hd::_tl->hd|[]->assertfalseend|Tail->begin(* FIXME: Exception handling *)matchlstwith|_hd::tl->Listtl|[]->assertfalseend|Length->to_int(List.lengthlst)|Reverse->List(List.revlst)|_->eval_error(`Unsupported_operator(`Unopop,Ty_list))let[@inline]binop(op:Ty.Binop.t)v1v2=letop'=`Binopopinmatchopwith|At->letlst=of_list1op'v1inleti=of_int2op'v2in(* TODO: change datastructure? *)beginmatchList.nth_optlstiwith|None->eval_error`Index_out_of_bounds|Somev->vend|List_cons->List(v1::of_list1op'v2)|List_append->List(of_list1op'v1@of_list2op'v2)|_->eval_error(`Unsupported_operator(`Binopop,Ty_list))let[@inline]triop(op:Ty.Triop.t)(v1:Value.t)(v2:Value.t)(v3:Value.t):Value.t=letop'=`Triopopinmatchopwith|List_set->letlst=of_list1op'v1inleti=of_int2op'v2inletrecsetilstvacc=match(i,lst)with|0,_::tl->List.rev_appendacc(v::tl)|i,hd::tl->set(i-1)tlv(hd::acc)|_,[]->eval_error`Index_out_of_boundsinList(setilstv3[])|_->eval_error(`Unsupported_operator(`Triopop,Ty_list))let[@inline]naryop(op:Ty.Naryop.t)(vs:Value.tlist):Value.t=letop'=`Naryopopinmatchopwith|Concat->List(List.concat_map(of_list0op')vs)|_->eval_error(`Unsupported_operator(`Naryopop,Ty_list))endmoduleI64=structletcmp_uxopy=opInt64.(addxmin_int)Int64.(addymin_int)[@@inline]letlt_uxy=cmp_uxInt64.Infix.(<)y[@@inline]endmoduleBitv=structlet[@inline]unopopbv=letbv=of_bitv1(`Unopop)bvinmatchopwith|Ty.Unop.Neg->to_bitv(Bitvector.negbv)|Not->to_bitv(Bitvector.lognotbv)|Clz->to_bitv(Bitvector.clzbv)|Ctz->to_bitv(Bitvector.ctzbv)|Popcnt->to_bitv(Bitvector.popcntbv)|_->eval_error(`Unsupported_operator(`Unopop,Ty_bitv(Bitvector.numbitsbv)))let[@inline]binopopbv1bv2=letbv1=of_bitv1(`Binopop)bv1inletbv2=of_bitv2(`Binopop)bv2inmatchopwith|Ty.Binop.Add->to_bitv(Bitvector.addbv1bv2)|Sub->to_bitv(Bitvector.subbv1bv2)|Mul->to_bitv(Bitvector.mulbv1bv2)|Div->to_bitv(Bitvector.divbv1bv2)|DivU->to_bitv(Bitvector.div_ubv1bv2)|Rem->to_bitv(Bitvector.rembv1bv2)|RemU->to_bitv(Bitvector.rem_ubv1bv2)|And->to_bitv(Bitvector.logandbv1bv2)|Or->to_bitv(Bitvector.logorbv1bv2)|Xor->to_bitv(Bitvector.logxorbv1bv2)|Shl->to_bitv(Bitvector.shlbv1bv2)|ShrL->to_bitv(Bitvector.lshrbv1bv2)|ShrA->to_bitv(Bitvector.ashrbv1bv2)|Rotl->to_bitv(Bitvector.rotate_leftbv1bv2)|Rotr->to_bitv(Bitvector.rotate_rightbv1bv2)|_->eval_error(`Unsupported_operator(`Binopop,Ty_bitv0))let[@inline]relopopbv1bv2=letbv1=of_bitv1(`Relopop)bv1inletbv2=of_bitv2(`Relopop)bv2inmatchopwith|Ty.Relop.Lt->Bitvector.ltbv1bv2|LtU->Bitvector.lt_ubv1bv2|Le->Bitvector.lebv1bv2|LeU->Bitvector.le_ubv1bv2|Eq->Bitvector.equalbv1bv2|Ne->not@@Bitvector.equalbv1bv2let[@inline]cvtopopbv=letbv=of_bitv1(`Cvtopop)bvinmatchopwith|Ty.Cvtop.Sign_extendm->to_bitv(Bitvector.sign_extendmbv)|Ty.Cvtop.Zero_extendm->to_bitv(Bitvector.zero_extendmbv)|_->eval_error(`Unsupported_operator(`Cvtopop,Ty_bitv(Bitvector.numbitsbv)))endmoduleF32=struct(* Stolen from Owi *)let[@inline]absx=Int32.logandxInt32.max_intlet[@inline]negx=Int32.logxorxInt32.min_intlet[@inline]unop(op:Ty.Unop.t)(v:Value.t):Value.t=letf=Int32.float_of_bits(of_fp321(`Unopop)v)inmatchopwith|Neg->to_fp32@@neg@@of_fp321(`Unopop)v|Abs->to_fp32@@abs@@of_fp321(`Unopop)v|Sqrt->fp32_of_float@@Float.sqrtf|Nearest->fp32_of_float@@Float.roundf|Ceil->fp32_of_float@@Float.ceilf|Floor->fp32_of_float@@Float.floorf|Trunc->fp32_of_float@@Float.truncf|Is_nan->ifFloat.is_nanfthenValue.TrueelseValue.False|_->eval_error(`Unsupported_operator(`Unopop,Ty_fp32))(* Stolen from Owi *)let[@inline]copy_signxy=Int32.logor(absx)(Int32.logandyInt32.min_int)let[@inline]binop(op:Ty.Binop.t)(v1:Value.t)(v2:Value.t):Value.t=leta=Int32.float_of_bits@@of_fp321(`Binopop)v1inletb=Int32.float_of_bits@@of_fp321(`Binopop)v2inmatchopwith|Add->fp32_of_float@@Float.addab|Sub->fp32_of_float@@Float.subab|Mul->fp32_of_float@@Float.mulab|Div->fp32_of_float@@Float.divab|Rem->fp32_of_float@@Float.remab|Min->fp32_of_float@@Float.minab|Max->fp32_of_float@@Float.maxab|Copysign->leta=of_fp321(`Binopop)v1inletb=of_fp321(`Binopop)v2into_fp32(copy_signab)|_->eval_error(`Unsupported_operator(`Binopop,Ty_fp32))let[@inline]relop(op:Ty.Relop.t)(v1:Value.t)(v2:Value.t):bool=leta=Int32.float_of_bits@@of_fp321(`Relopop)v1inletb=Int32.float_of_bits@@of_fp322(`Relopop)v2inmatchopwith|Eq->Float.Infix.(a=b)|Ne->Float.Infix.(a<>b)|Lt->Float.Infix.(a<b)|Le->Float.Infix.(a<=b)|_->eval_error(`Unsupported_operator(`Relopop,Ty_fp32))endmoduleF64=struct(* Stolen from owi *)let[@inline]absx=Int64.logandxInt64.max_intlet[@inline]negx=Int64.logxorxInt64.min_intlet[@inline]unop(op:Ty.Unop.t)(v:Value.t):Value.t=letf=Int64.float_of_bits@@of_fp641(`Unopop)vinmatchopwith|Neg->to_fp64@@neg@@of_fp641(`Unopop)v|Abs->to_fp64@@abs@@of_fp641(`Unopop)v|Sqrt->fp64_of_float@@Float.sqrtf|Nearest->fp64_of_float@@Float.roundf|Ceil->fp64_of_float@@Float.ceilf|Floor->fp64_of_float@@Float.floorf|Trunc->fp64_of_float@@Float.truncf|Is_nan->ifFloat.is_nanfthenValue.TrueelseValue.False|_->Fmt.failwith{|unop: Unsupported f32 operator "%a"|}Ty.Unop.ppopletcopy_signxy=Int64.logor(absx)(Int64.logandyInt64.min_int)let[@inline]binop(op:Ty.Binop.t)(v1:Value.t)(v2:Value.t):Value.t=leta=Int64.float_of_bits@@of_fp641(`Binopop)v1inletb=Int64.float_of_bits@@of_fp642(`Binopop)v2inmatchopwith|Add->fp64_of_float@@Float.addab|Sub->fp64_of_float@@Float.subab|Mul->fp64_of_float@@Float.mulab|Div->fp64_of_float@@Float.divab|Rem->fp64_of_float@@Float.remab|Min->fp64_of_float@@Float.minab|Max->fp64_of_float@@Float.maxab|Copysign->leta=of_fp641(`Binopop)v1inletb=of_fp642(`Binopop)v2into_fp64@@copy_signab|_->eval_error(`Unsupported_operator(`Binopop,Ty_fp64))let[@inline]relop(op:Ty.Relop.t)(v1:Value.t)(v2:Value.t):bool=leta=Int64.float_of_bits@@of_fp641(`Relopop)v1inletb=Int64.float_of_bits@@of_fp642(`Relopop)v2inmatchopwith|Eq->Float.Infix.(a=b)|Ne->Float.Infix.(a<>b)|Lt->Float.Infix.(a<b)|Le->Float.Infix.(a<=b)|_->eval_error(`Unsupported_operator(`Relopop,Ty_fp64))endmoduleI32CvtOp=structlettrunc_f32_s(x:int32)=ifInt32.Infix.(x<>x)theneval_error`Conversion_to_integerelseletxf=Int32.float_of_bitsxinifFloat.Infix.(xf>=-.Int32.(to_floatmin_int)||xf<Int32.(to_floatmin_int))theneval_error`Integer_overflowelseInt32.of_floatxflettrunc_f32_u(x:int32)=ifInt32.Infix.(x<>x)theneval_error`Conversion_to_integerelseletxf=Int32.float_of_bitsxinifFloat.Infix.(xf>=-.Int32.(to_floatmin_int)*.2.0||xf<=-1.0)theneval_error`Integer_overflowelseInt32.of_floatxflettrunc_f64_s(x:int64)=ifInt64.Infix.(x<>x)theneval_error`Conversion_to_integerelseletxf=Int64.float_of_bitsxinifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)||xf<Int64.(to_floatmin_int))theneval_error`Integer_overflowelseInt32.of_floatxflettrunc_f64_u(x:int64)=ifInt64.Infix.(x<>x)theneval_error`Conversion_to_integerelseletxf=Int64.float_of_bitsxinifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)*.2.0||xf<=-1.0)theneval_error`Integer_overflowelseInt32.of_floatxflettrunc_sat_f32_sx=ifInt32.Infix.(x<>x)then0lelseletxf=Int32.float_of_bitsxinifFloat.Infix.(xf<Int32.(to_floatmin_int))thenInt32.min_intelseifFloat.Infix.(xf>=-.Int32.(to_floatmin_int))thenInt32.max_intelseInt32.of_floatxflettrunc_sat_f32_ux=ifInt32.Infix.(x<>x)then0lelseletxf=Int32.float_of_bitsxinifFloat.Infix.(xf<=-1.0)then0lelseifFloat.Infix.(xf>=-.Int32.(to_floatmin_int)*.2.0)then-1lelseInt32.of_floatxflettrunc_sat_f64_sx=ifInt64.Infix.(x<>x)then0lelseletxf=Int64.float_of_bitsxinifFloat.Infix.(xf<Int64.(to_floatmin_int))thenInt32.min_intelseifFloat.Infix.(xf>=-.Int64.(to_floatmin_int))thenInt32.max_intelseInt32.of_floatxflettrunc_sat_f64_ux=ifInt64.Infix.(x<>x)then0lelseletxf=Int64.float_of_bitsxinifFloat.Infix.(xf<=-1.0)then0lelseifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)*.2.0)then-1lelseInt32.of_floatxfletcvtopopv=letop'=`Cvtopopinmatchopwith|Ty.Cvtop.WrapI64->bitv_of_int32(Int64.to_int32(int64_of_bitv1op'v))|TruncSF32->bitv_of_int32(trunc_f32_s(of_fp321op'v))|TruncUF32->bitv_of_int32(trunc_f32_u(of_fp321op'v))|TruncSF64->bitv_of_int32(trunc_f64_s(of_fp641op'v))|TruncUF64->bitv_of_int32(trunc_f64_u(of_fp641op'v))|Trunc_sat_f32_s->bitv_of_int32(trunc_sat_f32_s(of_fp321op'v))|Trunc_sat_f32_u->bitv_of_int32(trunc_sat_f32_u(of_fp321op'v))|Trunc_sat_f64_s->bitv_of_int32(trunc_sat_f64_s(of_fp641op'v))|Trunc_sat_f64_u->bitv_of_int32(trunc_sat_f64_u(of_fp641op'v))|Reinterpret_float->bitv_of_int32(of_fp321op'v)|Sign_extendn->to_bitv(Bitvector.sign_extendn(of_bitv1op'v))|Zero_extendn->to_bitv(Bitvector.zero_extendn(of_bitv1op'v))|OfBool->letb=of_bool1(`CvtopOfBool)vinifbthento_bitv(Bitvector.makeZ.one32)elseto_bitv(Bitvector.makeZ.zero32)|ToBool->letbv=of_bitv1(`CvtopToBool)vinifnot(Bitvector.eqzbv)thenValue.TrueelseFalse|_->eval_error(`Unsupported_operator(op',Ty_bitv32))endmoduleI64CvtOp=structletextend_i32_u(x:int32)=Int64.(logand(of_int32x)0x0000_0000_ffff_ffffL)lettrunc_f32_s(x:int32)=ifInt32.Infix.(x<>x)theneval_error`Conversion_to_integerelseletxf=Int32.float_of_bitsxinifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)||xf<Int64.(to_floatmin_int))theneval_error`Integer_overflowelseInt64.of_floatxflettrunc_f32_u(x:int32)=ifInt32.Infix.(x<>x)theneval_error`Conversion_to_integerelseletxf=Int32.float_of_bitsxinifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)*.2.0||xf<=-1.0)theneval_error`Integer_overflowelseifFloat.Infix.(xf>=-.Int64.(to_floatmin_int))thenInt64.(logxor(of_float(xf-.0x1p63))min_int)elseInt64.of_floatxflettrunc_f64_s(x:int64)=ifInt64.Infix.(x<>x)theneval_error`Conversion_to_integerelseletxf=Int64.float_of_bitsxinifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)||xf<Int64.(to_floatmin_int))theneval_error`Integer_overflowelseInt64.of_floatxflettrunc_f64_u(x:int64)=ifInt64.Infix.(x<>x)theneval_error`Conversion_to_integerelseletxf=Int64.float_of_bitsxinifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)*.2.0||xf<=-1.0)theneval_error`Integer_overflowelseifFloat.Infix.(xf>=-.Int64.(to_floatmin_int))thenInt64.(logxor(of_float(xf-.0x1p63))min_int)elseInt64.of_floatxflettrunc_sat_f32_s(x:int32)=ifInt32.Infix.(x<>x)then0Lelseletxf=Int32.float_of_bitsxinifFloat.Infix.(xf<Int64.(to_floatmin_int))thenInt64.min_intelseifFloat.Infix.(xf>=-.Int64.(to_floatmin_int))thenInt64.max_intelseInt64.of_floatxflettrunc_sat_f32_u(x:int32)=ifInt32.Infix.(x<>x)then0Lelseletxf=Int32.float_of_bitsxinifFloat.Infix.(xf<=-1.0)then0LelseifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)*.2.0)then-1LelseifFloat.Infix.(xf>=-.Int64.(to_floatmin_int))thenInt64.(logxor(of_float(xf-.0x1p63))min_int)elseInt64.of_floatxflettrunc_sat_f64_s(x:int64)=ifInt64.Infix.(x<>x)then0Lelseletxf=Int64.float_of_bitsxinifFloat.Infix.(xf<Int64.(to_floatmin_int))thenInt64.min_intelseifFloat.Infix.(xf>=-.Int64.(to_floatmin_int))thenInt64.max_intelseInt64.of_floatxflettrunc_sat_f64_u(x:int64)=ifInt64.Infix.(x<>x)then0Lelseletxf=Int64.float_of_bitsxinifFloat.Infix.(xf<=-1.0)then0LelseifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)*.2.0)then-1LelseifFloat.Infix.(xf>=-.Int64.(to_floatmin_int))thenInt64.(logxor(of_float(xf-.0x1p63))min_int)elseInt64.of_floatxfletcvtop(op:Ty.Cvtop.t)(v:Value.t):Value.t=letop'=`Cvtopopinmatchopwith|Sign_extendn->to_bitv(Bitvector.sign_extendn(of_bitv1op'v))|Zero_extendn->to_bitv(Bitvector.zero_extendn(of_bitv1op'v))|TruncSF32->bitv_of_int64(trunc_f32_s(of_fp321op'v))|TruncUF32->bitv_of_int64(trunc_f32_u(of_fp321op'v))|TruncSF64->bitv_of_int64(trunc_f64_s(of_fp641op'v))|TruncUF64->bitv_of_int64(trunc_f64_u(of_fp641op'v))|Trunc_sat_f32_s->bitv_of_int64(trunc_sat_f32_s(of_fp321op'v))|Trunc_sat_f32_u->bitv_of_int64(trunc_sat_f32_u(of_fp321op'v))|Trunc_sat_f64_s->bitv_of_int64(trunc_sat_f64_s(of_fp641op'v))|Trunc_sat_f64_u->bitv_of_int64(trunc_sat_f64_u(of_fp641op'v))|Reinterpret_float->bitv_of_int64(of_fp641op'v)|WrapI64->type_error1v(Ty_bitv64)op'"Cannot wrapI64 on an I64"|ToBool|OfBool|_->eval_error(`Unsupported_operator(op',Ty_bitv64))endmoduleF32CvtOp=structletdemote_f64x=letxf=Int64.float_of_bitsxinifFloat.Infix.(xf=xf)thenInt32.bits_of_floatxfelseletnan64bits=xinletsign_field=Int64.(shift_left(shift_right_logicalnan64bits63)31)inletsignificand_field=Int64.(shift_right_logical(shift_leftnan64bits12)41)inletfields=Int64.logorsign_fieldsignificand_fieldinInt32.logor0x7fc0_0000l(Int64.to_int32fields)letconvert_i32_sx=Int32.bits_of_float(Int32.to_floatx)letconvert_i32_ux=Int32.bits_of_floatInt32.(Int32.Infix.(ifx>=0lthento_floatxelseto_float(logor(shift_right_logicalx1)(logandx1l))*.2.0))letconvert_i64_sx=Int32.bits_of_floatInt64.(Int64.Infix.(ifabsx<0x10_0000_0000_0000Lthento_floatxelseletr=iflogandx0xfffL=0Lthen0Lelse1Linto_float(logor(shift_rightx12)r)*.0x1p12))letconvert_i64_ux=Int32.bits_of_floatInt64.(Int64.Infix.(ifI64.lt_ux0x10_0000_0000_0000Lthento_floatxelseletr=iflogandx0xfffL=0Lthen0Lelse1Linto_float(logor(shift_right_logicalx12)r)*.0x1p12))letcvtop(op:Ty.Cvtop.t)(v:Value.t):Value.t=letop'=`Cvtopopinmatchopwith|DemoteF64->to_fp32(demote_f64(of_fp641op'v))|ConvertSI32->to_fp32(convert_i32_s(int32_of_bitv1op'v))|ConvertUI32->to_fp32(convert_i32_u(int32_of_bitv1op'v))|ConvertSI64->to_fp32(convert_i64_s(int64_of_bitv1op'v))|ConvertUI64->to_fp32(convert_i64_u(int64_of_bitv1op'v))|Reinterpret_int->to_fp32(int32_of_bitv1op'v)|PromoteF32->type_error1v(Ty_fp32)op'"F64 must promote F32"|ToString|OfString|_->eval_error(`Unsupported_operator(op',Ty_fp32))endmoduleF64CvtOp=structletpromote_f32x=letxf=Int32.float_of_bitsxinifFloat.Infix.(xf=xf)thenInt64.bits_of_floatxfelseletnan32bits=I64CvtOp.extend_i32_uxinletsign_field=Int64.(shift_left(shift_right_logicalnan32bits31)63)inletsignificand_field=Int64.(shift_right_logical(shift_leftnan32bits41)12)inletfields=Int64.logorsign_fieldsignificand_fieldinInt64.logor0x7ff8_0000_0000_0000Lfieldsletconvert_i32_sx=Int64.bits_of_float(Int32.to_floatx)(*
* Unlike the other convert_u functions, the high half of the i32 range is
* within the range where f32 can represent odd numbers, so we can't do the
* shift. Instead, we can use int64 signed arithmetic.
*)letconvert_i32_ux=Int64.bits_of_floatInt64.(to_float(logand(of_int32x)0x0000_0000_ffff_ffffL))letconvert_i64_sx=Int64.bits_of_float(Int64.to_floatx)(*
* Values in the low half of the int64 range can be converted with a signed
* conversion. The high half is beyond the range where f64 can represent odd
* numbers, so we can shift the value right, adjust the least significant
* bit to round correctly, do a conversion, and then scale it back up.
*)letconvert_i64_u(x:int64)=Int64.bits_of_floatInt64.(Int64.Infix.(ifx>=0Lthento_floatxelseto_float(logor(shift_right_logicalx1)(logandx1L))*.2.0))letcvtop(op:Ty.Cvtop.t)v:Value.t=letop'=`Cvtopopinmatchopwith|PromoteF32->to_fp64(promote_f32(of_fp321op'v))|ConvertSI32->to_fp64(convert_i32_s(int32_of_bitv1op'v))|ConvertUI32->to_fp64(convert_i32_u(int32_of_bitv1op'v))|ConvertSI64->to_fp64(convert_i64_s(int64_of_bitv1op'v))|ConvertUI64->to_fp64(convert_i64_u(int64_of_bitv1op'v))|Reinterpret_int->to_fp64(int64_of_bitv1op'v)|DemoteF64->type_error1v(Ty_fp64)op'"F32 must demote a F64"|ToString|OfString|_->eval_error(`Unsupported_operator(op',Ty_fp64))end(* Dispatch *)letunoptyopv=matchtywith|Ty.Ty_int->Int.unopopv|Ty_real->Real.unopopv|Ty_bool->Bool.unopopv|Ty_str->Str.unopopv|Ty_list->Lst.unopopv|Ty_bitv_->Bitv.unopopv|Ty_fp32->F32.unopopv|Ty_fp64->F64.unopopv|Ty_fp_|Ty_app|Ty_unit|Ty_none|Ty_regexp|Ty_roundingMode->eval_error(`Unsupported_theoryty)letbinoptyopv1v2=matchtywith|Ty.Ty_int->Int.binopopv1v2|Ty_real->Real.binopopv1v2|Ty_bool->Bool.binopopv1v2|Ty_str->Str.binopopv1v2|Ty_list->Lst.binopopv1v2|Ty_bitv_->Bitv.binopopv1v2|Ty_fp32->F32.binopopv1v2|Ty_fp64->F64.binopopv1v2|Ty_fp_|Ty_app|Ty_unit|Ty_none|Ty_regexp|Ty_roundingMode->eval_error(`Unsupported_theoryty)lettrioptyopv1v2v3=matchtywith|Ty.Ty_bool->Bool.triopopv1v2v3|Ty_str->Str.triopopv1v2v3|Ty_list->Lst.triopopv1v2v3|ty->eval_error(`Unsupported_theoryty)letreloptyopv1v2=matchtywith|Ty.Ty_int->Int.relopopv1v2|Ty_real->Real.relopopv1v2|Ty_bool->Bool.relopopv1v2|Ty_str->Str.relopopv1v2|Ty_bitv_->Bitv.relopopv1v2|Ty_fp32->F32.relopopv1v2|Ty_fp64->F64.relopopv1v2|ty->eval_error(`Unsupported_theoryty)letcvtoptyopv=matchtywith|Ty.Ty_int->Int.cvtopopv|Ty_real->Real.cvtopopv|Ty_str->Str.cvtopopv|Ty_bitv32->I32CvtOp.cvtopopv|Ty_bitv64->I64CvtOp.cvtopopv(* Remaining fall into arbitrary-width bv cvtop operations *)|Ty_bitv_m->Bitv.cvtopopv|Ty_fp32->F32CvtOp.cvtopopv|Ty_fp64->F64CvtOp.cvtopopv|ty->eval_error(`Unsupported_theoryty)letnaryoptyopvs=matchtywith|Ty.Ty_bool->Bool.naryopopvs|Ty_str->Str.naryopopvs|Ty_list->Lst.naryopopvs|ty->eval_error(`Unsupported_theoryty)