diff --git a/src/compile.ml b/src/compile.ml index 9ab6882d491..23203ccaa20 100644 --- a/src/compile.ml +++ b/src/compile.ml @@ -396,7 +396,7 @@ end let compile_unboxed_const i = G.i (Wasm.Ast.Const (nr (Wasm.Values.I32 i))) let compile_const_64 i = G.i (Wasm.Ast.Const (nr (Wasm.Values.I64 i))) let compile_unboxed_zero = compile_unboxed_const 0l -(*let compile_unboxed_one = compile_unboxed_const 1l LATER*) +let compile_unboxed_one = compile_unboxed_const 1l (* Some common arithmetic, used for pointer and index arithmetic *) let compile_op_const op i = @@ -437,7 +437,7 @@ let from_0_to_n env mk_body = let (set_n, get_n) = new_local env "n" in let (set_i, get_i) = new_local env "i" in set_n ^^ - compile_unboxed_const 0l ^^ + compile_unboxed_zero ^^ set_i ^^ compile_while @@ -543,13 +543,13 @@ module Heap = struct (* Check that the new heap pointer is within the memory *) get_pages_needed ^^ - compile_unboxed_const 0l ^^ + compile_unboxed_zero ^^ G.i (Compare (Wasm.Values.I32 I32Op.GtU)) ^^ G.if_ (ValBlockType None) ( get_pages_needed ^^ G.i MemoryGrow ^^ (* Check result *) - compile_unboxed_const 0l ^^ + compile_unboxed_zero ^^ G.i (Compare (Wasm.Values.I32 I32Op.LtS)) ^^ G.if_ (ValBlockType None) (G.i Unreachable) G.nop ) G.nop @@ -781,8 +781,8 @@ module Bool = struct directly, and to use the booleans directly with WebAssembly’s If. *) let lit = function - | false -> compile_unboxed_const 0l - | true -> compile_unboxed_const 1l + | false -> compile_unboxed_zero + | true -> compile_unboxed_one end (* Bool *) @@ -930,7 +930,7 @@ module Var = struct let static_fun_pointer env fi = Tagged.obj env Tagged.Closure [ compile_unboxed_const fi; - compile_unboxed_const 0l (* number of parameters: none *) + compile_unboxed_zero (* number of parameters: none *) ] (* Local variables may in general be mutable (or at least late-defined). @@ -1264,8 +1264,7 @@ module BoxedSmallWord = struct get_i ^^ compile_elem ^^ Heap.store_field payload_field ^^ get_i - let box env = Func.share_code env "box_i32" ["n", I32Type] [I32Type] (fun env -> - let get_n = G.i (LocalGet (nr 0l)) in + let box env = Func.share_code1 env "box_i32" ("n", I32Type) [I32Type] (fun env get_n -> get_n ^^ compile_unboxed_const (Int32.of_int (1 lsl 10)) ^^ G.i (Compare (Wasm.Values.I32 I32Op.LtU)) ^^ G.if_ (ValBlockType (Some I32Type)) @@ -1273,18 +1272,44 @@ module BoxedSmallWord = struct (compile_box env get_n) ) - let unbox env = Func.share_code env "unbox_i32" ["n", I32Type] [I32Type] (fun env -> - let get_n = G.i (LocalGet (nr 0l)) in + let unbox env = Func.share_code1 env "unbox_i32" ("n", I32Type) [I32Type] (fun env get_n -> get_n ^^ BitTagged.if_unboxed env (ValBlockType (Some I32Type)) ( get_n ^^ BitTagged.untag_i32 env) ( get_n ^^ Heap.load_field payload_field) ) - (*let lit env n = compile_unboxed_const n ^^ box env*) + let _lit env n = compile_unboxed_const n ^^ box env end (* BoxedSmallWord *) +module UnboxedSmallWord = struct + (* While smaller-than-32bit words are treated as i32 from the WebAssembly perspective, + there are certain differences that are type based. This module provides helpers to abstract + over those. *) + + let shift_of_type = function + | Type.Word8 -> 24l + | Type.Word16 -> 16l + | _ -> 0l + + let bitwidth_mask_of_type = function + | Type.Word8 -> 0b111l + | Type.Word16 -> 0b1111l + | p -> todo "bitwidth_mask_of_type" (Arrange_type.prim p) 0l + + let const_of_type ty n = Int32.(shift_left n (to_int (shift_of_type ty))) + + let padding_of_type ty = Int32.(sub (const_of_type ty 1l) one) + + let mask_of_type ty = Int32.lognot (padding_of_type ty) + + let name_of_type ty seed = match Arrange.prim ty with + | Wasm.Sexpr.Atom s -> seed ^ "<" ^ s ^ ">" + | wtf -> todo "name_of_type" wtf seed + +end (* UnboxedSmallWord *) + (* Primitive functions *) module Prim = struct open Wasm.Values @@ -1305,26 +1330,36 @@ module Prim = struct ) ( get_i ) - let prim_word32toNat env = + (* The Word8 and Word16 bits sit in the MSBs of the i32, in this manner + we can perform almost all operations, with the exception of + - Mul (needs shr of one operand) + - Shr (needs masking of result) + - Rot (needs duplication into LSBs, masking of amount and masking of result) + - ctz (needs shr of operand or sub from result) + + Both Word8/16 easily fit into the vanilla stackrep, so no boxing is necessary. + This MSB-stored schema is also essentially what the interpreter is using. + *) + let prim_word32toNat = G.i (Convert (Wasm.Values.I64 I64Op.ExtendUI32)) - let prim_maskedWord32toNat mask env = - compile_unboxed_const mask ^^ - G.i (Binary (I32 I32Op.And)) ^^ - prim_word32toNat env - let prim_by_shiftWord32toInt b env = + let prim_shiftWordNtoI32 b = compile_unboxed_const b ^^ - G.i (Binary (I32 I32Op.Shl)) ^^ + G.i (Binary (I32 I32Op.ShrU)) + let prim_shiftWordNtoUnsigned b = + prim_shiftWordNtoI32 b ^^ + prim_word32toNat + let prim_word32toInt = + G.i (Convert (Wasm.Values.I64 I64Op.ExtendSI32)) + let prim_shiftWordNtoSigned b = compile_unboxed_const b ^^ G.i (Binary (I32 I32Op.ShrS)) ^^ - prim_word32toNat env - let prim_intToWord32 env = + prim_word32toInt + let prim_intToWord32 = G.i (Convert (Wasm.Values.I32 I32Op.WrapI64)) - let prim_word32toInt env = - G.i (Convert (Wasm.Values.I64 I64Op.ExtendSI32)) - let prim_maskToWord32 mask env = - prim_intToWord32 env ^^ - compile_unboxed_const mask ^^ - G.i (Binary (I32 I32Op.And)) + let prim_shiftToWordN b = + prim_intToWord32 ^^ + compile_unboxed_const b ^^ + G.i (Binary (I32 I32Op.Shl)) end (* Prim *) module Object = struct @@ -1834,7 +1869,7 @@ module Tuple = struct (* We represent the boxed empty tuple as the unboxed scalar 0, i.e. simply as number (but really anything is fine, we never look at this) *) - let compile_unit = compile_unboxed_const 1l + let compile_unit = compile_unboxed_one (* Expects on the stack the pointer to the array. *) let load_n n = Heap.load_field (Int32.add Array.header_size n) @@ -2122,7 +2157,7 @@ module OrthogonalPersistence = struct set_i ^^ get_i ^^ - compile_unboxed_const 0l ^^ + compile_unboxed_zero ^^ G.i (Compare (Wasm.Values.I32 I32Op.Eq)) ^^ G.if_ (ValBlockType None) (* First run, call the start function *) @@ -2389,6 +2424,8 @@ module Serialization = struct Tagged.branch env (ValBlockType (Some I32Type)) [ Tagged.Int, compile_unboxed_const 3l + ; Tagged.SmallWord, + compile_unboxed_const 2l ; Tagged.Reference, compile_unboxed_const 2l ; Tagged.Some, @@ -2513,7 +2550,7 @@ module Serialization = struct Func.share_code3 env "extract_references" (("start", I32Type), ("to", I32Type), ("tbl_area", I32Type)) [I32Type] (fun env get_start get_to get_tbl_area -> let (set_i, get_i) = new_local env "i" in - compile_unboxed_const 0l ^^ set_i ^^ + compile_unboxed_zero ^^ set_i ^^ walk_heap_from_to env get_start get_to (fun get_x -> get_x ^^ @@ -2593,7 +2630,7 @@ module Serialization = struct set_end ^^ (* Empty table of references *) - compile_unboxed_const 0l ^^ set_tbl_size + compile_unboxed_zero ^^ set_tbl_size ) (* We have real data on the heap. Copy. *) ( get_x ^^ @@ -2680,7 +2717,7 @@ module Serialization = struct (* First load databuf reference (last entry) at the heap position somehow *) (* now load the databuf *) get_start ^^ compile_add_const ptr_unskew ^^ - compile_unboxed_const 1l ^^ + compile_unboxed_one ^^ get_elembuf ^^ get_tbl_size ^^ compile_sub_const 1l ^^ G.i (Call (nr (Dfinity.elem_internalize_i env))) ^^ @@ -2698,7 +2735,7 @@ module Serialization = struct get_start ^^ compile_add_const ptr_unskew ^^ get_data_len ^^ get_databuf ^^ - compile_unboxed_const 0l ^^ + compile_unboxed_zero ^^ G.i (Call (nr (Dfinity.data_internalize_i env))) ^^ (* Check if we got something unboxed (data buf size 1 word) *) @@ -2727,7 +2764,7 @@ module Serialization = struct Heap.get_heap_ptr ^^ get_tbl_size ^^ compile_sub_const 1l ^^ get_elembuf ^^ - compile_unboxed_const 0l ^^ + compile_unboxed_zero ^^ G.i (Call (nr (Dfinity.elem_internalize_i env))) ^^ (* Fix references *) @@ -2909,6 +2946,7 @@ module StackRep = struct | Type.Prim Type.Nat -> UnboxedInt64 | Type.Prim Type.Int -> UnboxedInt64 | Type.Prim Type.Word32 -> UnboxedWord32 + | Type.Prim Type.(Word8 | Word16 | Char) -> Vanilla | Type.Prim Type.Text -> Vanilla | p -> todo "of_type" (Arrange_ir.typ p) Vanilla @@ -3285,9 +3323,18 @@ let compile_lit env lit = Syntax.(match lit with | NatLit n -> SR.UnboxedInt64, (try compile_const_64 (Big_int.int64_of_big_int n) with Failure _ -> Printf.eprintf "compile_lit: Overflow in literal %s\n" (Big_int.string_of_big_int n); G.i Unreachable) + | Word8Lit n -> SR.Vanilla, + (try compile_unboxed_const (Value.Word8.to_bits n) + with Failure _ -> Printf.eprintf "compile_lit: Overflow in literal %d\n" (Int32.to_int (Value.Word8.to_bits n)); G.i Unreachable) + | Word16Lit n -> SR.Vanilla, + (try compile_unboxed_const (Value.Word16.to_bits n) + with Failure _ -> Printf.eprintf "compile_lit: Overflow in literal %d\n" (Int32.to_int (Value.Word16.to_bits n)); G.i Unreachable) | Word32Lit n -> SR.UnboxedWord32, (try compile_unboxed_const n - with Failure _ -> Printf.eprintf "compile_lit: Overflow in literal %d\n" (Int32.to_int n); G.i Unreachable) (* TODO: check we are 64 bit *) + with Failure _ -> Printf.eprintf "compile_lit: Overflow in literal %d\n" (Int32.to_int n); G.i Unreachable) + | CharLit c -> SR.Vanilla, + (try compile_unboxed_const Int32.(shift_left (of_int c) 8) + with Failure _ -> Printf.eprintf "compile_lit: Overflow in literal %d\n" c; G.i Unreachable) | NullLit -> SR.Vanilla, Opt.null | TextLit t -> SR.Vanilla, Text.lit env t | _ -> todo "compile_lit" (Arrange.lit lit) (SR.Vanilla, G.i Unreachable) @@ -3305,41 +3352,50 @@ let compile_unop env t op = Syntax.(match op, t with get_n ^^ G.i (Binary (Wasm.Values.I64 I64Op.Sub)) ) - | NegOp, Type.Prim Type.Word16 -> - SR.UnboxedWord32, - Func.share_code env "neg16" ["n", I32Type] [I32Type] (fun env -> - let get_n = G.i (LocalGet (nr 0l)) in - compile_unboxed_zero ^^ - get_n ^^ - G.i (Binary (Wasm.Values.I32 I32Op.Sub)) ^^ - compile_unboxed_const 0xFFFFl ^^ - G.i (Binary (Wasm.Values.I32 I32Op.And)) - ) - | NegOp, Type.Prim Type.Word32 -> - SR.UnboxedWord32, - Func.share_code env "neg32" ["n", I32Type] [I32Type] (fun env -> - let get_n = G.i (LocalGet (nr 0l)) in + | NegOp, Type.Prim Type.(Word8 | Word16 | Word32) -> + StackRep.of_type t, + Func.share_code1 env "neg32" ("n", I32Type) [I32Type] (fun env get_n -> compile_unboxed_zero ^^ get_n ^^ G.i (Binary (Wasm.Values.I32 I32Op.Sub)) ) - | PosOp, Type.Prim (Type.Int | Type.Nat) -> + | NotOp, Type.Prim Type.(Word8 | Word16 | Word32 as ty) -> + StackRep.of_type t, compile_unboxed_const (UnboxedSmallWord.mask_of_type ty) ^^ + G.i (Binary (Wasm.Values.I32 I32Op.Xor)) + | PosOp, Type.Prim Type.(Int | Nat) -> SR.UnboxedInt64, G.nop - | PosOp, Type.Prim (Type.Word8 | Type.Word16 | Type.Word32) -> - SR.UnboxedWord32, + | PosOp, Type.Prim Type.(Word8 | Word16 | Word32) -> + StackRep.of_type t, G.nop | _ -> todo "compile_unop" (Arrange.unop op) (SR.Vanilla, G.i Unreachable) ) +(* Makes sure that we only shift/rotate the maximum number of bits available in the word. *) +let clamp_shift_amount = function + | Type.Word32 -> G.nop + | ty -> compile_unboxed_const (UnboxedSmallWord.bitwidth_mask_of_type ty) ^^ + G.i (Binary (Wasm.Values.I32 I32Op.And)) + +(* Makes sure that the word payload (e.g. shift/rotate amount) is in the LSB bits of the word. *) +let lsb_adjust = function + | Type.Word32 -> G.nop + | ty -> Prim.prim_shiftWordNtoI32 (UnboxedSmallWord.shift_of_type ty) + +(* Makes sure that the word representation invariant is restored. *) +let sanitize_word_result = function + | Type.Word32 -> G.nop + | ty -> compile_unboxed_const (UnboxedSmallWord.mask_of_type ty) ^^ + G.i (Binary (Wasm.Values.I32 I32Op.And)) + (* This returns a single StackRep, to be used for both arguments and the result. One could imagine operators that require or produce different StackReps, but none of these do, so a single value is fine. *) -let compile_binop env t op = +let rec compile_binop env t op = StackRep.of_type t, Syntax.(match t, op with - | Type.Prim Type.Nat, AddOp -> G.i (Binary (Wasm.Values.I64 I64Op.Add)) + | Type.Prim Type.(Nat | Int), AddOp -> G.i (Binary (Wasm.Values.I64 I64Op.Add)) | Type.Prim Type.Nat, SubOp -> Func.share_code2 env "nat_sub" (("n1", I64Type), ("n2", I64Type)) [I64Type] (fun env get_n1 get_n2 -> get_n1 ^^ get_n2 ^^ G.i (Compare (Wasm.Values.I64 I64Op.LtU)) ^^ @@ -3347,14 +3403,66 @@ let compile_binop env t op = (G.i Unreachable) (get_n1 ^^ get_n2 ^^ G.i (Binary (Wasm.Values.I64 I64Op.Sub))) ) - | Type.Prim Type.Nat, MulOp -> G.i (Binary (Wasm.Values.I64 I64Op.Mul)) + | Type.Prim Type.(Nat | Int), MulOp -> G.i (Binary (Wasm.Values.I64 I64Op.Mul)) | Type.Prim Type.Nat, DivOp -> G.i (Binary (Wasm.Values.I64 I64Op.DivU)) | Type.Prim Type.Nat, ModOp -> G.i (Binary (Wasm.Values.I64 I64Op.RemU)) - | Type.Prim Type.Int, AddOp -> G.i (Binary (Wasm.Values.I64 I64Op.Add)) | Type.Prim Type.Int, SubOp -> G.i (Binary (Wasm.Values.I64 I64Op.Sub)) - | Type.Prim Type.Int, MulOp -> G.i (Binary (Wasm.Values.I64 I64Op.Mul)) | Type.Prim Type.Int, DivOp -> G.i (Binary (Wasm.Values.I64 I64Op.DivS)) | Type.Prim Type.Int, ModOp -> G.i (Binary (Wasm.Values.I64 I64Op.RemS)) + + | Type.Prim Type.(Word8 | Word16 | Word32), AddOp -> G.i (Binary (Wasm.Values.I32 I32Op.Add)) + | Type.Prim Type.(Word8 | Word16 | Word32), SubOp -> G.i (Binary (Wasm.Values.I32 I32Op.Sub)) + | Type.(Prim (Word8|Word16|Word32 as ty)), MulOp -> lsb_adjust ty ^^ + G.i (Binary (Wasm.Values.I32 I32Op.Mul)) + | Type.Prim Type.(Word8 | Word16 | Word32), DivOp -> G.i (Binary (Wasm.Values.I32 I32Op.DivU)) + | Type.Prim Type.(Word8 | Word16 | Word32), ModOp -> G.i (Binary (Wasm.Values.I32 I32Op.RemU)) + | Type.(Prim (Word8|Word16|Word32 as ty)), PowOp -> + let rec pow () = Func.share_code2 env (UnboxedSmallWord.name_of_type ty "pow") + (("n", I32Type), ("exp", I32Type)) [I32Type] + Wasm.Values.(fun env get_n get_exp -> + let one = compile_unboxed_const (UnboxedSmallWord.const_of_type ty 1l) in + let (set_res, get_res) = new_local env "res" in + let mul = snd (compile_binop env t MulOp) in + let square_recurse_with_shifted sanitize = + get_n ^^ get_exp ^^ compile_unboxed_const 1l ^^ + G.i (Binary (I32 I32Op.ShrU)) ^^ sanitize ^^ + pow () ^^ set_res ^^ get_res ^^ get_res ^^ mul + in get_exp ^^ G.i (Test (I32 I32Op.Eqz)) ^^ + G.if_ (StackRep.to_block_type env SR.UnboxedWord32) + one + (get_exp ^^ one ^^ G.i (Binary (I32 I32Op.And)) ^^ G.i (Test (I32 I32Op.Eqz)) ^^ + G.if_ (StackRep.to_block_type env SR.UnboxedWord32) + (square_recurse_with_shifted G.nop) + (get_n ^^ + square_recurse_with_shifted (sanitize_word_result ty) ^^ + mul))) + in pow () + | Type.Prim Type.(Word8 | Word16 | Word32), AndOp -> G.i (Binary (Wasm.Values.I32 I32Op.And)) + | Type.Prim Type.(Word8 | Word16 | Word32), OrOp -> G.i (Binary (Wasm.Values.I32 I32Op.Or)) + | Type.Prim Type.(Word8 | Word16 | Word32), XorOp -> G.i (Binary (Wasm.Values.I32 I32Op.Xor)) + | Type.(Prim (Word8|Word16|Word32 as ty)), ShLOp -> + clamp_shift_amount ty ^^ + G.i (Binary (Wasm.Values.I32 I32Op.Shl)) + | Type.(Prim (Word8|Word16|Word32 as ty)), ShROp -> + clamp_shift_amount ty ^^ + G.i (Binary (Wasm.Values.I32 I32Op.ShrU)) ^^ + sanitize_word_result ty + | Type.Prim Type. Word32, RotLOp -> G.i (Binary (Wasm.Values.I32 I32Op.Rotl)) + | Type.Prim Type.(Word8 | Word16 as ty), RotLOp -> + Func.share_code2 env (UnboxedSmallWord.name_of_type ty "rotl") (("n", I32Type), ("by", I32Type)) [I32Type] + Wasm.Values.(fun env get_n get_by -> + let beside_adjust = compile_unboxed_const (Int32.sub 32l (UnboxedSmallWord.shift_of_type ty)) ^^ G.i (Binary (I32 I32Op.ShrU)) in + get_n ^^ get_n ^^ beside_adjust ^^ G.i (Binary (I32 I32Op.Or)) ^^ + get_by ^^ lsb_adjust ty ^^ clamp_shift_amount ty ^^ G.i (Binary (I32 I32Op.Rotl)) ^^ + sanitize_word_result ty) + | Type.Prim Type. Word32, RotROp -> G.i (Binary (Wasm.Values.I32 I32Op.Rotr)) + | Type.Prim Type.(Word8 | Word16 as ty), RotROp -> + Func.share_code2 env (UnboxedSmallWord.name_of_type ty "rotr") (("n", I32Type), ("by", I32Type)) [I32Type] + Wasm.Values.(fun env get_n get_by -> + get_n ^^ get_n ^^ lsb_adjust ty ^^ G.i (Binary (I32 I32Op.Or)) ^^ + get_by ^^ lsb_adjust ty ^^ clamp_shift_amount ty ^^ G.i (Binary (I32 I32Op.Rotr)) ^^ + sanitize_word_result ty) + | Type.Prim Type.Text, CatOp -> Text.concat env | _ -> todo "compile_binop" (Arrange.binop op) (G.i Unreachable) ) @@ -3363,9 +3471,24 @@ let compile_eq env t = match t with | Type.Prim Type.Text -> Text.compare env | Type.Prim Type.Bool -> G.i (Compare (Wasm.Values.I32 I32Op.Eq)) | Type.Prim (Type.Nat | Type.Int) -> G.i (Compare (Wasm.Values.I64 I64Op.Eq)) - | Type.Prim Type.Word32 -> G.i (Compare (Wasm.Values.I32 I32Op.Eq)) + | Type.Prim Type.(Word8 | Word16 | Word32 | Char) -> G.i (Compare (Wasm.Values.I32 I32Op.Eq)) | _ -> todo "compile_eq" (Arrange.relop Syntax.EqOp) (G.i Unreachable) +let get_relops = Syntax.(function + | GeOp -> I64Op.GeU, I64Op.GeS, I32Op.GeU, I32Op.GeS + | GtOp -> I64Op.GtU, I64Op.GtS, I32Op.GtU, I32Op.GtS + | LeOp -> I64Op.LeU, I64Op.LeS, I32Op.LeU, I32Op.LeS + | LtOp -> I64Op.LtU, I64Op.LtS, I32Op.LtU, I32Op.LtS + | _ -> failwith "uncovered relop") + +let compile_comparison t op = + let u64op, s64op, u32op, s32op = get_relops op + in Type.(match t with + | Nat -> G.i (Compare (Wasm.Values.I64 u64op)) + | Int -> G.i (Compare (Wasm.Values.I64 s64op)) + | (Word8 | Word16 | Word32 | Char) -> G.i (Compare (Wasm.Values.I32 u32op)) + | _ -> todo "compile_comparison" (Arrange.prim t) (G.i Unreachable)) + let compile_relop env t op = StackRep.of_type t, Syntax.(match t, op with @@ -3373,18 +3496,11 @@ let compile_relop env t op = | _, NeqOp -> compile_eq env t ^^ G.if_ (StackRep.to_block_type env SR.bool) (Bool.lit false) (Bool.lit true) - | Type.Prim Type.Nat, GeOp -> G.i (Compare (Wasm.Values.I64 I64Op.GeU)) - | Type.Prim Type.Nat, GtOp -> G.i (Compare (Wasm.Values.I64 I64Op.GtU)) - | Type.Prim Type.Nat, LeOp -> G.i (Compare (Wasm.Values.I64 I64Op.LeU)) - | Type.Prim Type.Nat, LtOp -> G.i (Compare (Wasm.Values.I64 I64Op.LtU)) - | Type.Prim Type.Int, GeOp -> G.i (Compare (Wasm.Values.I64 I64Op.GeS)) - | Type.Prim Type.Int, GtOp -> G.i (Compare (Wasm.Values.I64 I64Op.GtS)) - | Type.Prim Type.Int, LeOp -> G.i (Compare (Wasm.Values.I64 I64Op.LeS)) - | Type.Prim Type.Int, LtOp -> G.i (Compare (Wasm.Values.I64 I64Op.LtS)) + | Type.Prim Type.(Nat | Int | Word8 | Word16 | Word32 | Char as t1), op1 -> + compile_comparison t1 op1 | _ -> todo "compile_relop" (Arrange.relop op) (G.i Unreachable) ) - (* compile_lexp is used for expressions on the left of an assignment operator, produces some code (with side effect), and some pure code *) let rec compile_lexp (env : E.t) exp = @@ -3445,6 +3561,15 @@ and compile_exp (env : E.t) exp = match p with | "Array.init" -> Array.init env | "Array.tabulate" -> Array.tabulate env + | "shrs" -> + let (set_am, get_am) = new_local env "am" in + BoxedSmallWord.unbox env ^^ + set_am ^^ + BoxedSmallWord.unbox env ^^ + get_am ^^ + G.i (Binary (Wasm.Values.I32 I32Op.ShrS)) ^^ + BoxedSmallWord.box env + | _ -> todo "compile_exp" (Arrange_ir.exp pe) (G.i Unreachable) end (* Unary prims *) @@ -3458,48 +3583,73 @@ and compile_exp (env : E.t) exp = | "Nat->Word8" | "Int->Word8" -> - SR.UnboxedWord32, + SR.Vanilla, compile_exp_as env SR.UnboxedInt64 e ^^ - Prim.prim_maskToWord32 0xFFl env + Prim.prim_shiftToWordN (UnboxedSmallWord.shift_of_type Type.Word8) | "Nat->Word16" | "Int->Word16" -> - SR.UnboxedWord32, + SR.Vanilla, compile_exp_as env SR.UnboxedInt64 e ^^ - Prim.prim_maskToWord32 0xFFFFl env + Prim.prim_shiftToWordN (UnboxedSmallWord.shift_of_type Type.Word16) | "Nat->Word32" | "Int->Word32" -> SR.UnboxedWord32, compile_exp_as env SR.UnboxedInt64 e ^^ - Prim.prim_intToWord32 env + Prim.prim_intToWord32 + + | "Char->Word32" -> + SR.UnboxedWord32, + compile_exp_vanilla env e ^^ + compile_unboxed_const 8l ^^ + G.i (Binary (Wasm.Values.I32 I32Op.ShrU)) | "Word8->Nat" -> SR.UnboxedInt64, - compile_exp_as env SR.UnboxedWord32 e ^^ - Prim.prim_maskedWord32toNat 0xFFl env + compile_exp_vanilla env e ^^ + Prim.prim_shiftWordNtoUnsigned (UnboxedSmallWord.shift_of_type Type.Word8) | "Word8->Int" -> SR.UnboxedInt64, - compile_exp_as env SR.UnboxedWord32 e ^^ - Prim.prim_by_shiftWord32toInt 24l env + compile_exp_vanilla env e ^^ + Prim.prim_shiftWordNtoSigned (UnboxedSmallWord.shift_of_type Type.Word8) | "Word16->Nat" -> SR.UnboxedInt64, - compile_exp_as env SR.UnboxedWord32 e ^^ - Prim.prim_maskedWord32toNat 0xFFFFl env + compile_exp_vanilla env e ^^ + Prim.prim_shiftWordNtoUnsigned (UnboxedSmallWord.shift_of_type Type.Word16) | "Word16->Int" -> SR.UnboxedInt64, - compile_exp_as env SR.UnboxedWord32 e ^^ - Prim.prim_by_shiftWord32toInt 16l env + compile_exp_vanilla env e ^^ + Prim.prim_shiftWordNtoSigned (UnboxedSmallWord.shift_of_type Type.Word16) | "Word32->Nat" -> SR.UnboxedInt64, compile_exp_as env SR.UnboxedWord32 e ^^ - Prim.prim_word32toNat env + Prim.prim_word32toNat | "Word32->Int" -> SR.UnboxedInt64, compile_exp_as env SR.UnboxedWord32 e ^^ - Prim.prim_word32toInt env + Prim.prim_word32toInt + + | "Word32->Char" -> + SR.Vanilla, + compile_exp_as env SR.UnboxedWord32 e ^^ + compile_unboxed_const 8l ^^ + G.i (Binary (Wasm.Values.I32 I32Op.Shl)) + + | "popcnt" -> + SR.UnboxedWord32, + compile_exp_as env SR.UnboxedWord32 e ^^ + G.i (Unary (Wasm.Values.I32 I32Op.Popcnt)) + | "clz" -> + SR.UnboxedWord32, + compile_exp_as env SR.UnboxedWord32 e ^^ + G.i (Unary (Wasm.Values.I32 I32Op.Clz)) + | "ctz" -> + SR.UnboxedWord32, + compile_exp_as env SR.UnboxedWord32 e ^^ + G.i (Unary (Wasm.Values.I32 I32Op.Ctz)) | "printInt" -> SR.unit, @@ -3691,7 +3841,7 @@ and compile_exp (env : E.t) exp = let (env1, i) = E.add_local_with_offset env name.it 1l in let sr, code = compile_exp env1 e in sr, - Tagged.obj env Tagged.MutBox [ compile_unboxed_const 0l ] ^^ + Tagged.obj env Tagged.MutBox [ compile_unboxed_zero ] ^^ G.i (LocalSet (nr i)) ^^ code | DefineE (name, _, e) -> diff --git a/src/prelude.ml b/src/prelude.ml index 298f76496e7..11bd6da7bfc 100644 --- a/src/prelude.ml +++ b/src/prelude.ml @@ -50,6 +50,15 @@ func word32ToNat(n : Word32) : Nat = (prim "Word32->Nat" : Word32 -> Nat) n; func intToWord32(n : Int) : Word32 = (prim "Int->Word32" : Int -> Word32) n; func word32ToInt(n : Word32) : Int = (prim "Word32->Int" : Word32 -> Int) n; +func charToWord32(c : Char) : Word32 = (prim "Char->Word32" : Char -> Word32) c; +func word32ToChar(w : Word32) : Char = (prim "Word32->Char" : Word32 -> Char) w; + +// Exotic bitwise operations +func shrsWord32(w : Word32, amount : Word32) : Word32 = (prim "shrs" : (Word32, Word32) -> Word32) (w, amount); +func popcntWord32(w : Word32) : Word32 = (prim "popcnt" : Word32 -> Word32) w; +func clzWord32(w : Word32) : Word32 = (prim "clz" : Word32 -> Word32) w; +func ctzWord32(w : Word32) : Word32 = (prim "ctz" : Word32 -> Word32) w; + // This would be nicer as a objects, but lets do them as functions // until the compiler has a concept of “static objects” @@ -141,6 +150,25 @@ let prim = function in k (Int (Big_int.big_int_of_int i)) | "Word32->Int" -> fun v k -> k (Int (Big_int.big_int_of_int32 (as_word32 v))) + | "Char->Word32" -> fun v k -> + let i = as_char v + in k (Word32 (Word32.of_int_u i)) + | "Word32->Char" -> fun v k -> + let i = Conv.of_signed_Word32 (as_word32 v) + in k (Char i) + | "shrs" -> fun v k -> + let w, a = as_pair v in + let i = Word32.shr_s (as_word32 w) (as_word32 a) + in k (Word32 i) + | "popcnt" -> fun v k -> + let i = Word32.popcnt (as_word32 v) + in k (Word32 i) + | "clz" -> fun v k -> + let i = Word32.clz (as_word32 v) + in k (Word32 i) + | "ctz" -> fun v k -> + let i = Word32.ctz (as_word32 v) + in k (Word32 i) | "print" -> fun v k -> Printf.printf "%s%!" (as_text v); k unit | "printInt" -> fun v k -> Printf.printf "%d%!" (Int.to_int (as_int v)); k unit | "Array.init" -> fun v k -> diff --git a/test/run-dfinity/data-params.as b/test/run-dfinity/data-params.as index 1d3359a7e43..cfa7fc937f6 100644 --- a/test/run-dfinity/data-params.as +++ b/test/run-dfinity/data-params.as @@ -10,7 +10,7 @@ let a = actor { printInt(c); print("\n"); }; - incnested(n1 : Nat, (n2 : Nat, n3: Nat)) : () { + incnested(n1 : Nat, (n2 : Nat, n3 : Nat)) : () { c += n1 + n2 + n3; printInt(c); print("\n"); @@ -72,3 +72,152 @@ a.printLabeled("Foo1: "); a.printLabeledOpt(?"Foo2: "); // a.readCounter(func (n : Nat) = { printInt n; print("\n") }); a.incn(10000000000000); + + +let w32 = actor { + private var c : Word32 = 0; + incn(n : Word32) : () { + c += n; + printInt(word32ToInt(c)); + print("\n"); + }; + incnn(n1 : Word32, n2 : Word32) : () { + c += n1 + n2; + printInt(word32ToInt(c)); + print("\n"); + }; + incnested(n1 : Word32, (n2 : Word32, n3 : Word32)) : () { + c += n1 + n2 + n3; + printInt(word32ToInt(c)); + print("\n"); + }; + incarray(a : [Word32]) : () { + for (i in a.vals()) { c += i }; + printInt(word32ToInt(c)); + print("\n"); + }; + incopt(a : ?Word32) : () { + switch a { + case null { c += 1000000 }; + case (?a) { c += a }; + }; + printInt(word32ToInt(c)); + print("\n"); + }; + increcord(a : shared { x : Word32; y : Word32 }) : () { + c += a.x; + c += a.y; + printInt(word32ToInt(c)); + print("\n"); + }; + printCounter() { + printInt(word32ToInt(c)); + print("\n"); + }; + printLabeled(l:Text) { + print l; + printInt(word32ToInt(c)); + print("\n"); + }; + printLabeledOpt(?l:?Text) { + print l; + printInt(word32ToInt(c)); + print("\n"); + }; + readCounter(f : shared Word32 -> ()) : () { + f(c); + }; +}; + + +w32.incn(1); +w32.incn(2); +w32.incn(3); +w32.incn(4); +w32.incn(1000); +w32.incnn(5,6); +w32.incnn(2000,3000); +w32.incnested(7,(8,9)); +w32.incarray([10,11,12,13]); +w32.incopt(null); +w32.incopt(?14); +w32.increcord(shared {x = 15 : Word32; y = 16 : Word32}); +w32.increcord(shared {x = 17 : Word32; y = 18 : Word32; z = 19 : Word32}); +w32.printCounter(); +w32.printLabeled("Foo1: "); +w32.printLabeledOpt(?"Foo2: "); + + + +let w16 = actor { + private var c : Word16 = 0; + incn(n : Word16) : () { + c += n; + printInt(word16ToInt(c)); + print("\n"); + }; + incnn(n1 : Word16, n2 : Word16) : () { + c += n1 + n2; + printInt(word16ToInt(c)); + print("\n"); + }; + incnested(n1 : Word16, (n2 : Word16, n3 : Word16)) : () { + c += n1 + n2 + n3; + printInt(word16ToInt(c)); + print("\n"); + }; + incarray(a : [Word16]) : () { + for (i in a.vals()) { c += i }; + printInt(word16ToInt(c)); + print("\n"); + }; + incopt(a : ?Word16) : () { + switch a { + case null { c += 10000 }; + case (?a) { c += a }; + }; + printInt(word16ToInt(c)); + print("\n"); + }; + increcord(a : shared { x : Word16; y : Word16 }) : () { + c += a.x; + c += a.y; + printInt(word16ToInt(c)); + print("\n"); + }; + printCounter() { + printInt(word16ToInt(c)); + print("\n"); + }; + printLabeled(l:Text) { + print l; + printInt(word16ToInt(c)); + print("\n"); + }; + printLabeledOpt(?l:?Text) { + print l; + printInt(word16ToInt(c)); + print("\n"); + }; + readCounter(f : shared Word16 -> ()) : () { + f(c); + }; +}; + + +w16.incn(1); +w16.incn(2); +w16.incn(3); +w16.incn(4); +w16.incn(1000); +w16.incnn(5,6); +w16.incnn(2000,3000); +w16.incnested(7,(8,9)); +w16.incarray([10,11,12,13]); +w16.incopt(null); +w16.incopt(?14); +w16.increcord(shared {x = 15 : Word16; y = 16 : Word16}); +w16.increcord(shared {x = 17 : Word16; y = 18 : Word16; z = 19 : Word16}); +w16.printCounter(); +w16.printLabeled("Foo1: "); +w16.printLabeledOpt(?"Foo2: "); diff --git a/test/run-dfinity/ok/data-params.dvm-run.ok b/test/run-dfinity/ok/data-params.dvm-run.ok index 47fc97de9b1..9884ed33c7f 100644 --- a/test/run-dfinity/ok/data-params.dvm-run.ok +++ b/test/run-dfinity/ok/data-params.dvm-run.ok @@ -16,3 +16,35 @@ Top-level code done. Foo1: 1006171 Foo2: 1006171 1317141083 +1 +3 +6 +10 +1010 +1021 +6021 +6045 +6091 +1006091 +1006105 +1006136 +1006171 +1006171 +Foo1: 1006171 +Foo2: 1006171 +1 +3 +6 +10 +1010 +1021 +6021 +6045 +6091 +16091 +16105 +16136 +16171 +16171 +Foo1: 16171 +Foo2: 16171 diff --git a/test/run-dfinity/ok/data-params.run-ir.ok b/test/run-dfinity/ok/data-params.run-ir.ok index 25d47d7f7f0..f879c2bfdac 100644 --- a/test/run-dfinity/ok/data-params.run-ir.ok +++ b/test/run-dfinity/ok/data-params.run-ir.ok @@ -1,4 +1,6 @@ data-params.as:46.19-46.27: warning, this pattern does not cover all possible values +data-params.as:122.19-122.27: warning, this pattern does not cover all possible values +data-params.as:197.19-197.27: warning, this pattern does not cover all possible values 1 3 6 @@ -16,3 +18,35 @@ data-params.as:46.19-46.27: warning, this pattern does not cover all possible va Foo1: 1006171 Foo2: 1006171 10000001006171 +1 +3 +6 +10 +1010 +1021 +6021 +6045 +6091 +1006091 +1006105 +1006136 +1006171 +1006171 +Foo1: 1006171 +Foo2: 1006171 +1 +3 +6 +10 +1010 +1021 +6021 +6045 +6091 +16091 +16105 +16136 +16171 +16171 +Foo1: 16171 +Foo2: 16171 diff --git a/test/run-dfinity/ok/data-params.run-low.ok b/test/run-dfinity/ok/data-params.run-low.ok index 25d47d7f7f0..f879c2bfdac 100644 --- a/test/run-dfinity/ok/data-params.run-low.ok +++ b/test/run-dfinity/ok/data-params.run-low.ok @@ -1,4 +1,6 @@ data-params.as:46.19-46.27: warning, this pattern does not cover all possible values +data-params.as:122.19-122.27: warning, this pattern does not cover all possible values +data-params.as:197.19-197.27: warning, this pattern does not cover all possible values 1 3 6 @@ -16,3 +18,35 @@ data-params.as:46.19-46.27: warning, this pattern does not cover all possible va Foo1: 1006171 Foo2: 1006171 10000001006171 +1 +3 +6 +10 +1010 +1021 +6021 +6045 +6091 +1006091 +1006105 +1006136 +1006171 +1006171 +Foo1: 1006171 +Foo2: 1006171 +1 +3 +6 +10 +1010 +1021 +6021 +6045 +6091 +16091 +16105 +16136 +16171 +16171 +Foo1: 16171 +Foo2: 16171 diff --git a/test/run-dfinity/ok/data-params.run.ok b/test/run-dfinity/ok/data-params.run.ok index 25d47d7f7f0..f879c2bfdac 100644 --- a/test/run-dfinity/ok/data-params.run.ok +++ b/test/run-dfinity/ok/data-params.run.ok @@ -1,4 +1,6 @@ data-params.as:46.19-46.27: warning, this pattern does not cover all possible values +data-params.as:122.19-122.27: warning, this pattern does not cover all possible values +data-params.as:197.19-197.27: warning, this pattern does not cover all possible values 1 3 6 @@ -16,3 +18,35 @@ data-params.as:46.19-46.27: warning, this pattern does not cover all possible va Foo1: 1006171 Foo2: 1006171 10000001006171 +1 +3 +6 +10 +1010 +1021 +6021 +6045 +6091 +1006091 +1006105 +1006136 +1006171 +1006171 +Foo1: 1006171 +Foo2: 1006171 +1 +3 +6 +10 +1010 +1021 +6021 +6045 +6091 +16091 +16105 +16136 +16171 +16171 +Foo1: 16171 +Foo2: 16171 diff --git a/test/run-dfinity/ok/data-params.tc.ok b/test/run-dfinity/ok/data-params.tc.ok index bad5a00208d..1db161147e8 100644 --- a/test/run-dfinity/ok/data-params.tc.ok +++ b/test/run-dfinity/ok/data-params.tc.ok @@ -1 +1,3 @@ data-params.as:46.19-46.27: warning, this pattern does not cover all possible values +data-params.as:122.19-122.27: warning, this pattern does not cover all possible values +data-params.as:197.19-197.27: warning, this pattern does not cover all possible values diff --git a/test/run-dfinity/ok/data-params.wasm.stderr.ok b/test/run-dfinity/ok/data-params.wasm.stderr.ok index bad5a00208d..1db161147e8 100644 --- a/test/run-dfinity/ok/data-params.wasm.stderr.ok +++ b/test/run-dfinity/ok/data-params.wasm.stderr.ok @@ -1 +1,3 @@ data-params.as:46.19-46.27: warning, this pattern does not cover all possible values +data-params.as:122.19-122.27: warning, this pattern does not cover all possible values +data-params.as:197.19-197.27: warning, this pattern does not cover all possible values diff --git a/test/run/conversions.as b/test/run/conversions.as index 35feabe47ec..cd1cf3c2021 100644 --- a/test/run/conversions.as +++ b/test/run/conversions.as @@ -135,3 +135,25 @@ println(word32ToInt 4294967295); // == (-1) // 2**32 - 1 roundtrip (-100000000); roundtrip (-1000000000); }; + + + + +// Char <--> Word32 + +assert(charToWord32 '\u{00}' == (0 : Word32)); +assert(charToWord32 '*' == (42 : Word32)); +assert(charToWord32 '\u{ffff}' == (65535 : Word32)); // 2**16 - 1 +assert(charToWord32 '\u{10ffff}' == (0x10FFFF : Word32)); + +{ + func roundtrip(w : Word32) = assert (charToWord32 (word32ToChar w) == w); + roundtrip 0; + roundtrip 10; + roundtrip 100; + roundtrip 1000; + roundtrip 10000; + roundtrip 100000; + roundtrip 1000000; + roundtrip 0x10FFFF; // largest code point +} diff --git a/test/run/ok/bit-ops.wasm.stderr.ok b/test/run/ok/bit-ops.wasm.stderr.ok index 2a9d2f8f16e..1f8ac7bdc39 100644 --- a/test/run/ok/bit-ops.wasm.stderr.ok +++ b/test/run/ok/bit-ops.wasm.stderr.ok @@ -1,82 +1,6 @@ compile_unop: NotOp compile_unop: NotOp compile_binop: OrOp -of_type: Word8 -compile_binop: OrOp -of_type: Word8 -compile_binop: AndOp -of_type: Word8 -compile_binop: AndOp -of_type: Word8 -compile_binop: XorOp -of_type: Word8 -compile_binop: XorOp -of_type: Word8 -compile_binop: ShiftLOp -of_type: Word8 -compile_binop: ShiftLOp -of_type: Word8 -compile_binop: ShiftROp -of_type: Word8 -compile_binop: ShiftROp -of_type: Word8 -compile_binop: RotLOp -of_type: Word8 -compile_binop: RotLOp -of_type: Word8 -compile_binop: RotROp -of_type: Word8 -compile_binop: RotROp -of_type: Word8 -compile_unop: NotOp -compile_unop: NotOp -compile_binop: OrOp -of_type: Word16 -compile_binop: OrOp -of_type: Word16 -compile_binop: AndOp -of_type: Word16 -compile_binop: AndOp -of_type: Word16 -compile_binop: XorOp -of_type: Word16 -compile_binop: XorOp -of_type: Word16 -compile_binop: ShiftLOp -of_type: Word16 -compile_binop: ShiftLOp -of_type: Word16 -compile_binop: ShiftROp -of_type: Word16 -compile_binop: ShiftROp -of_type: Word16 -compile_binop: RotLOp -of_type: Word16 -compile_binop: RotLOp -of_type: Word16 -compile_binop: RotROp -of_type: Word16 -compile_binop: RotROp -of_type: Word16 -compile_unop: NotOp -compile_unop: NotOp -compile_binop: OrOp -compile_binop: OrOp -compile_binop: AndOp -compile_binop: AndOp -compile_binop: XorOp -compile_binop: XorOp -compile_binop: ShiftLOp -compile_binop: ShiftLOp -compile_binop: ShiftROp -compile_binop: ShiftROp -compile_binop: RotLOp -compile_binop: RotLOp -compile_binop: RotROp -compile_binop: RotROp -compile_unop: NotOp -compile_unop: NotOp -compile_binop: OrOp of_type: Word64 compile_binop: OrOp of_type: Word64 diff --git a/test/run/ok/literals.wasm-run.ok b/test/run/ok/literals.wasm-run.ok deleted file mode 100644 index 11a148f71ae..00000000000 --- a/test/run/ok/literals.wasm-run.ok +++ /dev/null @@ -1 +0,0 @@ -_out/literals.wasm:0x___: runtime trap: unreachable executed diff --git a/test/run/ok/literals.wasm.stderr.ok b/test/run/ok/literals.wasm.stderr.ok deleted file mode 100644 index db71b22da87..00000000000 --- a/test/run/ok/literals.wasm.stderr.ok +++ /dev/null @@ -1,3 +0,0 @@ -compile_lit: (Word8Lit 255) -compile_lit: (Word16Lit 6_5535) -compile_lit: (CharLit 2612) diff --git a/test/run/ok/numeric-ops.wasm.stderr.ok b/test/run/ok/numeric-ops.wasm.stderr.ok index 2230f1fa5ce..bf44ccb511d 100644 --- a/test/run/ok/numeric-ops.wasm.stderr.ok +++ b/test/run/ok/numeric-ops.wasm.stderr.ok @@ -31,66 +31,6 @@ of_type: Float compile_binop: PowOp of_type: Float compile_binop: AddOp -of_type: Word8 -compile_binop: AddOp -of_type: Word8 -compile_binop: SubOp -of_type: Word8 -compile_binop: SubOp -of_type: Word8 -compile_binop: MulOp -of_type: Word8 -compile_binop: MulOp -of_type: Word8 -compile_binop: DivOp -of_type: Word8 -compile_binop: DivOp -of_type: Word8 -compile_binop: ModOp -of_type: Word8 -compile_binop: ModOp -of_type: Word8 -compile_binop: PowOp -of_type: Word8 -compile_binop: PowOp -of_type: Word8 -compile_binop: AddOp -of_type: Word16 -compile_binop: AddOp -of_type: Word16 -compile_binop: SubOp -of_type: Word16 -compile_binop: SubOp -of_type: Word16 -compile_binop: MulOp -of_type: Word16 -compile_binop: MulOp -of_type: Word16 -compile_binop: DivOp -of_type: Word16 -compile_binop: DivOp -of_type: Word16 -compile_binop: ModOp -of_type: Word16 -compile_binop: ModOp -of_type: Word16 -compile_binop: PowOp -of_type: Word16 -compile_binop: PowOp -of_type: Word16 -compile_binop: AddOp -compile_binop: AddOp -compile_binop: SubOp -compile_binop: SubOp -compile_binop: MulOp -compile_binop: MulOp -compile_binop: DivOp -compile_binop: DivOp -compile_binop: ModOp -compile_binop: ModOp -compile_binop: PowOp -compile_binop: PowOp -compile_binop: AddOp of_type: Word64 compile_binop: AddOp of_type: Word64 diff --git a/test/run/ok/relational-ops.wasm.stderr.ok b/test/run/ok/relational-ops.wasm.stderr.ok index 339785ac3b0..3b0ee159540 100644 --- a/test/run/ok/relational-ops.wasm.stderr.ok +++ b/test/run/ok/relational-ops.wasm.stderr.ok @@ -23,62 +23,6 @@ of_type: Float compile_relop: GeOp of_type: Float compile_eq: EqOp -of_type: Word8 -compile_eq: EqOp -of_type: Word8 -compile_eq: EqOp -of_type: Word8 -compile_eq: EqOp -of_type: Word8 -compile_relop: LtOp -of_type: Word8 -compile_relop: LtOp -of_type: Word8 -compile_relop: LeOp -of_type: Word8 -compile_relop: LeOp -of_type: Word8 -compile_relop: GtOp -of_type: Word8 -compile_relop: GtOp -of_type: Word8 -compile_relop: GeOp -of_type: Word8 -compile_relop: GeOp -of_type: Word8 -compile_eq: EqOp -of_type: Word16 -compile_eq: EqOp -of_type: Word16 -compile_eq: EqOp -of_type: Word16 -compile_eq: EqOp -of_type: Word16 -compile_relop: LtOp -of_type: Word16 -compile_relop: LtOp -of_type: Word16 -compile_relop: LeOp -of_type: Word16 -compile_relop: LeOp -of_type: Word16 -compile_relop: GtOp -of_type: Word16 -compile_relop: GtOp -of_type: Word16 -compile_relop: GeOp -of_type: Word16 -compile_relop: GeOp -of_type: Word16 -compile_relop: LtOp -compile_relop: LtOp -compile_relop: LeOp -compile_relop: LeOp -compile_relop: GtOp -compile_relop: GtOp -compile_relop: GeOp -compile_relop: GeOp -compile_eq: EqOp of_type: Word64 compile_eq: EqOp of_type: Word64 @@ -102,30 +46,6 @@ compile_relop: GeOp of_type: Word64 compile_relop: GeOp of_type: Word64 -compile_eq: EqOp -of_type: Char -compile_eq: EqOp -of_type: Char -compile_eq: EqOp -of_type: Char -compile_eq: EqOp -of_type: Char -compile_relop: LtOp -of_type: Char -compile_relop: LtOp -of_type: Char -compile_relop: LeOp -of_type: Char -compile_relop: LeOp -of_type: Char -compile_relop: GtOp -of_type: Char -compile_relop: GtOp -of_type: Char -compile_relop: GeOp -of_type: Char -compile_relop: GeOp -of_type: Char compile_relop: LtOp compile_relop: LtOp compile_relop: LeOp diff --git a/test/run/ok/word-rotations.wasm-run.ok b/test/run/ok/word-rotations.wasm-run.ok deleted file mode 100644 index 8f241da436a..00000000000 --- a/test/run/ok/word-rotations.wasm-run.ok +++ /dev/null @@ -1 +0,0 @@ -_out/word-rotations.wasm:0x___: runtime trap: unreachable executed diff --git a/test/run/ok/word-rotations.wasm.stderr.ok b/test/run/ok/word-rotations.wasm.stderr.ok deleted file mode 100644 index 4a2e9f4a79f..00000000000 --- a/test/run/ok/word-rotations.wasm.stderr.ok +++ /dev/null @@ -1,74 +0,0 @@ -compile_binop: RotROp -compile_binop: RotROp -compile_eq: EqOp -of_type: Word16 -compile_lit: (Word16Lit 5_4715) -compile_binop: RotROp -of_type: Word16 -compile_lit: (Word16Lit 4) -compile_lit: (Word16Lit 23_485) -compile_eq: EqOp -of_type: Word16 -compile_lit: (Word16Lit 5_4715) -compile_binop: RotROp -of_type: Word16 -compile_lit: (Word16Lit 20) -compile_lit: (Word16Lit 23_485) -compile_eq: EqOp -of_type: Word8 -compile_lit: (Word8Lit 202) -compile_binop: RotROp -of_type: Word8 -compile_lit: (Word8Lit 3) -compile_lit: (Word8Lit 86) -compile_eq: EqOp -of_type: Word8 -compile_lit: (Word8Lit 202) -compile_binop: RotROp -of_type: Word8 -compile_lit: (Word8Lit 11) -compile_lit: (Word8Lit 86) -compile_eq: EqOp -of_type: Word8 -compile_lit: (Word8Lit 202) -compile_binop: RotROp -of_type: Word8 -compile_lit: (Word8Lit 19) -compile_lit: (Word8Lit 86) -compile_binop: RotLOp -compile_binop: RotLOp -compile_eq: EqOp -of_type: Word16 -compile_lit: (Word16Lit 4_8085) -compile_binop: RotLOp -of_type: Word16 -compile_lit: (Word16Lit 4) -compile_lit: (Word16Lit 23_485) -compile_eq: EqOp -of_type: Word16 -compile_lit: (Word16Lit 4_8085) -compile_binop: RotLOp -of_type: Word16 -compile_lit: (Word16Lit 20) -compile_lit: (Word16Lit 23_485) -compile_eq: EqOp -of_type: Word8 -compile_lit: (Word8Lit 178) -compile_binop: RotLOp -of_type: Word8 -compile_lit: (Word8Lit 3) -compile_lit: (Word8Lit 86) -compile_eq: EqOp -of_type: Word8 -compile_lit: (Word8Lit 178) -compile_binop: RotLOp -of_type: Word8 -compile_lit: (Word8Lit 11) -compile_lit: (Word8Lit 86) -compile_eq: EqOp -of_type: Word8 -compile_lit: (Word8Lit 178) -compile_binop: RotLOp -of_type: Word8 -compile_lit: (Word8Lit 19) -compile_lit: (Word8Lit 86) diff --git a/test/run/ok/words.run-ir.ok b/test/run/ok/words.run-ir.ok index e55f4fecf66..150b24d3944 100644 --- a/test/run/ok/words.run-ir.ok +++ b/test/run/ok/words.run-ir.ok @@ -1,5 +1,6 @@ 8912765 8912765 4286054531 -8912765 +4286054530 -8912766 8917332 8917332 8908198 8908198 31969 31969 @@ -11,10 +12,16 @@ 8908458 8908458 584576 584576 35 35 +4294967294 -2 +4218928893 -76038403 1140833920 1140833920 4194373630 -100593666 +29 29 +17 17 +5 5 55734 -9802 9802 9802 +9801 9801 60301 -5235 51167 -14369 31969 31969 @@ -30,6 +37,7 @@ 28083 28083 34 34 222 -34 +221 -35 101 101 223 -33 213 -43 diff --git a/test/run/ok/words.run-low.ok b/test/run/ok/words.run-low.ok index e55f4fecf66..150b24d3944 100644 --- a/test/run/ok/words.run-low.ok +++ b/test/run/ok/words.run-low.ok @@ -1,5 +1,6 @@ 8912765 8912765 4286054531 -8912765 +4286054530 -8912766 8917332 8917332 8908198 8908198 31969 31969 @@ -11,10 +12,16 @@ 8908458 8908458 584576 584576 35 35 +4294967294 -2 +4218928893 -76038403 1140833920 1140833920 4194373630 -100593666 +29 29 +17 17 +5 5 55734 -9802 9802 9802 +9801 9801 60301 -5235 51167 -14369 31969 31969 @@ -30,6 +37,7 @@ 28083 28083 34 34 222 -34 +221 -35 101 101 223 -33 213 -43 diff --git a/test/run/ok/words.run.ok b/test/run/ok/words.run.ok index e55f4fecf66..150b24d3944 100644 --- a/test/run/ok/words.run.ok +++ b/test/run/ok/words.run.ok @@ -1,5 +1,6 @@ 8912765 8912765 4286054531 -8912765 +4286054530 -8912766 8917332 8917332 8908198 8908198 31969 31969 @@ -11,10 +12,16 @@ 8908458 8908458 584576 584576 35 35 +4294967294 -2 +4218928893 -76038403 1140833920 1140833920 4194373630 -100593666 +29 29 +17 17 +5 5 55734 -9802 9802 9802 +9801 9801 60301 -5235 51167 -14369 31969 31969 @@ -30,6 +37,7 @@ 28083 28083 34 34 222 -34 +221 -35 101 101 223 -33 213 -43 diff --git a/test/run/ok/words.wasm.stderr.ok b/test/run/ok/words.wasm.stderr.ok deleted file mode 100644 index df2dd2439f9..00000000000 --- a/test/run/ok/words.wasm.stderr.ok +++ /dev/null @@ -1,79 +0,0 @@ -compile_binop: AddOp -compile_binop: SubOp -compile_binop: MulOp -compile_binop: DivOp -compile_binop: ModOp -compile_binop: PowOp -compile_binop: AndOp -compile_binop: OrOp -compile_binop: XorOp -compile_binop: ShiftLOp -compile_binop: ShiftROp -compile_binop: RotLOp -compile_binop: RotROp -compile_lit: (Word16Lit 4_567) -compile_lit: (Word16Lit 7) -compile_lit: (Word16Lit 5_5734) -compile_lit: (Word16Lit 15) -compile_lit: (Word16Lit 20_000) -compile_binop: AddOp -of_type: Word16 -compile_binop: SubOp -of_type: Word16 -compile_binop: MulOp -of_type: Word16 -compile_binop: DivOp -of_type: Word16 -compile_binop: ModOp -of_type: Word16 -compile_binop: PowOp -of_type: Word16 -compile_lit: (Word16Lit 2) -compile_binop: AndOp -of_type: Word16 -compile_binop: OrOp -of_type: Word16 -compile_binop: XorOp -of_type: Word16 -compile_binop: ShiftLOp -of_type: Word16 -compile_binop: ShiftROp -of_type: Word16 -compile_binop: RotLOp -of_type: Word16 -compile_binop: RotROp -of_type: Word16 -compile_lit: (Word8Lit 67) -compile_lit: (Word8Lit 7) -compile_lit: (Word8Lit 34) -compile_unop: NegOp -compile_lit: (Word8Lit 15) -compile_lit: (Word8Lit 200) -compile_unop: NegOp -compile_binop: AddOp -of_type: Word8 -compile_binop: SubOp -of_type: Word8 -compile_binop: MulOp -of_type: Word8 -compile_binop: DivOp -of_type: Word8 -compile_binop: ModOp -of_type: Word8 -compile_binop: PowOp -of_type: Word8 -compile_lit: (Word8Lit 2) -compile_binop: AndOp -of_type: Word8 -compile_binop: OrOp -of_type: Word8 -compile_binop: XorOp -of_type: Word8 -compile_binop: ShiftLOp -of_type: Word8 -compile_binop: ShiftROp -of_type: Word8 -compile_binop: RotLOp -of_type: Word8 -compile_binop: RotROp -of_type: Word8 diff --git a/test/run/words.as b/test/run/words.as index e2a2132b80b..f1c52165cee 100644 --- a/test/run/words.as +++ b/test/run/words.as @@ -1,3 +1,4 @@ +// CHECK: func $start // Word32 operations { func printW32ln(w : Word32) { printInt(word32ToNat w); print " "; printInt(word32ToInt w); print "\n" }; @@ -8,27 +9,58 @@ let d : Word32 = -15; let e : Word32 = 20000; - +// CHECK: get_local $c +// LATER: HECK-NOT: call $box_i32 +// CHECK: call $printW32ln printW32ln(+c); +// CHECK: call $printW32ln printW32ln(-c); +// CHECK: call $printW32ln + printW32ln(^c); +// CHECK: call $printW32ln printW32ln(a + c); +// CHECK: call $printW32ln printW32ln(c - a); + +// CHECK-NOT: i32.shr_u +// CHECK: call $printW32ln printW32ln(a * b); +// CHECK: call $printW32ln printW32ln(a / b); +// CHECK: call $printW32ln printW32ln(c % a); +// CHECK: call $printW32ln printW32ln(a ** 2); +// CHECK: call $printW32ln printW32ln(a & c); +// CHECK: call $printW32ln printW32ln(a | c); +// CHECK: call $printW32ln printW32ln(a ^ c); +// CHECK: call $printW32ln printW32ln(a << b); +// CHECK: call $printW32ln printW32ln(a >> b); - // printW32ln(shrs d b); // TODO(Gabor) +// CHECK: call $printW32ln + printW32ln(shrsWord32(d, 3)); +// CHECK: call $printW32ln + printW32ln(shrsWord32(-1216614433, 4)); // 0b10110111011110111110111111011111l == -1216614433l --> -76038403 +// CHECK: call $printW32ln printW32ln(c <<> b); +// CHECK: call $printW32ln printW32ln(c <>> b); - // printW32ln(lognot d); // TODO(Gabor) - // printW32ln(clz c); // TODO(Gabor) - // printW32ln(ctz e); // TODO(Gabor) +// CHECK: call $printW32ln + printW32ln(popcntWord32 d); // -15 = 0xfffffff1 = 0b1111_1111_1111_1111_1111_1111_1111_0001 (population = 29) +// CHECK: call $printW32ln + printW32ln(clzWord32 e); // 20000 = 0x00004e20 (leading zeros = 17) +// CHECK: call $printW32ln + printW32ln(ctzWord32 e); // 20000 = 0x00004e20 (trailing zeros = 5) + + assert (3 : Word32 ** (4 : Word32) == (81 : Word32)); + assert (3 : Word32 ** (7 : Word32) == (2187 : Word32)); + assert (3 : Word32 ** (14 : Word32) == (4782969 : Word32)); + assert (3 : Word32 ** (20 : Word32) == (3486784401 : Word32)); }; // Word16 operations @@ -42,26 +74,68 @@ let e : Word16 = 20000; +// CHECK: call $printW16ln printW16ln(+c); +// CHECK: call $printW16ln printW16ln(-c); +// CHECK: call $printW16ln + printW16ln(^c); +// CHECK: call $printW16ln printW16ln(a + c); +// CHECK: call $printW16ln printW16ln(c - a); + +// CHECK: get_local $a +// CHECK-NEXT: get_local $b +// CHECK-NEXT: i32.const 16 +// CHECK-NEXT: i32.shr_u +// CHECK-NEXT: i32.mul +// CHECK-NEXT: call $printW16ln printW16ln(a * b); +// CHECK: call $printW16ln printW16ln(a / b); +// CHECK: call $printW16ln printW16ln(c % a); +// CHECK: call $printW16ln printW16ln(a ** 2); +// CHECK: call $printW16ln printW16ln(a & c); +// CHECK: call $printW16ln printW16ln(a | c); +// CHECK: call $printW16ln printW16ln(a ^ c); +// CHECK: call $printW16ln printW16ln(a << b); + +// CHECK: get_local $b +// CHECK-NEXT: i32.const 15 +// CHECK-NEXT: i32.and +// CHECK-NEXT: i32.shr_u +// CHECK-NEXT: i32.const -65536 +// CHECK-NEXT: i32.and +// CHECK-NEXT: call $printW16ln printW16ln(a >> b); // printW16ln(shrs d b); // TODO(Gabor) + +// CHECK: get_local $b +// CHECK-NEXT: call $rotl +// CHECK-NEXT: call $printW16ln printW16ln(c <<> b); + +// CHECK: get_local $b +// CHECK-NEXT: call $rotr +// CHECK-NEXT: call $printW16ln printW16ln(c <>> b); - // printW16ln(lognot d); // TODO(Gabor) + // printW16ln(popcnt d); // TODO(Gabor) // printW16ln(clz c); // TODO(Gabor) // printW16ln(ctz e); // TODO(Gabor) + + + assert (3 : Word16 ** (0 : Word16) == (1 : Word16)); + assert (3 : Word16 ** (1 : Word16) == (3 : Word16)); + assert (3 : Word16 ** (4 : Word16) == (81 : Word16)); + assert (3 : Word16 ** (7 : Word16) == (2187 : Word16)); }; // Word8 operations @@ -75,24 +149,62 @@ let e : Word8 = 200; +// CHECK: call $printW8ln printW8ln(+c); +// CHECK: call $printW8ln printW8ln(-c); +// CHECK: call $printW8ln + printW8ln(^c); +// CHECK: call $printW8ln printW8ln(a + c); +// CHECK: call $printW8ln printW8ln(c - a); +// CHECK: get_local $b +// CHECK-NEXT: i32.const 24 +// CHECK-NEXT: i32.shr_u +// CHECK-NEXT: i32.mul +// CHECK-NEXT: call $printW8ln printW8ln(a * b); +// CHECK: call $printW8ln printW8ln(a / b); +// CHECK: call $printW8ln printW8ln(c % a); +// CHECK: call $printW8ln printW8ln(a ** 2); +// CHECK: call $printW8ln printW8ln(a & c); +// CHECK: call $printW8ln printW8ln(a | c); +// CHECK: call $printW8ln printW8ln(a ^ c); +// CHECK: call $printW8ln printW8ln(a << b); + +// CHECK: get_local $b +// CHECK-NEXT: i32.const 7 +// CHECK-NEXT: i32.and +// CHECK-NEXT: i32.shr_u +// CHECK-NEXT: i32.const -16777216 +// CHECK-NEXT: i32.and +// CHECK-NEXT: call $printW8ln printW8ln(a >> b); // printW8ln(shrs d b); // TODO(Gabor) + +// CHECK: get_local $b +// CHECK-NEXT: call $rotl +// CHECK-NEXT: call $printW8ln printW8ln(c <<> b); +// CHECK: get_local $b +// CHECK-NEXT: call $rotr +// CHECK-NEXT: call $printW8ln printW8ln(c <>> b); - // printW8ln(lognot d); // TODO(Gabor) + // printW8ln(popcnt d); // TODO(Gabor) // printW8ln(clz c); // TODO(Gabor) // printW8ln(ctz e); // TODO(Gabor) + + assert (3 : Word8 ** (0 : Word8) == (1 : Word8)); + assert (3 : Word8 ** (3 : Word8) == (27 : Word8)); + assert (3 : Word8 ** (4 : Word8) == (81 : Word8)); + assert (3 : Word8 ** (5 : Word8) == (243 : Word8)); };