revm_interpreter/instructions/
i256.rs1use core::cmp::Ordering;
2use primitives::U256;
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
6#[repr(i8)]
7pub enum Sign {
8 Minus = -1,
11 Zero = 0,
13 #[allow(dead_code)] Plus = 1,
16}
17
18pub const MAX_POSITIVE_VALUE: U256 = U256::from_limbs([
20 0xffffffffffffffff,
21 0xffffffffffffffff,
22 0xffffffffffffffff,
23 0x7fffffffffffffff,
24]);
25
26pub 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#[inline]
38pub fn i256_sign(val: &U256) -> Sign {
39 if val.bit(U256::BITS - 1) {
40 Sign::Minus
41 } else {
42 unsafe { core::mem::transmute::<bool, Sign>(!val.is_zero()) }
44 }
45}
46
47#[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 unsafe {
61 val.as_limbs_mut()[3] &= FLIPH_BITMASK_U64;
62 }
63}
64
65#[inline]
67pub fn two_compl_mut(op: &mut U256) {
68 *op = two_compl(*op);
69}
70
71#[inline]
73pub fn two_compl(op: U256) -> U256 {
74 op.wrapping_neg()
75}
76
77#[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 Ordering::Equal => first.cmp(second),
86 o => o,
87 }
88}
89
90#[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 let mut d = first / second;
105
106 u256_remove_sign(&mut d);
108
109 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#[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 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 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 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}