revm_interpreter/instructions/
i256.rs1use core::cmp::Ordering;
2use primitives::U256;
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
5#[repr(i8)]
6pub enum Sign {
7 Minus = -1,
9 Zero = 0,
10 #[allow(dead_code)] 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 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 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 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 let mut d = first / second;
93
94 u256_remove_sign(&mut d);
96
97 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 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 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 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}