revm_interpreter/instructions/
i256.rs

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