diff --git a/ml-proto/README.md b/ml-proto/README.md index 0fedba1f8d..5627b75618 100644 --- a/ml-proto/README.md +++ b/ml-proto/README.md @@ -28,7 +28,7 @@ You'll get an executable named `src/wasm`. Alternatively, you can also say (in `src`): ``` -ocamlbuild -Is "given, spec, host" -libs "bigarray, nums, str" main.native +ocamlbuild -Is "given, spec, host" -libs "bigarray, str" main.native ``` and get an executable named `src/main.native`. diff --git a/ml-proto/TestingTodo.md b/ml-proto/TestingTodo.md index 9574ca8d08..2eb96f7d44 100644 --- a/ml-proto/TestingTodo.md +++ b/ml-proto/TestingTodo.md @@ -15,18 +15,18 @@ Misc semantics: Operator semantics: - test that promote/demote, sext/trunc, zext/trunc is bit-preserving if not NaN - - test that clz/ctz handle zero + - ~~test that clz/ctz handle zero~~ - test that numbers slightly outside of the int32 range round into the int32 range in floating-to-int32 conversion - test that neg, abs, copysign, reinterpretcast, store+load, set+get, preserve the sign bit and significand bits of NaN and don't canonicalize - - test that shifts don't mask their shift count. 32 is particularly nice to test. + - ~~test that shifts don't mask their shift count. 32 is particularly nice to test.~~ - test that `page_size` returns something sane [(power of 2?)](https://github.com/WebAssembly/design/pull/296) - test that arithmetic operands are evaluated left-to-right - - test that add/sub/mul/wrap/wrapping-store silently wrap on overflow - - test that sdiv/udiv/srem/urem trap on divide-by-zero - - test that sdiv traps on overflow - - test that srem doesn't trap when the corresponding sdiv would overflow + - ~~test that add/sub/mul/wrap/wrapping-store silently wrap on overflow~~ + - ~~test that sdiv/udiv/srem/urem trap on divide-by-zero~~ + - ~~test that sdiv traps on overflow~~ + - ~~test that srem doesn't trap when the corresponding sdiv would overflow~~ - test that float-to-integer conversion traps on overflow and invalid - - test that unsigned operations are properly unsigned + - ~~test that unsigned operations are properly unsigned~~ Floating point semantics: - test for round-to-nearest rounding @@ -49,6 +49,7 @@ Linear memory semantics: - test loading "uninitialized" things from aliased stack frames return what's there - test that loadwithoffset traps in overflow cases - test that newly allocated memory is zeroed + - test that resize_memory does a full 32-bit unsigned check for page_size divisibility Function pointer semantics: - test that function pointers work [correctly](https://github.com/WebAssembly/design/issues/89) diff --git a/ml-proto/runtests.py b/ml-proto/runtests.py index 8abba2fbfa..8c7b4823a7 100755 --- a/ml-proto/runtests.py +++ b/ml-proto/runtests.py @@ -51,7 +51,7 @@ def find_interpreter(path): def rebuild_interpreter(path): print("// building %s" % path) sys.stdout.flush() - exitCode = subprocess.call(["ocamlbuild", "-libs", "bigarray, nums, str", "-Is", "given, spec, host", "-cflags", "-g", "host/main.native"], cwd=os.path.abspath("src")) + exitCode = subprocess.call(["ocamlbuild", "-libs", "bigarray, str", "-Is", "given, spec, host", "-cflags", "-g", "host/main.native"], cwd=os.path.abspath("src")) if (exitCode != 0): raise Exception("ocamlbuild failed with exit code %i" % exitCode) if not os.path.exists(path): diff --git a/ml-proto/src/Makefile b/ml-proto/src/Makefile index a2ec1a78d8..6cfebf08a7 100644 --- a/ml-proto/src/Makefile +++ b/ml-proto/src/Makefile @@ -10,7 +10,7 @@ Makefile = Makefile OCB_FLAGS += # -use-ocamlfind OCB_FLAGS += # -cflags -w OCB_FLAGS += # -cflags +a-4-41-42-44-45 -OCB_FLAGS += -libs nums,str,bigarray +OCB_FLAGS += -libs str,bigarray OCB_FLAGS += -I host -I given -I spec OCB = ocamlbuild $(OCB_FLAGS) @@ -34,7 +34,7 @@ clean: check: # check that we can find all relevant libraries # when using ocamlfind - ocamlfind query str num bigarray + ocamlfind query str bigarray zip: git archive --format=zip --prefix=$(NAME)/ \ diff --git a/ml-proto/src/host/parser.mly b/ml-proto/src/host/parser.mly index 20afa22434..65ddf704fe 100644 --- a/ml-proto/src/host/parser.mly +++ b/ml-proto/src/host/parser.mly @@ -34,10 +34,10 @@ let parse_error s = Error.error Source.no_region s let literal at s t = try match t with - | Types.Int32Type -> Values.Int32 (Int32.of_string s) @@ at - | Types.Int64Type -> Values.Int64 (Int64.of_string s) @@ at - | Types.Float32Type -> Values.Float32 (Float32.of_string s) @@ at - | Types.Float64Type -> Values.Float64 (Float64.of_string s) @@ at + | Types.Int32Type -> Values.Int32 (I32.of_string s) @@ at + | Types.Int64Type -> Values.Int64 (I64.of_string s) @@ at + | Types.Float32Type -> Values.Float32 (F32.of_string s) @@ at + | Types.Float64Type -> Values.Float64 (F64.of_string s) @@ at with _ -> Error.error at "constant out of range" diff --git a/ml-proto/src/spec/arithmetic.ml b/ml-proto/src/spec/arithmetic.ml index 5b06f17095..97f35228a5 100644 --- a/ml-proto/src/spec/arithmetic.ml +++ b/ml-proto/src/spec/arithmetic.ml @@ -11,292 +11,257 @@ open Values exception TypeError of int * value * value_type -(* Int traits *) - -module type INT = -sig - type t - val size : int - val max_int : t - val neg : t -> t - val abs : t -> t - val lognot : t -> t - val add : t -> t -> t - val sub : t -> t -> t - val mul : t -> t -> t - val div : t -> t -> t - val rem : t -> t -> t - val logand : t -> t -> t - val logor : t -> t -> t - val logxor : t -> t -> t - val shift_left : t -> int -> t - val shift_right : t -> int -> t - val shift_right_logical : t -> int -> t - val to_int : t -> int - val of_int : int -> t - val of_int32 : int32 -> t - val of_int64 : int64 -> t - val to_float : t -> float - val of_float : float -> t - val bits_of_float : float -> t - val to_big_int_u : t -> Big_int.big_int - val of_big_int_u : Big_int.big_int -> t - val to_value : t -> value - val of_value : int -> value -> t - val zero : t - val one : t -end +(* Value unpacking *) -let to_big_int_u_for size to_big_int i = - let open Big_int in - let value_range = Big_int.power_int_positive_int 2 size in - let i' = to_big_int i in - if ge_big_int i' zero_big_int then i' else add_big_int i' value_range +let i32_of_value n = + function Int32 i -> i | v -> raise (TypeError (n, v, Int32Type)) -let of_big_int_u_for size of_big_int i = - let open Big_int in - let value_range = Big_int.power_int_positive_int 2 size in - let i' = if ge_big_int i zero_big_int then i else sub_big_int i value_range - in of_big_int i' +let i64_of_value n = + function Int64 i -> i | v -> raise (TypeError (n, v, Int64Type)) -module Int32X = -struct - include Int32 - let size = 32 - let of_int32 i = i - let of_int64 = Int64.to_int32 - let to_big_int_u = to_big_int_u_for size Big_int.big_int_of_int32 - let of_big_int_u = of_big_int_u_for size Big_int.int32_of_big_int - let to_value i = Int32 i - let of_value n = - function Int32 i -> i | v -> raise (TypeError (n, v, Int32Type)) -end +let f32_of_value n = + function Float32 z -> z | v -> raise (TypeError (n, v, Float32Type)) -module Int64X = -struct - include Int64 - let size = 64 - let of_int64 i = i - let to_big_int_u = to_big_int_u_for size Big_int.big_int_of_int64 - let of_big_int_u = of_big_int_u_for size Big_int.int64_of_big_int - let to_value i = Int64 i - let of_value n = - function Int64 i -> i | v -> raise (TypeError (n, v, Int64Type)) -end +let f64_of_value n = + function Float64 z -> z | v -> raise (TypeError (n, v, Float64Type)) -(* Float traits *) - -module type FLOAT = -sig - type t - type bits - val of_float : float -> t - val to_float : t -> float - val of_string : string -> t - val to_string : t -> string - val of_bits : bits -> t - val to_bits : t -> bits - val add : t -> t -> t - val sub : t -> t -> t - val mul : t -> t -> t - val div : t -> t -> t - val sqrt : t -> t - val min : t -> t -> t - val max : t -> t -> t - val ceil : t -> t - val floor : t -> t - val trunc : t -> t - val nearest : t -> t - val abs : t -> t - val neg : t -> t - val copysign : t -> t -> t - val eq : t -> t -> bool - val ne : t -> t -> bool - val lt : t -> t -> bool - val le : t -> t -> bool - val gt : t -> t -> bool - val ge : t -> t -> bool - val size : int - val of_value : int -> value -> t - val to_value : t -> value -end +(* Int operators *) -module Float32X = +module Int32Op = struct - include Float32 - let size = 32 - let to_value z = Float32 z - let of_value n = - function Float32 z -> z | v -> raise (TypeError (n, v, Float32Type)) -end + open Ast.Int32Op -module Float64X = -struct - include Float64 - let size = 64 - let to_value z = Float64 z - let of_value n = - function Float64 z -> z | v -> raise (TypeError (n, v, Float64Type)) -end + let unop op = + let f = match op with + | Clz -> I32.clz + | Ctz -> I32.ctz + | Popcnt -> I32.popcnt + in fun v -> Int32 (f (i32_of_value 1 v)) + let binop op = + let f = match op with + | Add -> I32.add + | Sub -> I32.sub + | Mul -> I32.mul + | DivS -> I32.div_s + | DivU -> I32.div_u + | RemS -> I32.rem_s + | RemU -> I32.rem_u + | And -> I32.and_ + | Or -> I32.or_ + | Xor -> I32.xor + | Shl -> I32.shl + | ShrU -> I32.shr_u + | ShrS -> I32.shr_s + in fun v1 v2 -> Int32 (f (i32_of_value 1 v1) (i32_of_value 2 v2)) -(* Int operators *) + let relop op = + let f = match op with + | Eq -> I32.eq + | Ne -> I32.ne + | LtS -> I32.lt_s + | LtU -> I32.lt_u + | LeS -> I32.le_s + | LeU -> I32.le_u + | GtS -> I32.gt_s + | GtU -> I32.gt_u + | GeS -> I32.ge_s + | GeU -> I32.ge_u + in fun v1 v2 -> f (i32_of_value 1 v1) (i32_of_value 2 v2) -module IntOp (IntOpSyntax : module type of Ast.IntOp ()) (Int : INT) = -struct - open IntOpSyntax - open Big_int + let cvt op = + match op with + | WrapInt64 -> + fun v -> Int32 (I32_convert.wrap_i64 (i64_of_value 1 v)) + | TruncSFloat32 -> + fun v -> Int32 (I32_convert.trunc_s_f32 (f32_of_value 1 v)) + | TruncUFloat32 -> + fun v -> Int32 (I32_convert.trunc_u_f32 (f32_of_value 1 v)) + | TruncSFloat64 -> + fun v -> Int32 (I32_convert.trunc_s_f64 (f64_of_value 1 v)) + | TruncUFloat64 -> + fun v -> Int32 (I32_convert.trunc_u_f64 (f64_of_value 1 v)) + | ReinterpretFloat -> + fun v -> Int32 (I32_convert.reinterpret_f32 (f32_of_value 1 v)) + | ExtendSInt32 -> + fun v -> raise (TypeError (1, v, Int32Type)) + | ExtendUInt32 -> + fun v -> raise (TypeError (1, v, Int32Type)) +end - let unsigned big_op i j = big_op (Int.to_big_int_u i) (Int.to_big_int_u j) +module Int64Op = +struct + open Ast.Int64Op let unop op = - let open Int in let f = match op with - | Clz -> - let rec loop acc n = - if n = zero then - size - else if logand n (shift_left one (size - 1)) <> zero then - acc - else - loop (1 + acc) (shift_left n 1) - in loop 0 - | Ctz -> - let rec loop acc n = - if n = zero then - size - else if logand n one = one then - acc - else - loop (1 + acc) (shift_right_logical n 1) - in loop 0 - | Popcnt -> - let rec loop acc i n = - if n = zero then - acc - else - let acc' = if logand n one = one then acc + 1 else acc in - loop acc' (i - 1) (shift_right_logical n 1) - in loop 0 size - in fun v -> to_value (of_int (f (of_value 1 v))) + | Clz -> I64.clz + | Ctz -> I64.ctz + | Popcnt -> I64.popcnt + in fun v -> Int64 (f (i64_of_value 1 v)) let binop op = let f = match op with - | Add -> Int.add - | Sub -> Int.sub - | Mul -> Int.mul - | DivS -> Int.div - | DivU -> fun i j -> Int.of_big_int_u (unsigned div_big_int i j) - | RemS -> Int.rem - | RemU -> fun i j -> Int.of_big_int_u (unsigned mod_big_int i j) - | And -> Int.logand - | Or -> Int.logor - | Xor -> Int.logxor - | Shl -> fun i j -> Int.shift_left i (Int.to_int j) - | ShrU -> fun i j -> Int.shift_right_logical i (Int.to_int j) - | ShrS -> fun i j -> Int.shift_right i (Int.to_int j) - in fun v1 v2 -> Int.to_value (f (Int.of_value 1 v1) (Int.of_value 2 v2)) + | Add -> I64.add + | Sub -> I64.sub + | Mul -> I64.mul + | DivS -> I64.div_s + | DivU -> I64.div_u + | RemS -> I64.rem_s + | RemU -> I64.rem_u + | And -> I64.and_ + | Or -> I64.or_ + | Xor -> I64.xor + | Shl -> I64.shl + | ShrU -> I64.shr_u + | ShrS -> I64.shr_s + in fun v1 v2 -> Int64 (f (i64_of_value 1 v1) (i64_of_value 2 v2)) let relop op = let f = match op with - | Eq -> (=) - | Ne -> (<>) - | LtS -> (<) - | LtU -> unsigned lt_big_int - | LeS -> (<=) - | LeU -> unsigned le_big_int - | GtS -> (>) - | GtU -> unsigned gt_big_int - | GeS -> (>=) - | GeU -> unsigned ge_big_int - in fun v1 v2 -> f (Int.of_value 1 v1) (Int.of_value 2 v2) - - let of_float_u x = - let limit = Int.to_float Int.max_int +. 1.0 in - if x < 0.0 || x >= 2.0 *. limit then Int.of_float 0.0 else - if x < limit then Int.of_float x else - Int.add (Int.of_float (x -. limit +. 1.0)) Int.max_int + | Eq -> I64.eq + | Ne -> I64.ne + | LtS -> I64.lt_s + | LtU -> I64.lt_u + | LeS -> I64.le_s + | LeU -> I64.le_u + | GtS -> I64.gt_s + | GtU -> I64.gt_u + | GeS -> I64.ge_s + | GeU -> I64.ge_u + in fun v1 v2 -> f (i64_of_value 1 v1) (i64_of_value 2 v2) let cvt op = - let f = match op with - | ExtendSInt32 -> fun v -> Int.of_int32 (Int32X.of_value 1 v) - | ExtendUInt32 -> fun v -> - Int.of_big_int_u (Int32X.to_big_int_u (Int32X.of_value 1 v)) - | WrapInt64 -> fun v -> Int.of_int64 (Int64X.of_value 1 v) - | TruncSFloat32 -> fun v -> Int.of_float (Float32.to_float (Float32X.of_value 1 v)) - | TruncUFloat32 -> fun v -> of_float_u (Float32.to_float (Float32X.of_value 1 v)) - | TruncSFloat64 -> fun v -> Int.of_float (Float64.to_float (Float64X.of_value 1 v)) - | TruncUFloat64 -> fun v -> of_float_u (Float64.to_float (Float64X.of_value 1 v)) - | ReinterpretFloat -> fun v -> - if Int.size = 32 - then Int.bits_of_float (Float32.to_float (Float32X.of_value 1 v)) - else Int.bits_of_float (Float64.to_float (Float64X.of_value 1 v)) - in fun v -> Int.to_value (f v) + match op with + | ExtendSInt32 -> + fun v -> Int64 (I64_convert.extend_s_i32 (i32_of_value 1 v)) + | ExtendUInt32 -> + fun v -> Int64 (I64_convert.extend_u_i32 (i32_of_value 1 v)) + | TruncSFloat32 -> + fun v -> Int64 (I64_convert.trunc_s_f32 (f32_of_value 1 v)) + | TruncUFloat32 -> + fun v -> Int64 (I64_convert.trunc_u_f32 (f32_of_value 1 v)) + | TruncSFloat64 -> + fun v -> Int64 (I64_convert.trunc_s_f64 (f64_of_value 1 v)) + | TruncUFloat64 -> + fun v -> Int64 (I64_convert.trunc_u_f64 (f64_of_value 1 v)) + | ReinterpretFloat -> + fun v -> Int64 (I64_convert.reinterpret_f64 (f64_of_value 1 v)) + | WrapInt64 -> + fun v -> raise (TypeError (1, v, Int64Type)) end -module Int32Op = IntOp (Ast.Int32Op) (Int32X) -module Int64Op = IntOp (Ast.Int64Op) (Int64X) - (* Float operators *) -module FloatOp (FloatOpSyntax : module type of Ast.FloatOp ()) (Float : FLOAT) = +module Float32Op = struct - open FloatOpSyntax + open Ast.Float32Op let unop op = let f = match op with - | Neg -> Float.neg - | Abs -> Float.abs - | Sqrt -> Float.sqrt - | Ceil -> Float.ceil - | Floor -> Float.floor - | Trunc -> Float.trunc - | Nearest -> Float.nearest - in fun v -> Float.to_value (f (Float.of_value 1 v)) + | Neg -> F32.neg + | Abs -> F32.abs + | Sqrt -> F32.sqrt + | Ceil -> F32.ceil + | Floor -> F32.floor + | Trunc -> F32.trunc + | Nearest -> F32.nearest + in fun v -> Float32 (f (f32_of_value 1 v)) let binop op = let f = match op with - | Add -> Float.add - | Sub -> Float.sub - | Mul -> Float.mul - | Div -> Float.div - | Min -> Float.min - | Max -> Float.max - | CopySign -> Float.copysign - in - fun v1 v2 -> Float.to_value (f (Float.of_value 1 v1) (Float.of_value 2 v2)) + | Add -> F32.add + | Sub -> F32.sub + | Mul -> F32.mul + | Div -> F32.div + | Min -> F32.min + | Max -> F32.max + | CopySign -> F32.copysign + in fun v1 v2 -> Float32 (f (f32_of_value 1 v1) (f32_of_value 2 v2)) let relop op = let f = match op with - | Eq -> Float.eq - | Ne -> Float.ne - | Lt -> Float.lt - | Le -> Float.le - | Gt -> Float.gt - | Ge -> Float.ge - in fun v1 v2 -> f (Float.of_value 1 v1) (Float.of_value 2 v2) + | Eq -> F32.eq + | Ne -> F32.ne + | Lt -> F32.lt + | Le -> F32.le + | Gt -> F32.gt + | Ge -> F32.ge + in fun v1 v2 -> f (f32_of_value 1 v1) (f32_of_value 2 v2) let cvt op = - let f = match op with - | ConvertSInt32 -> fun v -> Int32.to_float (Int32X.of_value 1 v) - | ConvertUInt32 -> fun v -> - Big_int.float_of_big_int (Int32X.to_big_int_u (Int32X.of_value 1 v)) - | ConvertSInt64 -> fun v -> Int64.to_float (Int64X.of_value 1 v) - | ConvertUInt64 -> fun v -> - Big_int.float_of_big_int (Int64X.to_big_int_u (Int64X.of_value 1 v)) - | PromoteFloat32 -> fun v -> (Float32.to_float (Float32X.of_value 1 v)) - | DemoteFloat64 -> fun v -> (Float64.to_float (Float64X.of_value 1 v)) - | ReinterpretInt -> fun v -> - if Float.size = 32 - then Int32.float_of_bits (Int32X.of_value 1 v) - else Int64.float_of_bits (Int64X.of_value 1 v) - in fun v -> (Float.to_value (Float.of_float (f v))) + match op with + | DemoteFloat64 -> + fun v -> Float32 (F32_convert.demote_f64 (f64_of_value 1 v)) + | ConvertSInt32 -> + fun v -> Float32 (F32_convert.convert_s_i32 (i32_of_value 1 v)) + | ConvertUInt32 -> + fun v -> Float32 (F32_convert.convert_u_i32 (i32_of_value 1 v)) + | ConvertSInt64 -> + fun v -> Float32 (F32_convert.convert_s_i64 (i64_of_value 1 v)) + | ConvertUInt64 -> + fun v -> Float32 (F32_convert.convert_u_i64 (i64_of_value 1 v)) + | ReinterpretInt -> + fun v -> Float32 (F32_convert.reinterpret_i32 (i32_of_value 1 v)) + | PromoteFloat32 -> + fun v -> raise (TypeError (1, v, Float32Type)) end -module Float32Op = FloatOp (Ast.Float32Op) (Float32X) -module Float64Op = FloatOp (Ast.Float64Op) (Float64X) +module Float64Op = +struct + open Ast.Float64Op + + let unop op = + let f = match op with + | Neg -> F64.neg + | Abs -> F64.abs + | Sqrt -> F64.sqrt + | Ceil -> F64.ceil + | Floor -> F64.floor + | Trunc -> F64.trunc + | Nearest -> F64.nearest + in fun v -> Float64 (f (f64_of_value 1 v)) + + let binop op = + let f = match op with + | Add -> F64.add + | Sub -> F64.sub + | Mul -> F64.mul + | Div -> F64.div + | Min -> F64.min + | Max -> F64.max + | CopySign -> F64.copysign + in fun v1 v2 -> Float64 (f (f64_of_value 1 v1) (f64_of_value 2 v2)) + + let relop op = + let f = match op with + | Eq -> F64.eq + | Ne -> F64.ne + | Lt -> F64.lt + | Le -> F64.le + | Gt -> F64.gt + | Ge -> F64.ge + in fun v1 v2 -> f (f64_of_value 1 v1) (f64_of_value 2 v2) + + let cvt op = + match op with + | PromoteFloat32 -> + fun v -> Float64 (F64_convert.promote_f32 (f32_of_value 1 v)) + | ConvertSInt32 -> + fun v -> Float64 (F64_convert.convert_s_i32 (i32_of_value 1 v)) + | ConvertUInt32 -> + fun v -> Float64 (F64_convert.convert_u_i32 (i32_of_value 1 v)) + | ConvertSInt64 -> + fun v -> Float64 (F64_convert.convert_s_i64 (i64_of_value 1 v)) + | ConvertUInt64 -> + fun v -> Float64 (F64_convert.convert_u_i64 (i64_of_value 1 v)) + | ReinterpretInt -> + fun v -> Float64 (F64_convert.reinterpret_i64 (i64_of_value 1 v)) + | DemoteFloat64 -> + fun v -> raise (TypeError (1, v, Float64Type)) +end (* Dispatch *) diff --git a/ml-proto/src/spec/eval.ml b/ml-proto/src/spec/eval.ml index a7034f2b72..b125f6b435 100644 --- a/ml-proto/src/spec/eval.ml +++ b/ml-proto/src/spec/eval.ml @@ -43,7 +43,7 @@ type config = } let page_size c = - Int32.of_int c.modul.host.page_size + I32.of_int32 (Int32.of_int c.modul.host.page_size) let lookup category list x = try List.nth list x.it with Failure _ -> @@ -79,6 +79,15 @@ let type_error at v t = ("runtime: type error, expected " ^ Types.string_of_value_type t ^ ", got " ^ Types.string_of_value_type (type_of v)) +let numerics_error at = function + | Numerics.IntegerOverflow -> + error at "runtime: integer overflow" + | Numerics.IntegerDivideByZero -> + error at "runtime: integer divide by zero" + | Numerics.InvalidConversionToInteger -> + error at "runtime: invalid conversion to integer" + | exn -> raise exn + let some v at = match v with | Some v -> v @@ -145,6 +154,7 @@ let rec eval_expr (c : config) (e : expr) = | CallIndirect (x, e1, es) -> let i = int32 (eval_expr c e1) e1.at in let vs = List.map (fun vo -> some (eval_expr c vo) vo.at) es in + (* TODO: The conversion to int could overflow. *) eval_func c.modul (table c x (Int32.to_int i @@ e1.at)) vs | Return eo -> @@ -176,14 +186,18 @@ let rec eval_expr (c : config) (e : expr) = | Unary (unop, e1) -> let v1 = some (eval_expr c e1) e1.at in (try Some (Arithmetic.eval_unop unop v1) - with Arithmetic.TypeError (_, v, t) -> type_error e1.at v t) + with + | Arithmetic.TypeError (_, v, t) -> type_error e1.at v t + | exn -> numerics_error e.at exn) | Binary (binop, e1, e2) -> let v1 = some (eval_expr c e1) e1.at in let v2 = some (eval_expr c e2) e2.at in (try Some (Arithmetic.eval_binop binop v1 v2) - with Arithmetic.TypeError (i, v, t) -> - type_error (if i = 1 then e1 else e2).at v t) + with + | Arithmetic.TypeError (i, v, t) -> + type_error (if i = 1 then e1 else e2).at v t + | exn -> numerics_error e.at exn) | Compare (relop, e1, e2) -> let v1 = some (eval_expr c e1) e1.at in @@ -197,18 +211,21 @@ let rec eval_expr (c : config) (e : expr) = | Convert (cvt, e1) -> let v1 = some (eval_expr c e1) e1.at in (try Some (Arithmetic.eval_cvt cvt v1) - with Arithmetic.TypeError (_, v, t) -> type_error e1.at v t) + with + | Arithmetic.TypeError (_, v, t) -> type_error e1.at v t + | exn -> numerics_error e.at exn) | PageSize -> Some (Int32 (page_size c)) | MemorySize -> - Some (Int32 (Int32.of_int (Memory.size c.modul.memory))) + Some (Int32 (I32.of_int32 (Int32.of_int (Memory.size c.modul.memory)))) | ResizeMemory e -> let i = int32 (eval_expr c e) e.at in - if (Int32.rem i (page_size c)) <> Int32.zero then + if (I32.rem_u i (page_size c)) <> I32.zero then error e.at "runtime: resize_memory operand not multiple of page_size"; + (* TODO: The conversion to int could overflow. *) Memory.resize c.modul.memory (Int32.to_int i); None diff --git a/ml-proto/src/given/float32.ml b/ml-proto/src/spec/f32.ml similarity index 90% rename from ml-proto/src/given/float32.ml rename to ml-proto/src/spec/f32.ml index e30eda5a6c..af602d794a 100644 --- a/ml-proto/src/given/float32.ml +++ b/ml-proto/src/spec/f32.ml @@ -1,8 +1,8 @@ -(* WebAssembly-compatible float32 implementation *) +(* WebAssembly-compatible f32 implementation *) (* - * We represent float32 as its bits in an int32 so that we can be assured that - * all the bits of NaNs are preserved in all cases where we require them to be. + * We represent f32 as its bits in an int32 so that we can be assured that all + * the bits of NaNs are preserved in all cases where we require them to be. *) type t = int32 type bits = int32 @@ -13,10 +13,6 @@ let nondeterministic_nan = 0x7fc0f0f0l let of_float = Int32.bits_of_float let to_float = Int32.float_of_bits -(* TODO: OCaml's string_of_float and float_of_string are insufficient *) -let of_string x = of_float (float_of_string x) -let to_string x = string_of_float (to_float x) - let of_bits x = x let to_bits x = x @@ -61,7 +57,7 @@ let nearest x = let min x y = let xf = arith_of_bits x in let yf = arith_of_bits y in - (* min(-0, 0) is -0 *) + (* min -0 0 is -0 *) if xf = yf then Int32.logor x y else if xf < yf then x else if xf > yf then y else @@ -70,7 +66,7 @@ let min x y = let max x y = let xf = arith_of_bits x in let yf = arith_of_bits y in - (* max(-0, 0) is 0 *) + (* max -0 0 is 0 *) if xf = yf then Int32.logand x y else if xf > yf then x else if xf < yf then y else @@ -93,4 +89,6 @@ let gt x y = (arith_of_bits x) > (arith_of_bits y) let le x y = (arith_of_bits x) <= (arith_of_bits y) let ge x y = (arith_of_bits x) >= (arith_of_bits y) -(* TODO: type conversion functions *) +(* TODO: OCaml's string_of_float and float_of_string are insufficient *) +let of_string x = of_float (float_of_string x) +let to_string x = string_of_float (to_float x) diff --git a/ml-proto/src/given/float32.mli b/ml-proto/src/spec/f32.mli similarity index 92% rename from ml-proto/src/given/float32.mli rename to ml-proto/src/spec/f32.mli index 126caf4453..1174efaa43 100644 --- a/ml-proto/src/given/float32.mli +++ b/ml-proto/src/spec/f32.mli @@ -1,4 +1,4 @@ -(* WebAssembly-compatible float32 implementation *) +(* WebAssembly-compatible f32 implementation *) type t type bits = int32 @@ -7,8 +7,6 @@ val of_float : float -> t val to_float : t -> float val of_bits : bits -> t val to_bits : t -> bits -val of_string : string -> t -val to_string : t -> string val zero : t @@ -32,3 +30,6 @@ val lt : t -> t -> bool val le : t -> t -> bool val gt : t -> t -> bool val ge : t -> t -> bool + +val of_string : string -> t +val to_string : t -> string diff --git a/ml-proto/src/spec/f32_convert.ml b/ml-proto/src/spec/f32_convert.ml new file mode 100644 index 0000000000..078d88d5bb --- /dev/null +++ b/ml-proto/src/spec/f32_convert.ml @@ -0,0 +1,28 @@ +(* WebAssembly-compatible type conversions to f32 implementation *) + +let make_nan_nondeterministic x = F32.mul x (F32.of_float 1.) + +let demote_f64 x = + make_nan_nondeterministic (F32.of_float (F64.to_float x)) + +let convert_s_i32 x = + make_nan_nondeterministic (F32.of_float (Int32.to_float x)) + +let convert_u_i32 x = + make_nan_nondeterministic + (F32.of_float (if x >= Int32.zero then + Int32.to_float x + else + Int32.to_float (Int32.shift_right_logical x 1) *. 2.)) + +let convert_s_i64 x = + make_nan_nondeterministic (F32.of_float (Int64.to_float x)) + +let convert_u_i64 x = + make_nan_nondeterministic + (F32.of_float (if x >= Int64.zero then + Int64.to_float x + else + Int64.to_float (Int64.shift_right_logical x 1) *. 2.)) + +let reinterpret_i32 = F32.of_bits diff --git a/ml-proto/src/spec/f32_convert.mli b/ml-proto/src/spec/f32_convert.mli new file mode 100644 index 0000000000..bcff3589b6 --- /dev/null +++ b/ml-proto/src/spec/f32_convert.mli @@ -0,0 +1,8 @@ +(* WebAssembly-compatible type conversions to f32 implementation *) + +val demote_f64 : F64.t -> F32.t +val convert_s_i32 : I32.t -> F32.t +val convert_u_i32 : I32.t -> F32.t +val convert_s_i64 : I64.t -> F32.t +val convert_u_i64 : I64.t -> F32.t +val reinterpret_i32 : I32.t -> F32.t diff --git a/ml-proto/src/given/float64.ml b/ml-proto/src/spec/f64.ml similarity index 90% rename from ml-proto/src/given/float64.ml rename to ml-proto/src/spec/f64.ml index d2a54f43d4..3c11879ef7 100644 --- a/ml-proto/src/given/float64.ml +++ b/ml-proto/src/spec/f64.ml @@ -1,8 +1,8 @@ -(* WebAssembly-compatible float64 implementation *) +(* WebAssembly-compatible f64 implementation *) (* - * We represent float64 as its bits in an int64 so that we can be assured that - * all the bits of NaNs are preserved in all cases where we require them to be. + * We represent f64 as its bits in an int64 so that we can be assured that all + * the bits of NaNs are preserved in all cases where we require them to be. *) type t = int64 type bits = int64 @@ -13,10 +13,6 @@ let nondeterministic_nan = 0x7fff0f0f0f0f0f0fL let of_float = Int64.bits_of_float let to_float = Int64.float_of_bits -(* TODO: OCaml's string_of_float and float_of_string are insufficient *) -let of_string x = of_float (float_of_string x) -let to_string x = string_of_float (to_float x) - let of_bits x = x let to_bits x = x @@ -61,7 +57,7 @@ let nearest x = let min x y = let xf = arith_of_bits x in let yf = arith_of_bits y in - (* min(-0, 0) is -0 *) + (* min -0 0 is -0 *) if xf = yf then Int64.logor x y else if xf < yf then x else if xf > yf then y else @@ -70,7 +66,7 @@ let min x y = let max x y = let xf = arith_of_bits x in let yf = arith_of_bits y in - (* max(-0, 0) is 0 *) + (* max -0 0 is 0 *) if xf = yf then Int64.logand x y else if xf > yf then x else if xf < yf then y else @@ -93,4 +89,6 @@ let gt x y = (arith_of_bits x) > (arith_of_bits y) let le x y = (arith_of_bits x) <= (arith_of_bits y) let ge x y = (arith_of_bits x) >= (arith_of_bits y) -(* TODO: type conversion functions *) +(* TODO: OCaml's string_of_float and float_of_string are insufficient *) +let of_string x = of_float (float_of_string x) +let to_string x = string_of_float (to_float x) diff --git a/ml-proto/src/given/float64.mli b/ml-proto/src/spec/f64.mli similarity index 92% rename from ml-proto/src/given/float64.mli rename to ml-proto/src/spec/f64.mli index fef07a86a1..45631cd7a8 100644 --- a/ml-proto/src/given/float64.mli +++ b/ml-proto/src/spec/f64.mli @@ -1,4 +1,4 @@ -(* WebAssembly-compatible float64 implementation *) +(* WebAssembly-compatible f64 implementation *) type t type bits = int64 @@ -7,8 +7,6 @@ val of_float : float -> t val to_float : t -> float val of_bits : bits -> t val to_bits : t -> bits -val of_string : string -> t -val to_string : t -> string val zero : t @@ -32,3 +30,6 @@ val lt : t -> t -> bool val le : t -> t -> bool val gt : t -> t -> bool val ge : t -> t -> bool + +val of_string : string -> t +val to_string : t -> string diff --git a/ml-proto/src/spec/f64_convert.ml b/ml-proto/src/spec/f64_convert.ml new file mode 100644 index 0000000000..dc572e0a5c --- /dev/null +++ b/ml-proto/src/spec/f64_convert.ml @@ -0,0 +1,28 @@ +(* WebAssembly-compatible type conversions to f64 implementation *) + +let make_nan_nondeterministic x = F64.mul x (F64.of_float 1.) + +let promote_f32 x = + make_nan_nondeterministic (F64.of_float (F32.to_float x)) + +let convert_s_i32 x = + make_nan_nondeterministic (F64.of_float (Int32.to_float x)) + +let convert_u_i32 x = + make_nan_nondeterministic + (F64.of_float (if x >= Int32.zero then + Int32.to_float x + else + Int32.to_float (Int32.shift_right_logical x 1) *. 2.)) + +let convert_s_i64 x = + make_nan_nondeterministic (F64.of_float (Int64.to_float x)) + +let convert_u_i64 x = + make_nan_nondeterministic + (F64.of_float (if x >= Int64.zero then + Int64.to_float x + else + Int64.to_float (Int64.shift_right_logical x 1) *. 2.)) + +let reinterpret_i64 = F64.of_bits diff --git a/ml-proto/src/spec/f64_convert.mli b/ml-proto/src/spec/f64_convert.mli new file mode 100644 index 0000000000..a1209a3e70 --- /dev/null +++ b/ml-proto/src/spec/f64_convert.mli @@ -0,0 +1,8 @@ +(* WebAssembly-compatible type conversions to f64 implementation *) + +val promote_f32 : F32.t -> F64.t +val convert_s_i32 : I32.t -> F64.t +val convert_u_i32 : I32.t -> F64.t +val convert_s_i64 : I64.t -> F64.t +val convert_u_i64 : I64.t -> F64.t +val reinterpret_i64 : I64.t -> F64.t diff --git a/ml-proto/src/spec/i32.ml b/ml-proto/src/spec/i32.ml new file mode 100644 index 0000000000..20896e4eda --- /dev/null +++ b/ml-proto/src/spec/i32.ml @@ -0,0 +1,122 @@ +(* WebAssembly-compatible i32 implementation *) + +(* + * Unsigned comparison in terms of signed comparison. + *) +let cmp_u x op y = + op (Int32.add x Int32.min_int) (Int32.add y Int32.min_int) + +(* + * Unsigned division and remainder in terms of signed division; algorithm from + * Hacker's Delight, Second Edition, by Henry S. Warren, Jr., section 9-3 + * "Unsigned Short Division from Signed Division". + *) +let divrem_u n d = + if d = Int32.zero then raise Numerics.IntegerDivideByZero else + let t = Int32.shift_right d (32 - 1) in + let n' = Int32.logand n (Int32.lognot t) in + let q = Int32.shift_left (Int32.div (Int32.shift_right_logical n' 1) d) 1 in + let r = Int32.sub n (Int32.mul q d) in + if cmp_u r (<) d then + q, r + else + Int32.add q Int32.one, Int32.sub r d + +type t = int32 + +let of_int32 x = x +let to_int32 x = x + +let zero = Int32.zero + +let add = Int32.add +let sub = Int32.sub +let mul = Int32.mul + +let div_s x y = + if y = Int32.zero then + raise Numerics.IntegerDivideByZero + else if x = Int32.min_int && y = Int32.minus_one then + raise Numerics.IntegerOverflow + else + Int32.div x y + +let div_u x y = + let q, r = divrem_u x y in q + +let rem_s x y = + if y = Int32.zero then + raise Numerics.IntegerDivideByZero + else + Int32.rem x y + +let rem_u x y = + let q, r = divrem_u x y in r + +let and_ = Int32.logand +let or_ = Int32.logor +let xor = Int32.logxor + +(* WebAssembly shift counts are unmasked and unsigned *) +let shift_ok n = n >= Int32.zero && n < Int32.of_int 32 + +let shl x y = + if shift_ok y then + Int32.shift_left x (Int32.to_int y) + else + Int32.zero + +let shr_s x y = + Int32.shift_right x (if shift_ok y then Int32.to_int y else 32 - 1) + +let shr_u x y = + if shift_ok y then + Int32.shift_right_logical x (Int32.to_int y) + else + Int32.zero + +let clz x = + Int32.of_int + (let rec loop acc n = + if n = Int32.zero then + 32 + else if and_ n (Int32.shift_left Int32.one (32 - 1)) <> Int32.zero then + acc + else + loop (1 + acc) (Int32.shift_left n 1) + in loop 0 x) + +let ctz x = + Int32.of_int + (let rec loop acc n = + if n = Int32.zero then + 32 + else if and_ n Int32.one = Int32.one then + acc + else + loop (1 + acc) (Int32.shift_right_logical n 1) + in loop 0 x) + +let popcnt x = + Int32.of_int + (let rec loop acc i n = + if n = Int32.zero then + acc + else + let acc' = if and_ n Int32.one = Int32.one then acc + 1 else acc in + loop acc' (i - 1) (Int32.shift_right_logical n 1) + in loop 0 32 x) + +let eq x y = x = y +let ne x y = x <> y +let lt_s x y = x < y +let lt_u x y = cmp_u x (<) y +let le_s x y = x <= y +let le_u x y = cmp_u x (<=) y +let gt_s x y = x > y +let gt_u x y = cmp_u x (>) y +let ge_s x y = x >= y +let ge_u x y = cmp_u x (>=) y + +let of_string = Int32.of_string +let to_string = Int32.to_string diff --git a/ml-proto/src/spec/i32.mli b/ml-proto/src/spec/i32.mli new file mode 100644 index 0000000000..b2d44abce2 --- /dev/null +++ b/ml-proto/src/spec/i32.mli @@ -0,0 +1,39 @@ +(* WebAssembly-compatible i32 implementation *) + +(* TODO Make this type opaque? *) +type t = int32 + +val of_int32 : int32 -> t +val to_int32 : t -> int32 + +val zero : t + +val add : t -> t -> t +val sub : t -> t -> t +val mul : t -> t -> t +val div_s : t -> t -> t +val div_u : t -> t -> t +val rem_s : t -> t -> t +val rem_u : t -> t -> t +val and_ : t -> t -> t +val or_ : t -> t -> t +val xor : t -> t -> t +val shl : t -> t -> t +val shr_s : t -> t -> t +val shr_u : t -> t -> t +val clz : t -> t +val ctz : t -> t +val popcnt : t -> t +val eq : t -> t -> bool +val ne : t -> t -> bool +val lt_s : t -> t -> bool +val lt_u : t -> t -> bool +val le_s : t -> t -> bool +val le_u : t -> t -> bool +val gt_s : t -> t -> bool +val gt_u : t -> t -> bool +val ge_s : t -> t -> bool +val ge_u : t -> t -> bool + +val of_string : string -> t +val to_string : t -> string diff --git a/ml-proto/src/spec/i32_convert.ml b/ml-proto/src/spec/i32_convert.ml new file mode 100644 index 0000000000..dd4b3f2bcf --- /dev/null +++ b/ml-proto/src/spec/i32_convert.ml @@ -0,0 +1,45 @@ +(* WebAssembly-compatible type conversions to i32 implementation *) + +let wrap_i64 x = Int64.to_int32 x + +let trunc_s_f32 x = + if F32.ne x x then + raise Numerics.InvalidConversionToInteger + else let xf = F32.to_float x in + if xf >= (Int32.to_float Int32.max_int) +. 1. || + xf <= (Int32.to_float Int32.min_int) -. 1. then + raise Numerics.IntegerOverflow + else + Int32.of_float xf + +let trunc_u_f32 x = + if F32.ne x x then + raise Numerics.InvalidConversionToInteger + else let xf = F32.to_float x in + if xf >= (Int32.to_float Int32.max_int) *. 2. +. 2. || + xf <= -1. then + raise Numerics.IntegerOverflow + else + Int64.to_int32 (Int64.of_float xf) + +let trunc_s_f64 x = + if F64.ne x x then + raise Numerics.InvalidConversionToInteger + else let xf = F64.to_float x in + if xf >= (Int32.to_float Int32.max_int) +. 1. || + xf <= (Int32.to_float Int32.min_int) -. 1. then + raise Numerics.IntegerOverflow + else + Int32.of_float xf + +let trunc_u_f64 x = + if F64.ne x x then + raise Numerics.InvalidConversionToInteger + else let xf = F64.to_float x in + if xf >= (Int32.to_float Int32.max_int) *. 2. +. 2. || + xf <= -1. then + raise Numerics.IntegerOverflow + else + Int64.to_int32 (Int64.of_float xf) + +let reinterpret_f32 = F32.to_bits diff --git a/ml-proto/src/spec/i32_convert.mli b/ml-proto/src/spec/i32_convert.mli new file mode 100644 index 0000000000..2737aadd22 --- /dev/null +++ b/ml-proto/src/spec/i32_convert.mli @@ -0,0 +1,8 @@ +(* WebAssembly-compatible type conversions to i32 implementation *) + +val wrap_i64 : I64.t -> I32.t +val trunc_s_f32 : F32.t -> I32.t +val trunc_u_f32 : F32.t -> I32.t +val trunc_s_f64 : F64.t -> I32.t +val trunc_u_f64 : F64.t -> I32.t +val reinterpret_f32 : F32.t -> I32.t diff --git a/ml-proto/src/spec/i64.ml b/ml-proto/src/spec/i64.ml new file mode 100644 index 0000000000..7d8333e4e2 --- /dev/null +++ b/ml-proto/src/spec/i64.ml @@ -0,0 +1,122 @@ +(* WebAssembly-compatible i64 implementation *) + +(* + * Unsigned comparison in terms of signed comparison. + *) +let cmp_u x op y = + op (Int64.add x Int64.min_int) (Int64.add y Int64.min_int) + +(* + * Unsigned division and remainder in terms of signed division; algorithm from + * Hacker's Delight, Second Edition, by Henry S. Warren, Jr., section 9-3 + * "Unsigned Short Division from Signed Division". + *) +let divrem_u n d = + if d = Int64.zero then raise Numerics.IntegerDivideByZero else + let t = Int64.shift_right d (64 - 1) in + let n' = Int64.logand n (Int64.lognot t) in + let q = Int64.shift_left (Int64.div (Int64.shift_right_logical n' 1) d) 1 in + let r = Int64.sub n (Int64.mul q d) in + if cmp_u r (<) d then + q, r + else + Int64.add q Int64.one, Int64.sub r d + +type t = int64 + +let of_int64 x = x +let to_int64 x = x + +let zero = Int64.zero + +let add = Int64.add +let sub = Int64.sub +let mul = Int64.mul + +let div_s x y = + if y = Int64.zero then + raise Numerics.IntegerDivideByZero + else if x = Int64.min_int && y = Int64.minus_one then + raise Numerics.IntegerOverflow + else + Int64.div x y + +let div_u x y = + let q, r = divrem_u x y in q + +let rem_s x y = + if y = Int64.zero then + raise Numerics.IntegerDivideByZero + else + Int64.rem x y + +let rem_u x y = + let q, r = divrem_u x y in r + +let and_ = Int64.logand +let or_ = Int64.logor +let xor = Int64.logxor + +(* WebAssembly shift counts are unmasked and unsigned *) +let shift_ok n = n >= Int64.zero && n < Int64.of_int 64 + +let shl x y = + if shift_ok y then + Int64.shift_left x (Int64.to_int y) + else + Int64.zero + +let shr_s x y = + Int64.shift_right x (if shift_ok y then Int64.to_int y else 64 - 1) + +let shr_u x y = + if shift_ok y then + Int64.shift_right_logical x (Int64.to_int y) + else + Int64.zero + +let clz x = + Int64.of_int + (let rec loop acc n = + if n = Int64.zero then + 64 + else if and_ n (Int64.shift_left Int64.one (64 - 1)) <> Int64.zero then + acc + else + loop (1 + acc) (Int64.shift_left n 1) + in loop 0 x) + +let ctz x = + Int64.of_int + (let rec loop acc n = + if n = Int64.zero then + 64 + else if and_ n Int64.one = Int64.one then + acc + else + loop (1 + acc) (Int64.shift_right_logical n 1) + in loop 0 x) + +let popcnt x = + Int64.of_int + (let rec loop acc i n = + if n = Int64.zero then + acc + else + let acc' = if and_ n Int64.one = Int64.one then acc + 1 else acc in + loop acc' (i - 1) (Int64.shift_right_logical n 1) + in loop 0 64 x) + +let eq x y = x = y +let ne x y = x <> y +let lt_s x y = x < y +let lt_u x y = cmp_u x (<) y +let le_s x y = x <= y +let le_u x y = cmp_u x (<=) y +let gt_s x y = x > y +let gt_u x y = cmp_u x (>) y +let ge_s x y = x >= y +let ge_u x y = cmp_u x (>=) y + +let of_string = Int64.of_string +let to_string = Int64.to_string diff --git a/ml-proto/src/spec/i64.mli b/ml-proto/src/spec/i64.mli new file mode 100644 index 0000000000..7643ef4650 --- /dev/null +++ b/ml-proto/src/spec/i64.mli @@ -0,0 +1,39 @@ +(* WebAssembly-compatible i64 implementation *) + +(* TODO Make this type opaque? *) +type t = int64 + +val of_int64 : int64 -> t +val to_int64 : t -> int64 + +val zero : t + +val add : t -> t -> t +val sub : t -> t -> t +val mul : t -> t -> t +val div_s : t -> t -> t +val div_u : t -> t -> t +val rem_s : t -> t -> t +val rem_u : t -> t -> t +val and_ : t -> t -> t +val or_ : t -> t -> t +val xor : t -> t -> t +val shl : t -> t -> t +val shr_s : t -> t -> t +val shr_u : t -> t -> t +val clz : t -> t +val ctz : t -> t +val popcnt : t -> t +val eq : t -> t -> bool +val ne : t -> t -> bool +val lt_s : t -> t -> bool +val lt_u : t -> t -> bool +val le_s : t -> t -> bool +val le_u : t -> t -> bool +val gt_s : t -> t -> bool +val gt_u : t -> t -> bool +val ge_s : t -> t -> bool +val ge_u : t -> t -> bool + +val of_string : string -> t +val to_string : t -> string diff --git a/ml-proto/src/spec/i64_convert.ml b/ml-proto/src/spec/i64_convert.ml new file mode 100644 index 0000000000..2a509cf758 --- /dev/null +++ b/ml-proto/src/spec/i64_convert.ml @@ -0,0 +1,51 @@ +(* WebAssembly-compatible type conversions to i64 implementation *) + +let extend_s_i32 x = Int64.of_int32 x + +let extend_u_i32 x = Int64.logand (Int64.of_int32 x) 0x00000000ffffffffL + +let trunc_s_f32 x = + if F32.ne x x then + raise Numerics.InvalidConversionToInteger + else let xf = F32.to_float x in + if xf >= (Int64.to_float Int64.max_int) +. 1. || + xf <= (Int64.to_float Int64.min_int) -. 1. then + raise Numerics.IntegerOverflow + else + Int64.of_float xf + +let trunc_u_f32 x = + if F32.ne x x then + raise Numerics.InvalidConversionToInteger + else let xf = F32.to_float x in + if xf >= (Int64.to_float Int64.max_int) *. 2. +. 2. || + xf <= -1. then + raise Numerics.IntegerOverflow + else if xf >= (Int64.to_float Int64.max_int) +. 1. then + Int64.logxor (Int64.of_float (xf -. 9223372036854775808.)) Int64.min_int + else + Int64.of_float xf + +let trunc_s_f64 x = + if F64.ne x x then + raise Numerics.InvalidConversionToInteger + else let xf = F64.to_float x in + if xf >= (Int64.to_float Int64.max_int) +. 1. || + xf <= (Int64.to_float Int64.min_int) -. 1. then + raise Numerics.IntegerOverflow + else + Int64.of_float xf + +let trunc_u_f64 x = + if F64.ne x x then + raise Numerics.InvalidConversionToInteger + else let xf = F64.to_float x in + if xf >= (Int64.to_float Int64.max_int) *. 2. +. 2. || + xf <= -1. then + raise Numerics.IntegerOverflow + else if xf >= (Int64.to_float Int64.max_int) +. 1. then + Int64.logxor (Int64.of_float (xf -. 9223372036854775808.)) Int64.min_int + else + Int64.of_float xf + +let reinterpret_f64 = F64.to_bits diff --git a/ml-proto/src/spec/i64_convert.mli b/ml-proto/src/spec/i64_convert.mli new file mode 100644 index 0000000000..50a3b3a3ea --- /dev/null +++ b/ml-proto/src/spec/i64_convert.mli @@ -0,0 +1,9 @@ +(* WebAssembly-compatible type conversions to i64 implementation *) + +val extend_s_i32 : I32.t -> I64.t +val extend_u_i32 : I32.t -> I64.t +val trunc_s_f32 : F32.t -> I64.t +val trunc_u_f32 : F32.t -> I64.t +val trunc_s_f64 : F64.t -> I64.t +val trunc_u_f64 : F64.t -> I64.t +val reinterpret_f64 : F64.t -> I64.t diff --git a/ml-proto/src/spec/memory.ml b/ml-proto/src/spec/memory.ml index 16181ec418..7f337fccd6 100644 --- a/ml-proto/src/spec/memory.ml +++ b/ml-proto/src/spec/memory.ml @@ -69,8 +69,9 @@ let resize mem n = open Values +(* TODO: The conversion to int could overflow *) let address_of_value = function - | Int32 i -> Int32.to_int i + | Int32 i -> Int32.to_int (I32.to_int32 i) | _ -> raise Address @@ -109,23 +110,23 @@ let load mem a memty ext = let open Types in try match memty, ext with - | Int8Mem, _ -> Int32 (load8 mem a ext) - | Int16Mem, _ -> Int32 (load16 mem a ext) - | Int32Mem, NX -> Int32 (load32 mem a) - | Int64Mem, NX -> Int64 (load64 mem a) - | Float32Mem, NX -> Float32 (Float32.of_bits (load32 mem a)) - | Float64Mem, NX -> Float64 (Float64.of_bits (load64 mem a)) + | Int8Mem, _ -> Int32 (I32.of_int32 (load8 mem a ext)) + | Int16Mem, _ -> Int32 (I32.of_int32 (load16 mem a ext)) + | Int32Mem, NX -> Int32 (I32.of_int32 (load32 mem a)) + | Int64Mem, NX -> Int64 (I64.of_int64 (load64 mem a)) + | Float32Mem, NX -> Float32 (F32.of_bits (load32 mem a)) + | Float64Mem, NX -> Float64 (F64.of_bits (load64 mem a)) | _ -> raise Type with Invalid_argument _ -> raise Bounds let store mem a memty v = try (match memty, v with - | Int8Mem, Int32 x -> store8 mem a x - | Int16Mem, Int32 x -> store16 mem a x - | Int32Mem, Int32 x -> store32 mem a x - | Int64Mem, Int64 x -> store64 mem a x - | Float32Mem, Float32 x -> store32 mem a (Float32.to_bits x) - | Float64Mem, Float64 x -> store64 mem a (Float64.to_bits x) + | Int8Mem, Int32 x -> store8 mem a (I32.to_int32 x) + | Int16Mem, Int32 x -> store16 mem a (I32.to_int32 x) + | Int32Mem, Int32 x -> store32 mem a (I32.to_int32 x) + | Int64Mem, Int64 x -> store64 mem a (I64.to_int64 x) + | Float32Mem, Float32 x -> store32 mem a (F32.to_bits x) + | Float64Mem, Float64 x -> store64 mem a (F64.to_bits x) | _ -> raise Type) with Invalid_argument _ -> raise Bounds diff --git a/ml-proto/src/spec/numerics.ml b/ml-proto/src/spec/numerics.ml new file mode 100644 index 0000000000..5809362e5d --- /dev/null +++ b/ml-proto/src/spec/numerics.ml @@ -0,0 +1,5 @@ +(* WebAssembly numeric utilities *) + +exception IntegerOverflow +exception IntegerDivideByZero +exception InvalidConversionToInteger diff --git a/ml-proto/src/spec/numerics.mli b/ml-proto/src/spec/numerics.mli new file mode 100644 index 0000000000..5809362e5d --- /dev/null +++ b/ml-proto/src/spec/numerics.mli @@ -0,0 +1,5 @@ +(* WebAssembly numeric utilities *) + +exception IntegerOverflow +exception IntegerDivideByZero +exception InvalidConversionToInteger diff --git a/ml-proto/src/spec/values.ml b/ml-proto/src/spec/values.ml index fcb426d685..b941db5ca6 100644 --- a/ml-proto/src/spec/values.ml +++ b/ml-proto/src/spec/values.ml @@ -10,7 +10,7 @@ open Types type ('i32, 'i64, 'f32, 'f64) op = Int32 of 'i32 | Int64 of 'i64 | Float32 of 'f32 | Float64 of 'f64 -type value = (int32, int64, Float32.t, Float64.t) op +type value = (I32.t, I64.t, F32.t, F64.t) op (* Typing *) @@ -22,19 +22,19 @@ let type_of = function | Float64 _ -> Float64Type let default_value = function - | Int32Type -> Int32 Int32.zero - | Int64Type -> Int64 Int64.zero - | Float32Type -> Float32 Float32.zero - | Float64Type -> Float64 Float64.zero + | Int32Type -> Int32 I32.zero + | Int64Type -> Int64 I64.zero + | Float32Type -> Float32 F32.zero + | Float64Type -> Float64 F64.zero (* String conversion *) let string_of_value = function - | Int32 i -> Int32.to_string i - | Int64 i -> Int64.to_string i - | Float32 z -> Float32.to_string z - | Float64 z -> Float64.to_string z + | Int32 i -> I32.to_string i + | Int64 i -> I64.to_string i + | Float32 z -> F32.to_string z + | Float64 z -> F64.to_string z let string_of_values = function | [v] -> string_of_value v diff --git a/ml-proto/test/i32.wasm b/ml-proto/test/i32.wasm new file mode 100644 index 0000000000..376a99faf3 --- /dev/null +++ b/ml-proto/test/i32.wasm @@ -0,0 +1,386 @@ +(; i32 operations ;) + +(module + (func $add (param $x i32) (param $y i32) (result i32) (i32.add (get_local $x) (get_local $y))) + (func $sub (param $x i32) (param $y i32) (result i32) (i32.sub (get_local $x) (get_local $y))) + (func $mul (param $x i32) (param $y i32) (result i32) (i32.mul (get_local $x) (get_local $y))) + (func $div_s (param $x i32) (param $y i32) (result i32) (i32.div_s (get_local $x) (get_local $y))) + (func $div_u (param $x i32) (param $y i32) (result i32) (i32.div_u (get_local $x) (get_local $y))) + (func $rem_s (param $x i32) (param $y i32) (result i32) (i32.rem_s (get_local $x) (get_local $y))) + (func $rem_u (param $x i32) (param $y i32) (result i32) (i32.rem_u (get_local $x) (get_local $y))) + (func $and (param $x i32) (param $y i32) (result i32) (i32.and (get_local $x) (get_local $y))) + (func $or (param $x i32) (param $y i32) (result i32) (i32.or (get_local $x) (get_local $y))) + (func $xor (param $x i32) (param $y i32) (result i32) (i32.xor (get_local $x) (get_local $y))) + (func $shl (param $x i32) (param $y i32) (result i32) (i32.shl (get_local $x) (get_local $y))) + (func $shr_s (param $x i32) (param $y i32) (result i32) (i32.shr_s (get_local $x) (get_local $y))) + (func $shr_u (param $x i32) (param $y i32) (result i32) (i32.shr_u (get_local $x) (get_local $y))) + (func $clz (param $x i32) (result i32) (i32.clz (get_local $x))) + (func $ctz (param $x i32) (result i32) (i32.ctz (get_local $x))) + (func $popcnt (param $x i32) (result i32) (i32.popcnt (get_local $x))) + (func $eq (param $x i32) (param $y i32) (result i32) (i32.eq (get_local $x) (get_local $y))) + (func $ne (param $x i32) (param $y i32) (result i32) (i32.ne (get_local $x) (get_local $y))) + (func $lt_s (param $x i32) (param $y i32) (result i32) (i32.lt_s (get_local $x) (get_local $y))) + (func $lt_u (param $x i32) (param $y i32) (result i32) (i32.lt_u (get_local $x) (get_local $y))) + (func $le_s (param $x i32) (param $y i32) (result i32) (i32.le_s (get_local $x) (get_local $y))) + (func $le_u (param $x i32) (param $y i32) (result i32) (i32.le_u (get_local $x) (get_local $y))) + (func $gt_s (param $x i32) (param $y i32) (result i32) (i32.gt_s (get_local $x) (get_local $y))) + (func $gt_u (param $x i32) (param $y i32) (result i32) (i32.gt_u (get_local $x) (get_local $y))) + (func $ge_s (param $x i32) (param $y i32) (result i32) (i32.ge_s (get_local $x) (get_local $y))) + (func $ge_u (param $x i32) (param $y i32) (result i32) (i32.ge_u (get_local $x) (get_local $y))) + + (export "add" $add) + (export "sub" $sub) + (export "mul" $mul) + (export "div_s" $div_s) + (export "div_u" $div_u) + (export "rem_s" $rem_s) + (export "rem_u" $rem_u) + (export "and" $and) + (export "or" $or) + (export "xor" $xor) + (export "shl" $shl) + (export "shr_s" $shr_s) + (export "shr_u" $shr_u) + (export "clz" $clz) + (export "ctz" $ctz) + (export "popcnt" $popcnt) + (export "eq" $eq) + (export "ne" $ne) + (export "lt_s" $lt_s) + (export "lt_u" $lt_u) + (export "le_s" $le_s) + (export "le_u" $le_u) + (export "gt_s" $gt_s) + (export "gt_u" $gt_u) + (export "ge_s" $ge_s) + (export "ge_u" $ge_u) +) + +(assert_eq (invoke "add" (i32.const 1) (i32.const 1)) (i32.const 2)) +(assert_eq (invoke "add" (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "add" (i32.const 0x7fffffff) (i32.const 1)) (i32.const 0x80000000)) +(assert_eq (invoke "add" (i32.const 0x80000000) (i32.const -1)) (i32.const 0x7fffffff)) +(assert_eq (invoke "add" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "add" (i32.const 0x3fffffff) (i32.const 1)) (i32.const 0x40000000)) + +(assert_eq (invoke "sub" (i32.const 1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "sub" (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "sub" (i32.const 0x7fffffff) (i32.const -1)) (i32.const 0x80000000)) +(assert_eq (invoke "sub" (i32.const 0x80000000) (i32.const 1)) (i32.const 0x7fffffff)) +(assert_eq (invoke "sub" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "sub" (i32.const 0x3fffffff) (i32.const -1)) (i32.const 0x40000000)) + +(assert_eq (invoke "mul" (i32.const 1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "mul" (i32.const 1) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "mul" (i32.const -1) (i32.const -1)) (i32.const 1)) +(assert_eq (invoke "mul" (i32.const 0x10000000) (i32.const 4096)) (i32.const 0)) +(assert_eq (invoke "mul" (i32.const 0x80000000) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "mul" (i32.const 0x80000000) (i32.const -1)) (i32.const 0x80000000)) +(assert_eq (invoke "mul" (i32.const 0x7fffffff) (i32.const -1)) (i32.const 0x80000001)) +(assert_eq (invoke "mul" (i32.const 0x01234567) (i32.const 0x76543210)) (i32.const 0x358e7470)) + +(assert_trap (invoke "div_s" (i32.const 1) (i32.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "div_s" (i32.const 0) (i32.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "div_s" (i32.const 0x80000000) (i32.const -1)) "runtime: integer overflow") +(assert_eq (invoke "div_s" (i32.const 1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "div_s" (i32.const 0) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "div_s" (i32.const -1) (i32.const -1)) (i32.const 1)) +(assert_eq (invoke "div_s" (i32.const 0x80000000) (i32.const 2)) (i32.const 0xc0000000)) +(assert_eq (invoke "div_s" (i32.const 5) (i32.const 2)) (i32.const 2)) +(assert_eq (invoke "div_s" (i32.const -5) (i32.const 2)) (i32.const -2)) +(assert_eq (invoke "div_s" (i32.const 5) (i32.const -2)) (i32.const -2)) +(assert_eq (invoke "div_s" (i32.const -5) (i32.const -2)) (i32.const 2)) +(assert_eq (invoke "div_s" (i32.const 7) (i32.const 3)) (i32.const 2)) +(assert_eq (invoke "div_s" (i32.const -7) (i32.const 3)) (i32.const -2)) +(assert_eq (invoke "div_s" (i32.const 7) (i32.const -3)) (i32.const -2)) +(assert_eq (invoke "div_s" (i32.const -7) (i32.const -3)) (i32.const 2)) +(assert_eq (invoke "div_s" (i32.const 11) (i32.const 5)) (i32.const 2)) +(assert_eq (invoke "div_s" (i32.const 17) (i32.const 7)) (i32.const 2)) + +(assert_trap (invoke "div_u" (i32.const 1) (i32.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "div_u" (i32.const 0) (i32.const 0)) "runtime: integer divide by zero") +(assert_eq (invoke "div_u" (i32.const 1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "div_u" (i32.const 0) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "div_u" (i32.const -1) (i32.const -1)) (i32.const 1)) +(assert_eq (invoke "div_u" (i32.const 0x80000000) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "div_u" (i32.const 0x80000000) (i32.const 2)) (i32.const 0x40000000)) +(assert_eq (invoke "div_u" (i32.const 0x8ff00ff0) (i32.const 0x10001)) (i32.const 0x8fef)) +(assert_eq (invoke "div_u" (i32.const 5) (i32.const 2)) (i32.const 2)) +(assert_eq (invoke "div_u" (i32.const -5) (i32.const 2)) (i32.const 0x7ffffffd)) +(assert_eq (invoke "div_u" (i32.const 5) (i32.const -2)) (i32.const 0)) +(assert_eq (invoke "div_u" (i32.const -5) (i32.const -2)) (i32.const 0)) +(assert_eq (invoke "div_u" (i32.const 7) (i32.const 3)) (i32.const 2)) +(assert_eq (invoke "div_u" (i32.const 11) (i32.const 5)) (i32.const 2)) +(assert_eq (invoke "div_u" (i32.const 17) (i32.const 7)) (i32.const 2)) + +(assert_trap (invoke "rem_s" (i32.const 1) (i32.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "rem_s" (i32.const 0) (i32.const 0)) "runtime: integer divide by zero") +(assert_eq (invoke "rem_s" (i32.const 0x7fffffff) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "rem_s" (i32.const 1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "rem_s" (i32.const 0) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "rem_s" (i32.const -1) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "rem_s" (i32.const 0x80000000) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "rem_s" (i32.const 0x80000000) (i32.const 2)) (i32.const 0)) +(assert_eq (invoke "rem_s" (i32.const 5) (i32.const 2)) (i32.const 1)) +(assert_eq (invoke "rem_s" (i32.const -5) (i32.const 2)) (i32.const -1)) +(assert_eq (invoke "rem_s" (i32.const 5) (i32.const -2)) (i32.const 1)) +(assert_eq (invoke "rem_s" (i32.const -5) (i32.const -2)) (i32.const -1)) +(assert_eq (invoke "rem_s" (i32.const 7) (i32.const 3)) (i32.const 1)) +(assert_eq (invoke "rem_s" (i32.const -7) (i32.const 3)) (i32.const -1)) +(assert_eq (invoke "rem_s" (i32.const 7) (i32.const -3)) (i32.const 1)) +(assert_eq (invoke "rem_s" (i32.const -7) (i32.const -3)) (i32.const -1)) +(assert_eq (invoke "rem_s" (i32.const 11) (i32.const 5)) (i32.const 1)) +(assert_eq (invoke "rem_s" (i32.const 17) (i32.const 7)) (i32.const 3)) + +(assert_trap (invoke "rem_u" (i32.const 1) (i32.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "rem_u" (i32.const 0) (i32.const 0)) "runtime: integer divide by zero") +(assert_eq (invoke "rem_u" (i32.const 1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "rem_u" (i32.const 0) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "rem_u" (i32.const -1) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "rem_u" (i32.const 0x80000000) (i32.const -1)) (i32.const 0x80000000)) +(assert_eq (invoke "rem_u" (i32.const 0x80000000) (i32.const 2)) (i32.const 0)) +(assert_eq (invoke "rem_u" (i32.const 0x8ff00ff0) (i32.const 0x10001)) (i32.const 0x8001)) +(assert_eq (invoke "rem_u" (i32.const 5) (i32.const 2)) (i32.const 1)) +(assert_eq (invoke "rem_u" (i32.const -5) (i32.const 2)) (i32.const 1)) +(assert_eq (invoke "rem_u" (i32.const 5) (i32.const -2)) (i32.const 5)) +(assert_eq (invoke "rem_u" (i32.const -5) (i32.const -2)) (i32.const -5)) +(assert_eq (invoke "rem_u" (i32.const 7) (i32.const 3)) (i32.const 1)) +(assert_eq (invoke "rem_u" (i32.const 11) (i32.const 5)) (i32.const 1)) +(assert_eq (invoke "rem_u" (i32.const 17) (i32.const 7)) (i32.const 3)) + +(assert_eq (invoke "and" (i32.const 1) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "and" (i32.const 0) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "and" (i32.const 1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "and" (i32.const 0) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "and" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "and" (i32.const 0x7fffffff) (i32.const -1)) (i32.const 0x7fffffff)) +(assert_eq (invoke "and" (i32.const 0xf0f0ffff) (i32.const 0xfffff0f0)) (i32.const 0xf0f0f0f0)) +(assert_eq (invoke "and" (i32.const 0xffffffff) (i32.const 0xffffffff)) (i32.const 0xffffffff)) + +(assert_eq (invoke "or" (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "or" (i32.const 0) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "or" (i32.const 1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "or" (i32.const 0) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "or" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const -1)) +(assert_eq (invoke "or" (i32.const 0x80000000) (i32.const 0)) (i32.const 0x80000000)) +(assert_eq (invoke "or" (i32.const 0xf0f0ffff) (i32.const 0xfffff0f0)) (i32.const 0xffffffff)) +(assert_eq (invoke "or" (i32.const 0xffffffff) (i32.const 0xffffffff)) (i32.const 0xffffffff)) + +(assert_eq (invoke "xor" (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "xor" (i32.const 0) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "xor" (i32.const 1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "xor" (i32.const 0) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "xor" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const -1)) +(assert_eq (invoke "xor" (i32.const 0x80000000) (i32.const 0)) (i32.const 0x80000000)) +(assert_eq (invoke "xor" (i32.const -1) (i32.const 0x80000000)) (i32.const 0x7fffffff)) +(assert_eq (invoke "xor" (i32.const -1) (i32.const 0x7fffffff)) (i32.const 0x80000000)) +(assert_eq (invoke "xor" (i32.const 0xf0f0ffff) (i32.const 0xfffff0f0)) (i32.const 0x0f0f0f0f)) +(assert_eq (invoke "xor" (i32.const 0xffffffff) (i32.const 0xffffffff)) (i32.const 0)) + +(assert_eq (invoke "shl" (i32.const 1) (i32.const 1)) (i32.const 2)) +(assert_eq (invoke "shl" (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "shl" (i32.const 0x7fffffff) (i32.const 1)) (i32.const 0xfffffffe)) +(assert_eq (invoke "shl" (i32.const 0xffffffff) (i32.const 1)) (i32.const 0xfffffffe)) +(assert_eq (invoke "shl" (i32.const 0x80000000) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "shl" (i32.const 0x40000000) (i32.const 1)) (i32.const 0x80000000)) +(assert_eq (invoke "shl" (i32.const 1) (i32.const 31)) (i32.const 0x80000000)) +(assert_eq (invoke "shl" (i32.const 1) (i32.const 32)) (i32.const 0)) +(assert_eq (invoke "shl" (i32.const 1) (i32.const 33)) (i32.const 0)) +(assert_eq (invoke "shl" (i32.const 1) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "shl" (i32.const 1) (i32.const 0x7fffffff)) (i32.const 0)) + +(assert_eq (invoke "shr_s" (i32.const 1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "shr_s" (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "shr_s" (i32.const -1) (i32.const 1)) (i32.const -1)) +(assert_eq (invoke "shr_s" (i32.const 0x7fffffff) (i32.const 1)) (i32.const 0x3fffffff)) +(assert_eq (invoke "shr_s" (i32.const 0x80000000) (i32.const 1)) (i32.const 0xc0000000)) +(assert_eq (invoke "shr_s" (i32.const 0x40000000) (i32.const 1)) (i32.const 0x20000000)) +(assert_eq (invoke "shr_s" (i32.const 1) (i32.const 32)) (i32.const 0)) +(assert_eq (invoke "shr_s" (i32.const 1) (i32.const 33)) (i32.const 0)) +(assert_eq (invoke "shr_s" (i32.const 1) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "shr_s" (i32.const 1) (i32.const 0x7fffffff)) (i32.const 0)) +(assert_eq (invoke "shr_s" (i32.const 1) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "shr_s" (i32.const 0x80000000) (i32.const 31)) (i32.const -1)) +(assert_eq (invoke "shr_s" (i32.const -1) (i32.const 32)) (i32.const -1)) +(assert_eq (invoke "shr_s" (i32.const -1) (i32.const 33)) (i32.const -1)) +(assert_eq (invoke "shr_s" (i32.const -1) (i32.const -1)) (i32.const -1)) +(assert_eq (invoke "shr_s" (i32.const -1) (i32.const 0x7fffffff)) (i32.const -1)) +(assert_eq (invoke "shr_s" (i32.const -1) (i32.const 0x80000000)) (i32.const -1)) + +(assert_eq (invoke "shr_u" (i32.const 1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "shr_u" (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "shr_u" (i32.const -1) (i32.const 1)) (i32.const 0x7fffffff)) +(assert_eq (invoke "shr_u" (i32.const 0x7fffffff) (i32.const 1)) (i32.const 0x3fffffff)) +(assert_eq (invoke "shr_u" (i32.const 0x80000000) (i32.const 1)) (i32.const 0x40000000)) +(assert_eq (invoke "shr_u" (i32.const 0x40000000) (i32.const 1)) (i32.const 0x20000000)) +(assert_eq (invoke "shr_u" (i32.const 1) (i32.const 32)) (i32.const 0)) +(assert_eq (invoke "shr_u" (i32.const 1) (i32.const 33)) (i32.const 0)) +(assert_eq (invoke "shr_u" (i32.const 1) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "shr_u" (i32.const 1) (i32.const 0x7fffffff)) (i32.const 0)) +(assert_eq (invoke "shr_u" (i32.const 1) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "shr_u" (i32.const 0x80000000) (i32.const 31)) (i32.const 1)) +(assert_eq (invoke "shr_u" (i32.const -1) (i32.const 32)) (i32.const 0)) +(assert_eq (invoke "shr_u" (i32.const -1) (i32.const 33)) (i32.const 0)) +(assert_eq (invoke "shr_u" (i32.const -1) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "shr_u" (i32.const -1) (i32.const 0x7fffffff)) (i32.const 0)) +(assert_eq (invoke "shr_u" (i32.const -1) (i32.const 0x80000000)) (i32.const 0)) + +(assert_eq (invoke "clz" (i32.const -1)) (i32.const 0)) ;; 0xFFFFFFFF +(assert_eq (invoke "clz" (i32.const 0)) (i32.const 32)) +(assert_eq (invoke "clz" (i32.const 32768)) (i32.const 16)) ;; 0x00008000 +(assert_eq (invoke "clz" (i32.const 255)) (i32.const 24)) ;; 0xFF +(assert_eq (invoke "clz" (i32.const -2147483648)) (i32.const 0)) ;; 0x80000000 +(assert_eq (invoke "clz" (i32.const 1)) (i32.const 31)) +(assert_eq (invoke "clz" (i32.const 2)) (i32.const 30)) + +(assert_eq (invoke "ctz" (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "ctz" (i32.const 0)) (i32.const 32)) +(assert_eq (invoke "ctz" (i32.const 32768)) (i32.const 15)) ;; 0x00008000 +(assert_eq (invoke "ctz" (i32.const 65536)) (i32.const 16)) ;; 0x00010000 +(assert_eq (invoke "ctz" (i32.const -2147483648)) (i32.const 31)) ;; 0x80000000 + +(assert_eq (invoke "popcnt" (i32.const -1)) (i32.const 32)) +(assert_eq (invoke "popcnt" (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "popcnt" (i32.const 32768)) (i32.const 1)) ;; 0x00008000 + +(assert_eq (invoke "eq" (i32.const 0) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "eq" (i32.const 1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "eq" (i32.const -1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "eq" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 1)) +(assert_eq (invoke "eq" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 1)) +(assert_eq (invoke "eq" (i32.const -1) (i32.const -1)) (i32.const 1)) +(assert_eq (invoke "eq" (i32.const 1) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "eq" (i32.const 0x80000000) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "eq" (i32.const 0x80000000) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "eq" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 0)) + +(assert_eq (invoke "ne" (i32.const 0) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "ne" (i32.const 1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "ne" (i32.const -1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "ne" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "ne" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 0)) +(assert_eq (invoke "ne" (i32.const -1) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "ne" (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "ne" (i32.const 0x80000000) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "ne" (i32.const 0x80000000) (i32.const -1)) (i32.const 1)) +(assert_eq (invoke "ne" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 1)) + +(assert_eq (invoke "lt_s" (i32.const 0) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i32.const 1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i32.const -1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "lt_s" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i32.const -1) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i32.const 1) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i32.const 0) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "lt_s" (i32.const 0x80000000) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "lt_s" (i32.const 0) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i32.const 0x80000000) (i32.const -1)) (i32.const 1)) +(assert_eq (invoke "lt_s" (i32.const -1) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 1)) +(assert_eq (invoke "lt_s" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 0)) + +(assert_eq (invoke "lt_u" (i32.const 0) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i32.const 1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i32.const -1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i32.const -1) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i32.const 1) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i32.const 0) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "lt_u" (i32.const 0x80000000) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i32.const 0) (i32.const 0x80000000)) (i32.const 1)) +(assert_eq (invoke "lt_u" (i32.const 0x80000000) (i32.const -1)) (i32.const 1)) +(assert_eq (invoke "lt_u" (i32.const -1) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 1)) + +(assert_eq (invoke "le_s" (i32.const 0) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "le_s" (i32.const 1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "le_s" (i32.const -1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "le_s" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 1)) +(assert_eq (invoke "le_s" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 1)) +(assert_eq (invoke "le_s" (i32.const -1) (i32.const -1)) (i32.const 1)) +(assert_eq (invoke "le_s" (i32.const 1) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "le_s" (i32.const 0) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "le_s" (i32.const 0x80000000) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "le_s" (i32.const 0) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "le_s" (i32.const 0x80000000) (i32.const -1)) (i32.const 1)) +(assert_eq (invoke "le_s" (i32.const -1) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "le_s" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 1)) +(assert_eq (invoke "le_s" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 0)) + +(assert_eq (invoke "le_u" (i32.const 0) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "le_u" (i32.const 1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "le_u" (i32.const -1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "le_u" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 1)) +(assert_eq (invoke "le_u" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 1)) +(assert_eq (invoke "le_u" (i32.const -1) (i32.const -1)) (i32.const 1)) +(assert_eq (invoke "le_u" (i32.const 1) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "le_u" (i32.const 0) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "le_u" (i32.const 0x80000000) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "le_u" (i32.const 0) (i32.const 0x80000000)) (i32.const 1)) +(assert_eq (invoke "le_u" (i32.const 0x80000000) (i32.const -1)) (i32.const 1)) +(assert_eq (invoke "le_u" (i32.const -1) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "le_u" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 0)) +(assert_eq (invoke "le_u" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 1)) + +(assert_eq (invoke "gt_s" (i32.const 0) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i32.const 1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i32.const -1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i32.const -1) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "gt_s" (i32.const 0) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i32.const 0x80000000) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i32.const 0) (i32.const 0x80000000)) (i32.const 1)) +(assert_eq (invoke "gt_s" (i32.const 0x80000000) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i32.const -1) (i32.const 0x80000000)) (i32.const 1)) +(assert_eq (invoke "gt_s" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 1)) + +(assert_eq (invoke "gt_u" (i32.const 0) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i32.const 1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i32.const -1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "gt_u" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i32.const -1) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "gt_u" (i32.const 0) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i32.const 0x80000000) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "gt_u" (i32.const 0) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i32.const 0x80000000) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i32.const -1) (i32.const 0x80000000)) (i32.const 1)) +(assert_eq (invoke "gt_u" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 1)) +(assert_eq (invoke "gt_u" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 0)) + +(assert_eq (invoke "ge_s" (i32.const 0) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i32.const 1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i32.const -1) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "ge_s" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i32.const -1) (i32.const -1)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i32.const 0) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "ge_s" (i32.const 0x80000000) (i32.const 0)) (i32.const 0)) +(assert_eq (invoke "ge_s" (i32.const 0) (i32.const 0x80000000)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i32.const 0x80000000) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "ge_s" (i32.const -1) (i32.const 0x80000000)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 0)) +(assert_eq (invoke "ge_s" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 1)) + +(assert_eq (invoke "ge_u" (i32.const 0) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i32.const 1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i32.const -1) (i32.const 1)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i32.const -1) (i32.const -1)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i32.const 0) (i32.const 1)) (i32.const 0)) +(assert_eq (invoke "ge_u" (i32.const 0x80000000) (i32.const 0)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i32.const 0) (i32.const 0x80000000)) (i32.const 0)) +(assert_eq (invoke "ge_u" (i32.const 0x80000000) (i32.const -1)) (i32.const 0)) +(assert_eq (invoke "ge_u" (i32.const -1) (i32.const 0x80000000)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i32.const 0x80000000) (i32.const 0x7fffffff)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i32.const 0x7fffffff) (i32.const 0x80000000)) (i32.const 0)) diff --git a/ml-proto/test/i64.wasm b/ml-proto/test/i64.wasm new file mode 100644 index 0000000000..dd569577a4 --- /dev/null +++ b/ml-proto/test/i64.wasm @@ -0,0 +1,386 @@ +(; i64 operations ;) + +(module + (func $add (param $x i64) (param $y i64) (result i64) (i64.add (get_local $x) (get_local $y))) + (func $sub (param $x i64) (param $y i64) (result i64) (i64.sub (get_local $x) (get_local $y))) + (func $mul (param $x i64) (param $y i64) (result i64) (i64.mul (get_local $x) (get_local $y))) + (func $div_s (param $x i64) (param $y i64) (result i64) (i64.div_s (get_local $x) (get_local $y))) + (func $div_u (param $x i64) (param $y i64) (result i64) (i64.div_u (get_local $x) (get_local $y))) + (func $rem_s (param $x i64) (param $y i64) (result i64) (i64.rem_s (get_local $x) (get_local $y))) + (func $rem_u (param $x i64) (param $y i64) (result i64) (i64.rem_u (get_local $x) (get_local $y))) + (func $and (param $x i64) (param $y i64) (result i64) (i64.and (get_local $x) (get_local $y))) + (func $or (param $x i64) (param $y i64) (result i64) (i64.or (get_local $x) (get_local $y))) + (func $xor (param $x i64) (param $y i64) (result i64) (i64.xor (get_local $x) (get_local $y))) + (func $shl (param $x i64) (param $y i64) (result i64) (i64.shl (get_local $x) (get_local $y))) + (func $shr_s (param $x i64) (param $y i64) (result i64) (i64.shr_s (get_local $x) (get_local $y))) + (func $shr_u (param $x i64) (param $y i64) (result i64) (i64.shr_u (get_local $x) (get_local $y))) + (func $clz (param $x i64) (result i64) (i64.clz (get_local $x))) + (func $ctz (param $x i64) (result i64) (i64.ctz (get_local $x))) + (func $popcnt (param $x i64) (result i64) (i64.popcnt (get_local $x))) + (func $eq (param $x i64) (param $y i64) (result i32) (i64.eq (get_local $x) (get_local $y))) + (func $ne (param $x i64) (param $y i64) (result i32) (i64.ne (get_local $x) (get_local $y))) + (func $lt_s (param $x i64) (param $y i64) (result i32) (i64.lt_s (get_local $x) (get_local $y))) + (func $lt_u (param $x i64) (param $y i64) (result i32) (i64.lt_u (get_local $x) (get_local $y))) + (func $le_s (param $x i64) (param $y i64) (result i32) (i64.le_s (get_local $x) (get_local $y))) + (func $le_u (param $x i64) (param $y i64) (result i32) (i64.le_u (get_local $x) (get_local $y))) + (func $gt_s (param $x i64) (param $y i64) (result i32) (i64.gt_s (get_local $x) (get_local $y))) + (func $gt_u (param $x i64) (param $y i64) (result i32) (i64.gt_u (get_local $x) (get_local $y))) + (func $ge_s (param $x i64) (param $y i64) (result i32) (i64.ge_s (get_local $x) (get_local $y))) + (func $ge_u (param $x i64) (param $y i64) (result i32) (i64.ge_u (get_local $x) (get_local $y))) + + (export "add" $add) + (export "sub" $sub) + (export "mul" $mul) + (export "div_s" $div_s) + (export "div_u" $div_u) + (export "rem_s" $rem_s) + (export "rem_u" $rem_u) + (export "and" $and) + (export "or" $or) + (export "xor" $xor) + (export "shl" $shl) + (export "shr_s" $shr_s) + (export "shr_u" $shr_u) + (export "clz" $clz) + (export "ctz" $ctz) + (export "popcnt" $popcnt) + (export "eq" $eq) + (export "ne" $ne) + (export "lt_s" $lt_s) + (export "lt_u" $lt_u) + (export "le_s" $le_s) + (export "le_u" $le_u) + (export "gt_s" $gt_s) + (export "gt_u" $gt_u) + (export "ge_s" $ge_s) + (export "ge_u" $ge_u) +) + +(assert_eq (invoke "add" (i64.const 1) (i64.const 1)) (i64.const 2)) +(assert_eq (invoke "add" (i64.const 1) (i64.const 0)) (i64.const 1)) +(assert_eq (invoke "add" (i64.const 0x7fffffffffffffff) (i64.const 1)) (i64.const 0x8000000000000000)) +(assert_eq (invoke "add" (i64.const 0x8000000000000000) (i64.const -1)) (i64.const 0x7fffffffffffffff)) +(assert_eq (invoke "add" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i64.const 0)) +(assert_eq (invoke "add" (i64.const 0x3fffffff) (i64.const 1)) (i64.const 0x40000000)) + +(assert_eq (invoke "sub" (i64.const 1) (i64.const 1)) (i64.const 0)) +(assert_eq (invoke "sub" (i64.const 1) (i64.const 0)) (i64.const 1)) +(assert_eq (invoke "sub" (i64.const 0x7fffffffffffffff) (i64.const -1)) (i64.const 0x8000000000000000)) +(assert_eq (invoke "sub" (i64.const 0x8000000000000000) (i64.const 1)) (i64.const 0x7fffffffffffffff)) +(assert_eq (invoke "sub" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i64.const 0)) +(assert_eq (invoke "sub" (i64.const 0x3fffffff) (i64.const -1)) (i64.const 0x40000000)) + +(assert_eq (invoke "mul" (i64.const 1) (i64.const 1)) (i64.const 1)) +(assert_eq (invoke "mul" (i64.const 1) (i64.const 0)) (i64.const 0)) +(assert_eq (invoke "mul" (i64.const -1) (i64.const -1)) (i64.const 1)) +(assert_eq (invoke "mul" (i64.const 0x1000000000000000) (i64.const 4096)) (i64.const 0)) +(assert_eq (invoke "mul" (i64.const 0x8000000000000000) (i64.const 0)) (i64.const 0)) +(assert_eq (invoke "mul" (i64.const 0x8000000000000000) (i64.const -1)) (i64.const 0x8000000000000000)) +(assert_eq (invoke "mul" (i64.const 0x7fffffffffffffff) (i64.const -1)) (i64.const 0x8000000000000001)) +(assert_eq (invoke "mul" (i64.const 0x0123456789abcdef) (i64.const 0xfedcba9876543210)) (i64.const 0x2236d88fe5618cf0)) + +(assert_trap (invoke "div_s" (i64.const 1) (i64.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "div_s" (i64.const 0) (i64.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "div_s" (i64.const 0x8000000000000000) (i64.const -1)) "runtime: integer overflow") +(assert_eq (invoke "div_s" (i64.const 1) (i64.const 1)) (i64.const 1)) +(assert_eq (invoke "div_s" (i64.const 0) (i64.const 1)) (i64.const 0)) +(assert_eq (invoke "div_s" (i64.const -1) (i64.const -1)) (i64.const 1)) +(assert_eq (invoke "div_s" (i64.const 0x8000000000000000) (i64.const 2)) (i64.const 0xc000000000000000)) +(assert_eq (invoke "div_s" (i64.const 5) (i64.const 2)) (i64.const 2)) +(assert_eq (invoke "div_s" (i64.const -5) (i64.const 2)) (i64.const -2)) +(assert_eq (invoke "div_s" (i64.const 5) (i64.const -2)) (i64.const -2)) +(assert_eq (invoke "div_s" (i64.const -5) (i64.const -2)) (i64.const 2)) +(assert_eq (invoke "div_s" (i64.const 7) (i64.const 3)) (i64.const 2)) +(assert_eq (invoke "div_s" (i64.const -7) (i64.const 3)) (i64.const -2)) +(assert_eq (invoke "div_s" (i64.const 7) (i64.const -3)) (i64.const -2)) +(assert_eq (invoke "div_s" (i64.const -7) (i64.const -3)) (i64.const 2)) +(assert_eq (invoke "div_s" (i64.const 11) (i64.const 5)) (i64.const 2)) +(assert_eq (invoke "div_s" (i64.const 17) (i64.const 7)) (i64.const 2)) + +(assert_trap (invoke "div_u" (i64.const 1) (i64.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "div_u" (i64.const 0) (i64.const 0)) "runtime: integer divide by zero") +(assert_eq (invoke "div_u" (i64.const 1) (i64.const 1)) (i64.const 1)) +(assert_eq (invoke "div_u" (i64.const 0) (i64.const 1)) (i64.const 0)) +(assert_eq (invoke "div_u" (i64.const -1) (i64.const -1)) (i64.const 1)) +(assert_eq (invoke "div_u" (i64.const 0x8000000000000000) (i64.const -1)) (i64.const 0)) +(assert_eq (invoke "div_u" (i64.const 0x8000000000000000) (i64.const 2)) (i64.const 0x4000000000000000)) +(assert_eq (invoke "div_u" (i64.const 0x8ff00ff00ff00ff0) (i64.const 0x100000001)) (i64.const 0x8ff00fef)) +(assert_eq (invoke "div_u" (i64.const 5) (i64.const 2)) (i64.const 2)) +(assert_eq (invoke "div_u" (i64.const -5) (i64.const 2)) (i64.const 0x7ffffffffffffffd)) +(assert_eq (invoke "div_u" (i64.const 5) (i64.const -2)) (i64.const 0)) +(assert_eq (invoke "div_u" (i64.const -5) (i64.const -2)) (i64.const 0)) +(assert_eq (invoke "div_u" (i64.const 7) (i64.const 3)) (i64.const 2)) +(assert_eq (invoke "div_u" (i64.const 11) (i64.const 5)) (i64.const 2)) +(assert_eq (invoke "div_u" (i64.const 17) (i64.const 7)) (i64.const 2)) + +(assert_trap (invoke "rem_s" (i64.const 1) (i64.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "rem_s" (i64.const 0) (i64.const 0)) "runtime: integer divide by zero") +(assert_eq (invoke "rem_s" (i64.const 0x7fffffffffffffff) (i64.const -1)) (i64.const 0)) +(assert_eq (invoke "rem_s" (i64.const 1) (i64.const 1)) (i64.const 0)) +(assert_eq (invoke "rem_s" (i64.const 0) (i64.const 1)) (i64.const 0)) +(assert_eq (invoke "rem_s" (i64.const -1) (i64.const -1)) (i64.const 0)) +(assert_eq (invoke "rem_s" (i64.const 0x8000000000000000) (i64.const -1)) (i64.const 0)) +(assert_eq (invoke "rem_s" (i64.const 0x8000000000000000) (i64.const 2)) (i64.const 0)) +(assert_eq (invoke "rem_s" (i64.const 5) (i64.const 2)) (i64.const 1)) +(assert_eq (invoke "rem_s" (i64.const -5) (i64.const 2)) (i64.const -1)) +(assert_eq (invoke "rem_s" (i64.const 5) (i64.const -2)) (i64.const 1)) +(assert_eq (invoke "rem_s" (i64.const -5) (i64.const -2)) (i64.const -1)) +(assert_eq (invoke "rem_s" (i64.const 7) (i64.const 3)) (i64.const 1)) +(assert_eq (invoke "rem_s" (i64.const -7) (i64.const 3)) (i64.const -1)) +(assert_eq (invoke "rem_s" (i64.const 7) (i64.const -3)) (i64.const 1)) +(assert_eq (invoke "rem_s" (i64.const -7) (i64.const -3)) (i64.const -1)) +(assert_eq (invoke "rem_s" (i64.const 11) (i64.const 5)) (i64.const 1)) +(assert_eq (invoke "rem_s" (i64.const 17) (i64.const 7)) (i64.const 3)) + +(assert_trap (invoke "rem_u" (i64.const 1) (i64.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "rem_u" (i64.const 0) (i64.const 0)) "runtime: integer divide by zero") +(assert_eq (invoke "rem_u" (i64.const 1) (i64.const 1)) (i64.const 0)) +(assert_eq (invoke "rem_u" (i64.const 0) (i64.const 1)) (i64.const 0)) +(assert_eq (invoke "rem_u" (i64.const -1) (i64.const -1)) (i64.const 0)) +(assert_eq (invoke "rem_u" (i64.const 0x8000000000000000) (i64.const -1)) (i64.const 0x8000000000000000)) +(assert_eq (invoke "rem_u" (i64.const 0x8000000000000000) (i64.const 2)) (i64.const 0)) +(assert_eq (invoke "rem_u" (i64.const 0x8ff00ff00ff00ff0) (i64.const 0x100000001)) (i64.const 0x80000001)) +(assert_eq (invoke "rem_u" (i64.const 5) (i64.const 2)) (i64.const 1)) +(assert_eq (invoke "rem_u" (i64.const -5) (i64.const 2)) (i64.const 1)) +(assert_eq (invoke "rem_u" (i64.const 5) (i64.const -2)) (i64.const 5)) +(assert_eq (invoke "rem_u" (i64.const -5) (i64.const -2)) (i64.const -5)) +(assert_eq (invoke "rem_u" (i64.const 7) (i64.const 3)) (i64.const 1)) +(assert_eq (invoke "rem_u" (i64.const 11) (i64.const 5)) (i64.const 1)) +(assert_eq (invoke "rem_u" (i64.const 17) (i64.const 7)) (i64.const 3)) + +(assert_eq (invoke "and" (i64.const 1) (i64.const 0)) (i64.const 0)) +(assert_eq (invoke "and" (i64.const 0) (i64.const 1)) (i64.const 0)) +(assert_eq (invoke "and" (i64.const 1) (i64.const 1)) (i64.const 1)) +(assert_eq (invoke "and" (i64.const 0) (i64.const 0)) (i64.const 0)) +(assert_eq (invoke "and" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i64.const 0)) +(assert_eq (invoke "and" (i64.const 0x7fffffffffffffff) (i64.const -1)) (i64.const 0x7fffffffffffffff)) +(assert_eq (invoke "and" (i64.const 0xf0f0ffff) (i64.const 0xfffff0f0)) (i64.const 0xf0f0f0f0)) +(assert_eq (invoke "and" (i64.const 0xffffffffffffffff) (i64.const 0xffffffffffffffff)) (i64.const 0xffffffffffffffff)) + +(assert_eq (invoke "or" (i64.const 1) (i64.const 0)) (i64.const 1)) +(assert_eq (invoke "or" (i64.const 0) (i64.const 1)) (i64.const 1)) +(assert_eq (invoke "or" (i64.const 1) (i64.const 1)) (i64.const 1)) +(assert_eq (invoke "or" (i64.const 0) (i64.const 0)) (i64.const 0)) +(assert_eq (invoke "or" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i64.const -1)) +(assert_eq (invoke "or" (i64.const 0x8000000000000000) (i64.const 0)) (i64.const 0x8000000000000000)) +(assert_eq (invoke "or" (i64.const 0xf0f0ffff) (i64.const 0xfffff0f0)) (i64.const 0xffffffff)) +(assert_eq (invoke "or" (i64.const 0xffffffffffffffff) (i64.const 0xffffffffffffffff)) (i64.const 0xffffffffffffffff)) + +(assert_eq (invoke "xor" (i64.const 1) (i64.const 0)) (i64.const 1)) +(assert_eq (invoke "xor" (i64.const 0) (i64.const 1)) (i64.const 1)) +(assert_eq (invoke "xor" (i64.const 1) (i64.const 1)) (i64.const 0)) +(assert_eq (invoke "xor" (i64.const 0) (i64.const 0)) (i64.const 0)) +(assert_eq (invoke "xor" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i64.const -1)) +(assert_eq (invoke "xor" (i64.const 0x8000000000000000) (i64.const 0)) (i64.const 0x8000000000000000)) +(assert_eq (invoke "xor" (i64.const -1) (i64.const 0x8000000000000000)) (i64.const 0x7fffffffffffffff)) +(assert_eq (invoke "xor" (i64.const -1) (i64.const 0x7fffffffffffffff)) (i64.const 0x8000000000000000)) +(assert_eq (invoke "xor" (i64.const 0xf0f0ffff) (i64.const 0xfffff0f0)) (i64.const 0x0f0f0f0f)) +(assert_eq (invoke "xor" (i64.const 0xffffffffffffffff) (i64.const 0xffffffffffffffff)) (i64.const 0)) + +(assert_eq (invoke "shl" (i64.const 1) (i64.const 1)) (i64.const 2)) +(assert_eq (invoke "shl" (i64.const 1) (i64.const 0)) (i64.const 1)) +(assert_eq (invoke "shl" (i64.const 0x7fffffffffffffff) (i64.const 1)) (i64.const 0xfffffffffffffffe)) +(assert_eq (invoke "shl" (i64.const 0xffffffffffffffff) (i64.const 1)) (i64.const 0xfffffffffffffffe)) +(assert_eq (invoke "shl" (i64.const 0x8000000000000000) (i64.const 1)) (i64.const 0)) +(assert_eq (invoke "shl" (i64.const 0x4000000000000000) (i64.const 1)) (i64.const 0x8000000000000000)) +(assert_eq (invoke "shl" (i64.const 1) (i64.const 63)) (i64.const 0x8000000000000000)) +(assert_eq (invoke "shl" (i64.const 1) (i64.const 64)) (i64.const 0)) +(assert_eq (invoke "shl" (i64.const 1) (i64.const 65)) (i64.const 0)) +(assert_eq (invoke "shl" (i64.const 1) (i64.const -1)) (i64.const 0)) +(assert_eq (invoke "shl" (i64.const 1) (i64.const 0x7fffffffffffffff)) (i64.const 0)) + +(assert_eq (invoke "shr_s" (i64.const 1) (i64.const 1)) (i64.const 0)) +(assert_eq (invoke "shr_s" (i64.const 1) (i64.const 0)) (i64.const 1)) +(assert_eq (invoke "shr_s" (i64.const -1) (i64.const 1)) (i64.const -1)) +(assert_eq (invoke "shr_s" (i64.const 0x7fffffffffffffff) (i64.const 1)) (i64.const 0x3fffffffffffffff)) +(assert_eq (invoke "shr_s" (i64.const 0x8000000000000000) (i64.const 1)) (i64.const 0xc000000000000000)) +(assert_eq (invoke "shr_s" (i64.const 0x4000000000000000) (i64.const 1)) (i64.const 0x2000000000000000)) +(assert_eq (invoke "shr_s" (i64.const 1) (i64.const 64)) (i64.const 0)) +(assert_eq (invoke "shr_s" (i64.const 1) (i64.const 65)) (i64.const 0)) +(assert_eq (invoke "shr_s" (i64.const 1) (i64.const -1)) (i64.const 0)) +(assert_eq (invoke "shr_s" (i64.const 1) (i64.const 0x7fffffffffffffff)) (i64.const 0)) +(assert_eq (invoke "shr_s" (i64.const 1) (i64.const 0x8000000000000000)) (i64.const 0)) +(assert_eq (invoke "shr_s" (i64.const 0x8000000000000000) (i64.const 63)) (i64.const -1)) +(assert_eq (invoke "shr_s" (i64.const -1) (i64.const 64)) (i64.const -1)) +(assert_eq (invoke "shr_s" (i64.const -1) (i64.const 65)) (i64.const -1)) +(assert_eq (invoke "shr_s" (i64.const -1) (i64.const -1)) (i64.const -1)) +(assert_eq (invoke "shr_s" (i64.const -1) (i64.const 0x7fffffffffffffff)) (i64.const -1)) +(assert_eq (invoke "shr_s" (i64.const -1) (i64.const 0x8000000000000000)) (i64.const -1)) + +(assert_eq (invoke "shr_u" (i64.const 1) (i64.const 1)) (i64.const 0)) +(assert_eq (invoke "shr_u" (i64.const 1) (i64.const 0)) (i64.const 1)) +(assert_eq (invoke "shr_u" (i64.const -1) (i64.const 1)) (i64.const 0x7fffffffffffffff)) +(assert_eq (invoke "shr_u" (i64.const 0x7fffffffffffffff) (i64.const 1)) (i64.const 0x3fffffffffffffff)) +(assert_eq (invoke "shr_u" (i64.const 0x8000000000000000) (i64.const 1)) (i64.const 0x4000000000000000)) +(assert_eq (invoke "shr_u" (i64.const 0x4000000000000000) (i64.const 1)) (i64.const 0x2000000000000000)) +(assert_eq (invoke "shr_u" (i64.const 1) (i64.const 64)) (i64.const 0)) +(assert_eq (invoke "shr_u" (i64.const 1) (i64.const 65)) (i64.const 0)) +(assert_eq (invoke "shr_u" (i64.const 1) (i64.const -1)) (i64.const 0)) +(assert_eq (invoke "shr_u" (i64.const 1) (i64.const 0x7fffffffffffffff)) (i64.const 0)) +(assert_eq (invoke "shr_u" (i64.const 1) (i64.const 0x8000000000000000)) (i64.const 0)) +(assert_eq (invoke "shr_u" (i64.const 0x8000000000000000) (i64.const 63)) (i64.const 1)) +(assert_eq (invoke "shr_u" (i64.const -1) (i64.const 64)) (i64.const 0)) +(assert_eq (invoke "shr_u" (i64.const -1) (i64.const 65)) (i64.const 0)) +(assert_eq (invoke "shr_u" (i64.const -1) (i64.const -1)) (i64.const 0)) +(assert_eq (invoke "shr_u" (i64.const -1) (i64.const 0x7fffffffffffffff)) (i64.const 0)) +(assert_eq (invoke "shr_u" (i64.const -1) (i64.const 0x8000000000000000)) (i64.const 0)) + +(assert_eq (invoke "clz" (i64.const -1)) (i64.const 0)) ;; 0xFFFFFFFF +(assert_eq (invoke "clz" (i64.const 0)) (i64.const 64)) +(assert_eq (invoke "clz" (i64.const 64768)) (i64.const 48)) ;; 0x00008000 +(assert_eq (invoke "clz" (i64.const 255)) (i64.const 56)) ;; 0xFF +(assert_eq (invoke "clz" (i64.const -9223372036854775808)) (i64.const 0)) ;; 0x8000000000000000 +(assert_eq (invoke "clz" (i64.const 1)) (i64.const 63)) +(assert_eq (invoke "clz" (i64.const 2)) (i64.const 62)) + +(assert_eq (invoke "ctz" (i64.const -1)) (i64.const 0)) +(assert_eq (invoke "ctz" (i64.const 0)) (i64.const 64)) +(assert_eq (invoke "ctz" (i64.const 32768)) (i64.const 15)) ;; 0x00008000 +(assert_eq (invoke "ctz" (i64.const 65536)) (i64.const 16)) ;; 0x00010000 +(assert_eq (invoke "ctz" (i64.const -9223372036854775808)) (i64.const 63)) ;; 0x8000000000000000 + +(assert_eq (invoke "popcnt" (i64.const -1)) (i64.const 64)) +(assert_eq (invoke "popcnt" (i64.const 0)) (i64.const 0)) +(assert_eq (invoke "popcnt" (i64.const 32768)) (i64.const 1)) ;; 0x00008000 + +(assert_eq (invoke "eq" (i64.const 0) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "eq" (i64.const 1) (i64.const 1)) (i32.const 1)) +(assert_eq (invoke "eq" (i64.const -1) (i64.const 1)) (i32.const 0)) +(assert_eq (invoke "eq" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 1)) +(assert_eq (invoke "eq" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 1)) +(assert_eq (invoke "eq" (i64.const -1) (i64.const -1)) (i32.const 1)) +(assert_eq (invoke "eq" (i64.const 1) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "eq" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "eq" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 0)) +(assert_eq (invoke "eq" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 0)) + +(assert_eq (invoke "ne" (i64.const 0) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "ne" (i64.const 1) (i64.const 1)) (i32.const 0)) +(assert_eq (invoke "ne" (i64.const -1) (i64.const 1)) (i32.const 1)) +(assert_eq (invoke "ne" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 0)) +(assert_eq (invoke "ne" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 0)) +(assert_eq (invoke "ne" (i64.const -1) (i64.const -1)) (i32.const 0)) +(assert_eq (invoke "ne" (i64.const 1) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "ne" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "ne" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 1)) +(assert_eq (invoke "ne" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 1)) + +(assert_eq (invoke "lt_s" (i64.const 0) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i64.const 1) (i64.const 1)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i64.const -1) (i64.const 1)) (i32.const 1)) +(assert_eq (invoke "lt_s" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i64.const -1) (i64.const -1)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i64.const 1) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i64.const 0) (i64.const 1)) (i32.const 1)) +(assert_eq (invoke "lt_s" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "lt_s" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 1)) +(assert_eq (invoke "lt_s" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 0)) +(assert_eq (invoke "lt_s" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 1)) +(assert_eq (invoke "lt_s" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 0)) + +(assert_eq (invoke "lt_u" (i64.const 0) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i64.const 1) (i64.const 1)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i64.const -1) (i64.const 1)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i64.const -1) (i64.const -1)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i64.const 1) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i64.const 0) (i64.const 1)) (i32.const 1)) +(assert_eq (invoke "lt_u" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 1)) +(assert_eq (invoke "lt_u" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 1)) +(assert_eq (invoke "lt_u" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 0)) +(assert_eq (invoke "lt_u" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 1)) + +(assert_eq (invoke "le_s" (i64.const 0) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "le_s" (i64.const 1) (i64.const 1)) (i32.const 1)) +(assert_eq (invoke "le_s" (i64.const -1) (i64.const 1)) (i32.const 1)) +(assert_eq (invoke "le_s" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 1)) +(assert_eq (invoke "le_s" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 1)) +(assert_eq (invoke "le_s" (i64.const -1) (i64.const -1)) (i32.const 1)) +(assert_eq (invoke "le_s" (i64.const 1) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "le_s" (i64.const 0) (i64.const 1)) (i32.const 1)) +(assert_eq (invoke "le_s" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "le_s" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 0)) +(assert_eq (invoke "le_s" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 1)) +(assert_eq (invoke "le_s" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 0)) +(assert_eq (invoke "le_s" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 1)) +(assert_eq (invoke "le_s" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 0)) + +(assert_eq (invoke "le_u" (i64.const 0) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "le_u" (i64.const 1) (i64.const 1)) (i32.const 1)) +(assert_eq (invoke "le_u" (i64.const -1) (i64.const 1)) (i32.const 0)) +(assert_eq (invoke "le_u" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 1)) +(assert_eq (invoke "le_u" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 1)) +(assert_eq (invoke "le_u" (i64.const -1) (i64.const -1)) (i32.const 1)) +(assert_eq (invoke "le_u" (i64.const 1) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "le_u" (i64.const 0) (i64.const 1)) (i32.const 1)) +(assert_eq (invoke "le_u" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "le_u" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 1)) +(assert_eq (invoke "le_u" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 1)) +(assert_eq (invoke "le_u" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 0)) +(assert_eq (invoke "le_u" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 0)) +(assert_eq (invoke "le_u" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 1)) + +(assert_eq (invoke "gt_s" (i64.const 0) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i64.const 1) (i64.const 1)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i64.const -1) (i64.const 1)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i64.const -1) (i64.const -1)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i64.const 1) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "gt_s" (i64.const 0) (i64.const 1)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 1)) +(assert_eq (invoke "gt_s" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 1)) +(assert_eq (invoke "gt_s" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 0)) +(assert_eq (invoke "gt_s" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 1)) + +(assert_eq (invoke "gt_u" (i64.const 0) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i64.const 1) (i64.const 1)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i64.const -1) (i64.const 1)) (i32.const 1)) +(assert_eq (invoke "gt_u" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i64.const -1) (i64.const -1)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i64.const 1) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "gt_u" (i64.const 0) (i64.const 1)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "gt_u" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 0)) +(assert_eq (invoke "gt_u" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 1)) +(assert_eq (invoke "gt_u" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 1)) +(assert_eq (invoke "gt_u" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 0)) + +(assert_eq (invoke "ge_s" (i64.const 0) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i64.const 1) (i64.const 1)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i64.const -1) (i64.const 1)) (i32.const 0)) +(assert_eq (invoke "ge_s" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i64.const -1) (i64.const -1)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i64.const 1) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i64.const 0) (i64.const 1)) (i32.const 0)) +(assert_eq (invoke "ge_s" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 0)) +(assert_eq (invoke "ge_s" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 0)) +(assert_eq (invoke "ge_s" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 1)) +(assert_eq (invoke "ge_s" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 0)) +(assert_eq (invoke "ge_s" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 1)) + +(assert_eq (invoke "ge_u" (i64.const 0) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i64.const 1) (i64.const 1)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i64.const -1) (i64.const 1)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i64.const 0x7fffffffffffffff) (i64.const 0x7fffffffffffffff)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i64.const -1) (i64.const -1)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i64.const 1) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i64.const 0) (i64.const 1)) (i32.const 0)) +(assert_eq (invoke "ge_u" (i64.const 0x8000000000000000) (i64.const 0)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i64.const 0) (i64.const 0x8000000000000000)) (i32.const 0)) +(assert_eq (invoke "ge_u" (i64.const 0x8000000000000000) (i64.const -1)) (i32.const 0)) +(assert_eq (invoke "ge_u" (i64.const -1) (i64.const 0x8000000000000000)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i64.const 0x8000000000000000) (i64.const 0x7fffffffffffffff)) (i32.const 1)) +(assert_eq (invoke "ge_u" (i64.const 0x7fffffffffffffff) (i64.const 0x8000000000000000)) (i32.const 0)) diff --git a/ml-proto/test/int32.wasm b/ml-proto/test/int32.wasm deleted file mode 100644 index 46463d8250..0000000000 --- a/ml-proto/test/int32.wasm +++ /dev/null @@ -1,37 +0,0 @@ -(; Int arith operations ;) - -(module - (func $clz (param $x i32) (result i32) - (i32.clz (get_local $x)) - ) - - (func $ctz (param $x i32) (result i32) - (i32.ctz (get_local $x)) - ) - - (func $popcnt (param $x i32) (result i32) - (i32.popcnt (get_local $x)) - ) - - (export "clz" $clz) - (export "ctz" $ctz) - (export "popcnt" $popcnt) -) - -(assert_eq (invoke "clz" (i32.const -1)) (i32.const 0)) ;; 0xFFFFFFFF -(assert_eq (invoke "clz" (i32.const 0)) (i32.const 32)) -(assert_eq (invoke "clz" (i32.const 32768)) (i32.const 16)) ;; 0x00008000 -(assert_eq (invoke "clz" (i32.const 255)) (i32.const 24)) ;; 0xFF -(assert_eq (invoke "clz" (i32.const -2147483648)) (i32.const 0)) ;; 0x80000000 -(assert_eq (invoke "clz" (i32.const 1)) (i32.const 31)) -(assert_eq (invoke "clz" (i32.const 2)) (i32.const 30)) - -(assert_eq (invoke "ctz" (i32.const -1)) (i32.const 0)) -(assert_eq (invoke "ctz" (i32.const 0)) (i32.const 32)) -(assert_eq (invoke "ctz" (i32.const 32768)) (i32.const 15)) ;; 0x00008000 -(assert_eq (invoke "ctz" (i32.const 65536)) (i32.const 16)) ;; 0x00010000 -(assert_eq (invoke "ctz" (i32.const -2147483648)) (i32.const 31)) ;; 0x80000000 - -(assert_eq (invoke "popcnt" (i32.const -1)) (i32.const 32)) -(assert_eq (invoke "popcnt" (i32.const 0)) (i32.const 0)) -(assert_eq (invoke "popcnt" (i32.const 32768)) (i32.const 1)) ;; 0x00008000 diff --git a/ml-proto/test/unsigned.wasm b/ml-proto/test/unsigned.wasm index bc17d658d5..ab3b9e7068 100644 --- a/ml-proto/test/unsigned.wasm +++ b/ml-proto/test/unsigned.wasm @@ -105,16 +105,16 @@ (assert_eq (invoke "i32.trunc_u" (f64.const 1e8)) (i32.const 100000000)) (assert_eq (invoke "i64.trunc_u" (f64.const 1e8)) (i64.const 100000000)) -(assert_eq (invoke "i32.trunc_u" (f64.const 1e16)) (i32.const 0)) +(assert_trap (invoke "i32.trunc_u" (f64.const 1e16)) "runtime: integer overflow") (assert_eq (invoke "i64.trunc_u" (f64.const 1e16)) (i64.const 10000000000000000)) -(assert_eq (invoke "i32.trunc_u" (f64.const 1e30)) (i32.const 0)) -(assert_eq (invoke "i64.trunc_u" (f64.const -1)) (i64.const 0)) +(assert_trap (invoke "i32.trunc_u" (f64.const 1e30)) "runtime: integer overflow") +(assert_trap (invoke "i64.trunc_u" (f64.const -1)) "runtime: integer overflow") ;; max_uint32 (assert_eq (invoke "i32.trunc_u" (f64.const 4294967295)) (i32.const -1)) (assert_eq (invoke "i64.trunc_u" (f64.const 4294967295)) (i64.const 4294967295)) ;; max_int64+1 -(assert_eq (invoke "i32.trunc_u" (f64.const 9223372036854775808)) (i32.const 0)) +(assert_trap (invoke "i32.trunc_u" (f64.const 9223372036854775808)) "runtime: integer overflow") (assert_eq (invoke "i64.trunc_u" (f64.const 9223372036854775808)) (i64.const -9223372036854775808)) diff --git a/ml-proto/travis/build-test.sh b/ml-proto/travis/build-test.sh index 686097c045..09f143c98f 100755 --- a/ml-proto/travis/build-test.sh +++ b/ml-proto/travis/build-test.sh @@ -11,7 +11,7 @@ export PATH=$PWD/ocaml/install/bin:$PATH cd src -ocamlbuild -libs "bigarray, nums, str" -Is "given, spec, host" main.native +ocamlbuild -libs "bigarray, str" -Is "given, spec, host" main.native cd ..