12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088(* 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 *)(* TODO: This module should be concrete or a part of the reducer *)typeop_type=[`UnopofTy.Unop.t|`BinopofTy.Binop.t|`RelopofTy.Relop.t|`TriopofTy.Triop.t|`CvtopofTy.Cvtop.t|`NaryopofTy.Naryop.t]letpp_op_typefmt=function|`Unopop->Fmt.pffmt"unop '%a'"Ty.Unop.ppop|`Binopop->Fmt.pffmt"binop '%a'"Ty.Binop.ppop|`Relopop->Fmt.pffmt"relop '%a'"Ty.Relop.ppop|`Triopop->Fmt.pffmt"triop '%a'"Ty.Triop.ppop|`Cvtopop->Fmt.pffmt"cvtop '%a'"Ty.Cvtop.ppop|`Naryopop->Fmt.pffmt"naryop '%a'"Ty.Naryop.ppopexceptionValueofTy.t(* FIXME: use snake case instead *)exceptionTypeErrorof{index:int;value:Value.t;ty:Ty.t;op:op_type;msg:string}(* FIXME: use snake case instead *)exceptionDivideByZeroexceptionConversion_to_integerexceptionInteger_overflow(* FIXME: use snake case instead *)exceptionIndex_out_of_boundsletof_argfnvopmsg=tryfvwithValuet->raise(TypeError{index=n;value=v;ty=t;op;msg})[@@inline]leterr_strnopty_expectedty_actual=Fmt.str"Argument %d of %a expected type %a but got %a instead."npp_op_typeopTy.ppty_expectedTy.ppty_actualmoduleInt=structletto_value(i:int):Value.t=Inti[@@inline]letof_value(n:int)(op:op_type)(v:Value.t):int=of_arg(functionInti->i|_->raise_notrace(ValueTy_int))nvop(err_strnopTy_int(Value.type_ofv))[@@inline]let_str_value(n:int)(op:op_type)(v:Value.t):string=of_arg(functionStrstr->str|_->raise_notrace(ValueTy_str))nvop(err_strnopTy_str(Value.type_ofv))letunop(op:Ty.Unop.t)(v:Value.t):Value.t=letf=matchopwith|Neg->Int.neg|Not->Int.lognot|Abs->Int.abs|_->Fmt.failwith{|unop: Unsupported int operator "%a"|}Ty.Unop.ppopinto_value(f(of_value1(`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|_->Fmt.failwith{|binop: Unsupported int operator "%a"|}Ty.Binop.ppopinto_value(f(of_value1(`Binopop)v1)(of_value2(`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)|_->Fmt.failwith{|relop: Unsupported int operator "%a"|}Ty.Relop.ppopinf(of_value1(`Relopop)v1)(of_value2(`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_value(of_boolv)|Reinterpret_float->Int(Int.of_float(matchvwithRealv->v|_->assertfalse))|_->Fmt.failwith{|cvtop: Unsupported int operator "%a"|}Ty.Cvtop.ppopendmoduleReal=structletto_value(v:float):Value.t=Realv[@@inline]letof_value(n:int)(op:op_type)(v:Value.t):float=of_arg(functionRealv->v|_->raise_notrace(ValueTy_int))nvop(err_strnopTy_real(Value.type_ofv))[@@inline]letunop(op:Ty.Unop.t)(v:Value.t):Value.t=letv=of_value1(`Unopop)vinmatchopwith|Neg->to_value@@Float.negv|Abs->to_value@@Float.absv|Sqrt->to_value@@Float.sqrtv|Nearest->to_value@@Float.roundv|Ceil->to_value@@Float.ceilv|Floor->to_value@@Float.floorv|Trunc->to_value@@Float.truncv|Is_nan->ifFloat.is_nanvthenValue.TrueelseValue.False|_->Fmt.failwith{|unop: Unsupported real operator "%a"|}Ty.Unop.ppopletbinop(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|_->Fmt.failwith{|binop: Unsupported real operator "%a"|}Ty.Binop.ppopinto_value(f(of_value1(`Binopop)v1)(of_value2(`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.(<>)|_->Fmt.failwith{|relop: Unsupported real operator "%a"|}Ty.Relop.ppopinf(of_value1(`Relopop)v1)(of_value2(`Relopop)v2)letcvtop(op:Ty.Cvtop.t)(v:Value.t):Value.t=letop'=`Cvtopopinmatchopwith|ToString->Str(Float.to_string(of_value1op'v))|OfString->letv=matchvwithStrv->v|_->raise_notrace(ValueTy_str)inbeginmatchFloat.of_string_optvwith|None->raise(Invalid_argument"float_of_int")|Somev->to_valuevend|Reinterpret_int->letv=matchvwithIntv->v|_->raise_notrace(ValueTy_int)into_value(float_of_intv)|Reinterpret_float->Int(Float.to_int(of_value1op'v))|_->Fmt.failwith{|cvtop: Unsupported real operator "%a"|}Ty.Cvtop.ppopendmoduleBool=structletto_value(b:bool):Value.t=ifbthenTrueelseFalse[@@inline]letof_value(n:int)(op:op_type)(v:Value.t):bool=of_arg(function|True->true|False->false|_->raise_notrace(ValueTy_bool))nvop(err_strnopTy_bool(Value.type_ofv))[@@inline]letunop(op:Ty.Unop.t)v=letb=of_value1(`Unopop)vinmatchopwith|Not->to_value(notb)|_->Fmt.failwith{|unop: Unsupported bool operator "%a"|}Ty.Unop.ppopletxorb1b2=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|_->Fmt.failwith{|binop: Unsupported bool operator "%a"|}Ty.Binop.ppopinto_value(f(of_value1(`Binopop)v1)(of_value2(`Binopop)v2))lettriop(op:Ty.Triop.t)cv1v2=matchopwith|Ite->(matchof_value1(`Triopop)cwithtrue->v1|false->v2)|_->Fmt.failwith{|triop: Unsupported bool operator "%a"|}Ty.Triop.ppopletrelop(op:Ty.Relop.t)v1v2=matchopwith|Eq->Value.equalv1v2|Ne->not(Value.equalv1v2)|_->Fmt.failwith{|relop: Unsupported bool operator "%a"|}Ty.Relop.ppopletnaryop(op:Ty.Naryop.t)vs=letb=matchopwith|Logand->List.fold_left(&&)true(List.mapi(funi->of_valuei(`Naryopop))vs)|Logor->List.fold_left(||)false(List.mapi(funi->of_valuei(`Naryopop))vs)|_->Fmt.failwith{|naryop: Unsupported bool operator "%a"|}Ty.Naryop.ppopinto_valuebendmoduleStr=structletto_value(str:string):Value.t=Strstr[@@inline]letof_value(n:int)(op:op_type)(v:Value.t):string=of_arg(functionStrstr->str|_->raise_notrace(ValueTy_str))nvop(err_strnopTy_str(Value.type_ofv))[@@inline]letreplacestt'=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_value1(`Unopop)vinmatchopwith|Length->Int.to_value(String.lengthstr)|Trim->to_value(String.trimstr)|_->Fmt.failwith{|unop: Unsupported str operator "%a"|}Ty.Unop.ppopletbinop(op:Ty.Binop.t)v1v2=letop'=`Binopopinletstr=of_value1op'v1inmatchopwith|At->(leti=Int.of_value2op'v2intryto_value(Fmt.str"%c"(String.getstri))withInvalid_argument_->raiseIndex_out_of_bounds)|String_prefix->Bool.to_value(String.starts_with~prefix:str(of_value2op'v2))|String_suffix->Bool.to_value(String.ends_with~suffix:str(of_value2op'v2))|String_contains->Bool.to_value(containsstr(of_value2op'v2))|_->Fmt.failwith{|binop: Unsupported str operator "%a"|}Ty.Binop.ppoplettriop(op:Ty.Triop.t)v1v2v3=letop'=`Triopopinletstr=of_value1op'v1inmatchopwith|String_extract->leti=Int.of_value2op'v2inletlen=Int.of_value3op'v3into_value(String.substrilen)|String_replace->lett=of_value2op'v2inlett'=of_value2op'v3into_value(replacestrtt')|String_index->lett=of_value2op'v2inleti=Int.of_value3op'v3inInt.to_value(indexofstrti)|_->Fmt.failwith{|triop: Unsupported str operator "%a"|}Ty.Triop.ppopletrelop(op:Ty.Relop.t)v1v2=letf=matchopwith|Lt->(<)|Le->(<=)|Gt->(>)|Ge->(>=)|Eq->(=)|Ne->(<>)|_->Fmt.failwith{|relop: Unsupported string operator "%a"|}Ty.Relop.ppopinletfxy=f(String.comparexy)0inf(of_value1(`Relopop)v1)(of_value2(`Relopop)v2)letcvtop(op:Ty.Cvtop.t)v=letop'=`Cvtopopinmatchopwith|String_to_code->letstr=of_value1op'vinInt.to_value(Char.codestr.[0])|String_from_code->letcode=Int.of_value1op'vinto_value(String.make1(Char.chrcode))|String_to_int->lets=of_value1op'vinleti=matchint_of_string_optswith|None->raise(Invalid_argument"string_to_int")|Somei->iinInt.to_valuei|String_from_int->to_value(string_of_int(Int.of_value1op'v))|String_to_float->lets=of_value1op'vinletf=matchfloat_of_string_optswith|None->raise(Invalid_argument"string_to_float")|Somef->finReal.to_valuef|_->Fmt.failwith{|cvtop: Unsupported str operator "%a"|}Ty.Cvtop.ppopletnaryop(op:Ty.Naryop.t)vs=letop'=`Naryopopinmatchopwith|Concat->to_value(String.concat""(List.map(of_value0op')vs))|_->Fmt.failwith{|naryop: Unsupported str operator "%a"|}Ty.Naryop.ppopendmoduleLst=structletof_value(n:int)(op:op_type)(v:Value.t):Value.tlist=of_arg(functionListlst->lst|_->raise_notrace(ValueTy_list))nvop(err_strnopTy_list(Value.type_ofv))[@@inline]letunop(op:Ty.Unop.t)(v:Value.t):Value.t=letlst=of_value1(`Unopop)vinmatchopwith|Head->beginmatchlstwithhd::_tl->hd|[]->assertfalseend|Tail->beginmatchlstwith_hd::tl->Listtl|[]->assertfalseend|Length->Int.to_value(List.lengthlst)|Reverse->List(List.revlst)|_->Fmt.failwith{|unop: Unsupported list operator "%a"|}Ty.Unop.ppopletbinop(op:Ty.Binop.t)v1v2=letop'=`Binopopinmatchopwith|At->letlst=of_value1op'v1inleti=Int.of_value2op'v2inbegin(* TODO: change datastructure? *)matchList.nth_optlstiwith|None->raiseIndex_out_of_bounds|Somev->vend|List_cons->List(v1::of_value1op'v2)|List_append->List(of_value1op'v1@of_value2op'v2)|_->Fmt.failwith{|binop: Unsupported list operator "%a"|}Ty.Binop.ppoplettriop(op:Ty.Triop.t)(v1:Value.t)(v2:Value.t)(v3:Value.t):Value.t=letop'=`Triopopinmatchopwith|List_set->letlst=of_value1op'v1inleti=Int.of_value2op'v2inletrecsetilstvacc=match(i,lst)with|0,_::tl->List.rev_appendacc(v::tl)|i,hd::tl->set(i-1)tlv(hd::acc)|_,[]->raiseIndex_out_of_boundsinList(setilstv3[])|_->Fmt.failwith{|triop: Unsupported list operator "%a"|}Ty.Triop.ppopletnaryop(op:Ty.Naryop.t)(vs:Value.tlist):Value.t=letop'=`Naryopopinmatchopwith|Concat->List(List.concat_map(of_value0op')vs)|_->Fmt.failwith{|naryop: Unsupported list operator "%a"|}Ty.Naryop.ppopendmoduleI64=structletcmp_uxopy=opInt64.(addxmin_int)Int64.(addymin_int)[@@inline]letlt_uxy=cmp_uxInt64.Infix.(<)y[@@inline]endmoduleBitv=structletto_valuebv:Value.t=Bitvbv[@@inline]leti32_to_valuev=to_value@@Bitvector.of_int32vleti64_to_valuev=to_value@@Bitvector.of_int64vletof_value(n:int)(op:op_type)(v:Value.t):Bitvector.t=lettodo=Ty.Ty_bitv32inof_arg(functionBitvbv->bv|_->raise_notrace(Valuetodo))nvop(err_strnoptodo(Value.type_ofv))leti32_of_valuenopv=of_valuenopv|>Bitvector.to_int32leti64_of_valuenopv=of_valuenopv|>Bitvector.to_int64letunopopbv=letbv=of_value1(`Unopop)bvinto_value@@matchopwith|Ty.Unop.Neg->Bitvector.negbv|Not->Bitvector.lognotbv|Clz->Bitvector.clzbv|Ctz->Bitvector.ctzbv|Popcnt->Bitvector.popcntbv|_->Fmt.failwith{|unop: Unsupported bitvectore operator "%a"|}Ty.Unop.ppopletbinopopbv1bv2=letbv1=of_value1(`Binopop)bv1inletbv2=of_value2(`Binopop)bv2into_value@@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|_->Fmt.failwith{|binop: unsupported bitvector operator "%a"|}Ty.Binop.ppopletrelopopbv1bv2=letbv1=of_value1(`Relopop)bv1inletbv2=of_value2(`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.equalbv1bv2endmoduleF32=structletto_float(v:int32):float=Int32.float_of_bitsv[@@inline]letof_float(v:float):int32=Int32.bits_of_floatv[@@inline]letto_value(f:int32):Value.t=Num(F32f)[@@inline]letto_value'(f:float):Value.t=to_value@@of_floatf[@@inline]letof_value(i:int)(op:op_type)(v:Value.t):int32=of_arg(functionNum(F32f)->f|_->raise_notrace(Value(Ty_fp32)))ivop(err_striop(Ty_fp32)(Value.type_ofv))[@@inline]letof_value'(i:int)(op:op_type)(v:Value.t):float=of_valueiopv|>to_float[@@inline](* Stolen from Owi *)letabsx=Int32.logandxInt32.max_intletnegx=Int32.logxorxInt32.min_intletunop(op:Ty.Unop.t)(v:Value.t):Value.t=letf=to_float@@of_value1(`Unopop)vinmatchopwith|Neg->to_value@@neg@@of_value1(`Unopop)v|Abs->to_value@@abs@@of_value1(`Unopop)v|Sqrt->to_value'@@Float.sqrtf|Nearest->to_value'@@Float.roundf|Ceil->to_value'@@Float.ceilf|Floor->to_value'@@Float.floorf|Trunc->to_value'@@Float.truncf|Is_nan->ifFloat.is_nanfthenValue.TrueelseValue.False|_->Fmt.failwith{|unop: Unsupported f32 operator "%a"|}Ty.Unop.ppop(* 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=of_value'1(`Binopop)v1inletb=of_value'1(`Binopop)v2inmatchopwith|Add->to_value'@@Float.addab|Sub->to_value'@@Float.subab|Mul->to_value'@@Float.mulab|Div->to_value'@@Float.divab|Rem->to_value'@@Float.remab|Min->to_value'@@Float.minab|Max->to_value'@@Float.maxab|Copysign->leta=of_value1(`Binopop)v1inletb=of_value1(`Binopop)v2into_value(copy_signab)|_->Fmt.failwith{|binop: Unsupported f32 operator "%a"|}Ty.Binop.ppopletrelop(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.(>=)|_->Fmt.failwith{|relop: Unsupported f32 operator "%a"|}Ty.Relop.ppopinf(of_value'1(`Relopop)v1)(of_value'2(`Relopop)v2)endmoduleF64=structletto_float(v:int64):float=Int64.float_of_bitsv[@@inline]letof_float(v:float):int64=Int64.bits_of_floatv[@@inline]letto_value(f:int64):Value.t=Num(F64f)[@@inline]letto_value'(f:float):Value.t=to_value@@of_floatf[@@inline]letof_value(i:int)(op:op_type)(v:Value.t):int64=of_arg(functionNum(F64f)->f|_->raise_notrace(Value(Ty_fp64)))ivop(err_striop(Ty_fp64)(Value.type_ofv))[@@inline]letof_value'(i:int)(op:op_type)(v:Value.t):float=of_valueiopv|>to_float[@@inline](* Stolen from owi *)letabsx=Int64.logandxInt64.max_intletnegx=Int64.logxorxInt64.min_intletunop(op:Ty.Unop.t)(v:Value.t):Value.t=letf=of_value'1(`Unopop)vinmatchopwith|Neg->to_value@@neg@@of_value1(`Unopop)v|Abs->to_value@@abs@@of_value1(`Unopop)v|Sqrt->to_value'@@Float.sqrtf|Nearest->to_value'@@Float.roundf|Ceil->to_value'@@Float.ceilf|Floor->to_value'@@Float.floorf|Trunc->to_value'@@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=of_value'1(`Binopop)v1inletb=of_value'1(`Binopop)v2inmatchopwith|Add->to_value'@@Float.addab|Sub->to_value'@@Float.subab|Mul->to_value'@@Float.mulab|Div->to_value'@@Float.divab|Rem->to_value'@@Float.remab|Min->to_value'@@Float.minab|Max->to_value'@@Float.maxab|Copysign->leta=of_value1(`Binopop)v1inletb=of_value1(`Binopop)v2into_value@@copy_signab|_->Fmt.failwith{|binop: Unsupported f32 operator "%a"|}Ty.Binop.ppopletrelop(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.(>=)|_->Fmt.failwith{|relop: Unsupported f32 operator "%a"|}Ty.Relop.ppopinf(of_value'1(`Relopop)v1)(of_value'2(`Relopop)v2)endmoduleI32CvtOp=struct(* let extend_s (n : int) (x : int32) : int32 = *)(* let shift = 32 - n in *)(* Int32.(shift_right (shift_left x shift) shift) *)lettrunc_f32_s(x:int32)=ifInt32.Infix.(x<>x)thenraiseConversion_to_integerelseletxf=F32.to_floatxinifFloat.Infix.(xf>=-.Int32.(to_floatmin_int)||xf<Int32.(to_floatmin_int))thenraiseInteger_overflowelseInt32.of_floatxflettrunc_f32_u(x:int32)=ifInt32.Infix.(x<>x)thenraiseConversion_to_integerelseletxf=F32.to_floatxinifFloat.Infix.(xf>=-.Int32.(to_floatmin_int)*.2.0||xf<=-1.0)thenraiseInteger_overflowelseInt32.of_floatxflettrunc_f64_s(x:int64)=ifInt64.Infix.(x<>x)thenraiseConversion_to_integerelseletxf=F64.to_floatxinifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)||xf<Int64.(to_floatmin_int))thenraiseInteger_overflowelseInt32.of_floatxflettrunc_f64_u(x:int64)=ifInt64.Infix.(x<>x)thenraiseConversion_to_integerelseletxf=F64.to_floatxinifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)*.2.0||xf<=-1.0)thenraiseInteger_overflowelseInt32.of_floatxflettrunc_sat_f32_sx=ifInt32.Infix.(x<>x)then0lelseletxf=F32.to_floatxinifFloat.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=F32.to_floatxinifFloat.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=F64.to_floatxinifFloat.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=F64.to_floatxinifFloat.Infix.(xf<=-1.0)then0lelseifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)*.2.0)then-1lelseInt32.of_floatxfletcvtopopv=letop'=`Cvtopopinmatchopwith|Ty.Cvtop.WrapI64->Bitv.i32_to_value(Int64.to_int32(Bitv.i64_of_value1op'v))|TruncSF32->Bitv.i32_to_value(trunc_f32_s(F32.of_value1op'v))|TruncUF32->Bitv.i32_to_value(trunc_f32_u(F32.of_value1op'v))|TruncSF64->Bitv.i32_to_value(trunc_f64_s(F64.of_value1op'v))|TruncUF64->Bitv.i32_to_value(trunc_f64_u(F64.of_value1op'v))|Trunc_sat_f32_s->Bitv.i32_to_value(trunc_sat_f32_s(F32.of_value1op'v))|Trunc_sat_f32_u->Bitv.i32_to_value(trunc_sat_f32_u(F32.of_value1op'v))|Trunc_sat_f64_s->Bitv.i32_to_value(trunc_sat_f64_s(F64.of_value1op'v))|Trunc_sat_f64_u->Bitv.i32_to_value(trunc_sat_f64_u(F64.of_value1op'v))|Reinterpret_float->Bitv.i32_to_value(F32.of_value1op'v)|Sign_extendn->Bitv.to_value(Bitvector.sign_extendn(Bitv.of_value1op'v))|Zero_extendn->Bitv.to_value(Bitvector.zero_extendn(Bitv.of_value1op'v))|OfBool->v(* already a num here *)|ToBool|_->Fmt.failwith{|cvtop: Unsupported i32 operator "%a"|}Ty.Cvtop.ppopendmoduleI64CvtOp=struct(* let extend_s n x = *)(* let shift = 64 - n in *)(* Int64.(shift_right (shift_left x shift) shift) *)letextend_i32_u(x:int32)=Int64.(logand(of_int32x)0x0000_0000_ffff_ffffL)lettrunc_f32_s(x:int32)=ifInt32.Infix.(x<>x)thenraiseConversion_to_integerelseletxf=F32.to_floatxinifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)||xf<Int64.(to_floatmin_int))thenraiseInteger_overflowelseInt64.of_floatxflettrunc_f32_u(x:int32)=ifInt32.Infix.(x<>x)thenraiseConversion_to_integerelseletxf=F32.to_floatxinifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)*.2.0||xf<=-1.0)thenraiseInteger_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)thenraiseConversion_to_integerelseletxf=F64.to_floatxinifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)||xf<Int64.(to_floatmin_int))thenraiseInteger_overflowelseInt64.of_floatxflettrunc_f64_u(x:int64)=ifInt64.Infix.(x<>x)thenraiseConversion_to_integerelseletxf=F64.to_floatxinifFloat.Infix.(xf>=-.Int64.(to_floatmin_int)*.2.0||xf<=-1.0)thenraiseInteger_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=F32.to_floatxinifFloat.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=F32.to_floatxinifFloat.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=F64.to_floatxinifFloat.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=F64.to_floatxinifFloat.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->Bitv.to_value(Bitvector.sign_extendn(Bitv.of_value1op'v))|Zero_extendn->Bitv.to_value(Bitvector.zero_extendn(Bitv.of_value1op'v))|TruncSF32->Bitv.i64_to_value(trunc_f32_s(F32.of_value1op'v))|TruncUF32->Bitv.i64_to_value(trunc_f32_u(F32.of_value1op'v))|TruncSF64->Bitv.i64_to_value(trunc_f64_s(F64.of_value1op'v))|TruncUF64->Bitv.i64_to_value(trunc_f64_u(F64.of_value1op'v))|Trunc_sat_f32_s->Bitv.i64_to_value(trunc_sat_f32_s(F32.of_value1op'v))|Trunc_sat_f32_u->Bitv.i64_to_value(trunc_sat_f32_u(F32.of_value1op'v))|Trunc_sat_f64_s->Bitv.i64_to_value(trunc_sat_f64_s(F64.of_value1op'v))|Trunc_sat_f64_u->Bitv.i64_to_value(trunc_sat_f64_u(F64.of_value1op'v))|Reinterpret_float->Bitv.i64_to_value(F64.of_value1op'v)|WrapI64->raise(TypeError{index=1;value=v;ty=Ty_bitv64;op=`CvtopWrapI64;msg="Cannot wrapI64 on an I64"})|ToBool|OfBool|_->Fmt.failwith{|cvtop: Unsupported i64 operator "%a"|}Ty.Cvtop.ppopendmoduleF32CvtOp=structletdemote_f64x=letxf=F64.to_floatxinifFloat.Infix.(xf=xf)thenF32.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=F32.of_float(Int32.to_floatx)letconvert_i32_ux=F32.of_floatInt32.(Int32.Infix.(ifx>=0lthento_floatxelseto_float(logor(shift_right_logicalx1)(logandx1l))*.2.0))letconvert_i64_sx=F32.of_floatInt64.(Int64.Infix.(ifabsx<0x10_0000_0000_0000Lthento_floatxelseletr=iflogandx0xfffL=0Lthen0Lelse1Linto_float(logor(shift_rightx12)r)*.0x1p12))letconvert_i64_ux=F32.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->F32.to_value(demote_f64(F64.of_value1op'v))|ConvertSI32->F32.to_value(convert_i32_s(Bitv.i32_of_value1op'v))|ConvertUI32->F32.to_value(convert_i32_u(Bitv.i32_of_value1op'v))|ConvertSI64->F32.to_value(convert_i64_s(Bitv.i64_of_value1op'v))|ConvertUI64->F32.to_value(convert_i64_u(Bitv.i64_of_value1op'v))|Reinterpret_int->F32.to_value(Bitv.i32_of_value1op'v)|PromoteF32->raise(TypeError{index=1;value=v;ty=Ty_fp32;op=`CvtopPromoteF32;msg="F64 must promote a F32"})|ToString|OfString|_->Fmt.failwith{|cvtop: Unsupported f32 operator "%a"|}Ty.Cvtop.ppopendmoduleF64CvtOp=structFloat.is_nanletpromote_f32x=letxf=F32.to_floatxinifFloat.Infix.(xf=xf)thenF64.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=F64.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=F64.of_floatInt64.(to_float(logand(of_int32x)0x0000_0000_ffff_ffffL))letconvert_i64_sx=F64.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)=F64.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->F64.to_value(promote_f32(F32.of_value1op'v))|ConvertSI32->F64.to_value(convert_i32_s(Bitv.i32_of_value1op'v))|ConvertUI32->F64.to_value(convert_i32_u(Bitv.i32_of_value1op'v))|ConvertSI64->F64.to_value(convert_i64_s(Bitv.i64_of_value1op'v))|ConvertUI64->F64.to_value(convert_i64_u(Bitv.i64_of_value1op'v))|Reinterpret_int->F64.to_value(Bitv.i64_of_value1op'v)|DemoteF64->raise(TypeError{index=1;value=v;ty=Ty_bitv64;op=`CvtopDemoteF64;msg="F32 must demote a F64"})|ToString|OfString|_->Fmt.failwith{|cvtop: Unsupported f64 operator "%a"|}Ty.Cvtop.ppopend(* 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->assertfalse[@@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|_->assertfalseletrelop=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|_->assertfalseletcvtop=function|Ty.Ty_int->Int.cvtop|Ty_real->Real.cvtop|Ty_str->Str.cvtop|Ty_bitv32->I32CvtOp.cvtop|Ty_bitv64->I64CvtOp.cvtop|Ty_fp32->F32CvtOp.cvtop|Ty_fp64->F64CvtOp.cvtop|_->assertfalseletnaryop=function|Ty.Ty_bool->Bool.naryop|Ty_str->Str.naryop|Ty_list->Lst.naryop|_->assertfalse