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 Plus = 1,
15}
16
17pub const MAX_POSITIVE_VALUE: U256 = U256::from_limbs([
19 0xffffffffffffffff,
20 0xffffffffffffffff,
21 0xffffffffffffffff,
22 0x7fffffffffffffff,
23]);
24
25pub 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#[inline]
37pub fn i256_sign(val: &U256) -> Sign {
38 if val.bit(U256::BITS - 1) {
39 Sign::Minus
40 } else {
41 unsafe { core::mem::transmute::<bool, Sign>(!val.is_zero()) }
43 }
44}
45
46#[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 unsafe {
60 val.as_limbs_mut()[3] &= FLIPH_BITMASK_U64;
61 }
62}
63
64#[inline]
66pub const fn two_compl_mut(op: &mut U256) {
67 *op = two_compl(*op);
68}
69
70#[inline]
72pub const fn two_compl(op: U256) -> U256 {
73 op.wrapping_neg()
74}
75
76#[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 Ordering::Equal => first.cmp(second),
85 o => o,
86 }
87}
88
89#[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 let mut d = first / second;
104
105 u256_remove_sign(&mut d);
107
108 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#[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 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 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 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}