Skip to content

Commit 2a29b7a

Browse files
committed
Copy the u256 implementation from compiler_builtins
1 parent 3cc2c03 commit 2a29b7a

File tree

3 files changed

+413
-0
lines changed

3 files changed

+413
-0
lines changed

src/math/support/big.rs

+302
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
//! Integers used for wide operations, larger than `u128`.
2+
3+
#![allow(unused)]
4+
5+
#[cfg(test)]
6+
mod tests;
7+
8+
use core::{fmt, ops};
9+
10+
use super::{DInt, HInt, Int, MinInt};
11+
12+
const WORD_LO_MASK: u64 = 0x00000000ffffffff;
13+
const WORD_HI_MASK: u64 = 0xffffffff00000000;
14+
const WORD_FULL_MASK: u64 = 0xffffffffffffffff;
15+
const U128_LO_MASK: u128 = u64::MAX as u128;
16+
const U128_HI_MASK: u128 = (u64::MAX as u128) << 64;
17+
18+
/// A 256-bit unsigned integer represented as 4 64-bit limbs.
19+
///
20+
/// Each limb is a native-endian number, but the array is little-limb-endian.
21+
#[allow(non_camel_case_types)]
22+
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
23+
pub struct u256(pub [u64; 4]);
24+
25+
impl u256 {
26+
pub const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
27+
28+
/// Reinterpret as a signed integer
29+
pub fn signed(self) -> i256 {
30+
i256(self.0)
31+
}
32+
}
33+
34+
/// A 256-bit signed integer represented as 4 64-bit limbs.
35+
///
36+
/// Each limb is a native-endian number, but the array is little-limb-endian.
37+
#[allow(non_camel_case_types)]
38+
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
39+
pub struct i256(pub [u64; 4]);
40+
41+
impl i256 {
42+
/// Reinterpret as an unsigned integer
43+
pub fn unsigned(self) -> u256 {
44+
u256(self.0)
45+
}
46+
}
47+
48+
impl MinInt for u256 {
49+
type OtherSign = i256;
50+
51+
type Unsigned = u256;
52+
53+
const SIGNED: bool = false;
54+
const BITS: u32 = 256;
55+
const ZERO: Self = Self([0u64; 4]);
56+
const ONE: Self = Self([1, 0, 0, 0]);
57+
const MIN: Self = Self([0u64; 4]);
58+
const MAX: Self = Self([u64::MAX; 4]);
59+
}
60+
61+
impl MinInt for i256 {
62+
type OtherSign = u256;
63+
64+
type Unsigned = u256;
65+
66+
const SIGNED: bool = false;
67+
const BITS: u32 = 256;
68+
const ZERO: Self = Self([0u64; 4]);
69+
const ONE: Self = Self([1, 0, 0, 0]);
70+
const MIN: Self = Self([0, 0, 0, 1 << 63]);
71+
const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX << 1]);
72+
}
73+
74+
macro_rules! impl_common {
75+
($ty:ty) => {
76+
impl ops::BitOr for $ty {
77+
type Output = Self;
78+
79+
fn bitor(mut self, rhs: Self) -> Self::Output {
80+
self.0[0] |= rhs.0[0];
81+
self.0[1] |= rhs.0[1];
82+
self.0[2] |= rhs.0[2];
83+
self.0[3] |= rhs.0[3];
84+
self
85+
}
86+
}
87+
88+
impl ops::Not for $ty {
89+
type Output = Self;
90+
91+
fn not(self) -> Self::Output {
92+
Self([!self.0[0], !self.0[1], !self.0[2], !self.0[3]])
93+
}
94+
}
95+
96+
impl ops::Shl<u32> for $ty {
97+
type Output = Self;
98+
99+
fn shl(self, rhs: u32) -> Self::Output {
100+
unimplemented!("only used to meet trait bounds")
101+
}
102+
}
103+
};
104+
}
105+
106+
impl_common!(i256);
107+
impl_common!(u256);
108+
109+
impl ops::Shr<u32> for u256 {
110+
type Output = Self;
111+
112+
fn shr(self, rhs: u32) -> Self::Output {
113+
assert!(rhs < Self::BITS, "attempted to shift right with overflow");
114+
115+
if rhs == 0 {
116+
return self;
117+
}
118+
119+
let mut ret = self;
120+
let byte_shift = rhs / 64;
121+
let bit_shift = rhs % 64;
122+
123+
for idx in 0..4 {
124+
let base_idx = idx + byte_shift as usize;
125+
126+
// FIXME(msrv): could be let...else.
127+
let base = match ret.0.get(base_idx) {
128+
Some(v) => v,
129+
None => {
130+
ret.0[idx] = 0;
131+
continue;
132+
}
133+
};
134+
135+
let mut new_val = base >> bit_shift;
136+
137+
if let Some(new) = ret.0.get(base_idx + 1) {
138+
new_val |= new.overflowing_shl(64 - bit_shift).0;
139+
}
140+
141+
ret.0[idx] = new_val;
142+
}
143+
144+
ret
145+
}
146+
}
147+
148+
macro_rules! word {
149+
(1, $val:expr) => {
150+
(($val >> (32 * 3)) & Self::from(WORD_LO_MASK)) as u64
151+
};
152+
(2, $val:expr) => {
153+
(($val >> (32 * 2)) & Self::from(WORD_LO_MASK)) as u64
154+
};
155+
(3, $val:expr) => {
156+
(($val >> (32 * 1)) & Self::from(WORD_LO_MASK)) as u64
157+
};
158+
(4, $val:expr) => {
159+
(($val >> (32 * 0)) & Self::from(WORD_LO_MASK)) as u64
160+
};
161+
}
162+
163+
impl HInt for u128 {
164+
type D = u256;
165+
166+
fn widen(self) -> Self::D {
167+
let w0 = self & u128::from(u64::MAX);
168+
let w1 = (self >> u64::BITS) & u128::from(u64::MAX);
169+
u256([w0 as u64, w1 as u64, 0, 0])
170+
}
171+
172+
fn zero_widen(self) -> Self::D {
173+
self.widen()
174+
}
175+
176+
fn zero_widen_mul(self, rhs: Self) -> Self::D {
177+
let product11: u64 = word!(1, self) * word!(1, rhs);
178+
let product12: u64 = word!(1, self) * word!(2, rhs);
179+
let product13: u64 = word!(1, self) * word!(3, rhs);
180+
let product14: u64 = word!(1, self) * word!(4, rhs);
181+
let product21: u64 = word!(2, self) * word!(1, rhs);
182+
let product22: u64 = word!(2, self) * word!(2, rhs);
183+
let product23: u64 = word!(2, self) * word!(3, rhs);
184+
let product24: u64 = word!(2, self) * word!(4, rhs);
185+
let product31: u64 = word!(3, self) * word!(1, rhs);
186+
let product32: u64 = word!(3, self) * word!(2, rhs);
187+
let product33: u64 = word!(3, self) * word!(3, rhs);
188+
let product34: u64 = word!(3, self) * word!(4, rhs);
189+
let product41: u64 = word!(4, self) * word!(1, rhs);
190+
let product42: u64 = word!(4, self) * word!(2, rhs);
191+
let product43: u64 = word!(4, self) * word!(3, rhs);
192+
let product44: u64 = word!(4, self) * word!(4, rhs);
193+
194+
let sum0: u128 = u128::from(product44);
195+
let sum1: u128 = u128::from(product34) + u128::from(product43);
196+
let sum2: u128 = u128::from(product24) + u128::from(product33) + u128::from(product42);
197+
let sum3: u128 = u128::from(product14)
198+
+ u128::from(product23)
199+
+ u128::from(product32)
200+
+ u128::from(product41);
201+
let sum4: u128 = u128::from(product13) + u128::from(product22) + u128::from(product31);
202+
let sum5: u128 = u128::from(product12) + u128::from(product21);
203+
let sum6: u128 = u128::from(product11);
204+
205+
let r0: u128 =
206+
(sum0 & u128::from(WORD_FULL_MASK)) + ((sum1 & u128::from(WORD_LO_MASK)) << 32);
207+
let r1: u128 = (sum0 >> 64)
208+
+ ((sum1 >> 32) & u128::from(WORD_FULL_MASK))
209+
+ (sum2 & u128::from(WORD_FULL_MASK))
210+
+ ((sum3 << 32) & u128::from(WORD_HI_MASK));
211+
212+
let (lo, carry) = r0.overflowing_add(r1 << 64);
213+
let hi = (r1 >> 64)
214+
+ (sum1 >> 96)
215+
+ (sum2 >> 64)
216+
+ (sum3 >> 32)
217+
+ sum4
218+
+ (sum5 << 32)
219+
+ (sum6 << 64)
220+
+ u128::from(carry);
221+
222+
u256([
223+
(lo & U128_LO_MASK) as u64,
224+
((lo >> 64) & U128_LO_MASK) as u64,
225+
(hi & U128_LO_MASK) as u64,
226+
((hi >> 64) & U128_LO_MASK) as u64,
227+
])
228+
}
229+
230+
fn widen_mul(self, rhs: Self) -> Self::D {
231+
self.zero_widen_mul(rhs)
232+
}
233+
234+
fn widen_hi(self) -> Self::D {
235+
self.widen() << <Self as MinInt>::BITS
236+
}
237+
}
238+
239+
impl HInt for i128 {
240+
type D = i256;
241+
242+
fn widen(self) -> Self::D {
243+
let mut ret = self.unsigned().zero_widen().signed();
244+
if self.is_negative() {
245+
ret.0[2] = u64::MAX;
246+
ret.0[3] = u64::MAX;
247+
}
248+
ret
249+
}
250+
251+
fn zero_widen(self) -> Self::D {
252+
self.unsigned().zero_widen().signed()
253+
}
254+
255+
fn zero_widen_mul(self, rhs: Self) -> Self::D {
256+
self.unsigned().zero_widen_mul(rhs.unsigned()).signed()
257+
}
258+
259+
fn widen_mul(self, rhs: Self) -> Self::D {
260+
unimplemented!("signed i128 widening multiply is not used")
261+
}
262+
263+
fn widen_hi(self) -> Self::D {
264+
self.widen() << <Self as MinInt>::BITS
265+
}
266+
}
267+
268+
impl DInt for u256 {
269+
type H = u128;
270+
271+
fn lo(self) -> Self::H {
272+
let mut tmp = [0u8; 16];
273+
tmp[..8].copy_from_slice(&self.0[0].to_le_bytes());
274+
tmp[8..].copy_from_slice(&self.0[1].to_le_bytes());
275+
u128::from_le_bytes(tmp)
276+
}
277+
278+
fn hi(self) -> Self::H {
279+
let mut tmp = [0u8; 16];
280+
tmp[..8].copy_from_slice(&self.0[2].to_le_bytes());
281+
tmp[8..].copy_from_slice(&self.0[3].to_le_bytes());
282+
u128::from_le_bytes(tmp)
283+
}
284+
}
285+
286+
impl DInt for i256 {
287+
type H = i128;
288+
289+
fn lo(self) -> Self::H {
290+
let mut tmp = [0u8; 16];
291+
tmp[..8].copy_from_slice(&self.0[0].to_le_bytes());
292+
tmp[8..].copy_from_slice(&self.0[1].to_le_bytes());
293+
i128::from_le_bytes(tmp)
294+
}
295+
296+
fn hi(self) -> Self::H {
297+
let mut tmp = [0u8; 16];
298+
tmp[..8].copy_from_slice(&self.0[2].to_le_bytes());
299+
tmp[8..].copy_from_slice(&self.0[3].to_le_bytes());
300+
i128::from_le_bytes(tmp)
301+
}
302+
}

0 commit comments

Comments
 (0)