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