| open Reference_interpreter |
| open Ast |
| open Types |
| open Value |
| open Al.Ast |
| open Al.Al_util |
| open Al.Print |
| open Source |
| open Util |
| |
| |
| (* Errors *) |
| |
| exception WrongConversion of string |
| |
| let error category msg = |
| raise (WrongConversion (Printf.sprintf "%s: invalid construction %s" category msg)) |
| |
| let error_value category v = error category ("`" ^ string_of_value v ^ "`") |
| |
| let error_values category vs = error category ("`[" ^ string_of_values ", " vs ^ "]`") |
| |
| let error_instr category instr' = |
| error category ("`" ^ Reference_interpreter.Sexpr.to_string 60 (Arrange.instr (instr' @@ no_region)) ^ "`") |
| |
| (* Constant *) |
| |
| let version = ref 3 |
| |
| |
| (* Destruct *) |
| |
| (* Destruct data structure *) |
| |
| let al_to_opt (f: value -> 'a) (v: value): 'a option = unwrap_optv v |> Option.map f |
| let al_to_list (f: value -> 'a) (v: value): 'a list = |
| unwrap_listv v |> (!) |> Array.to_list |> List.map f |
| let al_to_seq f s = al_to_list f s |> List.to_seq |
| let al_to_phrase (f: value -> 'a) (v: value): 'a phrase = f v @@ no_region |
| |
| |
| (* Destruct minor *) |
| |
| type layout = { width : int; exponent : int; mantissa : int } |
| let layout32 = { width = 32; exponent = 8; mantissa = 23 } |
| let layout64 = { width = 64; exponent = 11; mantissa = 52 } |
| |
| let mask_sign layout = Z.shift_left Z.one (layout.width - 1) |
| let mask_mag layout = Z.pred (mask_sign layout) |
| let mask_mant layout = Z.(pred (shift_left one layout.mantissa)) |
| let mask_exp layout = Z.(mask_mag layout - mask_mant layout) |
| let bias layout = let em1 = layout.exponent - 1 in Z.((one + one)**em1 - one) |
| |
| let al_to_z_nat: value -> Z.t = unwrap_natv |
| let al_to_z_int: value -> Z.t = unwrap_intv |
| let z_to_intN signed unsigned z = if z < Z.zero then signed z else unsigned z |
| |
| let al_to_fmagN layout = function |
| | CaseV ("NORM", [ m; n ]) -> |
| Z.(shift_left (al_to_z_int n + bias layout) layout.mantissa + al_to_z_nat m) |
| | CaseV ("SUBNORM", [ m ]) -> al_to_z_nat m |
| | CaseV ("INF", []) -> mask_exp layout |
| | CaseV ("NAN", [ m ]) -> Z.(mask_exp layout + al_to_z_nat m) |
| | v -> error_value "fmagN" v |
| |
| let al_to_floatN layout = function |
| | CaseV ("POS", [ mag ]) -> al_to_fmagN layout mag |
| | CaseV ("NEG", [ mag ]) -> Z.(mask_sign layout + al_to_fmagN layout mag) |
| | v -> error_value "floatN" v |
| |
| let e64 = Z.(shift_left one 64) |
| let z_to_vec128 i = |
| let hi, lo = Z.div_rem i e64 in |
| V128.I64x2.of_lanes [Z.to_int64_unsigned lo; Z.to_int64_unsigned hi] |
| |
| let al_to_nat (v: value): int = al_to_z_nat v |> Z.to_int |
| let al_to_nat8 (v: value): I8.t = al_to_z_nat v |> Z.to_int |> I8.of_int_u |
| let al_to_int8 (v: value): I8.t = al_to_z_nat v |> Z.to_int |> I8.of_int_s |
| let al_to_int16 (v: value): I16.t = al_to_z_nat v |> Z.to_int |> I16.of_int_s |
| let al_to_nat32 (v: value): I32.t = al_to_z_nat v |> z_to_intN Z.to_int32 Z.to_int32_unsigned |
| let al_to_nat64 (v: value): I64.t = al_to_z_nat v |> z_to_intN Z.to_int64 Z.to_int64_unsigned |
| let al_to_float32 (v: value): F32.t = al_to_floatN layout32 v |> Z.to_int32_unsigned |> F32.of_bits |
| let al_to_float64 (v: value): F64.t = al_to_floatN layout64 v |> Z.to_int64_unsigned |> F64.of_bits |
| let al_to_vec128 (v: value): V128.t = al_to_z_nat v |> z_to_vec128 |
| let al_to_idx: value -> idx = al_to_phrase al_to_nat32 |
| let al_to_byte (v: value): Char.t = al_to_nat v |> Char.chr |
| let al_to_bytes (v: value): string = al_to_seq al_to_byte v |> String.of_seq |
| let al_to_string = function |
| | TextV str -> str |
| | v -> error_value "text" v |
| let al_to_name name = name |> al_to_string |> Utf8.decode |
| let al_to_bool = unwrap_boolv |
| |
| |
| (* Destruct type *) |
| |
| let al_to_null: value -> null = function |
| | OptV None -> NoNull |
| | OptV _ -> Null |
| | v -> error_value "null" v |
| |
| let al_to_final: value -> final = function |
| | OptV None -> NoFinal |
| | OptV _ -> Final |
| | v -> error_value "final" v |
| |
| let al_to_mut: value -> mut = function |
| | OptV None -> Cons |
| | OptV _ -> Var |
| | v -> error_value "mut" v |
| |
| let rec al_to_storagetype: value -> storagetype = function |
| | CaseV ("I8", []) -> PackStorageT I8T |
| | CaseV ("I16", []) -> PackStorageT I16T |
| | v -> ValStorageT (al_to_valtype v) |
| |
| and al_to_fieldtype: value -> fieldtype = function |
| | CaseV (_, [ mut; st ]) -> FieldT (al_to_mut mut, al_to_storagetype st) |
| | v -> error_value "fieldtype" v |
| |
| and al_to_resulttype: value -> resulttype = function |
| v -> al_to_list al_to_valtype v |
| |
| and al_to_comptype: value -> comptype = function |
| | CaseV ("STRUCT", [ ftl ]) -> StructT (al_to_list al_to_fieldtype ftl) |
| | CaseV ("ARRAY", [ ft ]) -> ArrayT (al_to_fieldtype ft) |
| | CaseV ("->", [ rt1; rt2 ]) -> FuncT (al_to_resulttype rt1, (al_to_resulttype rt2)) |
| | v -> error_value "comptype" v |
| |
| and al_to_subtype: value -> subtype = function |
| | CaseV ("SUB", [ fin; tul; st ]) -> |
| SubT (al_to_final fin, al_to_list al_to_typeuse tul, al_to_comptype st) |
| | v -> error_value "subtype" v |
| |
| and al_to_rectype: value -> rectype = function |
| | CaseV ("REC", [ stl ]) -> RecT (al_to_list al_to_subtype stl) |
| | v -> error_value "rectype" v |
| |
| and al_to_deftype: value -> deftype = function |
| | CaseV ("_DEF", [ rt; i32 ]) -> DefT (al_to_rectype rt, al_to_nat32 i32) |
| | v -> error_value "deftype" v |
| |
| and al_to_typeuse: value -> typeuse = function |
| | v when !version <= 2 -> Idx (al_to_idx v).it |
| | CaseV ("_IDX", [ idx ]) -> Idx (al_to_idx idx).it |
| | CaseV ("REC", [ n ]) -> Rec (al_to_nat32 n) |
| | CaseV ("_DEF", _) as dt -> Def (al_to_deftype dt) |
| | v -> error_value "typeuse" v |
| |
| and al_to_idx_of_typeuse: value -> idx = function |
| | v when !version <= 2 -> al_to_idx v |
| | CaseV ("_IDX", [ idx ]) -> al_to_idx idx |
| | v -> error_value "idx_of_typeuse" v |
| |
| and al_to_heaptype: value -> heaptype = function |
| | CaseV (tag, []) as v -> |
| (match tag with |
| | "BOT" -> BotHT |
| | "ANY" -> AnyHT |
| | "NONE" -> NoneHT |
| | "EQ" -> EqHT |
| | "I31" -> I31HT |
| | "STRUCT" -> StructHT |
| | "ARRAY" -> ArrayHT |
| | "FUNC" | "FUNCREF" -> FuncHT |
| | "NOFUNC" -> NoFuncHT |
| | "EXN" | "EXNREF" -> ExnHT |
| | "NOEXN" -> NoExnHT |
| | "EXTERN" | "EXTERNREF" -> ExternHT |
| | "NOEXTERN" -> NoExternHT |
| | _ -> error_value "absheaptype" v) |
| | CaseV (("_IDX" | "REC" | "_DEF"), _) as v -> UseHT (al_to_typeuse v) |
| | v -> error_value "heaptype" v |
| |
| and al_to_reftype: value -> reftype = function |
| | CaseV ("REF", [ n; ht ]) -> al_to_null n, al_to_heaptype ht |
| | v -> error_value "reftype" v |
| |
| and al_to_addrtype: value -> addrtype = function |
| | CaseV ("I32", []) -> I32AT |
| | CaseV ("I64", []) -> I64AT |
| | v -> error_value "addrtype" v |
| |
| and al_to_numtype: value -> numtype = function |
| | CaseV ("I32", []) -> I32T |
| | CaseV ("I64", []) -> I64T |
| | CaseV ("F32", []) -> F32T |
| | CaseV ("F64", []) -> F64T |
| | v -> error_value "numtype" v |
| |
| and al_to_packtype: value -> packtype = function |
| | CaseV ("I8", []) -> I8T |
| | CaseV ("I16", []) -> I16T |
| | v -> error_value "packtype" v |
| |
| and al_to_valtype: value -> valtype = function |
| | CaseV ("I32", _) | CaseV ("I64", _) |
| | CaseV ("F32", _) | CaseV ("F64", _) as v -> NumT (al_to_numtype v) |
| | CaseV ("V128", []) -> VecT V128T |
| | CaseV ("REF", _) as v -> RefT (al_to_reftype v) |
| | CaseV ("BOT", []) -> BotT |
| | v -> error_value "valtype" v |
| |
| let al_to_blocktype: value -> blocktype = function |
| | CaseV ("_IDX", [ idx ]) -> VarBlockType (al_to_idx idx) |
| | CaseV ("_RESULT", [ vt_opt ]) -> ValBlockType (al_to_opt al_to_valtype vt_opt) |
| | v -> error_value "blocktype" v |
| |
| let al_to_limits: value -> limits = function |
| | CaseV ("[", [ min; max ]) -> { min = al_to_nat64 min; max = al_to_opt al_to_nat64 max } |
| | v -> error_value "limits" v |
| |
| |
| let al_to_globaltype: value -> globaltype = function |
| | TupV [ mut; vt ] | CaseV (_, [ mut; vt ]) -> GlobalT (al_to_mut mut, al_to_valtype vt) |
| | v -> error_value "globaltype" v |
| |
| let al_to_tabletype: value -> tabletype = function |
| | TupV [ at; limits; rt ] | CaseV (_, [ at; limits; rt ]) -> TableT (al_to_addrtype at, al_to_limits limits, al_to_reftype rt) |
| | v -> error_value "tabletype" v |
| |
| let al_to_memorytype: value -> memorytype = function |
| | CaseV ("PAGE", [ at; limits ]) -> MemoryT (al_to_addrtype at, al_to_limits limits) |
| | v -> error_value "memorytype" v |
| |
| let al_to_tagtype: value -> tagtype = function |
| | tu -> TagT (al_to_typeuse tu) |
| |
| |
| (* Destruct operator *) |
| |
| let num i = `Nat (Z.of_int i) |
| let two = num 2 |
| let four = num 4 |
| let eight = num 8 |
| let sixteen = num 16 |
| let thirtytwo = num 32 |
| let sixtyfour = num 64 |
| |
| let al_to_sx : value -> Pack.sx = function |
| | CaseV ("S", []) -> Pack.S |
| | CaseV ("U", []) -> Pack.U |
| | v -> error_value "sx" v |
| |
| let al_to_op f1 f2 = function |
| | [ CaseV ("I32", []); op ] -> I32 (f1 op) |
| | [ CaseV ("I64", []); op ] -> I64 (f1 op) |
| | [ CaseV ("F32", []); op ] -> F32 (f2 op) |
| | [ CaseV ("F64", []); op ] -> F64 (f2 op) |
| | l -> error_values "op" l |
| |
| let al_to_int_unop: value -> IntOp.unop = function |
| | CaseV ("CLZ", []) -> IntOp.Clz |
| | CaseV ("CTZ", []) -> IntOp.Ctz |
| | CaseV ("POPCNT", []) -> IntOp.Popcnt |
| | CaseV ("EXTEND", [NumV z]) when z = eight -> IntOp.ExtendS Pack.Pack8 |
| | CaseV ("EXTEND", [NumV z]) when z = sixteen -> IntOp.ExtendS Pack.Pack16 |
| | CaseV ("EXTEND", [NumV z]) when z = thirtytwo -> IntOp.ExtendS Pack.Pack32 |
| | CaseV ("EXTEND", [NumV z]) when z = sixtyfour -> IntOp.ExtendS Pack.Pack64 |
| | v -> error_value "integer unop" v |
| let al_to_float_unop: value -> FloatOp.unop = function |
| | CaseV ("NEG", []) -> FloatOp.Neg |
| | CaseV ("ABS", []) -> FloatOp.Abs |
| | CaseV ("CEIL", []) -> FloatOp.Ceil |
| | CaseV ("FLOOR", []) -> FloatOp.Floor |
| | CaseV ("TRUNC", []) -> FloatOp.Trunc |
| | CaseV ("NEAREST", []) -> FloatOp.Nearest |
| | CaseV ("SQRT", []) -> FloatOp.Sqrt |
| | v -> error_value "float unop" v |
| let al_to_unop: value list -> Ast.unop = al_to_op al_to_int_unop al_to_float_unop |
| |
| let al_to_int_binop: value -> IntOp.binop = function |
| | CaseV ("ADD", []) -> IntOp.Add |
| | CaseV ("SUB", []) -> IntOp.Sub |
| | CaseV ("MUL", []) -> IntOp.Mul |
| | CaseV ("DIV", [sx]) -> IntOp.Div (al_to_sx sx) |
| | CaseV ("REM", [sx]) -> IntOp.Rem (al_to_sx sx) |
| | CaseV ("AND", []) -> IntOp.And |
| | CaseV ("OR", []) -> IntOp.Or |
| | CaseV ("XOR", []) -> IntOp.Xor |
| | CaseV ("SHL", []) -> IntOp.Shl |
| | CaseV ("SHR", [sx]) -> IntOp.Shr (al_to_sx sx) |
| | CaseV ("ROTL", []) -> IntOp.Rotl |
| | CaseV ("ROTR", []) -> IntOp.Rotr |
| | v -> error_value "integer binop" v |
| let al_to_float_binop: value -> FloatOp.binop = function |
| | CaseV ("ADD", []) -> FloatOp.Add |
| | CaseV ("SUB", []) -> FloatOp.Sub |
| | CaseV ("MUL", []) -> FloatOp.Mul |
| | CaseV ("DIV", []) -> FloatOp.Div |
| | CaseV ("MIN", []) -> FloatOp.Min |
| | CaseV ("MAX", []) -> FloatOp.Max |
| | CaseV ("COPYSIGN", []) -> FloatOp.CopySign |
| | v -> error_value "float binop" v |
| let al_to_binop: value list -> Ast.binop = al_to_op al_to_int_binop al_to_float_binop |
| |
| let al_to_int_testop: value -> IntOp.testop = function |
| | CaseV ("EQZ", []) -> IntOp.Eqz |
| | v -> error_value "integer testop" v |
| let al_to_testop: value list -> Ast.testop = function |
| | [ CaseV ("I32", []); op ] -> Value.I32 (al_to_int_testop op) |
| | [ CaseV ("I64", []); op ] -> Value.I64 (al_to_int_testop op) |
| | l -> error_values "testop" l |
| |
| let al_to_int_relop: value -> IntOp.relop = function |
| | CaseV ("EQ", []) -> IntOp.Eq |
| | CaseV ("NE", []) -> IntOp.Ne |
| | CaseV ("LT", [sx]) -> IntOp.Lt (al_to_sx sx) |
| | CaseV ("GT", [sx]) -> IntOp.Gt (al_to_sx sx) |
| | CaseV ("LE", [sx]) -> IntOp.Le (al_to_sx sx) |
| | CaseV ("GE", [sx]) -> IntOp.Ge (al_to_sx sx) |
| | v -> error_value "integer relop" v |
| let al_to_float_relop: value -> FloatOp.relop = function |
| | CaseV ("EQ", []) -> FloatOp.Eq |
| | CaseV ("NE", []) -> FloatOp.Ne |
| | CaseV ("LT", []) -> FloatOp.Lt |
| | CaseV ("GT", []) -> FloatOp.Gt |
| | CaseV ("LE", []) -> FloatOp.Le |
| | CaseV ("GE", []) -> FloatOp.Ge |
| | v -> error_value "float relop" v |
| let al_to_relop: value list -> relop = al_to_op al_to_int_relop al_to_float_relop |
| |
| let al_to_int_cvtop: value list -> IntOp.cvtop = function |
| | [ _; CaseV ("I32", []); CaseV ("EXTEND", [ sx ]) ] -> IntOp.ExtendI32 (al_to_sx sx) |
| | [ _; CaseV ("I64", []); CaseV ("WRAP", []) ] -> IntOp.WrapI64 |
| | [ _; CaseV ("F32", []); CaseV ("TRUNC", [ sx ]) ] -> IntOp.TruncF32 (al_to_sx sx) |
| | [ _; CaseV ("F64", []); CaseV ("TRUNC", [ sx ]) ] -> IntOp.TruncF64 (al_to_sx sx) |
| | [ _; CaseV ("F32", []); CaseV ("TRUNC_SAT", [ sx ]) ] -> IntOp.TruncSatF32 (al_to_sx sx) |
| | [ _; CaseV ("F64", []); CaseV ("TRUNC_SAT", [ sx ]) ] -> IntOp.TruncSatF64 (al_to_sx sx) |
| | [ _; _; CaseV ("REINTERPRET", []) ] -> IntOp.ReinterpretFloat |
| | l -> error_values "integer cvtop" l |
| let al_to_float_cvtop : value list -> FloatOp.cvtop = function |
| | [ _; CaseV ("I32", []); CaseV ("CONVERT", [ sx ]) ] -> FloatOp.ConvertI32 (al_to_sx sx) |
| | [ _; CaseV ("I64", []); CaseV ("CONVERT", [ sx ]) ] -> FloatOp.ConvertI64 (al_to_sx sx) |
| | [ _; CaseV ("F32", []); CaseV ("PROMOTE", []) ] -> FloatOp.PromoteF32 |
| | [ _; CaseV ("F64", []); CaseV ("DEMOTE", []) ] -> FloatOp.DemoteF64 |
| | [ _; _; CaseV ("REINTERPRET", []) ] -> FloatOp.ReinterpretInt |
| | l -> error_values "float cvtop" l |
| let al_to_cvtop: value list -> cvtop = function |
| | CaseV ("I32", []) :: _ as op -> I32 (al_to_int_cvtop op) |
| | CaseV ("I64", []) :: _ as op -> I64 (al_to_int_cvtop op) |
| | CaseV ("F32", []) :: _ as op -> F32 (al_to_float_cvtop op) |
| | CaseV ("F64", []) :: _ as op -> F64 (al_to_float_cvtop op) |
| | l -> error_values "cvtop" l |
| |
| (* Vector operator *) |
| |
| let al_to_vop f1 f2 = function |
| | [ CaseV ("X", [ CaseV ("I8", []); NumV z ]); vop ] when z = sixteen -> V128 (V128.I8x16 (f1 vop)) |
| | [ CaseV ("X", [ CaseV ("I16", []); NumV z ]); vop ] when z = eight -> V128 (V128.I16x8 (f1 vop)) |
| | [ CaseV ("X", [ CaseV ("I32", []); NumV z ]); vop ] when z = four -> V128 (V128.I32x4 (f1 vop)) |
| | [ CaseV ("X", [ CaseV ("I64", []); NumV z ]); vop ] when z = two -> V128 (V128.I64x2 (f1 vop)) |
| | [ CaseV ("X", [ CaseV ("F32", []); NumV z ]); vop ] when z = four -> V128 (V128.F32x4 (f2 vop)) |
| | [ CaseV ("X", [ CaseV ("F64", []); NumV z ]); vop ] when z = two -> V128 (V128.F64x2 (f2 vop)) |
| | l -> error_values "vop" l |
| |
| let al_to_vvop f = function |
| | [ CaseV ("V128", []); vop ] -> V128 (f vop) |
| | l -> error_values "vvop" l |
| |
| let al_to_int_vtestop : value -> V128Op.itestop = function |
| | CaseV ("ALL_TRUE", []) -> V128Op.AllTrue |
| | v -> error_value "integer vtestop" v |
| |
| let al_to_float_vtestop : value -> Ast.void = function |
| | v -> error_value "float vtestop" v |
| |
| let al_to_vtestop : value list -> vtestop = |
| al_to_vop al_to_int_vtestop al_to_float_vtestop |
| |
| let al_to_vbitmaskop : value list -> vbitmaskop = function |
| | [ CaseV ("X", [ CaseV ("I8", []); NumV z ]) ] when z = sixteen -> V128 (V128.I8x16 (V128Op.Bitmask)) |
| | [ CaseV ("X", [ CaseV ("I16", []); NumV z ]) ] when z = eight -> V128 (V128.I16x8 (V128Op.Bitmask)) |
| | [ CaseV ("X", [ CaseV ("I32", []); NumV z ]) ] when z = four -> V128 (V128.I32x4 (V128Op.Bitmask)) |
| | [ CaseV ("X", [ CaseV ("I64", []); NumV z ]) ] when z = two -> V128 (V128.I64x2 (V128Op.Bitmask)) |
| | l -> error_values "vbitmaskop" l |
| |
| let al_to_int_vrelop : value -> V128Op.irelop = function |
| | CaseV ("EQ", []) -> V128Op.Eq |
| | CaseV ("NE", []) -> V128Op.Ne |
| | CaseV ("LT", [sx]) -> V128Op.Lt (al_to_sx sx) |
| | CaseV ("LE", [sx]) -> V128Op.Le (al_to_sx sx) |
| | CaseV ("GT", [sx]) -> V128Op.Gt (al_to_sx sx) |
| | CaseV ("GE", [sx]) -> V128Op.Ge (al_to_sx sx) |
| | v -> error_value "integer vrelop" v |
| |
| let al_to_float_vrelop : value -> V128Op.frelop = function |
| | CaseV ("EQ", []) -> V128Op.Eq |
| | CaseV ("NE", []) -> V128Op.Ne |
| | CaseV ("LT", []) -> V128Op.Lt |
| | CaseV ("LE", []) -> V128Op.Le |
| | CaseV ("GT", []) -> V128Op.Gt |
| | CaseV ("GE", []) -> V128Op.Ge |
| | v -> error_value "float vrelop" v |
| |
| let al_to_vrelop : value list -> vrelop = |
| al_to_vop al_to_int_vrelop al_to_float_vrelop |
| |
| let al_to_int_vunop : value -> V128Op.iunop = function |
| | CaseV ("ABS", []) -> V128Op.Abs |
| | CaseV ("NEG", []) -> V128Op.Neg |
| | CaseV ("POPCNT", []) -> V128Op.Popcnt |
| | v -> error_value "integer vunop" v |
| |
| let al_to_float_vunop : value -> V128Op.funop = function |
| | CaseV ("ABS", []) -> V128Op.Abs |
| | CaseV ("NEG", []) -> V128Op.Neg |
| | CaseV ("SQRT", []) -> V128Op.Sqrt |
| | CaseV ("CEIL", []) -> V128Op.Ceil |
| | CaseV ("FLOOR", []) -> V128Op.Floor |
| | CaseV ("TRUNC", []) -> V128Op.Trunc |
| | CaseV ("NEAREST", []) -> V128Op.Nearest |
| | v -> error_value "float vunop" v |
| |
| let al_to_vunop : value list -> vunop = |
| al_to_vop al_to_int_vunop al_to_float_vunop |
| |
| let al_to_int_vbinop : value -> V128Op.ibinop = function |
| | CaseV ("ADD", []) -> V128Op.Add |
| | CaseV ("SUB", []) -> V128Op.Sub |
| | CaseV ("MUL", []) -> V128Op.Mul |
| | CaseV ("MIN", [sx]) -> V128Op.Min (al_to_sx sx) |
| | CaseV ("MAX", [sx]) -> V128Op.Max (al_to_sx sx) |
| | CaseV ("AVGR", []) -> V128Op.AvgrU |
| | CaseV ("ADD_SAT", [sx]) -> V128Op.AddSat (al_to_sx sx) |
| | CaseV ("SUB_SAT", [sx]) -> V128Op.SubSat (al_to_sx sx) |
| | CaseV ("Q15MULR_SAT", [(*CaseV ("S", [])*)]) -> V128Op.Q15MulRSatS |
| | CaseV ("RELAXED_Q15MULR", [(*CaseV ("S", [])*)]) -> V128Op.RelaxedQ15MulRS |
| | v -> error_value "integer vbinop" v |
| |
| let al_to_float_vbinop : value -> V128Op.fbinop = function |
| | CaseV ("ADD", []) -> V128Op.Add |
| | CaseV ("SUB", []) -> V128Op.Sub |
| | CaseV ("MUL", []) -> V128Op.Mul |
| | CaseV ("DIV", []) -> V128Op.Div |
| | CaseV ("MIN", []) -> V128Op.Min |
| | CaseV ("MAX", []) -> V128Op.Max |
| | CaseV ("PMIN", []) -> V128Op.Pmin |
| | CaseV ("PMAX", []) -> V128Op.Pmax |
| | CaseV ("RELAXED_MIN", []) -> V128Op.RelaxedMin |
| | CaseV ("RELAXED_MAX", []) -> V128Op.RelaxedMax |
| | v -> error_value "float vbinop" v |
| |
| let al_to_vbinop : value list -> vbinop = al_to_vop al_to_int_vbinop al_to_float_vbinop |
| |
| let al_to_int_vternop : value -> V128Op.iternop = function |
| | CaseV ("RELAXED_LANESELECT", []) -> V128Op.RelaxedLaneselect |
| | v -> error_value "integer vternop" v |
| |
| let al_to_float_vternop : value -> V128Op.fternop = function |
| | CaseV ("RELAXED_MADD", []) -> V128Op.RelaxedMadd |
| | CaseV ("RELAXED_NMADD", []) -> V128Op.RelaxedNmadd |
| | v -> error_value "float vternop" v |
| |
| let al_to_vternop : value list -> vternop = al_to_vop al_to_int_vternop al_to_float_vternop |
| |
| let al_to_half : value -> V128Op.half = function |
| | CaseV ("HIGH", []) -> V128Op.High |
| | CaseV ("LOW", []) -> V128Op.Low |
| | v -> error_value "half" v |
| |
| let al_to_special_vbinop = function |
| | CaseV ("VSWIZZLOP", [ CaseV ("X", [ CaseV ("I8", []); NumV z ]); op ]) as v when z = sixteen -> |
| (match op with |
| | CaseV ("SWIZZLE", []) -> V128 (V128.I8x16 (V128Op.Swizzle)) |
| | CaseV ("RELAXED_SWIZZLE", []) -> V128 (V128.I8x16 (V128Op.RelaxedSwizzle)) |
| | _ -> error_value "special vbinop" v) |
| | CaseV ("VSWIZZLE", [ CaseV ("X", [ CaseV ("I8", []); NumV z ]) ]) when z = sixteen && !version <= 2 -> V128 (V128.I8x16 (V128Op.Swizzle)) |
| | CaseV ("VSHUFFLE", [ CaseV ("X", [ CaseV ("I8", []); NumV z ]); l ]) when z = sixteen -> V128 (V128.I8x16 (V128Op.Shuffle (al_to_list al_to_nat8 l))) |
| | CaseV ("VNARROW", [ CaseV ("X", [ CaseV ("I8", []); NumV z1 ]); CaseV ("X", [ CaseV ("I16", []); NumV z2 ]); CaseV ("S", []) ]) when z1 = sixteen && z2 = eight -> V128 (V128.I8x16 V128Op.(Narrow S)) |
| | CaseV ("VNARROW", [ CaseV ("X", [ CaseV ("I16", []); NumV z1 ]); CaseV ("X", [ CaseV ("I32", []); NumV z2 ]); CaseV ("S", []) ]) when z1 = eight && z2 = four -> V128 (V128.I16x8 V128Op.(Narrow S)) |
| | CaseV ("VNARROW", [ CaseV ("X", [ CaseV ("I8", []); NumV z1 ]); CaseV ("X", [ CaseV ("I16", []); NumV z2 ]); CaseV ("U", []) ]) when z1 = sixteen && z2 = eight -> V128 (V128.I8x16 V128Op.(Narrow U)) |
| | CaseV ("VNARROW", [ CaseV ("X", [ CaseV ("I16", []); NumV z1 ]); CaseV ("X", [ CaseV ("I32", []); NumV z2 ]); CaseV ("U", []) ]) when z1 = eight && z2 = four -> V128 (V128.I16x8 V128Op.(Narrow U)) |
| | CaseV ("VEXTBINOP", [ c1; c2; ext ]) as v -> |
| let ext' = |
| match ext with |
| | CaseV ("EXTMUL", [half; sx]) -> V128Op.(ExtMul (al_to_half half, al_to_sx sx)) |
| | CaseV ("DOT", [(*CaseV ("S", [])*)]) -> V128Op.DotS |
| | CaseV ("RELAXED_DOT", [(*CaseV ("S", [])*)]) -> V128Op.RelaxedDot |
| | _ -> error_value "special vextbinop operator" ext |
| in |
| (match c1, c2 with |
| | CaseV ("X", [ CaseV ("I16", []); NumV z1 ]), CaseV ("X", [ CaseV ("I8", []); NumV z2 ]) when z1 = eight && z2 = sixteen -> V128 (V128.I16x8 ext') |
| | CaseV ("X", [ CaseV ("I32", []); NumV z1 ]), CaseV ("X", [ CaseV ("I16", []); NumV z2 ]) when z1 = four && z2 = eight -> V128 (V128.I32x4 ext') |
| | CaseV ("X", [ CaseV ("I64", []); NumV z1 ]), CaseV ("X", [ CaseV ("I32", []); NumV z2 ]) when z1 = two && z2 = four -> V128 (V128.I64x2 ext') |
| | _ -> error_value "special vextbinop shapes" v) |
| | v -> error_value "special vbinop" v |
| |
| let al_to_special_vternop = function |
| | CaseV ("VEXTTERNOP", [ c1; c2; ext ]) as v -> |
| let ext' = |
| match ext with |
| | CaseV ("RELAXED_DOT_ADD", [(*CaseV ("S", [])*)]) -> V128Op.RelaxedDotAddS |
| | _ -> error_value "special vextternop operator" ext |
| in |
| (match c1, c2 with |
| | CaseV ("X", [ CaseV ("I32", []); NumV z1 ]), CaseV ("X", [ CaseV ("I8", []); NumV z2 ]) when z1 = four && z2 = sixteen -> V128 (V128.I32x4 ext') |
| | _ -> error_value "special vextternop shapes" v) |
| | v -> error_value "special vternop" v |
| |
| let al_to_int_vcvtop : value list -> V128Op.icvtop = function |
| | [ _sh; CaseV ("EXTEND", [ half; sx ] ) ] -> V128Op.Extend (al_to_half half, al_to_sx sx) |
| | [ sh; CaseV ("TRUNC_SAT", [ sx; _zero ] ) ] as l -> ( |
| match sh with |
| | CaseV ("X", [ CaseV ("F32", []); NumV z ]) when z = four -> V128Op.TruncSatF32x4 (al_to_sx sx) |
| | CaseV ("X", [ CaseV ("F64", []); NumV z ]) when z = two -> V128Op.TruncSatZeroF64x2 (al_to_sx sx) |
| | _ -> error_values "integer vcvtop" l |
| ) |
| | [ sh; CaseV ("RELAXED_TRUNC", [ sx; _zero ] ) ] as l -> ( |
| match sh with |
| | CaseV ("X", [ CaseV ("F32", []); NumV z ]) when z = four -> V128Op.RelaxedTruncF32x4 (al_to_sx sx) |
| | CaseV ("X", [ CaseV ("F64", []); NumV z ]) when z = two -> V128Op.RelaxedTruncZeroF64x2 (al_to_sx sx) |
| | _ -> error_values "integer vcvtop" l |
| ) |
| | l -> error_values "integer vcvtop" l |
| |
| let al_to_float_vcvtop : value list -> V128Op.fcvtop = function |
| | [ _sh; CaseV ("DEMOTE", [ _zero ]) ] -> V128Op.DemoteZeroF64x2 |
| | [ _sh; CaseV ("CONVERT", [ _half; sx ]) ] -> V128Op.ConvertI32x4 (al_to_sx sx) |
| | [ _sh; CaseV ("PROMOTE", [ ]) ] -> V128Op.PromoteLowF32x4 |
| | l -> error_values "float vcvtop" l |
| |
| let al_to_vcvtop : value list -> vcvtop = function |
| | CaseV ("X", [ CaseV ("I8", []); NumV z ]) :: op when z = sixteen -> V128 (V128.I8x16 (al_to_int_vcvtop op)) |
| | CaseV ("X", [ CaseV ("I16", []); NumV z ]) :: op when z = eight -> V128 (V128.I16x8 (al_to_int_vcvtop op)) |
| | CaseV ("X", [ CaseV ("I32", []); NumV z ]) :: op when z = four -> V128 (V128.I32x4 (al_to_int_vcvtop op)) |
| | CaseV ("X", [ CaseV ("I64", []); NumV z ]) :: op when z = two -> V128 (V128.I64x2 (al_to_int_vcvtop op)) |
| | CaseV ("X", [ CaseV ("F32", []); NumV z ]) :: op when z = four -> V128 (V128.F32x4 (al_to_float_vcvtop op)) |
| | CaseV ("X", [ CaseV ("F64", []); NumV z ]) :: op when z = two -> V128 (V128.F64x2 (al_to_float_vcvtop op)) |
| | l -> error_values "vcvtop" l |
| |
| let al_to_special_vcvtop = function |
| | [ CaseV ("X", [ CaseV ("I16", []); NumV z1 ]); CaseV ("X", [ CaseV ("I8", []); NumV z2 ]); CaseV ("EXTADD_PAIRWISE", [ sx ]) ] when z1 = eight && z2 = sixteen -> |
| V128 (V128.I16x8 (V128Op.ExtAddPairwise (al_to_sx sx))) |
| | [ CaseV ("X", [ CaseV ("I32", []); NumV z1 ]); CaseV ("X", [ CaseV ("I16", []); NumV z2 ]); CaseV ("EXTADD_PAIRWISE", [ sx ]) ] when z1 = four && z2 = eight -> |
| V128 (V128.I32x4 (V128Op.ExtAddPairwise (al_to_sx sx))) |
| | l -> error_values "special vcvtop" l |
| |
| let al_to_int_vshiftop : value -> V128Op.ishiftop = function |
| | CaseV ("SHL", []) -> V128Op.Shl |
| | CaseV ("SHR", [sx]) -> V128Op.Shr (al_to_sx sx) |
| | v -> error_value "integer vshiftop" v |
| let al_to_float_vshiftop : value -> void = error_value "float vshiftop" |
| let al_to_vshiftop : value list -> vshiftop = al_to_vop al_to_int_vshiftop al_to_float_vshiftop |
| |
| let al_to_vvtestop' : value -> V128Op.vtestop = function |
| | CaseV ("ANY_TRUE", []) -> V128Op.AnyTrue |
| | v -> error_value "vvtestop" v |
| let al_to_vvtestop : value list -> vvtestop = al_to_vvop al_to_vvtestop' |
| |
| let al_to_vvunop' : value -> V128Op.vunop = function |
| | CaseV ("NOT", []) -> V128Op.Not |
| | v -> error_value "vvunop" v |
| let al_to_vvunop : value list -> vvunop = al_to_vvop al_to_vvunop' |
| |
| let al_to_vvbinop' = function |
| | CaseV ("AND", []) -> V128Op.And |
| | CaseV ("OR", []) -> V128Op.Or |
| | CaseV ("XOR", []) -> V128Op.Xor |
| | CaseV ("ANDNOT", []) -> V128Op.AndNot |
| | v -> error_value "vvbinop" v |
| let al_to_vvbinop : value list -> vvbinop = al_to_vvop al_to_vvbinop' |
| |
| let al_to_vvternop' : value -> V128Op.vternop = function |
| | CaseV ("BITSELECT", []) -> V128Op.Bitselect |
| | v -> error_value "vvternop" v |
| let al_to_vvternop : value list -> vvternop = al_to_vvop al_to_vvternop' |
| |
| let al_to_vsplatop : value list -> vsplatop = function |
| | [ CaseV ("X", [ CaseV ("I8", []); NumV z ]) ] when z = sixteen -> V128 (V128.I8x16 Splat) |
| | [ CaseV ("X", [ CaseV ("I16", []); NumV z ]) ] when z = eight -> V128 (V128.I16x8 Splat) |
| | [ CaseV ("X", [ CaseV ("I32", []); NumV z ]) ] when z = four -> V128 (V128.I32x4 Splat) |
| | [ CaseV ("X", [ CaseV ("I64", []); NumV z ]) ] when z = two -> V128 (V128.I64x2 Splat) |
| | [ CaseV ("X", [ CaseV ("F32", []); NumV z ]) ] when z = four -> V128 (V128.F32x4 Splat) |
| | [ CaseV ("X", [ CaseV ("F64", []); NumV z ]) ] when z = two -> V128 (V128.F64x2 Splat) |
| | vs -> error_values "vsplatop" vs |
| |
| let al_to_vextractop : value list -> vextractop = function |
| | [ CaseV ("X", [ CaseV ("I8", []); NumV z ]); OptV (Some sx); n ] when z = sixteen -> |
| V128 (V128.I8x16 (Extract (al_to_nat8 n, al_to_sx sx))) |
| | [ CaseV ("X", [ CaseV ("I16", []); NumV z ]); OptV (Some sx); n ] when z = eight -> |
| V128 (V128.I16x8 (Extract (al_to_nat8 n, al_to_sx sx))) |
| | [ CaseV ("X", [ CaseV ("I32", []); NumV z ]); OptV None; n ] when z = four -> |
| V128 (V128.I32x4 (Extract (al_to_nat8 n, ()))) |
| | [ CaseV ("X", [ CaseV ("I64", []); NumV z ]); OptV None; n ] when z = two -> |
| V128 (V128.I64x2 (Extract (al_to_nat8 n, ()))) |
| | [ CaseV ("X", [ CaseV ("F32", []); NumV z ]); OptV None; n ] when z = four -> |
| V128 (V128.F32x4 (Extract (al_to_nat8 n, ()))) |
| | [ CaseV ("X", [ CaseV ("F64", []); NumV z ]); OptV None; n ] when z = two -> |
| V128 (V128.F64x2 (Extract (al_to_nat8 n, ()))) |
| | vs -> error_values "vextractop" vs |
| |
| let al_to_vreplaceop : value list -> vreplaceop = function |
| | [ CaseV ("X", [ CaseV ("I8", []); NumV z ]); n ] when z = sixteen -> V128 (V128.I8x16 (Replace (al_to_nat8 n))) |
| | [ CaseV ("X", [ CaseV ("I16", []); NumV z ]); n ] when z = eight -> V128 (V128.I16x8 (Replace (al_to_nat8 n))) |
| | [ CaseV ("X", [ CaseV ("I32", []); NumV z ]); n ] when z = four -> V128 (V128.I32x4 (Replace (al_to_nat8 n))) |
| | [ CaseV ("X", [ CaseV ("I64", []); NumV z ]); n ] when z = two -> V128 (V128.I64x2 (Replace (al_to_nat8 n))) |
| | [ CaseV ("X", [ CaseV ("F32", []); NumV z ]); n ] when z = four -> V128 (V128.F32x4 (Replace (al_to_nat8 n))) |
| | [ CaseV ("X", [ CaseV ("F64", []); NumV z ]); n ] when z = two -> V128 (V128.F64x2 (Replace (al_to_nat8 n))) |
| | vs -> error_values "vreplaceop" vs |
| |
| let al_to_packsize : value -> Pack.packsize = function |
| | NumV z when z = eight -> Pack.Pack8 |
| | NumV z when z = sixteen -> Pack.Pack16 |
| | NumV z when z = thirtytwo -> Pack.Pack32 |
| | NumV z when z = sixtyfour -> Pack.Pack64 |
| | v -> error_value "packsize" v |
| |
| let al_to_memop (f: value -> 'p) : value list -> idx * (numtype, 'p) memop = function |
| | [ nt; p; StrV str ] when !version <= 2 -> |
| 0l @@ no_region, |
| { |
| ty = al_to_numtype nt; |
| align = Record.find "ALIGN" str |> al_to_nat; |
| offset = Record.find "OFFSET" str |> al_to_nat64; |
| pack = f p; |
| } |
| | [ nt; p; idx; StrV str ] -> |
| al_to_idx idx, |
| { |
| ty = al_to_numtype nt; |
| align = Record.find "ALIGN" str |> al_to_nat; |
| offset = Record.find "OFFSET" str |> al_to_nat64; |
| pack = f p; |
| } |
| | v -> error_values "memop" v |
| |
| let al_to_packsize_sx: value -> Pack.packsize * Pack.sx = function |
| | CaseV ("_", [ p; sx ]) -> al_to_packsize p, al_to_sx sx |
| | v -> error_value "packsize sx" v |
| |
| let al_to_loadop: value list -> idx * loadop = al_to_opt al_to_packsize_sx |> al_to_memop |
| |
| let al_to_storeop: value list -> idx * storeop = al_to_opt al_to_packsize |> al_to_memop |
| |
| let al_to_vmemop' (f: value -> 'p): value list -> (vectype, 'p) memop = function |
| | [ StrV str ] -> |
| { |
| ty = V128T; |
| align = Record.find "ALIGN" str |> al_to_nat; |
| offset = Record.find "OFFSET" str |> al_to_nat64; |
| pack = f (natV Z.zero); |
| } |
| | [ p; StrV str ] -> |
| { |
| ty = V128T; |
| align = Record.find "ALIGN" str |> al_to_nat; |
| offset = Record.find "OFFSET" str |> al_to_nat64; |
| pack = f p; |
| } |
| | v -> error_values "vmemop" v |
| |
| let al_to_vmemop (f: value -> 'p) (g: value list -> value * (value list)): value list -> idx * (vectype, 'p) memop = function |
| | vl when !version <= 2 -> |
| 0l @@ no_region, al_to_vmemop' f vl |
| | vl -> |
| let idx, vl' = g vl in |
| al_to_idx idx, al_to_vmemop' f vl' |
| |
| let al_to_packshape = function |
| | [NumV z1; NumV z2] when z1 = eight && z2 = eight -> Pack.Pack8x8 |
| | [NumV z1; NumV z2] when z1 = sixteen && z2 = four -> Pack.Pack16x4 |
| | [NumV z1; NumV z2] when z1 = thirtytwo && z2 = two -> Pack.Pack32x2 |
| | vs -> error_value "packshape" (TupV vs) |
| |
| let al_to_vloadop': value -> Pack.packsize * Pack.vext = function |
| | CaseV ("SHAPE", [ v1; v2; ext ] ) -> |
| let packshape = al_to_packshape [v1; v2] in |
| ( |
| Pack.Pack64, |
| Pack.ExtLane (packshape, al_to_sx ext) |
| ) |
| | CaseV ("SPLAT", [ packsize ]) -> al_to_packsize packsize, Pack.ExtSplat |
| | CaseV ("ZERO", [ packsize ]) -> al_to_packsize packsize, Pack.ExtZero |
| | v -> error_value "vloadop'" v |
| |
| let al_to_vloadop: value list -> idx * vloadop = function |
| | CaseV ("V128", []) :: vl -> |
| let split vl = |
| match vl with |
| | memop :: idx :: vl' -> idx, memop :: vl' |
| | _ -> error_values "vloadop" vl |
| in |
| al_to_vmemop (al_to_opt al_to_vloadop') split vl |
| | vs -> error_value "vloadop" (TupV vs) |
| |
| let al_to_vstoreop = function |
| | CaseV ("V128", []) :: vl -> |
| let split = Util.Lib.List.split_hd in |
| al_to_vmemop (fun _ -> ()) split vl |
| | vs -> error_value "vstoreop" (TupV vs) |
| |
| let al_to_vlaneop: value list -> idx * vlaneop * I8.t = function |
| | CaseV ("V128", []) :: vl -> |
| let h, t = Util.Lib.List.split_last vl in |
| let split vl = |
| match vl with |
| | ps :: idx :: vl' -> idx, ps :: vl' |
| | _ -> error_values "vlaneop" vl |
| in |
| let idx, op = al_to_vmemop al_to_packsize split h in |
| idx, op, al_to_nat8 t |
| | vs -> error_value "vlaneop" (TupV vs) |
| |
| |
| (* Destruct expressions *) |
| |
| let al_to_catch' = function |
| | CaseV ("CATCH", [ idx1; idx2 ]) -> Catch (al_to_idx idx1, al_to_idx idx2) |
| | CaseV ("CATCH_REF", [ idx1; idx2 ]) -> CatchRef (al_to_idx idx1, al_to_idx idx2) |
| | CaseV ("CATCH_ALL", [ idx ]) -> CatchAll (al_to_idx idx) |
| | CaseV ("CATCH_ALL_REF", [ idx ]) -> CatchAllRef (al_to_idx idx) |
| | v -> error_value "catch" v |
| let al_to_catch (v: value): Ast.catch = al_to_phrase al_to_catch' v |
| |
| let al_to_num: value -> num = function |
| | CaseV ("CONST", [ CaseV ("I32", []); i32 ]) -> I32 (al_to_nat32 i32) |
| | CaseV ("CONST", [ CaseV ("I64", []); i64 ]) -> I64 (al_to_nat64 i64) |
| | CaseV ("CONST", [ CaseV ("F32", []); f32 ]) -> F32 (al_to_float32 f32) |
| | CaseV ("CONST", [ CaseV ("F64", []); f64 ]) -> F64 (al_to_float64 f64) |
| | v -> error_value "num" v |
| |
| let al_to_vec: value -> vec = function |
| | CaseV ("VCONST", [ CaseV ("V128", []); v128 ]) -> V128 (al_to_vec128 v128) |
| | v -> error_value "vec" v |
| |
| let rec al_to_instr (v: value): Ast.instr = al_to_phrase al_to_instr' v |
| and al_to_instr': value -> Ast.instr' = function |
| (* wasm values *) |
| | CaseV ("CONST", _) as v -> Const (al_to_phrase al_to_num v) |
| | CaseV ("VCONST", _) as v -> VecConst (al_to_phrase al_to_vec v) |
| | CaseV ("REF.NULL", [ ht ]) -> RefNull (al_to_heaptype ht) |
| (* wasm instructions *) |
| | CaseV ("UNREACHABLE", []) -> Unreachable |
| | CaseV ("NOP", []) -> Nop |
| | CaseV ("DROP", []) -> Drop |
| | CaseV ("UNOP", op) -> Unary (al_to_unop op) |
| | CaseV ("BINOP", op) -> Binary (al_to_binop op) |
| | CaseV ("TESTOP", op) -> Test (al_to_testop op) |
| | CaseV ("RELOP", op) -> Compare (al_to_relop op) |
| | CaseV ("CVTOP", op) -> Convert (al_to_cvtop op) |
| | CaseV ("VTESTOP", vop) -> VecTest (al_to_vtestop vop) |
| | CaseV ("VRELOP", vop) -> VecCompare (al_to_vrelop vop) |
| | CaseV ("VUNOP", vop) -> VecUnary (al_to_vunop vop) |
| | CaseV ("VBINOP", vop) -> VecBinary (al_to_vbinop vop) |
| | CaseV ("VTERNOP", vop) -> VecTernary (al_to_vternop vop) |
| | CaseV (("VSWIZZLOP" | "VSWIZZLE" | "VSHUFFLE" | "VNARROW" | "VEXTBINOP"), _) as v -> VecBinary (al_to_special_vbinop v) |
| | CaseV ("VEXTTERNOP", _) as v -> VecTernary (al_to_special_vternop v) |
| | CaseV ("VCVTOP", vop) -> VecConvert (al_to_vcvtop vop) |
| | CaseV ("VEXTUNOP", vop) -> VecConvert (al_to_special_vcvtop vop) |
| | CaseV ("VSHIFTOP", vop) -> VecShift (al_to_vshiftop vop) |
| | CaseV ("VBITMASK", vop) -> VecBitmask (al_to_vbitmaskop vop) |
| | CaseV ("VVTESTOP", vop) -> VecTestBits (al_to_vvtestop vop) |
| | CaseV ("VVUNOP", vop) -> VecUnaryBits (al_to_vvunop vop) |
| | CaseV ("VVBINOP", vop) -> VecBinaryBits (al_to_vvbinop vop) |
| | CaseV ("VVTERNOP", vop) -> VecTernaryBits (al_to_vvternop vop) |
| | CaseV ("VSPLAT", vop) -> VecSplat (al_to_vsplatop vop) |
| | CaseV ("VEXTRACT_LANE", vop) -> VecExtract (al_to_vextractop vop) |
| | CaseV ("VREPLACE_LANE", vop) -> VecReplace (al_to_vreplaceop vop) |
| | CaseV ("REF.IS_NULL", []) -> RefIsNull |
| | CaseV ("REF.FUNC", [ idx ]) -> RefFunc (al_to_idx idx) |
| | CaseV ("SELECT", []) when !version = 1 -> Select None |
| | CaseV ("SELECT", [ vtl_opt ]) -> Select (al_to_opt (al_to_list al_to_valtype) vtl_opt) |
| | CaseV ("LOCAL.GET", [ idx ]) -> LocalGet (al_to_idx idx) |
| | CaseV ("LOCAL.SET", [ idx ]) -> LocalSet (al_to_idx idx) |
| | CaseV ("LOCAL.TEE", [ idx ]) -> LocalTee (al_to_idx idx) |
| | CaseV ("GLOBAL.GET", [ idx ]) -> GlobalGet (al_to_idx idx) |
| | CaseV ("GLOBAL.SET", [ idx ]) -> GlobalSet (al_to_idx idx) |
| | CaseV ("TABLE.GET", [ idx ]) -> TableGet (al_to_idx idx) |
| | CaseV ("TABLE.SET", [ idx ]) -> TableSet (al_to_idx idx) |
| | CaseV ("TABLE.SIZE", [ idx ]) -> TableSize (al_to_idx idx) |
| | CaseV ("TABLE.GROW", [ idx ]) -> TableGrow (al_to_idx idx) |
| | CaseV ("TABLE.FILL", [ idx ]) -> TableFill (al_to_idx idx) |
| | CaseV ("TABLE.COPY", [ idx1; idx2 ]) -> TableCopy (al_to_idx idx1, al_to_idx idx2) |
| | CaseV ("TABLE.INIT", [ idx1; idx2 ]) -> TableInit (al_to_idx idx1, al_to_idx idx2) |
| | CaseV ("ELEM.DROP", [ idx ]) -> ElemDrop (al_to_idx idx) |
| | CaseV ("BLOCK", [ bt; instrs ]) -> |
| Block (al_to_blocktype bt, al_to_list al_to_instr instrs) |
| | CaseV ("LOOP", [ bt; instrs ]) -> |
| Loop (al_to_blocktype bt, al_to_list al_to_instr instrs) |
| | CaseV ("IF", [ bt; instrs1; instrs2 ]) -> |
| If (al_to_blocktype bt, al_to_list al_to_instr instrs1, al_to_list al_to_instr instrs2) |
| | CaseV ("BR", [ idx ]) -> Br (al_to_idx idx) |
| | CaseV ("BR_IF", [ idx ]) -> BrIf (al_to_idx idx) |
| | CaseV ("BR_TABLE", [ idxs; idx ]) -> BrTable (al_to_list al_to_idx idxs, al_to_idx idx) |
| | CaseV ("BR_ON_NULL", [ idx ]) -> BrOnNull (al_to_idx idx) |
| | CaseV ("BR_ON_NON_NULL", [ idx ]) -> BrOnNonNull (al_to_idx idx) |
| | CaseV ("BR_ON_CAST", [ idx; rt1; rt2 ]) -> |
| BrOnCast (al_to_idx idx, al_to_reftype rt1, al_to_reftype rt2) |
| | CaseV ("BR_ON_CAST_FAIL", [ idx; rt1; rt2 ]) -> |
| BrOnCastFail (al_to_idx idx, al_to_reftype rt1, al_to_reftype rt2) |
| | CaseV ("RETURN", []) -> Return |
| | CaseV ("CALL", [ idx ]) -> Call (al_to_idx idx) |
| | CaseV ("CALL_REF", [ typeuse ]) -> CallRef (al_to_idx_of_typeuse typeuse) |
| | CaseV ("CALL_INDIRECT", [ idx1; typeuse2 ]) -> |
| CallIndirect (al_to_idx idx1, al_to_idx_of_typeuse typeuse2) |
| | CaseV ("RETURN_CALL", [ idx ]) -> ReturnCall (al_to_idx idx) |
| | CaseV ("RETURN_CALL_REF", [ typeuse ]) -> ReturnCallRef (al_to_idx_of_typeuse typeuse) |
| | CaseV ("RETURN_CALL_INDIRECT", [ idx1; typeuse2 ]) -> |
| ReturnCallIndirect (al_to_idx idx1, al_to_idx_of_typeuse typeuse2) |
| | CaseV ("THROW", [ idx ]) -> Throw (al_to_idx idx) |
| | CaseV ("THROW_REF", []) -> ThrowRef |
| | CaseV ("TRY_TABLE", [ bt; catches; instrs ]) -> |
| TryTable (al_to_blocktype bt, al_to_list al_to_catch catches, al_to_list al_to_instr instrs) |
| | CaseV ("LOAD", loadop) -> let idx, op = al_to_loadop loadop in Load (idx, op) |
| | CaseV ("STORE", storeop) -> let idx, op = al_to_storeop storeop in Store (idx, op) |
| | CaseV ("VLOAD", vloadop) -> let idx, op = al_to_vloadop vloadop in VecLoad (idx, op) |
| | CaseV ("VLOAD_LANE", vlaneop) -> |
| let idx, op, i = al_to_vlaneop vlaneop in VecLoadLane (idx, op, i) |
| | CaseV ("VSTORE", vstoreop) -> let idx, op = al_to_vstoreop vstoreop in VecStore (idx, op) |
| | CaseV ("VSTORE_LANE", vlaneop) -> |
| let idx, op, i = al_to_vlaneop vlaneop in VecStoreLane (idx, op, i) |
| | CaseV ("MEMORY.SIZE", [ idx ]) -> MemorySize (al_to_idx idx) |
| | CaseV ("MEMORY.GROW", [ idx ]) -> MemoryGrow (al_to_idx idx) |
| | CaseV ("MEMORY.FILL", [ idx ]) -> MemoryFill (al_to_idx idx) |
| | CaseV ("MEMORY.COPY", [ idx1; idx2 ]) -> MemoryCopy (al_to_idx idx1, al_to_idx idx2) |
| | CaseV ("MEMORY.INIT", [ idx1; idx2 ]) -> MemoryInit (al_to_idx idx1, al_to_idx idx2) |
| | CaseV ("DATA.DROP", [ idx ]) -> DataDrop (al_to_idx idx) |
| | CaseV ("REF.AS_NON_NULL", []) -> RefAsNonNull |
| | CaseV ("REF.TEST", [ rt ]) -> RefTest (al_to_reftype rt) |
| | CaseV ("REF.CAST", [ rt ]) -> RefCast (al_to_reftype rt) |
| | CaseV ("REF.EQ", []) -> RefEq |
| | CaseV ("REF.I31", []) -> RefI31 |
| | CaseV ("I31.GET", [ sx ]) -> I31Get (al_to_sx sx) |
| | CaseV ("STRUCT.NEW", [ idx ]) -> StructNew (al_to_idx idx, Explicit) |
| | CaseV ("STRUCT.NEW_DEFAULT", [ idx ]) -> StructNew (al_to_idx idx, Implicit) |
| | CaseV ("STRUCT.GET", [ sx_opt; idx1; idx2 ]) -> |
| StructGet (al_to_idx idx1, al_to_nat32 idx2, al_to_opt al_to_sx sx_opt) |
| | CaseV ("STRUCT.SET", [ idx1; idx2 ]) -> StructSet (al_to_idx idx1, al_to_nat32 idx2) |
| | CaseV ("ARRAY.NEW", [ idx ]) -> ArrayNew (al_to_idx idx, Explicit) |
| | CaseV ("ARRAY.NEW_DEFAULT", [ idx ]) -> ArrayNew (al_to_idx idx, Implicit) |
| | CaseV ("ARRAY.NEW_FIXED", [ idx; i32 ]) -> |
| ArrayNewFixed (al_to_idx idx, al_to_nat32 i32) |
| | CaseV ("ARRAY.NEW_ELEM", [ idx1; idx2 ]) -> |
| ArrayNewElem (al_to_idx idx1, al_to_idx idx2) |
| | CaseV ("ARRAY.NEW_DATA", [ idx1; idx2 ]) -> |
| ArrayNewData (al_to_idx idx1, al_to_idx idx2) |
| | CaseV ("ARRAY.GET", [ sx_opt; idx ]) -> |
| ArrayGet (al_to_idx idx, al_to_opt al_to_sx sx_opt) |
| | CaseV ("ARRAY.SET", [ idx ]) -> ArraySet (al_to_idx idx) |
| | CaseV ("ARRAY.LEN", []) -> ArrayLen |
| | CaseV ("ARRAY.COPY", [ idx1; idx2 ]) -> ArrayCopy (al_to_idx idx1, al_to_idx idx2) |
| | CaseV ("ARRAY.FILL", [ idx ]) -> ArrayFill (al_to_idx idx) |
| | CaseV ("ARRAY.INIT_DATA", [ idx1; idx2 ]) -> |
| ArrayInitData (al_to_idx idx1, al_to_idx idx2) |
| | CaseV ("ARRAY.INIT_ELEM", [ idx1; idx2 ]) -> |
| ArrayInitElem (al_to_idx idx1, al_to_idx idx2) |
| | CaseV ("ANY.CONVERT_EXTERN", []) -> ExternConvert Internalize |
| | CaseV ("EXTERN.CONVERT_ANY", []) -> ExternConvert Externalize |
| | v -> error_value "instruction" v |
| |
| let al_to_const: value -> const = al_to_list al_to_instr |> al_to_phrase |
| |
| |
| (* Deconstruct module *) |
| |
| let al_to_type: value -> type_ = function |
| | CaseV ("TYPE", [ rt ]) -> al_to_phrase al_to_rectype rt |
| | v -> error_value "type" v |
| |
| let al_to_local': value -> local' = function |
| | CaseV ("LOCAL", [ vt ]) -> Local (al_to_valtype vt) |
| | v -> error_value "local" v |
| let al_to_local: value -> local = al_to_phrase al_to_local' |
| |
| let al_to_func': value -> func' = function |
| | CaseV ("FUNC", [ idx; locals; instrs ]) -> |
| Func (al_to_idx idx, al_to_list al_to_local locals, al_to_list al_to_instr instrs) |
| | v -> error_value "func" v |
| let al_to_func: value -> func = al_to_phrase al_to_func' |
| |
| let al_to_global': value -> global' = function |
| | CaseV ("GLOBAL", [ gt; const ]) -> |
| Global (al_to_globaltype gt, al_to_const const) |
| | v -> error_value "global" v |
| let al_to_global: value -> global = al_to_phrase al_to_global' |
| |
| let al_to_table': value -> table' = function |
| | CaseV ("TABLE", [ tt; const ]) -> |
| Table (al_to_tabletype tt, al_to_const const) |
| | v -> error_value "table" v |
| let al_to_table: value -> table = al_to_phrase al_to_table' |
| |
| let al_to_memory': value -> memory' = function |
| | CaseV ("MEMORY", [ mt ]) -> Memory (al_to_memorytype mt) |
| | v -> error_value "memory" v |
| let al_to_memory: value -> memory = al_to_phrase al_to_memory' |
| |
| let al_to_tag': value -> tag' = function |
| | CaseV ("TAG", [ tt ]) -> Tag (al_to_tagtype tt) |
| | v -> error_value "tag" v |
| let al_to_tag: value -> tag = al_to_phrase al_to_tag' |
| |
| let al_to_segmentmode': value -> segmentmode' = function |
| | CaseV ("PASSIVE", []) -> Passive |
| | CaseV ("ACTIVE", [ idx; const ]) -> Active (al_to_idx idx, al_to_const const) |
| | CaseV ("DECLARE", []) -> Declarative |
| | v -> error_value "segmentmode" v |
| let al_to_segmentmode: value -> segmentmode = al_to_phrase al_to_segmentmode' |
| |
| let al_to_elem': value -> elem' = function |
| | CaseV ("ELEM", [ rt; consts; mode ]) -> |
| Elem (al_to_reftype rt, al_to_list al_to_const consts, al_to_segmentmode mode) |
| | v -> error_value "elem" v |
| let al_to_elem: value -> elem = al_to_phrase al_to_elem' |
| |
| let al_to_data': value -> data' = function |
| | CaseV ("DATA", [ bytes; mode ]) -> |
| Data (al_to_bytes bytes, al_to_segmentmode mode) |
| | v -> error_value "data" v |
| let al_to_data: value -> data = al_to_phrase al_to_data' |
| |
| let al_to_externtype = function |
| | CaseV ("FUNC", [typeuse]) -> ExternFuncT (al_to_typeuse typeuse) |
| | CaseV ("GLOBAL", [globaltype]) -> ExternGlobalT (al_to_globaltype globaltype) |
| | CaseV ("TABLE", [tabletype]) -> ExternTableT (al_to_tabletype tabletype) |
| | CaseV ("MEM", [memtype]) -> ExternMemoryT (al_to_memorytype memtype) |
| | CaseV ("TAG", [tagtype]) -> ExternTagT (al_to_tagtype tagtype) |
| | v -> error_value "externtype" v |
| |
| let al_to_import = function |
| | CaseV ("IMPORT", [ module_name; item_name; xt ]) -> |
| Import (al_to_name module_name, al_to_name item_name, al_to_externtype xt) @@ no_region |
| | v -> error_value "import" v |
| |
| let al_to_externidx': value -> externidx' = function |
| | CaseV ("FUNC", [ idx ]) -> FuncX (al_to_idx idx) |
| | CaseV ("TABLE", [ idx ]) -> TableX (al_to_idx idx) |
| | CaseV ("MEM", [ idx ]) -> MemoryX (al_to_idx idx) |
| | CaseV ("GLOBAL", [ idx ]) -> GlobalX (al_to_idx idx) |
| | CaseV ("TAG", [ idx ]) -> TagX (al_to_idx idx) |
| | v -> error_value "externidx" v |
| let al_to_externidx: value -> externidx = al_to_phrase al_to_externidx' |
| |
| let al_to_start': value -> start' = function |
| | CaseV ("START", [ idx ]) -> Start (al_to_idx idx) |
| | v -> error_value "start" v |
| let al_to_start: value -> start = al_to_phrase al_to_start' |
| |
| let al_to_export': value -> export' = function |
| | CaseV ("EXPORT", [ name; xx ]) -> Export (al_to_name name, al_to_externidx xx) |
| | v -> error_value "export" v |
| let al_to_export: value -> export = al_to_phrase al_to_export' |
| |
| let rec al_to_module': value -> module_' = function |
| | CaseV ("MODULE", [ |
| types; imports; funcs; globals; tables; memories; elems; datas; start; exports |
| ]) when !version <= 2 -> |
| al_to_module' (CaseV ("MODULE", [ |
| types; imports; listV [||]; globals; memories; tables; funcs; datas; elems; start; exports |
| ])) |
| | CaseV ("MODULE", [ |
| types; imports; tags; globals; memories; tables; funcs; datas; elems; start; exports |
| ]) -> |
| { |
| types = al_to_list al_to_type types; |
| imports = al_to_list al_to_import imports; |
| tags = al_to_list al_to_tag tags; |
| globals = al_to_list al_to_global globals; |
| memories = al_to_list al_to_memory memories; |
| tables = al_to_list al_to_table tables; |
| funcs = al_to_list al_to_func funcs; |
| datas = al_to_list al_to_data datas; |
| elems = al_to_list al_to_elem elems; |
| start = al_to_opt al_to_start start; |
| exports = al_to_list al_to_export exports; |
| } |
| | v -> error_value "module" v |
| let al_to_module: value -> module_ = al_to_phrase al_to_module' |
| |
| |
| (* Destruct value *) |
| |
| let rec al_to_field: value -> Aggr.field = function |
| | CaseV ("PACK", [pt; c]) -> Aggr.PackField (al_to_packtype pt, ref (al_to_nat c)) |
| | v -> Aggr.ValField (ref (al_to_value v)) |
| |
| and al_to_array: value -> Aggr.array = function |
| | StrV r when Record.mem "TYPE" r && Record.mem "FIELDS" r -> |
| Aggr.Array ( |
| al_to_deftype (Record.find "TYPE" r), |
| al_to_list al_to_field (Record.find "FIELDS" r) |
| ) |
| | v -> error_value "array" v |
| |
| and al_to_struct: value -> Aggr.struct_ = function |
| | StrV r when Record.mem "TYPE" r && Record.mem "FIELDS" r -> |
| Aggr.Struct ( |
| al_to_deftype (Record.find "TYPE" r), |
| al_to_list al_to_field (Record.find "FIELDS" r) |
| ) |
| | v -> error_value "struct" v |
| |
| and al_to_tag: value -> Tag.t = function |
| | StrV r when Record.mem "TYPE" r -> |
| Tag.alloc (al_to_tagtype (Record.find "TYPE" r)) |
| | v -> error_value "tag" v |
| |
| and al_to_exn: value -> Exn.exn_ = function |
| | StrV r when Record.mem "TAG" r && Record.mem "FIELDS" r -> |
| let tag_insts = Ds.Store.access "TAGS" in |
| let tag = Record.find "TAG" r |> al_to_nat |> listv_nth tag_insts |> al_to_tag in |
| Exn.Exn ( |
| tag, |
| al_to_list al_to_value (Record.find "FIELDS" r) |
| ) |
| | v -> error_value "exn" v |
| |
| and al_to_funcinst: value -> Instance.funcinst = function |
| | StrV r when Record.mem "TYPE" r && Record.mem "MODULE" r && Record.mem "CODE" r -> |
| Func.AstFunc ( |
| al_to_deftype (Record.find "TYPE" r), |
| Reference_interpreter.Lib.Promise.make (), (* TODO: Fulfill the promise with module instance *) |
| al_to_func (Record.find "CODE" r) |
| ) |
| | v -> error_value "funcinst" v |
| |
| and al_to_ref: value -> ref_ = function |
| | CaseV ("REF.NULL", [ ht ]) -> NullRef (al_to_heaptype ht) |
| | CaseV ("REF.I31_NUM", [ i ]) -> I31.I31Ref (al_to_nat i) |
| | CaseV ("REF.STRUCT_ADDR", [ addr ]) -> |
| let struct_insts = Ds.Store.access "STRUCTS" in |
| let struct_ = addr |> al_to_nat |> listv_nth struct_insts |> al_to_struct in |
| Aggr.StructRef struct_ |
| | CaseV ("REF.ARRAY_ADDR", [ addr ]) -> |
| let arr_insts = Ds.Store.access "ARRAYS" in |
| let arr = addr |> al_to_nat |> listv_nth arr_insts |> al_to_array in |
| Aggr.ArrayRef arr |
| | CaseV ("REF.FUNC_ADDR", [ addr ]) -> |
| let func_insts = Ds.Store.access "FUNCS" in |
| let func = addr |> al_to_nat |> listv_nth func_insts |> al_to_funcinst in |
| Instance.FuncRef func |
| | CaseV ("REF.HOST_ADDR", [ i32 ]) -> Script.HostRef (al_to_nat32 i32) |
| | CaseV ("REF.EXTERN", [ r ]) -> Extern.ExternRef (al_to_ref r) |
| | v -> error_value "ref" v |
| |
| and al_to_value: value -> Value.value = function |
| | CaseV ("CONST", _) as v -> Num (al_to_num v) |
| | CaseV (ref_, _) as v when String.sub ref_ 0 4 = "REF." -> Ref (al_to_ref v) |
| | CaseV ("VCONST", _) as v -> Vec (al_to_vec v) |
| | v -> error_value "value" v |
| |
| |
| (* Construct *) |
| |
| (* Construct data structure *) |
| |
| let al_of_list f l = List.map f l |> listV_of_list |
| let al_of_seq f s = List.of_seq s |> al_of_list f |
| let al_of_opt f opt = Option.map f opt |> optV |
| |
| |
| (* Construct minor *) |
| |
| let al_of_z_nat z = natV z |
| let al_of_z_int z = intV z |
| |
| let al_of_fmagN layout i = |
| let n = Z.logand i (mask_exp layout) in |
| let m = Z.logand i (mask_mant layout) in |
| if n = Z.zero then |
| CaseV ("SUBNORM", [ al_of_z_nat m ]) |
| else if n <> mask_exp layout then |
| CaseV ("NORM", [ al_of_z_nat m; al_of_z_int Z.(shift_right n layout.mantissa - bias layout) ]) |
| else if m = Z.zero then |
| CaseV ("INF", []) |
| else |
| CaseV ("NAN", [ al_of_z_nat m ]) |
| |
| let al_of_floatN layout i = |
| let i' = Z.logand i (mask_mag layout) in |
| let mag = al_of_fmagN layout i in |
| CaseV ((if i' = i then "POS" else "NEG"), [ mag ]) |
| |
| let vec128_to_z vec = |
| match V128.I64x2.to_lanes vec with |
| | [ v1; v2 ] -> Z.(of_int64_unsigned v1 + e64 * of_int64_unsigned v2) |
| | _ -> assert false |
| |
| let al_of_nat i = Z.of_int i |> al_of_z_nat |
| let al_of_nat8 i8 = |
| (* NOTE: int8 is considered to be unsigned *) |
| Z.of_int (I8.to_int_u i8) |> al_of_z_nat |
| let al_of_nat16 i16 = |
| (* NOTE: int32 is considered to be unsigned *) |
| Z.of_int (I16.to_int_u i16) |> al_of_z_nat |
| let al_of_nat32 i32 = |
| (* NOTE: int32 is considered to be unsigned *) |
| Z.of_int32_unsigned i32 |> al_of_z_nat |
| let al_of_nat64 i64 = |
| (* NOTE: int32 is considered to be unsigned *) |
| Z.of_int64_unsigned i64 |> al_of_z_nat |
| let al_of_float32 f32 = F32.to_bits f32 |> Z.of_int32_unsigned |> al_of_floatN layout32 |
| let al_of_float64 f64 = F64.to_bits f64 |> Z.of_int64_unsigned |> al_of_floatN layout64 |
| let al_of_vec128 vec = vec128_to_z vec |> al_of_z_nat |
| let al_of_bool b = Stdlib.Bool.to_int b |> al_of_nat |
| let al_of_idx idx = al_of_nat32 idx.it |
| let al_of_byte byte = Char.code byte |> al_of_nat |
| let al_of_bytes bytes_ = String.to_seq bytes_ |> al_of_seq al_of_byte |
| let al_of_name name = TextV (Utf8.encode name) |
| let al_of_memidx idx = if !version <= 2 then [] else [al_of_idx idx] |
| |
| (* Helper *) |
| |
| let arg_of_case case i = function |
| | CaseV (case', args) when case = case' -> List.nth args i |
| | v -> fail_value "arg_of_case" v |
| |
| let arg_of_tup i = function |
| | TupV args -> List.nth args i |
| | v -> fail_value "arg_of_tup" v |
| |
| (* Construct type *) |
| |
| let al_of_null = function |
| | NoNull -> none "NULL" |
| | Null -> some "NULL" |
| |
| let al_of_final = function |
| | NoFinal -> none "FINAL" |
| | Final -> some "FINAL" |
| |
| let al_of_mut = function |
| | Cons -> none "MUT" |
| | Var -> some "MUT" |
| |
| let rec al_of_storagetype = function |
| | ValStorageT vt -> al_of_valtype vt |
| | PackStorageT _ as st -> nullary (string_of_storagetype st) |
| |
| and al_of_fieldtype = function |
| | FieldT (mut, st) -> CaseV ("", [ al_of_mut mut; al_of_storagetype st ]) |
| |
| and al_of_resulttype rt = al_of_list al_of_valtype rt |
| |
| and al_of_comptype = function |
| | StructT ftl -> CaseV ("STRUCT", [ al_of_list al_of_fieldtype ftl ]) |
| | ArrayT ft -> CaseV ("ARRAY", [ al_of_fieldtype ft ]) |
| | FuncT (rt1, rt2) -> CaseV ("->", [ al_of_resulttype rt1; al_of_resulttype rt2 ]) |
| |
| and al_of_subtype = function |
| | SubT (fin, tul, st) -> |
| CaseV ("SUB", [ al_of_final fin; al_of_list al_of_typeuse tul; al_of_comptype st ]) |
| |
| and al_of_rectype = function |
| | RecT stl -> CaseV ("REC", [ al_of_list al_of_subtype stl ]) |
| |
| and al_of_deftype = function |
| | DefT (rt, i) -> CaseV ("_DEF", [al_of_rectype rt; al_of_nat32 i]) |
| |
| and al_of_typeuse = function |
| | Idx idx when !version <= 2 -> al_of_nat32 idx |
| | Idx idx -> CaseV ("_IDX", [ al_of_nat32 idx ]) |
| | Rec n -> CaseV ("REC", [ al_of_nat32 n ]) |
| | Def dt -> al_of_deftype dt |
| |
| and al_of_typeuse_of_idx = function |
| | idx when !version <= 2 -> al_of_idx idx |
| | idx -> CaseV ("_IDX", [ al_of_idx idx ]) |
| |
| and al_of_heaptype = function |
| | UseHT tu -> al_of_typeuse tu |
| | BotHT -> nullary "BOT" |
| | FuncHT | ExternHT as ht when !version <= 2 -> |
| string_of_heaptype ht ^ "REF" |> nullary |
| | ht -> string_of_heaptype ht |> nullary |
| |
| and al_of_reftype (null, ht) = |
| if !version <= 2 then |
| al_of_heaptype ht |
| else |
| CaseV ("REF", [ al_of_null null; al_of_heaptype ht ]) |
| |
| and al_of_addrtype at = string_of_addrtype at |> nullary |
| |
| and al_of_numtype nt = string_of_numtype nt |> nullary |
| |
| and al_of_vectype vt = string_of_vectype vt |> nullary |
| |
| and al_of_valtype = function |
| | RefT rt -> al_of_reftype rt |
| | NumT nt -> al_of_numtype nt |
| | VecT vt -> al_of_vectype vt |
| | BotT -> nullary "BOT" |
| |
| let al_of_blocktype = function |
| | VarBlockType idx -> CaseV ("_IDX", [ al_of_idx idx ]) |
| | ValBlockType vt_opt -> |
| if !version = 1 then |
| al_of_opt al_of_valtype vt_opt |
| else |
| CaseV ("_RESULT", [ al_of_opt al_of_valtype vt_opt ]) |
| |
| let al_of_limits limits = |
| CaseV ("[", [ al_of_nat64 limits.min; al_of_opt al_of_nat64 limits.max ]) (* TODO: Something better tan this is needed *) |
| |
| let al_of_tagtype = function |
| | TagT tu -> al_of_typeuse tu |
| |
| let al_of_globaltype = function |
| | GlobalT (mut, vt) -> CaseV ("", [ al_of_mut mut; al_of_valtype vt ]) |
| |
| let al_of_tabletype = function |
| | TableT (at, limits, rt) -> |
| if !version <= 2 then |
| CaseV ("", [ al_of_limits limits; al_of_reftype rt ]) |
| else |
| CaseV ("", [ al_of_addrtype at; al_of_limits limits; al_of_reftype rt ]) |
| |
| let al_of_memorytype = function |
| | MemoryT (at, limits) -> |
| if !version <= 2 then |
| CaseV ("PAGE", [ al_of_limits limits ]) |
| else |
| CaseV ("PAGE", [ al_of_addrtype at; al_of_limits limits ]) |
| |
| (* Construct value *) |
| |
| let al_of_num = function |
| | I32 i32 -> CaseV ("CONST", [ nullary "I32"; al_of_nat32 i32 ]) |
| | I64 i64 -> CaseV ("CONST", [ nullary "I64"; al_of_nat64 i64 ]) |
| | F32 f32 -> CaseV ("CONST", [ nullary "F32"; al_of_float32 f32 ]) |
| | F64 f64 -> CaseV ("CONST", [ nullary "F64"; al_of_float64 f64 ]) |
| |
| let al_of_vec = function |
| | V128 v128 -> CaseV ("VCONST", [ nullary "V128"; al_of_vec128 v128 ]) |
| |
| let al_of_vec_shape shape (lanes: int64 list) = |
| al_of_vec (V128 ( |
| match shape with |
| | V128.I8x16() -> V128.I8x16.of_lanes (List.map I8.of_int_s (List.map Int64.to_int lanes)) |
| | V128.I16x8() -> V128.I16x8.of_lanes (List.map I16.of_int_s (List.map Int64.to_int lanes)) |
| | V128.I32x4() -> V128.I32x4.of_lanes (List.map Int64.to_int32 lanes) |
| | V128.I64x2() -> V128.I64x2.of_lanes lanes |
| | V128.F32x4() -> V128.F32x4.of_lanes (List.map (fun i -> i |> Int64.to_int32 |> F32.of_bits) lanes) |
| | V128.F64x2() -> V128.F64x2.of_lanes (List.map F64.of_bits lanes) |
| )) |
| |
| let rec al_of_ref = function |
| | NullRef ht -> CaseV ("REF.NULL", [ al_of_heaptype ht ]) |
| (* |
| | I31.I31Ref i -> |
| CaseV ("REF.I31_NUM", [ NumV (Int64.of_int i) ]) |
| | Aggr.StructRef a -> |
| CaseV ("REF.STRUCT_ADDR", [ NumV (int64_of_int32_u a) ]) |
| | Aggr.ArrayRef a -> |
| CaseV ("REF.ARRAY_ADDR", [ NumV (int64_of_int32_u a) ]) |
| | Instance.FuncRef a -> |
| CaseV ("REF.FUNC_ADDR", [ NumV (int64_of_int32_u a) ]) |
| *) |
| | Script.HostRef i32 -> CaseV ("REF.HOST_ADDR", [ al_of_nat32 i32 ]) |
| | Extern.ExternRef r -> CaseV ("REF.EXTERN", [ al_of_ref r ]) |
| | r -> string_of_ref r |> error "al_of_ref" |
| |
| let al_of_value = function |
| | Num n -> al_of_num n |
| | Vec v -> al_of_vec v |
| | Ref r -> al_of_ref r |
| |
| |
| (* Construct operation *) |
| |
| let al_of_sx = function |
| | Pack.S -> nullary "S" |
| | Pack.U -> nullary "U" |
| |
| let al_of_op f1 f2 = function |
| | I32 op -> [ nullary "I32"; f1 op ] |
| | I64 op -> [ nullary "I64"; f1 op ] |
| | F32 op -> [ nullary "F32"; f2 op ] |
| | F64 op -> [ nullary "F64"; f2 op ] |
| |
| let al_of_int_unop = function |
| | IntOp.Clz -> CaseV ("CLZ", []) |
| | IntOp.Ctz -> CaseV ("CTZ", []) |
| | IntOp.Popcnt -> CaseV ("POPCNT", []) |
| | IntOp.ExtendS Pack.Pack8 -> CaseV ("EXTEND", [al_of_nat 8]) |
| | IntOp.ExtendS Pack.Pack16 -> CaseV ("EXTEND", [al_of_nat 16]) |
| | IntOp.ExtendS Pack.Pack32 -> CaseV ("EXTEND", [al_of_nat 32]) |
| | IntOp.ExtendS Pack.Pack64 -> CaseV ("EXTEND", [al_of_nat 64]) |
| |
| let al_of_float_unop = function |
| | FloatOp.Neg -> CaseV ("NEG", []) |
| | FloatOp.Abs -> CaseV ("ABS", []) |
| | FloatOp.Ceil -> CaseV ("CEIL", []) |
| | FloatOp.Floor -> CaseV ("FLOOR", []) |
| | FloatOp.Trunc -> CaseV ("TRUNC", []) |
| | FloatOp.Nearest -> CaseV ("NEAREST", []) |
| | FloatOp.Sqrt -> CaseV ("SQRT", []) |
| |
| let al_of_unop = al_of_op al_of_int_unop al_of_float_unop |
| |
| let al_of_int_binop = function |
| | IntOp.Add -> CaseV ("ADD", []) |
| | IntOp.Sub -> CaseV ("SUB", []) |
| | IntOp.Mul -> CaseV ("MUL", []) |
| | IntOp.Div sx -> CaseV ("DIV", [al_of_sx sx]) |
| | IntOp.Rem sx -> CaseV ("REM", [al_of_sx sx]) |
| | IntOp.And -> CaseV ("AND", []) |
| | IntOp.Or -> CaseV ("OR", []) |
| | IntOp.Xor -> CaseV ("XOR", []) |
| | IntOp.Shl -> CaseV ("SHL", []) |
| | IntOp.Shr sx -> CaseV ("SHR", [al_of_sx sx]) |
| | IntOp.Rotl -> CaseV ("ROTL", []) |
| | IntOp.Rotr -> CaseV ("ROTR", []) |
| |
| let al_of_float_binop = function |
| | FloatOp.Add -> CaseV ("ADD", []) |
| | FloatOp.Sub -> CaseV ("SUB", []) |
| | FloatOp.Mul -> CaseV ("MUL", []) |
| | FloatOp.Div -> CaseV ("DIV", []) |
| | FloatOp.Min -> CaseV ("MIN", []) |
| | FloatOp.Max -> CaseV ("MAX", []) |
| | FloatOp.CopySign -> CaseV ("COPYSIGN", []) |
| |
| let al_of_binop = al_of_op al_of_int_binop al_of_float_binop |
| |
| let al_of_int_testop: IntOp.testop -> value = function |
| | IntOp.Eqz -> CaseV ("EQZ", []) |
| |
| let al_of_float_testop: FloatOp.testop -> value = function |
| | _ -> . |
| |
| let al_of_testop: testop -> value list = al_of_op al_of_int_testop al_of_float_testop |
| |
| let al_of_int_relop = function |
| | IntOp.Eq -> CaseV ("EQ", []) |
| | IntOp.Ne -> CaseV ("NE", []) |
| | IntOp.Lt sx -> CaseV ("LT", [al_of_sx sx]) |
| | IntOp.Gt sx -> CaseV ("GT", [al_of_sx sx]) |
| | IntOp.Le sx -> CaseV ("LE", [al_of_sx sx]) |
| | IntOp.Ge sx -> CaseV ("GE", [al_of_sx sx]) |
| |
| let al_of_float_relop = function |
| | FloatOp.Eq -> CaseV ("EQ", []) |
| | FloatOp.Ne -> CaseV ("NE", []) |
| | FloatOp.Lt -> CaseV ("LT", []) |
| | FloatOp.Gt -> CaseV ("GT", []) |
| | FloatOp.Le -> CaseV ("LE", []) |
| | FloatOp.Ge -> CaseV ("GE", []) |
| |
| let al_of_relop = al_of_op al_of_int_relop al_of_float_relop |
| |
| let al_of_int_cvtop num_bits = function |
| | IntOp.ExtendI32 sx -> "I32", "EXTEND", [ al_of_sx sx ] |
| | IntOp.WrapI64 -> "I64", "WRAP", [] |
| | IntOp.TruncF32 sx -> "F32", "TRUNC", [ al_of_sx sx ] |
| | IntOp.TruncF64 sx -> "F64", "TRUNC", [ al_of_sx sx ] |
| | IntOp.TruncSatF32 sx -> "F32", "TRUNC_SAT", [ al_of_sx sx ] |
| | IntOp.TruncSatF64 sx -> "F64", "TRUNC_SAT", [ al_of_sx sx ] |
| | IntOp.ReinterpretFloat -> "F" ^ num_bits, "REINTERPRET", [] |
| |
| let al_of_float_cvtop num_bits = function |
| | FloatOp.ConvertI32 sx -> "I32", "CONVERT", [ al_of_sx sx ] |
| | FloatOp.ConvertI64 sx -> "I64", "CONVERT", [ al_of_sx sx ] |
| | FloatOp.PromoteF32 -> "F32", "PROMOTE", [] |
| | FloatOp.DemoteF64 -> "F64", "DEMOTE", [] |
| | FloatOp.ReinterpretInt -> "I" ^ num_bits, "REINTERPRET", [] |
| |
| let al_of_cvtop = function |
| | I32 op -> |
| let to_, op', sx = al_of_int_cvtop "32" op in |
| [ nullary "I32"; nullary to_; caseV (op', sx) ] |
| | I64 op -> |
| let to_, op', sx = al_of_int_cvtop "64" op in |
| [ nullary "I64"; nullary to_; caseV (op', sx) ] |
| | F32 op -> |
| let to_, op', sx = al_of_float_cvtop "32" op in |
| [ nullary "F32"; nullary to_; caseV (op', sx) ] |
| | F64 op -> |
| let to_, op', sx = al_of_float_cvtop "64" op in |
| [ nullary "F64"; nullary to_; caseV (op', sx) ] |
| |
| (* Vector operator *) |
| |
| let al_of_half = function |
| | V128Op.Low -> nullary "LOW" |
| | V128Op.High -> nullary "HIGH" |
| |
| let al_of_vop f1 f2 = function |
| | V128 vop -> ( |
| match vop with |
| | V128.I8x16 op -> [ CaseV ("X", [ nullary "I8"; numV sixteen ]); f1 op ] |
| | V128.I16x8 op -> [ CaseV ("X", [ nullary "I16"; numV eight ]); f1 op ] |
| | V128.I32x4 op -> [ CaseV ("X", [ nullary "I32"; numV four ]); f1 op ] |
| | V128.I64x2 op -> [ CaseV ("X", [ nullary "I64"; numV two ]); f1 op ] |
| | V128.F32x4 op -> [ CaseV ("X", [ nullary "F32"; numV four ]); f2 op ] |
| | V128.F64x2 op -> [ CaseV ("X", [ nullary "F64"; numV two ]); f2 op ] |
| ) |
| |
| let al_of_vop_opt f1 f2 = function |
| | V128 vop -> ( |
| match vop with |
| | V128.I8x16 op -> Option.map (fun v -> [ CaseV ("X", [ nullary "I8"; numV sixteen ]); v ]) (f1 op) |
| | V128.I16x8 op -> Option.map (fun v -> [ CaseV ("X", [ nullary "I16"; numV eight ]); v ]) (f1 op) |
| | V128.I32x4 op -> Option.map (fun v -> [ CaseV ("X", [ nullary "I32"; numV four ]); v ]) (f1 op) |
| | V128.I64x2 op -> Option.map (fun v -> [ CaseV ("X", [ nullary "I64"; numV two ]); v ]) (f1 op) |
| | V128.F32x4 op -> Option.map (fun v -> [ CaseV ("X", [ nullary "F32"; numV four ]); v ]) (f2 op) |
| | V128.F64x2 op -> Option.map (fun v -> [ CaseV ("X", [ nullary "F64"; numV two ]); v ]) (f2 op) |
| ) |
| |
| let al_of_viop f1: |
| ('a, 'a, 'a, 'a, void, void) V128.laneop vecop -> value list = function |
| | V128 vop -> ( |
| match vop with |
| | V128.I8x16 op -> [ CaseV ("X", [ nullary "I8"; numV sixteen ]); f1 op ] |
| | V128.I16x8 op -> [ CaseV ("X", [ nullary "I16"; numV eight ]); f1 op ] |
| | V128.I32x4 op -> [ CaseV ("X", [ nullary "I32"; numV four ]); f1 op ] |
| | V128.I64x2 op -> [ CaseV ("X", [ nullary "I64"; numV two ]); f1 op ] |
| | _ -> . |
| ) |
| |
| let al_of_vbitmaskop = function |
| | V128 (vop : V128Op.bitmaskop) -> ( |
| match vop with |
| | V128.I8x16 _ -> [ CaseV ("X", [ nullary "I8"; numV sixteen ]) ] |
| | V128.I16x8 _ -> [ CaseV ("X", [ nullary "I16"; numV eight ]) ] |
| | V128.I32x4 _ -> [ CaseV ("X", [ nullary "I32"; numV four ]) ] |
| | V128.I64x2 _ -> [ CaseV ("X", [ nullary "I64"; numV two ]) ] |
| | _ -> . |
| ) |
| |
| let al_of_int_vtestop : V128Op.itestop -> value = function |
| | V128Op.AllTrue -> nullary "ALL_TRUE" |
| |
| let al_of_float_vtestop : Ast.void -> value = function |
| | _ -> . |
| |
| let al_of_vtestop = al_of_vop al_of_int_vtestop al_of_float_vtestop |
| |
| let al_of_int_vrelop : V128Op.irelop -> value = function |
| | V128Op.Eq -> nullary "EQ" |
| | V128Op.Ne -> nullary "NE" |
| | V128Op.Lt sx -> caseV ("LT", [al_of_sx sx]) |
| | V128Op.Le sx -> caseV ("LE", [al_of_sx sx]) |
| | V128Op.Gt sx -> caseV ("GT", [al_of_sx sx]) |
| | V128Op.Ge sx -> caseV ("GE", [al_of_sx sx]) |
| |
| let al_of_float_vrelop : V128Op.frelop -> value = function |
| | V128Op.Eq -> nullary "EQ" |
| | V128Op.Ne -> nullary "NE" |
| | V128Op.Lt -> nullary "LT" |
| | V128Op.Le -> nullary "LE" |
| | V128Op.Gt -> nullary "GT" |
| | V128Op.Ge -> nullary "GE" |
| |
| let al_of_vrelop = al_of_vop al_of_int_vrelop al_of_float_vrelop |
| |
| let al_of_int_vunop : V128Op.iunop -> value = function |
| | V128Op.Abs -> nullary "ABS" |
| | V128Op.Neg -> nullary "NEG" |
| | V128Op.Popcnt -> nullary "POPCNT" |
| |
| let al_of_float_vunop : V128Op.funop -> value = function |
| | V128Op.Abs -> nullary "ABS" |
| | V128Op.Neg -> nullary "NEG" |
| | V128Op.Sqrt -> nullary "SQRT" |
| | V128Op.Ceil -> nullary "CEIL" |
| | V128Op.Floor -> nullary "FLOOR" |
| | V128Op.Trunc -> nullary "TRUNC" |
| | V128Op.Nearest -> nullary "NEAREST" |
| |
| let al_of_vunop = al_of_vop al_of_int_vunop al_of_float_vunop |
| |
| let al_of_int_vbinop_opt : V128Op.ibinop -> value option = function |
| | V128Op.Add -> Some (nullary "ADD") |
| | V128Op.Sub -> Some (nullary "SUB") |
| | V128Op.Mul -> Some (nullary "MUL") |
| | V128Op.Min sx -> Some (caseV ("MIN", [al_of_sx sx])) |
| | V128Op.Max sx -> Some (caseV ("MAX", [al_of_sx sx])) |
| | V128Op.AvgrU -> Some (nullary "AVGR") |
| | V128Op.AddSat sx -> Some (caseV ("ADD_SAT", [al_of_sx sx])) |
| | V128Op.SubSat sx -> Some (caseV ("SUB_SAT", [al_of_sx sx])) |
| | V128Op.Q15MulRSatS -> Some (caseV ("Q15MULR_SAT", [(*nullary "S"*)])) |
| | V128Op.RelaxedQ15MulRS -> Some (caseV ("RELAXED_Q15MULR", [(*nullary "S"*)])) |
| | _ -> None |
| |
| let al_of_float_vbinop_opt : V128Op.fbinop -> value option = function |
| | V128Op.Add -> Some (nullary "ADD") |
| | V128Op.Sub -> Some (nullary "SUB") |
| | V128Op.Mul -> Some (nullary "MUL") |
| | V128Op.Div -> Some (nullary "DIV") |
| | V128Op.Min -> Some (nullary "MIN") |
| | V128Op.Max -> Some (nullary "MAX") |
| | V128Op.Pmin -> Some (nullary "PMIN") |
| | V128Op.Pmax -> Some (nullary "PMAX") |
| | V128Op.RelaxedMin -> Some (nullary "RELAXED_MIN") |
| | V128Op.RelaxedMax -> Some (nullary "RELAXED_MAX") |
| |
| let al_of_vbinop_opt = al_of_vop_opt al_of_int_vbinop_opt al_of_float_vbinop_opt |
| |
| let al_of_int_vternop_opt : V128Op.iternop -> value option = function |
| | V128Op.RelaxedLaneselect -> Some (nullary "RELAXED_LANESELECT") |
| | _ -> None |
| |
| let al_of_float_vternop_opt : V128Op.fternop -> value option = function |
| | V128Op.RelaxedMadd -> Some (nullary "RELAXED_MADD") |
| | V128Op.RelaxedNmadd -> Some (nullary "RELAXED_NMADD") |
| |
| let al_of_vternop_opt = al_of_vop_opt al_of_int_vternop_opt al_of_float_vternop_opt |
| |
| let al_of_special_vbinop = function |
| | V128 (V128.I8x16 (V128Op.Swizzle)) when !version <= 2 -> CaseV ("VSWIZZLE", [ CaseV ("X", [ nullary "I8"; numV sixteen ]); ]) |
| | V128 (V128.I8x16 (V128Op.Swizzle)) -> CaseV ("VSWIZZLOP", [ CaseV ("X", [ nullary "I8"; numV sixteen ]); nullary "SWIZZLE" ]) |
| | V128 (V128.I8x16 (V128Op.RelaxedSwizzle)) -> CaseV ("VSWIZZLOP", [ CaseV ("X", [ nullary "I8"; numV sixteen ]); nullary "RELAXED_SWIZZLE" ]) |
| | V128 (V128.I8x16 (V128Op.Shuffle l)) -> CaseV ("VSHUFFLE", [ CaseV ("X", [ nullary "I8"; numV sixteen ]); al_of_list al_of_nat8 l ]) |
| | V128 (V128.I8x16 (V128Op.Narrow sx)) -> CaseV ("VNARROW", [ CaseV ("X", [ nullary "I8"; numV sixteen ]); CaseV ("X", [ nullary "I16"; numV eight ]); al_of_sx sx ]) |
| | V128 (V128.I16x8 (V128Op.Narrow sx)) -> CaseV ("VNARROW", [ CaseV ("X", [ nullary "I16"; numV eight]); CaseV ("X", [ nullary "I32"; numV four ]); al_of_sx sx ]) |
| | V128 (V128.I16x8 (V128Op.ExtMul (half, sx))) -> CaseV ("VEXTBINOP", [ CaseV ("X", [ nullary "I16"; numV eight ]); CaseV ("X", [ nullary "I8"; numV sixteen ]); caseV ("EXTMUL", [al_of_half half; al_of_sx sx]) ]) |
| | V128 (V128.I32x4 (V128Op.ExtMul (half, sx))) -> CaseV ("VEXTBINOP", [ CaseV ("X", [ nullary "I32"; numV four ]); CaseV ("X", [ nullary "I16"; numV eight ]); caseV ("EXTMUL", [al_of_half half; al_of_sx sx]) ]) |
| | V128 (V128.I64x2 (V128Op.ExtMul (half, sx))) -> CaseV ("VEXTBINOP", [ CaseV ("X", [ nullary "I64"; numV two ]); CaseV ("X", [ nullary "I32"; numV four ]); caseV ("EXTMUL", [al_of_half half; al_of_sx sx]) ]) |
| | V128 (V128.I32x4 (V128Op.DotS)) -> CaseV ("VEXTBINOP", [ CaseV ("X", [ nullary "I32"; numV four ]); CaseV ("X", [ nullary "I16"; numV eight ]); caseV ("DOT", [(*al_of_extension Pack.SX*)]) ]) |
| | V128 (V128.I16x8 (V128Op.RelaxedDot)) -> CaseV ("VEXTBINOP", [ CaseV ("X", [ nullary "I16"; numV eight ]); CaseV ("X", [ nullary "I8"; numV sixteen ]); caseV ("RELAXED_DOT", [(*al_of_extension Pack.SX*)]) ]) |
| | vop -> error_instr "al_of_special_vbinop" (VecBinary vop) |
| |
| let al_of_special_vternop = function |
| | V128 (V128.I32x4 V128Op.RelaxedDotAddS) -> CaseV ("VEXTTERNOP", [ CaseV ("X", [ nullary "I32"; numV four ]); CaseV ("X", [ nullary "I8"; numV sixteen ]); caseV ("RELAXED_DOT_ADD", [(*al_of_extension Pack.SX*)]) ]) |
| | vop -> error_instr "al_of_special_vternop" (VecTernary vop) |
| |
| let al_of_int_vcvtop_opt = function |
| | V128Op.Extend (half, sx) -> Some (None, caseV ("EXTEND", [al_of_half half; al_of_sx sx])) |
| | V128Op.TruncSatF32x4 sx -> Some (Some (CaseV ("X", [ nullary "F32"; numV four ])), caseV ("TRUNC_SAT", [al_of_sx sx; noneV])) |
| | V128Op.TruncSatZeroF64x2 sx -> Some (Some (CaseV ("X", [ nullary "F64"; numV two ])), caseV ("TRUNC_SAT", [al_of_sx sx; someV (nullary "ZERO")])) |
| | V128Op.RelaxedTruncF32x4 sx -> Some (Some (CaseV ("X", [ nullary "F32"; numV four ])), caseV ("RELAXED_TRUNC", [al_of_sx sx; noneV])) |
| | V128Op.RelaxedTruncZeroF64x2 sx -> Some (Some (CaseV ("X", [ nullary "F64"; numV two ])), caseV ("RELAXED_TRUNC", [al_of_sx sx; someV (nullary "ZERO")])) |
| | _ -> None |
| |
| let al_of_float32_vcvtop_opt = function |
| | V128Op.DemoteZeroF64x2 -> Some (Some (CaseV ("X", [ nullary "F64"; numV two ])), caseV ("DEMOTE", [nullary "ZERO"])) |
| | V128Op.ConvertI32x4 sx -> Some (Some (CaseV ("X", [ nullary "I32"; numV four ])), caseV ("CONVERT", [noneV; al_of_sx sx])) |
| | _ -> None |
| |
| let al_of_float64_vcvtop_opt = function |
| | V128Op.PromoteLowF32x4 -> Some (Some (CaseV ("X", [ nullary "F32"; numV four ])), nullary "PROMOTE") |
| | V128Op.ConvertI32x4 sx -> Some (Some (CaseV ("X", [ nullary "I32"; numV four ])), caseV ("CONVERT", [someV (nullary "LOW"); al_of_sx sx])) |
| | _ -> None |
| |
| let al_of_vcvtop_opt = function |
| | V128 vop -> ( |
| match vop with |
| | V128.I8x16 op -> ( |
| Option.map (fun (to_, op') -> |
| let sh = match to_ with Some sh -> sh | None -> error_instr "al_of_vcvtop" (VecConvert (V128 vop)) in |
| [ CaseV ("X", [ nullary "I8"; numV sixteen ]); sh; op' ] |
| ) (al_of_int_vcvtop_opt op) |
| ) |
| | V128.I16x8 op -> ( |
| Option.map (fun (to_, op') -> |
| let sh = match to_ with Some sh -> sh | None -> CaseV ("X", [ nullary "I8"; numV sixteen ]) in |
| [ CaseV ("X", [ nullary "I16"; numV eight ]); sh; op' ] |
| ) (al_of_int_vcvtop_opt op) |
| ) |
| | V128.I32x4 op -> ( |
| Option.map (fun (to_, op') -> |
| let sh = match to_ with Some sh -> sh | None -> CaseV ("X", [ nullary "I16"; numV eight ]) in |
| [ CaseV ("X", [ nullary "I32"; numV four ]); sh; op' ] |
| ) (al_of_int_vcvtop_opt op) |
| ) |
| | V128.I64x2 op -> ( |
| Option.map (fun (to_, op') -> |
| let sh = match to_ with Some sh -> sh | None -> CaseV ("X", [ nullary "I32"; numV four ]) in |
| [ CaseV ("X", [ nullary "I64"; numV two ]); sh; op' ] |
| ) (al_of_int_vcvtop_opt op) |
| ) |
| | V128.F32x4 op -> ( |
| Option.map (fun (to_, op') -> |
| let sh = match to_ with Some sh -> sh | None -> error_instr "al_of_vcvtop" (VecConvert (V128 vop)) in |
| [ CaseV ("X", [ nullary "F32"; numV four ]); sh; op' ] |
| ) (al_of_float32_vcvtop_opt op) |
| ) |
| | V128.F64x2 op -> ( |
| Option.map (fun (to_, op') -> |
| let sh = match to_ with Some sh -> sh | None -> error_instr "al_of_vcvtop" (VecConvert (V128 vop)) in |
| [ CaseV ("X", [ nullary "F64"; numV two ]); sh; op' ] |
| ) (al_of_float64_vcvtop_opt op) |
| ) |
| ) |
| |
| |
| let al_of_special_vcvtop = function |
| | V128 (V128.I16x8 (V128Op.ExtAddPairwise sx)) -> CaseV ("VEXTUNOP", [ CaseV ("X", [ nullary "I16"; numV eight]); CaseV ("X", [ nullary "I8"; numV sixteen ]); caseV ("EXTADD_PAIRWISE", [al_of_sx sx]) ]) |
| | V128 (V128.I32x4 (V128Op.ExtAddPairwise sx)) -> CaseV ("VEXTUNOP", [ CaseV ("X", [ nullary "I32"; numV four]); CaseV ("X", [ nullary "I16"; numV eight ]); caseV ("EXTADD_PAIRWISE", [al_of_sx sx]) ]) |
| | vop -> error_instr "al_of_special_vcvtop" (VecConvert vop) |
| |
| let al_of_int_vshiftop : V128Op.ishiftop -> value = function |
| | V128Op.Shl -> nullary "SHL" |
| | V128Op.Shr sx -> caseV ("SHR", [al_of_sx sx]) |
| |
| let al_of_vshiftop = al_of_viop al_of_int_vshiftop |
| |
| let al_of_vvtestop : vvtestop -> value list = function |
| | V128 vop -> ( |
| match vop with |
| | V128Op.AnyTrue -> |
| [ nullary "V128"; nullary "ANY_TRUE" ] |
| ) |
| |
| let al_of_vvunop : vvunop -> value list = function |
| | V128 vop -> ( |
| match vop with |
| | V128Op.Not -> [ nullary "V128"; nullary "NOT" ] |
| ) |
| |
| let al_of_vvbinop : vvbinop -> value list = function |
| | V128 vop -> ( |
| match vop with |
| | V128Op.And -> [ nullary "V128"; nullary "AND" ] |
| | V128Op.Or -> [ nullary "V128"; nullary "OR" ] |
| | V128Op.Xor -> [ nullary "V128"; nullary "XOR" ] |
| | V128Op.AndNot -> [ nullary "V128"; nullary "ANDNOT" ] |
| ) |
| |
| let al_of_vvternop : vvternop -> value list = function |
| | V128 vop -> ( |
| match vop with |
| | V128Op.Bitselect -> |
| [ nullary "V128"; nullary "BITSELECT" ] |
| ) |
| |
| let al_of_vsplatop : vsplatop -> value list = function |
| | V128 vop -> ( |
| match vop with |
| | V128.I8x16 _ -> [ CaseV ("X", [ nullary "I8"; numV sixteen ]) ] |
| | V128.I16x8 _ -> [ CaseV ("X", [ nullary "I16"; numV eight ]) ] |
| | V128.I32x4 _ -> [ CaseV ("X", [ nullary "I32"; numV four ]) ] |
| | V128.I64x2 _ -> [ CaseV ("X", [ nullary "I64"; numV two ]) ] |
| | V128.F32x4 _ -> [ CaseV ("X", [ nullary "F32"; numV four ]) ] |
| | V128.F64x2 _ -> [ CaseV ("X", [ nullary "F64"; numV two ]) ] |
| ) |
| |
| let al_of_vextractop : vextractop -> value list = function |
| | V128 vop -> ( |
| match vop with |
| | V128.I8x16 vop' -> ( |
| match vop' with |
| | Extract (n, sx) -> |
| [ CaseV ("X", [ nullary "I8"; numV sixteen ]); optV (Some (al_of_sx sx)); al_of_nat8 n; ] |
| ) |
| | V128.I16x8 vop' -> ( |
| match vop' with |
| | Extract (n, sx) -> |
| [ CaseV ("X", [ nullary "I16"; numV eight ]); optV (Some (al_of_sx sx)); al_of_nat8 n; ] |
| ) |
| | V128.I32x4 vop' -> ( |
| match vop' with |
| | Extract (n, _) -> [ CaseV ("X", [ nullary "I32"; numV four ]); optV None; al_of_nat8 n ] |
| ) |
| | V128.I64x2 vop' -> ( |
| match vop' with |
| | Extract (n, _) -> [ CaseV ("X", [ nullary "I64"; numV two ]); optV None; al_of_nat8 n ] |
| ) |
| | V128.F32x4 vop' -> ( |
| match vop' with |
| | Extract (n, _) -> [ CaseV ("X", [ nullary "F32"; numV four ]); optV None; al_of_nat8 n ] |
| ) |
| | V128.F64x2 vop' -> ( |
| match vop' with |
| | Extract (n, _) -> [ CaseV ("X", [ nullary "F64"; numV two ]); optV None; al_of_nat8 n ] |
| ) |
| ) |
| |
| let al_of_vreplaceop : vreplaceop -> value list = function |
| | V128 vop -> ( |
| match vop with |
| | V128.I8x16 (Replace n) -> [ CaseV ("X", [ nullary "I8"; numV sixteen ]); al_of_nat8 n ] |
| | V128.I16x8 (Replace n) -> [ CaseV ("X", [ nullary "I16"; numV eight ]); al_of_nat8 n ] |
| | V128.I32x4 (Replace n) -> [ CaseV ("X", [ nullary "I32"; numV four ]); al_of_nat8 n ] |
| | V128.I64x2 (Replace n) -> [ CaseV ("X", [ nullary "I64"; numV two ]); al_of_nat8 n ] |
| | V128.F32x4 (Replace n) -> [ CaseV ("X", [ nullary "F32"; numV four ]); al_of_nat8 n ] |
| | V128.F64x2 (Replace n) -> [ CaseV ("X", [ nullary "F64"; numV two ]); al_of_nat8 n ] |
| ) |
| |
| let al_of_packsize = function |
| | Pack.Pack8 -> al_of_nat 8 |
| | Pack.Pack16 -> al_of_nat 16 |
| | Pack.Pack32 -> al_of_nat 32 |
| | Pack.Pack64 -> al_of_nat 64 |
| |
| let al_of_packshape = function |
| | Pack.Pack8x8 -> [NumV eight; NumV eight] |
| | Pack.Pack16x4 -> [NumV sixteen; NumV four] |
| | Pack.Pack32x2 -> [NumV thirtytwo; NumV two] |
| |
| let al_of_memop f idx memop = |
| let str = |
| Record.empty |
| |> Record.add "ALIGN" (al_of_nat memop.align) |
| |> Record.add "OFFSET" (al_of_nat64 memop.offset) |
| in |
| [ al_of_numtype memop.ty; f memop.pack ] @ al_of_memidx idx @ [ StrV str ] |
| |
| let al_of_packsize_sx (ps, sx) = |
| CaseV ("_", [ al_of_packsize ps; al_of_sx sx ]) |
| |
| let al_of_loadop = al_of_opt al_of_packsize_sx |> al_of_memop |
| |
| let al_of_storeop = al_of_opt al_of_packsize |> al_of_memop |
| |
| let al_of_vloadop idx vloadop = |
| let str = |
| Record.empty |
| |> Record.add "ALIGN" (al_of_nat vloadop.align) |
| |> Record.add "OFFSET" (al_of_nat64 vloadop.offset) |
| in |
| |
| let vmemop = match vloadop.pack with |
| | Option.Some (packsize, vext) -> ( |
| match vext with |
| | Pack.ExtLane (packshape, sx) -> |
| CaseV ("SHAPE", al_of_packshape packshape @ [al_of_sx sx]) |
| | Pack.ExtSplat -> CaseV ("SPLAT", [ al_of_packsize packsize ]) |
| | Pack.ExtZero -> CaseV ("ZERO", [ al_of_packsize packsize ]) |
| ) |> Option.some |> optV |
| | None -> OptV None in |
| |
| al_of_vectype V128T :: vmemop :: al_of_memidx idx @ [ StrV str ] |
| |
| let al_of_vstoreop idx vstoreop = |
| let str = |
| Record.empty |
| |> Record.add "ALIGN" (al_of_nat vstoreop.align) |
| |> Record.add "OFFSET" (al_of_nat64 vstoreop.offset) |
| in |
| |
| al_of_vectype V128T :: al_of_memidx idx @ [ StrV str ] |
| |
| let al_of_vlaneop idx vlaneop laneidx = |
| let packsize = vlaneop.pack in |
| |
| let str = |
| Record.empty |
| |> Record.add "ALIGN" (al_of_nat vlaneop.align) |
| |> Record.add "OFFSET" (al_of_nat64 vlaneop.offset) |
| in |
| |
| [ al_of_vectype V128T; al_of_packsize packsize ] @ al_of_memidx idx @ [ StrV str; al_of_nat8 laneidx ] |
| |
| (* Construct instruction *) |
| |
| let al_of_catch catch = |
| match catch.it with |
| | Catch (idx1, idx2) -> CaseV ("CATCH", [ al_of_idx idx1; al_of_idx idx2 ]) |
| | CatchRef (idx1, idx2) -> CaseV ("CATCH_REF", [ al_of_idx idx1; al_of_idx idx2 ]) |
| | CatchAll idx -> CaseV ("CATCH_ALL", [ al_of_idx idx ]) |
| | CatchAllRef idx -> CaseV ("CATCH_ALL_REF", [ al_of_idx idx ]) |
| |
| let rec al_of_instr instr = |
| match instr.it with |
| (* wasm values *) |
| | Const num -> al_of_num num.it |
| | VecConst vec -> al_of_vec vec.it |
| | RefNull ht -> CaseV ("REF.NULL", [ al_of_heaptype ht ]) |
| (* wasm instructions *) |
| | Unreachable -> nullary "UNREACHABLE" |
| | Nop -> nullary "NOP" |
| | Drop -> nullary "DROP" |
| | Unary op -> CaseV ("UNOP", al_of_unop op) |
| | Binary op -> CaseV ("BINOP", al_of_binop op) |
| | Test op -> CaseV ("TESTOP", al_of_testop op) |
| | Compare op -> CaseV ("RELOP", al_of_relop op) |
| | Convert op -> CaseV ("CVTOP", al_of_cvtop op) |
| | VecTest vop -> CaseV ("VTESTOP", al_of_vtestop vop) |
| | VecCompare vop -> CaseV ("VRELOP", al_of_vrelop vop) |
| | VecUnary vop -> CaseV ("VUNOP", al_of_vunop vop) |
| | VecBinary vop -> (match al_of_vbinop_opt vop with Some l -> CaseV ("VBINOP", l) | None -> al_of_special_vbinop vop) |
| | VecTernary vop -> (match al_of_vternop_opt vop with Some l -> CaseV ("VTERNOP", l) | None -> al_of_special_vternop vop) |
| | VecConvert vop -> (match al_of_vcvtop_opt vop with Some l -> CaseV ("VCVTOP", l) | None -> al_of_special_vcvtop vop) |
| | VecShift vop -> CaseV ("VSHIFTOP", al_of_vshiftop vop) |
| | VecBitmask vop -> CaseV ("VBITMASK", al_of_vbitmaskop vop) |
| | VecTestBits vop -> CaseV ("VVTESTOP", al_of_vvtestop vop) |
| | VecUnaryBits vop -> CaseV ("VVUNOP", al_of_vvunop vop) |
| | VecBinaryBits vop -> CaseV ("VVBINOP", al_of_vvbinop vop) |
| | VecTernaryBits vop -> CaseV ("VVTERNOP", al_of_vvternop vop) |
| | VecSplat vop -> CaseV ("VSPLAT", al_of_vsplatop vop) |
| | VecExtract vop -> CaseV ("VEXTRACT_LANE", al_of_vextractop vop) |
| | VecReplace vop -> CaseV ("VREPLACE_LANE", al_of_vreplaceop vop) |
| | RefIsNull -> nullary "REF.IS_NULL" |
| | RefFunc idx -> CaseV ("REF.FUNC", [ al_of_idx idx ]) |
| | Select vtl_opt when !version = 1 -> assert (vtl_opt = None); nullary "SELECT" |
| | Select vtl_opt -> CaseV ("SELECT", [ al_of_opt (al_of_list al_of_valtype) vtl_opt ]) |
| | LocalGet idx -> CaseV ("LOCAL.GET", [ al_of_idx idx ]) |
| | LocalSet idx -> CaseV ("LOCAL.SET", [ al_of_idx idx ]) |
| | LocalTee idx -> CaseV ("LOCAL.TEE", [ al_of_idx idx ]) |
| | GlobalGet idx -> CaseV ("GLOBAL.GET", [ al_of_idx idx ]) |
| | GlobalSet idx -> CaseV ("GLOBAL.SET", [ al_of_idx idx ]) |
| | TableGet idx -> CaseV ("TABLE.GET", [ al_of_idx idx ]) |
| | TableSet idx -> CaseV ("TABLE.SET", [ al_of_idx idx ]) |
| | TableSize idx -> CaseV ("TABLE.SIZE", [ al_of_idx idx ]) |
| | TableGrow idx -> CaseV ("TABLE.GROW", [ al_of_idx idx ]) |
| | TableFill idx -> CaseV ("TABLE.FILL", [ al_of_idx idx ]) |
| | TableCopy (idx1, idx2) -> CaseV ("TABLE.COPY", [ al_of_idx idx1; al_of_idx idx2 ]) |
| | TableInit (idx1, idx2) -> CaseV ("TABLE.INIT", [ al_of_idx idx1; al_of_idx idx2 ]) |
| | ElemDrop idx -> CaseV ("ELEM.DROP", [ al_of_idx idx ]) |
| | Block (bt, instrs) -> |
| CaseV ("BLOCK", [ al_of_blocktype bt; al_of_list al_of_instr instrs ]) |
| | Loop (bt, instrs) -> |
| CaseV ("LOOP", [ al_of_blocktype bt; al_of_list al_of_instr instrs ]) |
| | If (bt, instrs1, instrs2) -> |
| CaseV ("IF", [ |
| al_of_blocktype bt; |
| al_of_list al_of_instr instrs1; |
| al_of_list al_of_instr instrs2; |
| ]) |
| | Br idx -> CaseV ("BR", [ al_of_idx idx ]) |
| | BrIf idx -> CaseV ("BR_IF", [ al_of_idx idx ]) |
| | BrTable (idxs, idx) -> |
| CaseV ("BR_TABLE", [ al_of_list al_of_idx idxs; al_of_idx idx ]) |
| | BrOnNull idx -> CaseV ("BR_ON_NULL", [ al_of_idx idx ]) |
| | BrOnNonNull idx -> CaseV ("BR_ON_NON_NULL", [ al_of_idx idx ]) |
| | BrOnCast (idx, rt1, rt2) -> |
| CaseV ("BR_ON_CAST", [ al_of_idx idx; al_of_reftype rt1; al_of_reftype rt2 ]) |
| | BrOnCastFail (idx, rt1, rt2) -> |
| CaseV ("BR_ON_CAST_FAIL", [ al_of_idx idx; al_of_reftype rt1; al_of_reftype rt2 ]) |
| | Return -> nullary "RETURN" |
| | Call idx -> CaseV ("CALL", [ al_of_idx idx ]) |
| | CallRef idx -> CaseV ("CALL_REF", [ al_of_typeuse_of_idx idx ]) |
| | CallIndirect (idx1, idx2) -> |
| let args = (if !version = 1 then [] else [ al_of_idx idx1 ]) @ [ al_of_typeuse_of_idx idx2 ] in |
| CaseV ("CALL_INDIRECT", args) |
| | ReturnCall idx -> CaseV ("RETURN_CALL", [ al_of_idx idx ]) |
| | ReturnCallRef idx -> CaseV ("RETURN_CALL_REF", [ al_of_idx idx ]) |
| | ReturnCallIndirect (idx1, idx2) -> |
| CaseV ("RETURN_CALL_INDIRECT", [ al_of_idx idx1; al_of_typeuse_of_idx idx2 ]) |
| | Throw idx -> CaseV ("THROW", [ al_of_idx idx ]) |
| | ThrowRef -> nullary "THROW_REF" |
| | TryTable (bt, catches, instrs) -> |
| CaseV ("TRY_TABLE", [ |
| al_of_blocktype bt; |
| al_of_list al_of_catch catches; |
| al_of_list al_of_instr instrs |
| ]) |
| | Load (idx, loadop) -> CaseV ("LOAD", al_of_loadop idx loadop) |
| | Store (idx, storeop) -> CaseV ("STORE", al_of_storeop idx storeop) |
| | VecLoad (idx, vloadop) -> CaseV ("VLOAD", al_of_vloadop idx vloadop) |
| | VecLoadLane (idx, vlaneop, i) -> CaseV ("VLOAD_LANE", al_of_vlaneop idx vlaneop i) |
| | VecStore (idx, vstoreop) -> CaseV ("VSTORE", al_of_vstoreop idx vstoreop) |
| | VecStoreLane (idx, vlaneop, i) -> CaseV ("VSTORE_LANE", al_of_vlaneop idx vlaneop i) |
| | MemorySize idx -> CaseV ("MEMORY.SIZE", al_of_memidx idx) |
| | MemoryGrow idx -> CaseV ("MEMORY.GROW", al_of_memidx idx) |
| | MemoryFill idx -> CaseV ("MEMORY.FILL", al_of_memidx idx) |
| | MemoryCopy (idx1, idx2) -> CaseV ("MEMORY.COPY", al_of_memidx idx1 @ al_of_memidx idx2) |
| | MemoryInit (idx1, idx2) -> CaseV ("MEMORY.INIT", al_of_memidx idx1 @ [ al_of_idx idx2 ]) |
| | DataDrop idx -> CaseV ("DATA.DROP", [ al_of_idx idx ]) |
| | RefAsNonNull -> nullary "REF.AS_NON_NULL" |
| | RefTest rt -> CaseV ("REF.TEST", [ al_of_reftype rt ]) |
| | RefCast rt -> CaseV ("REF.CAST", [ al_of_reftype rt ]) |
| | RefEq -> nullary "REF.EQ" |
| | RefI31 -> nullary "REF.I31" |
| | I31Get sx -> CaseV ("I31.GET", [ al_of_sx sx ]) |
| | StructNew (idx, Explicit) -> CaseV ("STRUCT.NEW", [ al_of_idx idx ]) |
| | StructNew (idx, Implicit) -> CaseV ("STRUCT.NEW_DEFAULT", [ al_of_idx idx ]) |
| | StructGet (idx1, idx2, sx_opt) -> |
| CaseV ("STRUCT.GET", [ |
| al_of_opt al_of_sx sx_opt; |
| al_of_idx idx1; |
| al_of_nat32 idx2; |
| ]) |
| | StructSet (idx1, idx2) -> CaseV ("STRUCT.SET", [ al_of_idx idx1; al_of_nat32 idx2 ]) |
| | ArrayNew (idx, Explicit) -> CaseV ("ARRAY.NEW", [ al_of_idx idx ]) |
| | ArrayNew (idx, Implicit) -> CaseV ("ARRAY.NEW_DEFAULT", [ al_of_idx idx ]) |
| | ArrayNewFixed (idx, i32) -> |
| CaseV ("ARRAY.NEW_FIXED", [ al_of_idx idx; al_of_nat32 i32 ]) |
| | ArrayNewElem (idx1, idx2) -> |
| CaseV ("ARRAY.NEW_ELEM", [ al_of_idx idx1; al_of_idx idx2 ]) |
| | ArrayNewData (idx1, idx2) -> |
| CaseV ("ARRAY.NEW_DATA", [ al_of_idx idx1; al_of_idx idx2 ]) |
| | ArrayGet (idx, sx_opt) -> |
| CaseV ("ARRAY.GET", [ al_of_opt al_of_sx sx_opt; al_of_idx idx ]) |
| | ArraySet idx -> CaseV ("ARRAY.SET", [ al_of_idx idx ]) |
| | ArrayLen -> nullary "ARRAY.LEN" |
| | ArrayCopy (idx1, idx2) -> CaseV ("ARRAY.COPY", [ al_of_idx idx1; al_of_idx idx2 ]) |
| | ArrayFill idx -> CaseV ("ARRAY.FILL", [ al_of_idx idx ]) |
| | ArrayInitData (idx1, idx2) -> |
| CaseV ("ARRAY.INIT_DATA", [ al_of_idx idx1; al_of_idx idx2 ]) |
| | ArrayInitElem (idx1, idx2) -> |
| CaseV ("ARRAY.INIT_ELEM", [ al_of_idx idx1; al_of_idx idx2 ]) |
| | ExternConvert Internalize -> nullary "ANY.CONVERT_EXTERN" |
| | ExternConvert Externalize -> nullary "EXTERN.CONVERT_ANY" |
| (* | _ -> CaseV ("TODO: Unconstructed Wasm instruction (al_of_instr)", []) *) |
| |
| let al_of_const const = al_of_list al_of_instr const.it |
| |
| |
| (* Construct module *) |
| |
| let al_of_type ty = |
| if !version <= 2 then |
| let subtypes = |
| al_of_rectype ty.it |
| |> arg_of_case "REC" 0 |
| |> unwrap_listv_to_list |
| in |
| |
| match subtypes with |
| | [ subtype ] -> |
| let rt = subtype |> arg_of_case "SUB" 2 in |
| CaseV ("TYPE", [ rt ]) |
| | _ -> failwith ("Rectype is not supported in Wasm " ^ (string_of_int !version)) |
| else |
| CaseV ("TYPE", [ al_of_rectype ty.it ]) |
| |
| let al_of_local local = |
| let Local t = local.it in |
| CaseV ("LOCAL", [ al_of_valtype t ]) |
| |
| let al_of_func func = |
| let Func (idx, locals, body) = func.it in |
| CaseV ("FUNC", [ |
| al_of_idx idx; |
| al_of_list al_of_local locals; |
| al_of_list al_of_instr body; |
| ]) |
| |
| let al_of_global global = |
| let Global (gt, const) = global.it in |
| CaseV ("GLOBAL", [ al_of_globaltype gt; al_of_const const ]) |
| |
| let al_of_table table = |
| let Table (tt, const) = table.it in |
| match !version with |
| | 1 -> CaseV ("TABLE", [ al_of_tabletype tt |> arg_of_case "" 0 ]) |
| | 2 -> CaseV ("TABLE", [ al_of_tabletype tt ]) |
| | _ -> CaseV ("TABLE", [ al_of_tabletype tt; al_of_const const ]) |
| |
| let al_of_memory memory = |
| let Memory mt = memory.it in |
| let arg = al_of_memorytype mt in |
| let arg' = |
| if !version = 1 then |
| arg_of_case "PAGE" 0 arg |
| else arg |
| in |
| CaseV ("MEMORY", [ arg' ]) |
| |
| let al_of_tag tag = |
| let Tag tt = tag.it in |
| CaseV ("TAG", [ al_of_tagtype tt ]) |
| |
| let al_of_segmentmode segmentmode = |
| match segmentmode.it with |
| | Passive -> nullary "PASSIVE" |
| | Active (index, offset) -> |
| CaseV ("ACTIVE", [ al_of_idx index; al_of_const offset ]) |
| | Declarative -> nullary "DECLARE" |
| |
| let al_of_elem elem = |
| let Elem (rt, consts, mode) = elem.it in |
| if !version = 1 then |
| CaseV ("ELEM", [ |
| al_of_segmentmode mode |> arg_of_case "ACTIVE" 1; |
| al_of_list al_of_const consts |
| |> unwrap_listv_to_list |
| |> List.map (fun expr -> expr |> unwrap_listv_to_list |> List.hd |> (arg_of_case "REF.FUNC" 0)) |
| |> listV_of_list; |
| ]) |
| else |
| CaseV ("ELEM", [ |
| al_of_reftype rt; |
| al_of_list al_of_const consts; |
| al_of_segmentmode mode; |
| ]) |
| |
| let al_of_data data = |
| let Data (bytes, mode) = data.it in |
| let seg = al_of_segmentmode mode in |
| let bytes_ = al_of_bytes bytes in |
| if !version = 1 then |
| CaseV ("DATA", [ arg_of_case "ACTIVE" 1 seg; bytes_ ]) |
| else |
| CaseV ("DATA", [ bytes_; seg ]) |
| |
| |
| let al_of_externtype = function |
| | ExternFuncT (typeuse) -> CaseV ("FUNC", [al_of_typeuse typeuse]) |
| | ExternGlobalT (globaltype) -> CaseV ("GLOBAL", [al_of_globaltype globaltype]) |
| | ExternTableT (tabletype) -> CaseV ("TABLE", [al_of_tabletype tabletype]) |
| | ExternMemoryT (memtype) -> CaseV ("MEM", [al_of_memorytype memtype]) |
| | ExternTagT (tagtype) -> CaseV ("TAG", [al_of_tagtype tagtype]) |
| |
| let al_of_import import = |
| let Import (module_name, item_name, xt) = import.it in |
| CaseV ("IMPORT", |
| [ al_of_name module_name; al_of_name item_name; al_of_externtype xt ]) |
| |
| let al_of_externidx xt = match xt.it with |
| | FuncX idx -> CaseV ("FUNC", [ al_of_idx idx ]) |
| | TableX idx -> CaseV ("TABLE", [ al_of_idx idx ]) |
| | MemoryX idx -> CaseV ("MEM", [ al_of_idx idx ]) |
| | GlobalX idx -> CaseV ("GLOBAL", [ al_of_idx idx ]) |
| | TagX idx -> CaseV ("TAG", [ al_of_idx idx ]) |
| |
| let al_of_start start = |
| let Start idx = start.it in |
| CaseV ("START", [ al_of_idx idx ]) |
| |
| let al_of_export export = |
| let Export (name, xx) = export.it in |
| CaseV ("EXPORT", [ al_of_name name; al_of_externidx xx ]) |
| |
| let al_of_module module_ = |
| CaseV ("MODULE", |
| if !version <= 2 then [ |
| al_of_list al_of_type module_.it.types; |
| al_of_list al_of_import module_.it.imports; |
| al_of_list al_of_func module_.it.funcs; |
| al_of_list al_of_global module_.it.globals; |
| al_of_list al_of_table module_.it.tables; |
| al_of_list al_of_memory module_.it.memories; |
| al_of_list al_of_elem module_.it.elems; |
| al_of_list al_of_data module_.it.datas; |
| al_of_opt al_of_start module_.it.start; |
| al_of_list al_of_export module_.it.exports; |
| ] else [ |
| al_of_list al_of_type module_.it.types; |
| al_of_list al_of_import module_.it.imports; |
| al_of_list al_of_tag module_.it.tags; |
| al_of_list al_of_global module_.it.globals; |
| al_of_list al_of_memory module_.it.memories; |
| al_of_list al_of_table module_.it.tables; |
| al_of_list al_of_func module_.it.funcs; |
| al_of_list al_of_data module_.it.datas; |
| al_of_list al_of_elem module_.it.elems; |
| al_of_opt al_of_start module_.it.start; |
| al_of_list al_of_export module_.it.exports; |
| ] |
| ) |