polkavm_common/
operation.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// This is mostly here so that we can share the implementation between the interpreter and the optimizer.

#[inline]
pub const fn divu(lhs: u32, rhs: u32) -> u32 {
    if rhs == 0 {
        u32::MAX
    } else {
        lhs / rhs
    }
}

#[inline]
pub const fn divu64(lhs: u64, rhs: u64) -> u64 {
    if rhs == 0 {
        u64::MAX
    } else {
        lhs / rhs
    }
}

#[inline]
pub const fn remu(lhs: u32, rhs: u32) -> u32 {
    if rhs == 0 {
        lhs
    } else {
        lhs % rhs
    }
}

#[inline]
pub const fn remu64(lhs: u64, rhs: u64) -> u64 {
    if rhs == 0 {
        lhs
    } else {
        lhs % rhs
    }
}

#[inline]
pub const fn div(lhs: i32, rhs: i32) -> i32 {
    if rhs == 0 {
        -1
    } else if lhs == i32::MIN && rhs == -1 {
        lhs
    } else {
        lhs / rhs
    }
}

#[inline]
pub const fn div64(lhs: i64, rhs: i64) -> i64 {
    if rhs == 0 {
        -1
    } else if lhs == i64::MIN && rhs == -1 {
        lhs
    } else {
        lhs / rhs
    }
}

#[inline]
pub const fn rem(lhs: i32, rhs: i32) -> i32 {
    if rhs == 0 {
        lhs
    } else if lhs == i32::MIN && rhs == -1 {
        0
    } else {
        lhs % rhs
    }
}

#[inline]
pub const fn rem64(lhs: i64, rhs: i64) -> i64 {
    if rhs == 0 {
        lhs
    } else if lhs == i64::MIN && rhs == -1 {
        0
    } else {
        lhs % rhs
    }
}

#[inline]
pub const fn mulh(lhs: i32, rhs: i32) -> i32 {
    ((lhs as i64).wrapping_mul(rhs as i64) >> 32) as i32
}

#[inline]
pub const fn mulh64(lhs: i64, rhs: i64) -> i64 {
    ((lhs as i128).wrapping_mul(rhs as i128) >> 64) as i64
}

#[inline]
pub const fn mulhsu(lhs: i32, rhs: u32) -> i32 {
    ((lhs as i64).wrapping_mul(rhs as i64) >> 32) as i32
}

#[inline]
pub const fn mulhsu64(lhs: i64, rhs: u64) -> i64 {
    ((lhs as i128).wrapping_mul(rhs as i128) >> 64) as i64
}

#[inline]
pub const fn mulhu(lhs: u32, rhs: u32) -> u32 {
    ((lhs as i64).wrapping_mul(rhs as i64) >> 32) as u32
}

#[inline]
pub const fn mulhu64(lhs: u64, rhs: u64) -> u64 {
    ((lhs as i128).wrapping_mul(rhs as i128) >> 64) as u64
}

#[test]
fn test_div_rem() {
    assert_eq!(divu(10, 2), 5);
    assert_eq!(divu(10, 0), u32::MAX);

    assert_eq!(divu64(10, 2), 5);
    assert_eq!(divu64(10, 0), u64::MAX);

    assert_eq!(div(10, 2), 5);
    assert_eq!(div(10, 0), -1);
    assert_eq!(div(i32::MIN, -1), i32::MIN);

    assert_eq!(div64(10, 2), 5);
    assert_eq!(div64(10, 0), -1);
    assert_eq!(div64(i64::MIN, -1), i64::MIN);

    assert_eq!(remu(10, 9), 1);
    assert_eq!(remu(10, 5), 0);
    assert_eq!(remu(10, 0), 10);

    assert_eq!(remu64(10, 9), 1);
    assert_eq!(remu64(10, 5), 0);
    assert_eq!(remu64(10, 0), 10);

    assert_eq!(rem(10, 9), 1);
    assert_eq!(rem(10, 5), 0);
    assert_eq!(rem(10, 0), 10);
    assert_eq!(rem(i32::MIN, -1), 0);

    assert_eq!(rem64(10, 9), 1);
    assert_eq!(rem64(10, 5), 0);
    assert_eq!(rem64(10, 0), 10);
    assert_eq!(rem64(i64::MIN, -1), 0);
}