Skip to main content

revm_interpreter/instructions/
i256.rs

1use core::cmp::Ordering;
2use primitives::U256;
3
4/// Represents the sign of a 256-bit signed integer value.
5#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
6#[repr(i8)]
7pub enum Sign {
8    // Same as `cmp::Ordering`
9    /// Negative value sign
10    Minus = -1,
11    /// Zero value sign  
12    Zero = 0,
13    /// Positive value sign
14    Plus = 1,
15}
16
17/// The maximum positive value for a 256-bit signed integer.
18pub const MAX_POSITIVE_VALUE: U256 = U256::from_limbs([
19    0xffffffffffffffff,
20    0xffffffffffffffff,
21    0xffffffffffffffff,
22    0x7fffffffffffffff,
23]);
24
25/// The minimum negative value for a 256-bit signed integer.
26pub const MIN_NEGATIVE_VALUE: U256 = U256::from_limbs([
27    0x0000000000000000,
28    0x0000000000000000,
29    0x0000000000000000,
30    0x8000000000000000,
31]);
32
33const FLIPH_BITMASK_U64: u64 = 0x7FFF_FFFF_FFFF_FFFF;
34
35/// Determines the sign of a 256-bit signed integer.
36#[inline]
37pub fn i256_sign(val: &U256) -> Sign {
38    if val.bit(U256::BITS - 1) {
39        Sign::Minus
40    } else {
41        // SAFETY: false == 0 == Zero, true == 1 == Plus
42        unsafe { core::mem::transmute::<bool, Sign>(!val.is_zero()) }
43    }
44}
45
46/// Determines the sign of a 256-bit signed integer and converts it to its absolute value.
47#[inline]
48pub fn i256_sign_compl(val: &mut U256) -> Sign {
49    let sign = i256_sign(val);
50    if sign == Sign::Minus {
51        two_compl_mut(val);
52    }
53    sign
54}
55
56#[inline]
57const fn u256_remove_sign(val: &mut U256) {
58    // SAFETY: U256 does not have any padding bytes
59    unsafe {
60        val.as_limbs_mut()[3] &= FLIPH_BITMASK_U64;
61    }
62}
63
64/// Computes the two's complement of a U256 value in place.
65#[inline]
66pub const fn two_compl_mut(op: &mut U256) {
67    *op = two_compl(*op);
68}
69
70/// Computes the two's complement of a U256 value.
71#[inline]
72pub const fn two_compl(op: U256) -> U256 {
73    op.wrapping_neg()
74}
75
76/// Compares two 256-bit signed integers.
77#[inline]
78pub fn i256_cmp(first: &U256, second: &U256) -> Ordering {
79    let first_sign = i256_sign(first);
80    let second_sign = i256_sign(second);
81    match first_sign.cmp(&second_sign) {
82        // Note: Adding `if first_sign != Sign::Zero` to short circuit zero comparisons performs
83        // slower on average, as of #582
84        Ordering::Equal => first.cmp(second),
85        o => o,
86    }
87}
88
89/// Performs signed division of two 256-bit integers.
90#[inline]
91pub fn i256_div(mut first: U256, mut second: U256) -> U256 {
92    let second_sign = i256_sign_compl(&mut second);
93    if second_sign == Sign::Zero {
94        return U256::ZERO;
95    }
96
97    let first_sign = i256_sign_compl(&mut first);
98    if first == MIN_NEGATIVE_VALUE && second == U256::from(1) {
99        return two_compl(MIN_NEGATIVE_VALUE);
100    }
101
102    // Necessary overflow checks are done above, perform the division
103    let mut d = first / second;
104
105    // Set sign bit to zero
106    u256_remove_sign(&mut d);
107
108    // Two's complement only if the signs are different
109    // Note: This condition has better codegen than an exhaustive match, as of #582
110    if (first_sign == Sign::Minus && second_sign != Sign::Minus)
111        || (second_sign == Sign::Minus && first_sign != Sign::Minus)
112    {
113        two_compl(d)
114    } else {
115        d
116    }
117}
118
119/// Performs signed modulo of two 256-bit integers.
120#[inline]
121pub fn i256_mod(mut first: U256, mut second: U256) -> U256 {
122    let first_sign = i256_sign_compl(&mut first);
123    if first_sign == Sign::Zero {
124        return U256::ZERO;
125    }
126
127    let second_sign = i256_sign_compl(&mut second);
128    if second_sign == Sign::Zero {
129        return U256::ZERO;
130    }
131
132    let mut r = first % second;
133
134    // Set sign bit to zero
135    u256_remove_sign(&mut r);
136
137    if first_sign == Sign::Minus {
138        two_compl(r)
139    } else {
140        r
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147    use core::num::Wrapping;
148    use primitives::uint;
149
150    #[test]
151    fn div_i256() {
152        // Sanity checks based on i8. Notice that we need to use `Wrapping` here because
153        // Rust will prevent the overflow by default whereas the EVM does not.
154        assert_eq!(Wrapping(i8::MIN) / Wrapping(-1), Wrapping(i8::MIN));
155        assert_eq!(i8::MAX / -1, -i8::MAX);
156
157        uint! {
158            assert_eq!(i256_div(MIN_NEGATIVE_VALUE, -1_U256), MIN_NEGATIVE_VALUE);
159            assert_eq!(i256_div(MIN_NEGATIVE_VALUE, 1_U256), MIN_NEGATIVE_VALUE);
160            assert_eq!(i256_div(MAX_POSITIVE_VALUE, 1_U256), MAX_POSITIVE_VALUE);
161            assert_eq!(i256_div(MAX_POSITIVE_VALUE, -1_U256), -1_U256 * MAX_POSITIVE_VALUE);
162            assert_eq!(i256_div(100_U256, -1_U256), -100_U256);
163            assert_eq!(i256_div(100_U256, 2_U256), 50_U256);
164        }
165    }
166    #[test]
167    fn test_i256_sign() {
168        uint! {
169            assert_eq!(i256_sign(&0_U256), Sign::Zero);
170            assert_eq!(i256_sign(&1_U256), Sign::Plus);
171            assert_eq!(i256_sign(&-1_U256), Sign::Minus);
172            assert_eq!(i256_sign(&MIN_NEGATIVE_VALUE), Sign::Minus);
173            assert_eq!(i256_sign(&MAX_POSITIVE_VALUE), Sign::Plus);
174        }
175    }
176
177    #[test]
178    fn test_i256_sign_compl() {
179        uint! {
180            let mut zero = 0_U256;
181            let mut positive = 1_U256;
182            let mut negative = -1_U256;
183            assert_eq!(i256_sign_compl(&mut zero), Sign::Zero);
184            assert_eq!(i256_sign_compl(&mut positive), Sign::Plus);
185            assert_eq!(i256_sign_compl(&mut negative), Sign::Minus);
186        }
187    }
188
189    #[test]
190    fn test_two_compl() {
191        uint! {
192            assert_eq!(two_compl(0_U256), 0_U256);
193            assert_eq!(two_compl(1_U256), -1_U256);
194            assert_eq!(two_compl(-1_U256), 1_U256);
195            assert_eq!(two_compl(2_U256), -2_U256);
196            assert_eq!(two_compl(-2_U256), 2_U256);
197
198            // Two's complement of the min value is itself.
199            assert_eq!(two_compl(MIN_NEGATIVE_VALUE), MIN_NEGATIVE_VALUE);
200        }
201    }
202
203    #[test]
204    fn test_two_compl_mut() {
205        uint! {
206            let mut value = 1_U256;
207            two_compl_mut(&mut value);
208            assert_eq!(value, -1_U256);
209        }
210    }
211
212    #[test]
213    fn test_i256_cmp() {
214        uint! {
215            assert_eq!(i256_cmp(&1_U256, &2_U256), Ordering::Less);
216            assert_eq!(i256_cmp(&2_U256, &2_U256), Ordering::Equal);
217            assert_eq!(i256_cmp(&3_U256, &2_U256), Ordering::Greater);
218            assert_eq!(i256_cmp(&-1_U256, &-1_U256), Ordering::Equal);
219            assert_eq!(i256_cmp(&-1_U256, &-2_U256), Ordering::Greater);
220            assert_eq!(i256_cmp(&-1_U256, &0_U256), Ordering::Less);
221            assert_eq!(i256_cmp(&-2_U256, &2_U256), Ordering::Less);
222        }
223    }
224
225    #[test]
226    fn test_i256_div() {
227        uint! {
228            assert_eq!(i256_div(1_U256, 0_U256), 0_U256);
229            assert_eq!(i256_div(0_U256, 1_U256), 0_U256);
230            assert_eq!(i256_div(0_U256, -1_U256), 0_U256);
231            assert_eq!(i256_div(MIN_NEGATIVE_VALUE, 1_U256), MIN_NEGATIVE_VALUE);
232            assert_eq!(i256_div(4_U256, 2_U256), 2_U256);
233            assert_eq!(i256_div(MIN_NEGATIVE_VALUE, MIN_NEGATIVE_VALUE), 1_U256);
234            assert_eq!(i256_div(2_U256, -1_U256), -2_U256);
235            assert_eq!(i256_div(-2_U256, -1_U256), 2_U256);
236        }
237    }
238
239    #[test]
240    fn test_i256_mod() {
241        uint! {
242            assert_eq!(i256_mod(0_U256, 1_U256), 0_U256);
243            assert_eq!(i256_mod(1_U256, 0_U256), 0_U256);
244            assert_eq!(i256_mod(4_U256, 2_U256), 0_U256);
245            assert_eq!(i256_mod(3_U256, 2_U256), 1_U256);
246            assert_eq!(i256_mod(MIN_NEGATIVE_VALUE, 1_U256), 0_U256);
247            assert_eq!(i256_mod(2_U256, 2_U256), 0_U256);
248            assert_eq!(i256_mod(2_U256, 3_U256), 2_U256);
249            assert_eq!(i256_mod(-2_U256, 3_U256), -2_U256);
250            assert_eq!(i256_mod(2_U256, -3_U256), 2_U256);
251            assert_eq!(i256_mod(-2_U256, -3_U256), -2_U256);
252        }
253    }
254}