123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856(* Shared registry mapping wax SIMD intrinsic names to WebAssembly [Vec*]
instructions and back. This is the single source of truth consumed by
[to_wasm] (forward lowering), [from_wasm] (reverse reconstruction) and
[Wax_lang.Typing] (operand/result signatures).
Surface convention: a vector op is written as a method intrinsic with the
lane shape baked into the name, e.g. [a.add_i32x4(b)], [v.splat_i32x4()],
[v.extract_lane_s_i8x16(0)]. The wax name is the WAT mnemonic [A.B] rewritten
as [B_A] (so [i32x4.add] -> [add_i32x4], [v128.and] -> [and_v128]). Constants
and bitselect are free functions ([v128_i32x4(...)], [v128_bitselect]);
loads/stores are methods on a memory object ([mem.loadv128(addr)]). *)moduleText=Ast.Text(* Operand / result valtype of a SIMD intrinsic, kept abstract from the wax and
wasm valtype representations so each consumer maps it to its own. *)typety=TV128|TI32|TI64|TF32|TF64letshape_str:Ast.vec_shape->string=function|I8x16->"i8x16"|I16x8->"i16x8"|I32x4->"i32x4"|I64x2->"i64x2"|F32x4->"f32x4"|F64x2->"f64x2"letlane_count:Ast.vec_shape->int=function|I8x16->16|I16x8->8|I32x4|F32x4->4|I64x2|F64x2->2(* Scalar type of one lane, used for splat operand / extract result / replace
value. *)letlane_scalar:Ast.vec_shape->ty=function|I8x16|I16x8|I32x4->TI32|I64x2->TI64|F32x4->TF32|F64x2->TF64letsgn:Ast.signage->string=functionSigned->"_s"|Unsigned->"_u"letint_shapes=[Ast.I8x16;Ast.I16x8;Ast.I32x4;Ast.I64x2]letfloat_shapes=[Ast.F32x4;Ast.F64x2]letall_shapes=int_shapes@float_shapesletsigns=[Ast.Signed;Ast.Unsigned](****)(* Per-family naming (authoritative). The forward table below is derived by
applying these to the enumerated set of valid ops, so the two directions
cannot disagree. *)letunop_name(op:Ast.vec_un_op):string=letsuffix,prefix=matchopwith|VecNegs->("neg",shape_strs)|VecAbss->("abs",shape_strs)|VecSqrtf->("sqrt",matchfwith`F32->"f32x4"|`F64->"f64x2")|VecNot->("not","v128")|VecTruncSat(f,s)->letfs=matchfwith`F32->"f32x4"|`F64->"f64x2"in("trunc_sat_"^fs^sgns,"i32x4")|VecConvert(f,s)->letlow=matchfwith`F32->""|`F64->"low_"inletpfx=matchfwith`F32->"f32x4"|`F64->"f64x2"in("convert_"^low^"i32x4"^sgns,pfx)|VecExtend(h,sz,s)->leths=matchhwith`Low->"low"|`High->"high"inletszs=matchszwith`_8->"i8x16"|`_16->"i16x8"|`_32->"i32x4"inletpfx=matchszwith`_8->"i16x8"|`_16->"i32x4"|`_32->"i64x2"in("extend_"^hs^"_"^szs^sgns,pfx)|VecPromote->("promote_low_f32x4","f64x2")|VecDemote->("demote_f64x2_zero","f32x4")|VecCeilf->("ceil",matchfwith`F32->"f32x4"|`F64->"f64x2")|VecFloorf->("floor",matchfwith`F32->"f32x4"|`F64->"f64x2")|VecTruncf->("trunc",matchfwith`F32->"f32x4"|`F64->"f64x2")|VecNearestf->("nearest",matchfwith`F32->"f32x4"|`F64->"f64x2")|VecPopcnt->("popcnt","i8x16")|VecExtAddPairwise(s,sz)->letszs=matchszwith`I8->"i8x16"|`I16->"i16x8"inletpfx=matchszwith`I8->"i16x8"|`I16->"i32x4"in("extadd_pairwise_"^szs^sgns,pfx)|VecRelaxedTruncs->("relaxed_trunc_f32x4"^sgns,"i32x4")|VecRelaxedTruncZeros->("relaxed_trunc_f64x2"^sgns^"_zero","i32x4")insuffix^"_"^prefixletcmp_namebase(s:Ast.signageoption)(sh:Ast.vec_shape):string=match(sh,s)with|(I8x16|I16x8|I32x4|I64x2),SomeSigned->base^"_s"|(I8x16|I16x8|I32x4),SomeUnsigned->base^"_u"|(F32x4|F64x2),None->base|_->invalid_arg"Simd.cmp_name"letbinop_name(op:Ast.vec_bin_op):string=letsuffix,prefix=matchopwith|VecAdds->("add",shape_strs)|VecSubs->("sub",shape_strs)|VecMuls->("mul",shape_strs)|VecDivf->("div",matchfwith`F32->"f32x4"|`F64->"f64x2")|VecMin(s,sh)->(("min"^matchswithSomex->sgnx|None->""),shape_strsh)|VecMax(s,sh)->(("max"^matchswithSomex->sgnx|None->""),shape_strsh)|VecPMinf->("pmin",matchfwith`F32->"f32x4"|`F64->"f64x2")|VecPMaxf->("pmax",matchfwith`F32->"f32x4"|`F64->"f64x2")|VecAvgrsz->("avgr_u",matchszwith`I8->"i8x16"|`I16->"i16x8")|VecQ15MulrSat->("q15mulr_sat_s","i16x8")|VecAddSat(s,sz)->("add_sat"^sgns,matchszwith`I8->"i8x16"|`I16->"i16x8")|VecSubSat(s,sz)->("sub_sat"^sgns,matchszwith`I8->"i8x16"|`I16->"i16x8")|VecDot->("dot_i16x8_s","i32x4")|VecEqs->("eq",shape_strs)|VecNes->("ne",shape_strs)|VecLt(s,sh)->(cmp_name"lt"ssh,shape_strsh)|VecGt(s,sh)->(cmp_name"gt"ssh,shape_strsh)|VecLe(s,sh)->(cmp_name"le"ssh,shape_strsh)|VecGe(s,sh)->(cmp_name"ge"ssh,shape_strsh)|VecAnd->("and","v128")|VecOr->("or","v128")|VecXor->("xor","v128")|VecAndNot->("andnot","v128")|VecNarrow(s,sz)->letins=matchszwith`I8->"i16x8"|`I16->"i32x4"inletpfx=matchszwith`I8->"i8x16"|`I16->"i16x8"in("narrow_"^ins^sgns,pfx)|VecSwizzle->("swizzle","i8x16")|VecExtMulLow(s,sz)->letins=matchszwith`_8->"i8x16"|`_16->"i16x8"|`_32->"i32x4"inletpfx=matchszwith`_8->"i16x8"|`_16->"i32x4"|`_32->"i64x2"in("extmul_low_"^ins^sgns,pfx)|VecExtMulHigh(s,sz)->letins=matchszwith`_8->"i8x16"|`_16->"i16x8"|`_32->"i32x4"inletpfx=matchszwith`_8->"i16x8"|`_16->"i32x4"|`_32->"i64x2"in("extmul_high_"^ins^sgns,pfx)|VecRelaxedSwizzle->("relaxed_swizzle","i8x16")|VecRelaxedMins->("relaxed_min",shape_strs)|VecRelaxedMaxs->("relaxed_max",shape_strs)|VecRelaxedQ15Mulr->("relaxed_q15mulr_s","i16x8")|VecRelaxedDot->("relaxed_dot_i8x16_i7x16_s","i16x8")insuffix^"_"^prefixletternop_name(op:Ast.vec_tern_op):string=letsuffix,prefix=matchopwith|VecRelaxedMAddf->("relaxed_madd",matchfwith`F32->"f32x4"|`F64->"f64x2")|VecRelaxedNMAddf->("relaxed_nmadd",matchfwith`F32->"f32x4"|`F64->"f64x2")|VecRelaxedLaneSelects->("relaxed_laneselect",shape_strs)|VecRelaxedDotAdd->("relaxed_dot_i8x16_i7x16_add_s","i32x4")insuffix^"_"^prefixletshift_name:Ast.vec_shift_op->string=function|Shls->"shl_"^shape_strs|Shr(sg,s)->"shr"^sgnsg^"_"^shape_strslettest_name:Ast.vec_test_op->string=function|AnyTrue->"any_true_v128"|AllTrues->"all_true_"^shape_strsletbitmask_name:Ast.vec_bitmask_op->string=function|Bitmasks->"bitmask_"^shape_strsletv128_shape_str:Wax_utils.V128.shape->string=function|I8x16->"i8x16"|I16x8->"i16x8"|I32x4->"i32x4"|I64x2->"i64x2"|F32x4->"f32x4"|F64x2->"f64x2"letsplat_names="splat_"^shape_strsletreplace_names="replace_lane_"^shape_strsletshuffle_name="shuffle_i8x16"letbitselect_name="v128_bitselect"letconst_name(s:Wax_utils.V128.shape)="v128_"^v128_shape_strs(* The free-function intrinsics are spelled [v128::<member>] in Wax; the registry
keys them by the full [v128_<member>] mnemonic. These convert between the two:
[free_full "bitselect" = "v128_bitselect"], [free_member "v128_bitselect" =
"bitselect"]. *)letfree_namespace="v128"letfree_fullmember=free_namespace^"_"^memberletfree_memberfull=letp=String.lengthfree_namespace+1inString.subfullp(String.lengthfull-p)(* The [v128::] free-function members: [bitselect] and one const constructor per
shape ([i8x16] … [f64x2]). *)letfree_member_names=free_memberbitselect_name::List.map(funs->free_member(const_names))[I8x16;I16x8;I32x4;I64x2;F32x4;F64x2]letextract_names(sign:Ast.signageoption)="extract_lane"^(matchsignwithSomex->sgnx|None->"")^"_"^shape_strs(* Memory load/store names: like the scalar accesses, the access width (or the
full-width family letter, [loadv128] beside [loadf32]) is in the method
name; the widening loads keep their [_s]/[_u] suffix (both variants exist,
so the suffix carries information). *)letvec_load_name:Ast.vec_load_op->string=function|Load128->"loadv128"|Load8x8S->"load8x8_s"|Load8x8U->"load8x8_u"|Load16x4S->"load16x4_s"|Load16x4U->"load16x4_u"|Load32x2S->"load32x2_s"|Load32x2U->"load32x2_u"|Load32Zero->"load32_zero"|Load64Zero->"load64_zero"letlane_width_str:[`I8|`I16|`I32|`I64]->string=function|`I8->"8"|`I16->"16"|`I32->"32"|`I64->"64"letload_lane_namew="load"^lane_width_strw^"_lane"letstore_lane_namew="store"^lane_width_strw^"_lane"letload_splat_namew="load"^lane_width_strw^"_splat"letstore_name="storev128"letvec_load_nat_align:Ast.vec_load_op->int=function|Load128->16|Load8x8S|Load8x8U|Load16x4S|Load16x4U|Load32x2S|Load32x2U|Load64Zero->8|Load32Zero->4letlane_nat_align:[`I8|`I16|`I32|`I64]->int=function|`I8->1|`I16->2|`I32->4|`I64->8(****)(* Forward direction: a method or free-function intrinsic taking stack operands
and possibly trailing constant lane immediates (memory ops are handled
separately by [mem_method]). *)typeimm=|No_imm|LaneofAst.vec_shape(** one lane index, [0 <= n < lane_count shape] *)|Shuffle(** exactly 16 indices, each [0 <= n < 32] *)typeintrinsic={operands:tylist;(** receiver-first stack operand types *)result:tyoption;imm:imm;free:bool;(** [true]: free function [f(args)]; [false]: method [recv.f(args)] *)build:intlist->Ast.locationText.instr_desc;(** lane immediates (in source order) -> instruction *)}letshuffle_stringlanes=String.init16(funi->Char.chr(List.nthlanesiland0xff))(* Enumerations of valid ops, mirroring what the WAT validator accepts. *)letunops:Ast.vec_un_oplist=letf32f64=[`F32;`F64]inList.concat[List.map(funs->Ast.VecNegs)all_shapes;List.map(funs->Ast.VecAbss)all_shapes;List.map(funf->Ast.VecSqrtf)f32f64;[VecNot;VecPopcnt;VecPromote;VecDemote];List.concat_map(funf->List.map(funs->Ast.VecTruncSat(f,s))signs)f32f64;List.concat_map(funf->List.map(funs->Ast.VecConvert(f,s))signs)f32f64;List.concat_map(funh->List.concat_map(funsz->List.map(funs->Ast.VecExtend(h,sz,s))signs)[`_8;`_16;`_32])[`Low;`High];List.map(funf->Ast.VecCeilf)f32f64;List.map(funf->Ast.VecFloorf)f32f64;List.map(funf->Ast.VecTruncf)f32f64;List.map(funf->Ast.VecNearestf)f32f64;List.concat_map(funsz->List.map(funs->Ast.VecExtAddPairwise(s,sz))signs)[`I8;`I16];List.map(funs->Ast.VecRelaxedTruncs)signs;List.map(funs->Ast.VecRelaxedTruncZeros)signs;]letbinops:Ast.vec_bin_oplist=letf32f64=[`F32;`F64]inleti8i16=[`I8;`I16]inleti8i16i32=[`_8;`_16;`_32]inletint_min_max=[Ast.I8x16;Ast.I16x8;Ast.I32x4]inletcmp_combos=List.concat[List.map(funsh->(SomeAst.Signed,sh))int_shapes;List.map(funsh->(SomeAst.Unsigned,sh))[Ast.I8x16;Ast.I16x8;Ast.I32x4];List.map(funsh->(None,sh))float_shapes;]inList.concat[List.map(funs->Ast.VecAdds)all_shapes;List.map(funs->Ast.VecSubs)all_shapes;List.map(funs->Ast.VecMuls)[Ast.I16x8;Ast.I32x4;Ast.I64x2;Ast.F32x4;Ast.F64x2];List.map(funf->Ast.VecDivf)f32f64;List.concat_map(funs->List.map(funsh->Ast.VecMin(Somes,sh))int_min_max)signs;List.map(funsh->Ast.VecMin(None,sh))float_shapes;List.concat_map(funs->List.map(funsh->Ast.VecMax(Somes,sh))int_min_max)signs;List.map(funsh->Ast.VecMax(None,sh))float_shapes;List.map(funf->Ast.VecPMinf)f32f64;List.map(funf->Ast.VecPMaxf)f32f64;List.map(funsz->Ast.VecAvgrsz)i8i16;[VecQ15MulrSat;VecDot];List.concat_map(funs->List.map(funsz->Ast.VecAddSat(s,sz))i8i16)signs;List.concat_map(funs->List.map(funsz->Ast.VecSubSat(s,sz))i8i16)signs;List.map(funs->Ast.VecEqs)all_shapes;List.map(funs->Ast.VecNes)all_shapes;List.map(fun(s,sh)->Ast.VecLt(s,sh))cmp_combos;List.map(fun(s,sh)->Ast.VecGt(s,sh))cmp_combos;List.map(fun(s,sh)->Ast.VecLe(s,sh))cmp_combos;List.map(fun(s,sh)->Ast.VecGe(s,sh))cmp_combos;[VecAnd;VecOr;VecXor;VecAndNot;VecSwizzle;VecRelaxedSwizzle];List.concat_map(funs->List.map(funsz->Ast.VecNarrow(s,sz))i8i16)signs;List.concat_map(funs->List.map(funsz->Ast.VecExtMulLow(s,sz))i8i16i32)signs;List.concat_map(funs->List.map(funsz->Ast.VecExtMulHigh(s,sz))i8i16i32)signs;List.map(funs->Ast.VecRelaxedMins)float_shapes;List.map(funs->Ast.VecRelaxedMaxs)float_shapes;[VecRelaxedQ15Mulr;VecRelaxedDot];]letternops:Ast.vec_tern_oplist=letf32f64=[`F32;`F64]inList.concat[List.map(funf->Ast.VecRelaxedMAddf)f32f64;List.map(funf->Ast.VecRelaxedNMAddf)f32f64;List.map(funs->Ast.VecRelaxedLaneSelects)all_shapes;[VecRelaxedDotAdd];]letv128=SomeTV128letuniform1=[TV128]letuniform2=[TV128;TV128]lettable:(string,intrinsic)Hashtbl.t=lett=Hashtbl.create512inletaddnamei=Hashtbl.replacetnameiinletsimplenameoperandsresultinstr=addname{operands;result;imm=No_imm;free=false;build=(fun_->instr)}inList.iter(funop->simple(unop_nameop)uniform1v128(Text.VecUnOpop))unops;List.iter(funop->simple(binop_nameop)uniform2v128(Text.VecBinOpop))binops;List.iter(funop->simple(ternop_nameop)[TV128;TV128;TV128]v128(Text.VecTernOpop))ternops;(* shifts: vector, then i32 count *)List.iter(funs->simple(shift_name(Shls))[TV128;TI32]v128(Text.VecShift(Shls)))int_shapes;List.iter(funsg->List.iter(funs->simple(shift_name(Shr(sg,s)))[TV128;TI32]v128(Text.VecShift(Shr(sg,s))))int_shapes)signs;(* tests / bitmask: vector -> i32 *)simple(test_nameAnyTrue)uniform1(SomeTI32)(Text.VecTestAnyTrue);List.iter(funs->simple(test_name(AllTrues))uniform1(SomeTI32)(Text.VecTest(AllTrues)))int_shapes;List.iter(funs->simple(bitmask_name(Bitmasks))uniform1(SomeTI32)(Text.VecBitmask(Bitmasks)))int_shapes;(* splat: scalar lane -> vector *)List.iter(funs->simple(splat_names)[lane_scalars]v128(Text.VecSplats))all_shapes;(* bitselect: three vectors -> vector (free function) *)addbitselect_name{operands=[TV128;TV128;TV128];result=v128;imm=No_imm;free=true;build=(fun_->Text.VecBitselect);};(* extract_lane: vector + lane immediate -> scalar *)List.iter(funs->letsigns_for=matchswith|Ast.I8x16|Ast.I16x8->[SomeAst.Signed;SomeAst.Unsigned]|_->[None]inList.iter(funsign->add(extract_namessign){operands=uniform1;result=Some(lane_scalars);imm=Lanes;free=false;build=(funlanes->Text.VecExtract(s,sign,List.hdlanes));})signs_for)all_shapes;(* replace_lane: vector + scalar value + lane immediate -> vector *)List.iter(funs->add(replace_names){operands=[TV128;lane_scalars];result=v128;imm=Lanes;free=false;build=(funlanes->Text.VecReplace(s,List.hdlanes));})all_shapes;(* shuffle: two vectors + 16 lane immediates -> vector *)addshuffle_name{operands=uniform2;result=v128;imm=Shuffle;free=false;build=(funlanes->Text.VecShuffle(shuffle_stringlanes));};tletclassifyname=Hashtbl.find_opttablenameletmethod_namesrecv_ty=Hashtbl.fold(funnameiacc->matchi.operandswith|hd::_when(noti.free)&&hd=recv_ty->name::acc|_->acc)table[]|>List.sortcompareletconst_shape_of_namename:Wax_utils.V128.shapeoption=letprefix="v128_"inifString.lengthname>String.lengthprefix&&String.subname0(String.lengthprefix)=prefixthenmatchString.subname(String.lengthprefix)(String.lengthname-String.lengthprefix)with|"i8x16"->SomeI8x16|"i16x8"->SomeI16x8|"i32x4"->SomeI32x4|"i64x2"->SomeI64x2|"f32x4"->SomeF32x4|"f64x2"->SomeF64x2|_->NoneelseNone(* Reserved free-function intrinsic names (vs. user functions). *)letis_free_intrinsicname=name=bitselect_name||const_shape_of_namename<>None(* Number of lane literals in a [v128_<shape>] const call. *)letconst_arity:Wax_utils.V128.shape->int=function|I8x16->16|I16x8->8|I32x4|F32x4->4|I64x2|F64x2->2letconst_is_float:Wax_utils.V128.shape->bool=function|F32x4|F64x2->true|_->false(****)(* Memory loads/stores ([mem.loadv128], [mem.load8_lane], …). The receiver is the memory object, not a
stack value; [m_operands] are the stack operands (address, then maybe the
stored/lane vector), followed by an optional constant lane immediate and the
usual trailing [align]/[offset] literals. *)typemem_intrinsic={m_operands:tylist;(** address first, then vector for store/lane ops *)m_result:tyoption;m_lane:bool;(** a trailing constant lane immediate is present *)m_nat_align:int;m_make:Text.idx->Ast.memarg->int->Ast.locationText.instr_desc;(** memory index, memarg, lane (0 if [not m_lane]) -> instruction *)}letmem_methodname:mem_intrinsicoption=letloadopnat=Some{m_operands=[TI32];m_result=v128;m_lane=false;m_nat_align=nat;m_make=(funmma_->Text.VecLoad(m,op,ma));}inletload_splatwnat=Some{m_operands=[TI32];m_result=v128;m_lane=false;m_nat_align=nat;m_make=(funmma_->Text.VecLoadSplat(m,w,ma));}inletload_lanewnat=Some{m_operands=[TI32;TV128];m_result=v128;m_lane=true;m_nat_align=nat;m_make=(funmmal->Text.VecLoadLane(m,w,ma,l));}inletstore_lanewnat=Some{m_operands=[TI32;TV128];m_result=None;m_lane=true;m_nat_align=nat;m_make=(funmmal->Text.VecStoreLane(m,w,ma,l));}inmatchnamewith|"loadv128"->loadLoad12816|"load8x8_s"->loadLoad8x8S8|"load8x8_u"->loadLoad8x8U8|"load16x4_s"->loadLoad16x4S8|"load16x4_u"->loadLoad16x4U8|"load32x2_s"->loadLoad32x2S8|"load32x2_u"->loadLoad32x2U8|"load32_zero"->loadLoad32Zero4|"load64_zero"->loadLoad64Zero8|"storev128"->Some{m_operands=[TI32;TV128];m_result=None;m_lane=false;m_nat_align=16;m_make=(funmma_->Text.VecStore(m,ma));}|"load8_splat"->load_splat`I81|"load16_splat"->load_splat`I162|"load32_splat"->load_splat`I324|"load64_splat"->load_splat`I648|"load8_lane"->load_lane`I81|"load16_lane"->load_lane`I162|"load32_lane"->load_lane`I324|"load64_lane"->load_lane`I648|"store8_lane"->store_lane`I81|"store16_lane"->store_lane`I162|"store32_lane"->store_lane`I324|"store64_lane"->store_lane`I648|_->Noneletis_mem_methodname=mem_methodname<>None(* Every SIMD memory-access method name ([loadv128], [store8_lane], …),
for completion after [mem.]. The set [mem_method] recognises. *)letmem_method_names=letwidths=[`I8;`I16;`I32;`I64]inList.mapvec_load_name[Load128;Load8x8S;Load8x8U;Load16x4S;Load16x4U;Load32x2S;Load32x2U;Load32Zero;Load64Zero;]@(store_name::List.mapload_splat_namewidths)@List.mapload_lane_namewidths@List.mapstore_lane_namewidths(* {1 WebAssembly text (WAT) mnemonics for plain vector instructions}
The "plain" vector instructions are those the WAT lexer emits as a single
[INSTR] token — splat, unop, binop, shift, test, bitmask — i.e. those with no
trailing immediate. Their WAT mnemonics live here so that output.ml (printing)
and the WAT lexer (recognising) share one source. The immediate/memory ops
(extract, replace, shuffle, ternary, loads/stores) use dedicated tokens and
keep their own handling. *)letwat_shape=function|Ast.I8x16->"i8x16"|Ast.I16x8->"i16x8"|Ast.I32x4->"i32x4"|Ast.I64x2->"i64x2"|Ast.F32x4->"f32x4"|Ast.F64x2->"f64x2"letwat_signageop(s:Ast.signage)=op^matchswithAst.Signed->"_s"|Ast.Unsigned->"_u"letwat_un_opop=letopenAstinmatchopwith|VecNeg_->"neg"|VecAbs_->"abs"|VecSqrt_->"sqrt"|VecNot->"not"|VecTruncSat(f,s)->(matchfwith|`F32->wat_signage"trunc_sat_f32x4"s|`F64->wat_signage"trunc_sat_f64x2"s^"_zero")|VecConvert(f,s)->letlow=matchfwith`F32->""|`F64->"low_"inwat_signage("convert_"^low^"i32x4")s|VecExtend(h,sz,s)->leth_str=matchhwith`Low->"low"|`High->"high"inletsz_str=matchszwith`_8->"i8x16"|`_16->"i16x8"|`_32->"i32x4"inwat_signage("extend_"^h_str^"_"^sz_str)s|VecPromote->"promote_low_f32x4"|VecDemote->"demote_f64x2_zero"|VecCeil_->"ceil"|VecFloor_->"floor"|VecTrunc_->"trunc"|VecNearest_->"nearest"|VecPopcnt->"popcnt"|VecExtAddPairwise(s,sz)->wat_signage("extadd_pairwise_"^matchszwith`I8->"i8x16"|`I16->"i16x8")s|VecRelaxedTruncs->wat_signage"relaxed_trunc_f32x4"s|VecRelaxedTruncZeros->wat_signage"relaxed_trunc_f64x2"s^"_zero"letwat_bin_opop=letopenAstinmatchopwith|VecAdd_->"add"|VecSub_->"sub"|VecMul_->"mul"|VecDiv_->"div"|VecMin(s,_)->"min"^Option.fold~none:""~some:(funs->wat_signage""s)s|VecMax(s,_)->"max"^Option.fold~none:""~some:(funs->wat_signage""s)s|VecPMin_->"pmin"|VecPMax_->"pmax"|VecAvgr_->"avgr_u"|VecQ15MulrSat->"q15mulr_sat_s"|VecAddSat(s,_)->wat_signage"add_sat"s|VecSubSat(s,_)->wat_signage"sub_sat"s|VecDot->"dot_i16x8_s"|VecEq_->"eq"|VecNe_->"ne"|VecLt(s,shape)->(match(shape,s)with|(I8x16|I16x8|I32x4|I64x2),SomeSigned->"lt_s"|(I8x16|I16x8|I32x4),SomeUnsigned->"lt_u"|(F32x4|F64x2),None->"lt"|_->assertfalse)|VecGt(s,shape)->(match(shape,s)with|(I8x16|I16x8|I32x4|I64x2),SomeSigned->"gt_s"|(I8x16|I16x8|I32x4),SomeUnsigned->"gt_u"|(F32x4|F64x2),None->"gt"|_->assertfalse)|VecLe(s,shape)->(match(shape,s)with|(I8x16|I16x8|I32x4|I64x2),SomeSigned->"le_s"|(I8x16|I16x8|I32x4),SomeUnsigned->"le_u"|(F32x4|F64x2),None->"le"|_->assertfalse)|VecGe(s,shape)->(match(shape,s)with|(I8x16|I16x8|I32x4|I64x2),SomeSigned->"ge_s"|(I8x16|I16x8|I32x4),SomeUnsigned->"ge_u"|(F32x4|F64x2),None->"ge"|_->assertfalse)|VecAnd->"and"|VecOr->"or"|VecXor->"xor"|VecAndNot->"andnot"|VecNarrow(s,sh)->letin_shape=matchshwith`I8->"i16x8"|`I16->"i32x4"inwat_signage("narrow_"^in_shape)s|VecSwizzle->"swizzle"|VecExtMulLow(s,sh)->letin_shape=matchshwith`_8->"i8x16"|`_16->"i16x8"|`_32->"i32x4"inwat_signage("extmul_low_"^in_shape)s|VecExtMulHigh(s,sh)->letin_shape=matchshwith`_8->"i8x16"|`_16->"i16x8"|`_32->"i32x4"inwat_signage("extmul_high_"^in_shape)s|VecRelaxedSwizzle->"relaxed_swizzle"|VecRelaxedMin_->"relaxed_min"|VecRelaxedMax_->"relaxed_max"|VecRelaxedQ15Mulr->"relaxed_q15mulr_s"|VecRelaxedDot->"relaxed_dot_i8x16_i7x16_s"letwat_un_op_shapeop=letopenAstinmatchopwith|VecNegs|VecAbss->wat_shapes|VecPopcnt->"i8x16"|VecNot->"v128"|VecTruncSat_->wat_shapeI32x4|VecCeilf|VecFloorf|VecTruncf|VecNearestf|VecSqrtf|VecConvert(f,_)->wat_shape(matchfwith`F32->F32x4|`F64->F64x2)|VecExtend(_,sz,_)->wat_shape(matchszwith`_8->I16x8|`_16->I32x4|`_32->I64x2)|VecPromote->wat_shapeF64x2|VecDemote->wat_shapeF32x4|VecExtAddPairwise(_,sz)->wat_shape(matchszwith`I8->I16x8|`I16->I32x4)|VecRelaxedTrunc_|VecRelaxedTruncZero_->wat_shapeI32x4letwat_bin_op_shapeop=letopenAstinmatchopwith|VecAdds|VecSubs|VecMuls|VecMin(_,s)|VecMax(_,s)|VecEqs|VecNes|VecLt(_,s)|VecGt(_,s)|VecLe(_,s)|VecGe(_,s)->wat_shapes|VecDivs|VecPMins|VecPMaxs->(matchswith`F32->"f32x4"|`F64->"f64x2")|VecDot->"i32x4"|VecNarrow(_,s)|VecAvgrs|VecAddSat(_,s)|VecSubSat(_,s)->(matchswith`I8->"i8x16"|`I16->"i16x8")|VecAnd|VecOr|VecXor|VecAndNot->"v128"|VecSwizzle|VecRelaxedSwizzle->"i8x16"|VecQ15MulrSat->"i16x8"|VecRelaxedMins|VecRelaxedMaxs->wat_shapes|VecRelaxedQ15Mulr->"i16x8"|VecRelaxedDot->"i16x8"|VecExtMulLow(_,s)|VecExtMulHigh(_,s)->wat_shape(matchswith`_8->I16x8|`_16->I32x4|`_32->I64x2)(* The WAT mnemonic of a plain vector instruction; [None] for any other. *)letwat_mnemonic(desc:_Ast.Text.instr_desc):stringoption=letopenAst.Textinmatchdescwith|VecSplatsh->Some(wat_shapesh^".splat")|VecUnOpop->Some(wat_un_op_shapeop^"."^wat_un_opop)|VecBinOpop->Some(wat_bin_op_shapeop^"."^wat_bin_opop)|VecTestop->(matchopwith|AnyTrue->Some"v128.any_true"|AllTrueshape->Some(wat_shapeshape^".all_true"))|VecShiftop->(matchopwith|Shlshape->Some(wat_shapeshape^".shl")|Shr(s,shape)->Some(wat_signage(wat_shapeshape^".shr")s))|VecBitmask(Bitmasks)->Some(wat_shapes^".bitmask")|_->None(* Every plain vector instruction, for the WAT lexer to fold into its keyword
table. Mirrors the valid sets accepted by the validator. *)letplain_vec_instrs:Ast.locationAst.Text.instr_desclist=letopenAst.TextinList.concat[List.map(funs->VecSplats)all_shapes;List.map(funo->VecUnOpo)unops;List.map(funo->VecBinOpo)binops;List.map(funs->VecTest(AllTrues))int_shapes;[VecTestAnyTrue];List.concat_map(funs->[VecShift(Shls);VecShift(Shr(Signed,s));VecShift(Shr(Unsigned,s));])int_shapes;List.map(funs->VecBitmask(Bitmasks))int_shapes;]