diff --git a/src/compile.ml b/src/compile.ml index 3febadc7e38..f5f688c5f81 100644 --- a/src/compile.ml +++ b/src/compile.ml @@ -1440,6 +1440,12 @@ module Prim = struct let prim_shiftToWordN b = prim_intToWord32 ^^ UnboxedSmallWord.shift_leftWordNtoI32 b + let prim_hashInt env = + let (set_n, get_n) = new_local64 env "n" in + set_n ^^ + get_n ^^ get_n ^^ compile_const_64 32L ^^ G.i (Binary (Wasm.Values.I64 I64Op.ShrU)) ^^ + G.i (Binary (Wasm.Values.I64 I64Op.Xor)) ^^ + prim_intToWord32 end (* Prim *) module Object = struct @@ -3782,6 +3788,11 @@ and compile_exp (env : E.t) exp = compile_unboxed_const 8l ^^ G.i (Binary (Wasm.Values.I32 I32Op.Shl)) + | "Int~hash" -> + SR.UnboxedWord32, + compile_exp_as env SR.UnboxedInt64 e ^^ + Prim.prim_hashInt env + | "popcnt" -> SR.UnboxedWord32, compile_exp_as env SR.UnboxedWord32 e ^^ diff --git a/src/prelude.ml b/src/prelude.ml index 2de8f86c42a..e343f5545f2 100644 --- a/src/prelude.ml +++ b/src/prelude.ml @@ -34,6 +34,10 @@ class revrange(x : Nat, y : Nat) { func printInt(x : Int) { (prim "printInt" : Int -> ()) x }; func print(x : Text) { (prim "print" : Text -> ()) x }; +// Hashing +func hashInt(n : Int) : Word32 = (prim "Int~hash" : Int -> Word32) n; + + // Conversions func natToWord8(n : Nat) : Word8 = (prim "Nat->Word8" : Nat -> Word8) n; func word8ToNat(n : Word8) : Nat = (prim "Word8->Nat" : Word8 -> Nat) n; @@ -138,6 +142,10 @@ end (* Conv *) let prim = function | "abs" -> fun v k -> k (Int (Nat.abs (as_int v))) + | "Int~hash" -> fun v k -> + let i = Word64.of_int_s (Big_int.int_of_big_int (as_int v)) in + let j = Word64.(and_ 0xFFFFFFFFL (xor (shr_u i 32L) i)) + in k (Word32 (Word32.of_int_u (Int64.to_int j))) | "Nat->Word8" -> fun v k -> let i = Big_int.int_of_big_int (as_int v) in k (Word8 (Word8.of_int_u i)) diff --git a/test/run-dfinity/ok/counter-class.wasm.stderr.ok b/test/run-dfinity/ok/counter-class.wasm.stderr.ok index cb1f1836617..306445d241a 100644 --- a/test/run-dfinity/ok/counter-class.wasm.stderr.ok +++ b/test/run-dfinity/ok/counter-class.wasm.stderr.ok @@ -18,31 +18,31 @@ non-closed actor: (ActorE (FuncE read (shared 1 -> 0) - (params $68) + (params $69) () (BlockE (LetD - (TupP (VarP $66)) - (TupE (CallE ( 1 -> 1) (PrimE @deserialize) (VarE $68))) + (TupP (VarP $67)) + (TupE (CallE ( 1 -> 1) (PrimE @deserialize) (VarE $69))) ) (CallE ( 1 -> 0) (FuncE $lambda ( 1 -> 0) - (params $65) + (params $66) () - (CallE ( 1 -> 0) (VarE $65) (VarE c)) + (CallE ( 1 -> 0) (VarE $66) (VarE c)) ) (FuncE $lambda ( 1 -> 0) - (params $67) + (params $68) () (CallE (shared 1 -> 0) - (VarE $66) - (CallE ( 1 -> 1) (PrimE @serialize) (VarE $67)) + (VarE $67) + (CallE ( 1 -> 1) (PrimE @serialize) (VarE $68)) ) ) ) diff --git a/test/run/hashes.as b/test/run/hashes.as new file mode 100644 index 00000000000..eed93e35d45 --- /dev/null +++ b/test/run/hashes.as @@ -0,0 +1,8 @@ + +assert (hashInt (10**7) == (10000000 : Word32)); +assert (hashInt 0 == (0 : Word32)); +assert (hashInt (10**18) == (2_860_824_243 : Word32)); + +assert (hashInt (-1) == (0 : Word32)); +assert (hashInt (-387) == (386 : Word32)); +assert (hashInt (-3876548352991) == (2_487_851_096 : Word32));