1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027(* 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_actuallet[@inline]of_argfnvop=tryfvwithValueexpected_ty->letactual_ty=Value.type_ofvinletmsg=err_strnopexpected_tyactual_tyintype_errornvexpected_tyopmsg(* Coercion helpers *)letof_intnopv=of_arg(functionIntx->x|_->raise_notrace(ValueTy_int))nvoplet[@inline]to_intx=Value.Intxletof_realnopv=of_arg(functionRealx->x|_->raise_notrace(ValueTy_real))nvoplet[@inline]to_realx=Value.Realxletof_boolnopv=of_arg(function|True->true|False->false|_->raise_notrace(ValueTy_bool))nvoplet[@inline]to_boolx=ifxthenValue.TrueelseFalseletof_strnopv=of_arg(functionStrx->x|_->raise_notrace(ValueTy_str))nvoplet[@inline]to_strx=Value.Strxletof_listnopv=of_arg(functionListx->x|_->raise_notrace(ValueTy_list))nvopletof_bitvnopv=of_arg(functionBitvx->x|_->raise_notrace(Value(Ty_bitv0)))nvopletint32_of_bitvnopv=of_bitvnopv|>Bitvector.to_int32letint64_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)letof_fp32iopv:int32=of_arg(functionNum(F32f)->f|_->raise_notrace(Value(Ty_fp32)))ivoplet[@inline]to_fp32(x:int32)=Value.Num(F32x)let[@inline]fp32_of_float(x:float)=to_fp32(Int32.bits_of_floatx)letof_fp64iopv:int64=of_arg(functionNum(F64f)->f|_->raise_notrace(Value(Ty_fp32)))ivoplet[@inline]to_fp64(x:int64)=Value.Num(F64x)let[@inline]fp64_of_float(x:float)=to_fp64(Int64.bits_of_floatx)(* Operator evaluation *)moduleInt=structletunop(op:Ty.Unop.t)(v:Value.t):Value.t=letf=matchopwith|Neg->Int.neg|Not->Int.lognot|Abs->Int.abs|_->eval_error(`Unsupported_operator(`Unopop,Ty_int))into_int(f(of_int1(`Unopop)v))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_squaring21xnletbinop(op:Ty.Binop.t)(v1:Value.t)(v2:Value.t):Value.t=letf=matchopwith|Add->Int.add|Sub->Int.sub|Mul->Int.mul|Div->Int.div|Rem->Int.rem|Pow->exp_by_squaring|Min->Int.min|Max->Int.max|And->Int.logand|Or->Int.logor|Xor->Int.logxor|Shl->Int.shift_left|ShrL->Int.shift_right_logical|ShrA->Int.shift_right|_->eval_error(`Unsupported_operator(`Binopop,Ty_int))into_int(f(of_int1(`Binopop)v1)(of_int2(`Binopop)v2))letrelop(op:Ty.Relop.t)(v1:Value.t)(v2:Value.t):bool=letf=matchopwith|Lt->(<)|Le->(<=)|Gt->(>)|Ge->(>=)|Eq->Int.equal|Ne->funab->not(Int.equalab)|_->eval_error(`Unsupported_operator(`Relopop,Ty_int))inf(of_int1(`Relopop)v1)(of_int2(`Relopop)v2)letof_bool:Value.t->int=function|True->1|False->0|_->assertfalse[@@inline]letcvtop(op:Ty.Cvtop.t)(v:Value.t):Value.t=matchopwith|OfBool->to_int(of_boolv)|Reinterpret_float->Int(Int.of_float(of_real1(`Cvtopop)v))|_->eval_error(`Unsupported_operator(`Cvtopop,Ty_int))endmoduleReal=structletunop(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))letbinop(op:Ty.Binop.t)(v1:Value.t)(v2:Value.t):Value.t=letf=matchopwith|Add->Float.add|Sub->Float.sub|Mul->Float.mul|Div->Float.div|Rem->Float.rem|Min->Float.min|Max->Float.max|Pow->Float.pow|_->eval_error(`Unsupported_operator(`Binopop,Ty_real))into_real(f(of_real1(`Binopop)v1)(of_real2(`Binopop)v2))letrelop(op:Ty.Relop.t)(v1:Value.t)(v2:Value.t):bool=letf=matchopwith|Lt->Float.Infix.(<)|Le->Float.Infix.(<=)|Gt->Float.Infix.(>)|Ge->Float.Infix.(>=)|Eq->Float.Infix.(=)|Ne->Float.Infix.(<>)|_->eval_error(`Unsupported_operator(`Relopop,Ty_real))inf(of_real1(`Relopop)v1)(of_real2(`Relopop)v2)letcvtop(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=structletunop(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->falseletbinop(op:Ty.Binop.t)v1v2=letf=matchopwith|And->(&&)|Or->(||)|Xor->xor|_->eval_error(`Unsupported_operator(`Binopop,Ty_bool))into_bool(f(of_bool1(`Binopop)v1)(of_bool2(`Binopop)v2))lettriop(op:Ty.Triop.t)cv1v2=matchopwith|Ite->(matchof_bool1(`Triopop)cwithtrue->v1|false->v2)|_->eval_error(`Unsupported_operator(`Triopop,Ty_bool))letrelop(op:Ty.Relop.t)v1v2=matchopwith|Eq->Value.equalv1v2|Ne->not(Value.equalv1v2)|_->eval_error(`Unsupported_operator(`Relopop,Ty_bool))letnaryop(op:Ty.Naryop.t)vs=letb=matchopwith|Logand->List.fold_left(&&)true(List.mapi(funi->of_booli(`Naryopop))vs)|Logor->List.fold_left(||)false(List.mapi(funi->of_booli(`Naryopop))vs)|_->eval_error(`Unsupported_operator(`Naryopop,Ty_bool))into_boolbendmoduleStr=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<0thenfalseelsetrueletunop(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))letbinop(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))lettriop(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))letrelop(op:Ty.Relop.t)v1v2=letf=matchopwith|Lt->(<)|Le->(<=)|Gt->(>)|Ge->(>=)|Eq->(=)|Ne->(<>)|_->eval_error(`Unsupported_operator(`Relopop,Ty_str))inletfxy=f(String.comparexy)0inf(of_str1(`Relopop)v1)(of_str2(`Relopop)v2)letcvtop(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))letnaryop(op:Ty.Naryop.t)vs=letop'=`Naryopopinmatchopwith|Concat->to_str(String.concat""(List.map(of_str0op')vs))|_->eval_error(`Unsupported_operator(`Naryopop,Ty_str))endmoduleLst=structletunop(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))letbinop(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))lettriop(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))letnaryop(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=structletunopopbv=letbv=of_bitv1(`Unopop)bvinto_bitv@@matchopwith|Ty.Unop.Neg->Bitvector.negbv|Not->Bitvector.lognotbv|Clz->Bitvector.clzbv|Ctz->Bitvector.ctzbv|Popcnt->Bitvector.popcntbv|_->eval_error(`Unsupported_operator(`Unopop,Ty_bitv(Bitvector.numbitsbv)))letbinopopbv1bv2=letbv1=of_bitv1(`Binopop)bv1inletbv2=of_bitv2(`Binopop)bv2into_bitv@@matchopwith|Ty.Binop.Add->Bitvector.addbv1bv2|Sub->Bitvector.subbv1bv2|Mul->Bitvector.mulbv1bv2|Div->Bitvector.divbv1bv2|DivU->Bitvector.div_ubv1bv2|Rem->Bitvector.rembv1bv2|RemU->Bitvector.rem_ubv1bv2|And->Bitvector.logandbv1bv2|Or->Bitvector.logorbv1bv2|Xor->Bitvector.logxorbv1bv2|Shl->Bitvector.shlbv1bv2|ShrL->Bitvector.lshrbv1bv2|ShrA->Bitvector.ashrbv1bv2|Rotl->Bitvector.rotate_leftbv1bv2|Rotr->Bitvector.rotate_rightbv1bv2|_->eval_error(`Unsupported_operator(`Binopop,Ty_bitv0))letrelopopbv1bv2=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|Gt->Bitvector.gtbv1bv2|GtU->Bitvector.gt_ubv1bv2|Ge->Bitvector.gebv1bv2|GeU->Bitvector.ge_ubv1bv2|Eq->Bitvector.equalbv1bv2|Ne->not@@Bitvector.equalbv1bv2letcvtopopbv=letbv=of_bitv1(`Cvtopop)bvinto_bitv@@matchopwith|Ty.Cvtop.Sign_extendm->Bitvector.sign_extendmbv|Ty.Cvtop.Zero_extendm->Bitvector.zero_extendmbv|_->eval_error(`Unsupported_operator(`Cvtopop,Ty_bitv(Bitvector.numbitsbv)))endmoduleF32=struct(* Stolen from Owi *)letabsx=Int32.logandxInt32.max_intletnegx=Int32.logxorxInt32.min_intletunop(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 *)letcopy_signxy=Int32.logor(absx)(Int32.logandyInt32.min_int)letbinop(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))letrelop(op:Ty.Relop.t)(v1:Value.t)(v2:Value.t):bool=letf=matchopwith|Eq->Float.Infix.(=)|Ne->Float.Infix.(<>)|Lt->Float.Infix.(<)|Le->Float.Infix.(<=)|Gt->Float.Infix.(>)|Ge->Float.Infix.(>=)|_->eval_error(`Unsupported_operator(`Relopop,Ty_fp32))inleta=Int32.float_of_bits@@of_fp321(`Relopop)v1inletb=Int32.float_of_bits@@of_fp322(`Relopop)v2infabendmoduleF64=struct(* Stolen from owi *)letabsx=Int64.logandxInt64.max_intletnegx=Int64.logxorxInt64.min_intletunop(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)letbinop(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))letrelop(op:Ty.Relop.t)(v1:Value.t)(v2:Value.t):bool=letf=matchopwith|Eq->Float.Infix.(=)|Ne->Float.Infix.(<>)|Lt->Float.Infix.(<)|Le->Float.Infix.(<=)|Gt->Float.Infix.(>)|Ge->Float.Infix.(>=)|_->eval_error(`Unsupported_operator(`Relopop,Ty_fp64))inleta=Int64.float_of_bits@@of_fp641(`Relopop)v1inletb=Int64.float_of_bits@@of_fp642(`Relopop)v2infabendmoduleI32CvtOp=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->v(* v is already a number here *)|ToBool|_->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 *)letopintrealboolstrlstbvf32f64tyop=matchtywith|Ty.Ty_int->intop|Ty_real->realop|Ty_bool->boolop|Ty_str->strop|Ty_list->lstop|Ty_bitv_->bvop|Ty_fp32->f32op|Ty_fp64->f64op|Ty_fp_|Ty_app|Ty_unit|Ty_none|Ty_regexp|Ty_roundingMode->eval_error(`Unsupported_theoryty)[@@inline]letunop=opInt.unopReal.unopBool.unopStr.unopLst.unopBitv.unopF32.unopF64.unopletbinop=opInt.binopReal.binopBool.binopStr.binopLst.binopBitv.binopF32.binopF64.binoplettriop=function|Ty.Ty_bool->Bool.triop|Ty_str->Str.triop|Ty_list->Lst.triop|ty->eval_error(`Unsupported_theoryty)letrelop=function|Ty.Ty_int->Int.relop|Ty_real->Real.relop|Ty_bool->Bool.relop|Ty_str->Str.relop|Ty_bitv_->Bitv.relop|Ty_fp32->F32.relop|Ty_fp64->F64.relop|ty->eval_error(`Unsupported_theoryty)letcvtop=function|Ty.Ty_int->Int.cvtop|Ty_real->Real.cvtop|Ty_str->Str.cvtop|Ty_bitv32->I32CvtOp.cvtop|Ty_bitv64->I64CvtOp.cvtop(* Remaining fall into arbitrary-width bv cvtop operations *)|Ty_bitv_m->Bitv.cvtop|Ty_fp32->F32CvtOp.cvtop|Ty_fp64->F64CvtOp.cvtop|ty->eval_error(`Unsupported_theoryty)letnaryop=function|Ty.Ty_bool->Bool.naryop|Ty_str->Str.naryop|Ty_list->Lst.naryop|ty->eval_error(`Unsupported_theoryty)