Skip to main content

rustdom_x/
common.rs

1const P_2EXP63: u64 = 1 << 63;
2const INT32_MAX: u32 = i32::MAX as u32;
3
4pub fn u64_from_i32_imm(imm: i32) -> u64 {
5    let x = imm as u32;
6    if x > INT32_MAX {
7        x as u64 | 0xffffffff00000000
8    } else {
9        x as u64
10    }
11}
12
13pub fn u64_from_u32_imm(imm: u32) -> u64 {
14    if imm > INT32_MAX {
15        imm as u64 | 0xffffffff00000000
16    } else {
17        imm as u64
18    }
19}
20
21pub fn mulh(a: u64, b: u64) -> u64 {
22    ((a as u128).wrapping_mul(b as u128) >> 64) as u64
23}
24
25pub fn smulh(a: u64, b: u64) -> u64 {
26    let v_src = (a as i64) as i128; //we have to go through i64 to get the proper complement version in i128 if the u64 is negative in i64
27    let v_dst = (b as i64) as i128;
28    (v_src.wrapping_mul(v_dst) >> 64) as u64
29}
30
31/*
32    Directly taken from: https://github.com/tevador/RandomX
33    Calculates rcp = 2**x / divisor for highest integer x such that rcp < 2**64.
34    divisor must not be 0 or a power of 2
35
36    Equivalent x86 assembly (divisor in rcx):
37
38    mov edx, 1
39    mov r8, rcx
40    xor eax, eax
41    bsr rcx, rcx
42    shl rdx, cl
43    div r8
44    ret
45*/
46pub fn randomx_reciprocal(divisor: u64) -> u64 {
47    assert_ne!(divisor, 0);
48
49    let mut quotient = P_2EXP63 / divisor;
50    let mut remainder = P_2EXP63 % divisor;
51    let mut bsr = 0;
52
53    let mut bit = divisor;
54
55    loop {
56        if bit == 0 {
57            break;
58        }
59        bsr += 1;
60        bit >>= 1;
61    }
62
63    for _ in 0..bsr {
64        if remainder >= divisor.wrapping_sub(remainder) {
65            quotient = quotient.wrapping_mul(2).wrapping_add(1);
66            remainder = remainder.wrapping_mul(2).wrapping_sub(divisor);
67        } else {
68            quotient = quotient.wrapping_mul(2);
69            remainder = remainder.wrapping_mul(2);
70        }
71    }
72    quotient
73}