lib/accy/src/kernel/library/random/block/squares.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const random = @import("../root.zig");
2
3 const std = random.base.std;
4 const kernel = random.base.kernel;
5
6 pub const squares_lanes: u64 = 1;
7 pub const squares_default_key: u64 = 0x123456789abcdef0;
8
9 pub fn squaresBlock(counter: u64, key: u64) u32 {
10 var x = counter *% key;
11 const y = x;
12 const z = y +% key;
13 x = x *% x +% y;
14 x = std.math.rotr(u64, x, 32);
15 x = x *% x +% z;
16 x = std.math.rotr(u64, x, 32);
17 x = x *% x +% y;
18 x = std.math.rotr(u64, x, 32);
19 return @truncate((x *% x +% z) >> 32);
20 }
21
22 pub fn zeroExtendWord(k: anytype, word: kernel.Value) !kernel.Value {
23 const wide = try k.cast(word, .i64);
24 const mask = try k.constantInt(.i64, 0xFFFFFFFF);
25 return k.and_(wide, mask);
26 }
27
28 pub fn rotateWide32(k: anytype, value: kernel.Value) !kernel.Value {
29 const half = try k.constantInt(.i64, 32);
30 const low = try k.ushr(value, half);
31 const high = try k.shl(value, half);
32 return k.or_(low, high);
33 }
34
35 pub fn squaresWord(
36 k: anytype,
37 counter: kernel.Value,
38 key: kernel.Value,
39 ) !kernel.Value {
40 var x = try k.mul(counter, key);
41 const y = x;
42 const z = try k.add(y, key);
43 x = try k.add(try k.mul(x, x), y);
44 x = try rotateWide32(k, x);
45 x = try k.add(try k.mul(x, x), z);
46 x = try rotateWide32(k, x);
47 x = try k.add(try k.mul(x, x), y);
48 x = try rotateWide32(k, x);
49 const final = try k.add(try k.mul(x, x), z);
50 const half = try k.constantInt(.i64, 32);
51 const high = try k.ushr(final, half);
52 return k.cast(high, .i32);
53 }
54
55 pub fn squaresKeyValue(k: anytype, key_lo: kernel.Value, key_hi: kernel.Value) !kernel.Value {
56 const lo = try zeroExtendWord(k, key_lo);
57 const hi = try zeroExtendWord(k, key_hi);
58 const half = try k.constantInt(.i64, 32);
59 return k.or_(try k.shl(hi, half), lo);
60 }