Skip to content

Commit 3ff25d9

Browse files
author
Jorge Aparicio
committed
put div intrinsics in their own module + some docs
1 parent a84579d commit 3ff25d9

File tree

3 files changed

+314
-309
lines changed

3 files changed

+314
-309
lines changed

src/div.rs

+278
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
use {Int, LargeInt, U64};
2+
3+
/// Returns `n / d`
4+
#[no_mangle]
5+
pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
6+
let u32_bits = u32::bits() as u32;
7+
8+
// Special cases
9+
if d == 0 {
10+
return 0; // ?!
11+
}
12+
13+
if n == 0 {
14+
return 0;
15+
}
16+
17+
let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros());
18+
19+
// d > n
20+
if sr > u32_bits - 1 {
21+
return 0;
22+
}
23+
24+
// d == 1
25+
if sr == u32_bits - 1 {
26+
return n;
27+
}
28+
29+
sr = sr + 1;
30+
31+
// 1 <= sr <= u32_bits - 1
32+
let mut q = n << (u32_bits - sr);
33+
let mut r = n >> sr;
34+
35+
let mut carry = 0;
36+
for _ in 0..sr {
37+
// r:q = ((r:q) << 1) | carry
38+
r = (r << 1) | (q >> (u32_bits - 1));
39+
q = (q << 1) | carry;
40+
41+
// carry = 0;
42+
// if r > d {
43+
// r -= d;
44+
// carry = 1;
45+
// }
46+
47+
let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32_bits - 1);
48+
carry = (s & 1) as u32;
49+
r -= d & s as u32;
50+
}
51+
52+
q = (q << 1) | carry;
53+
q
54+
}
55+
56+
/// Returns `n / d` and sets `*rem = n % d`
57+
#[no_mangle]
58+
pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 {
59+
let d = __udivsi3(a, b);
60+
if let Some(rem) = rem {
61+
*rem = a - (d * b);
62+
}
63+
return d;
64+
}
65+
66+
/// Returns `n / d` and sets `*rem = n % d`
67+
#[no_mangle]
68+
pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
69+
let u32_bits = u32::bits() as u32;
70+
let u64_bits = u64::bits() as u32;
71+
72+
// NOTE X is unknown, K != 0
73+
if n.high() == 0 {
74+
if d.high() == 0 {
75+
// 0 X
76+
// ---
77+
// 0 X
78+
79+
if let Some(rem) = rem {
80+
*rem = u64::from(n.low() % d.low());
81+
}
82+
return u64::from(n.low() / d.low());
83+
} else
84+
// d.high() != 0
85+
{
86+
// 0 X
87+
// ---
88+
// K X
89+
90+
if let Some(rem) = rem {
91+
*rem = u64::from(n.low());
92+
}
93+
return 0;
94+
};
95+
}
96+
97+
let mut sr;
98+
let mut q = U64 { low: 0, high: 0 };
99+
let mut r = U64 { low: 0, high: 0 };
100+
101+
// n.high() != 0
102+
if d.low() == 0 {
103+
if d.high() == 0 {
104+
// K X
105+
// ---
106+
// 0 0
107+
108+
// NOTE copied verbatim from compiler-rt. This probably lets the intrinsic decide how to
109+
// handle the division by zero (SIGFPE, 0, etc.). But this part shouldn't be reachable
110+
// from safe code.
111+
if let Some(rem) = rem {
112+
*rem = u64::from(n.high() % d.low());
113+
}
114+
return u64::from(n.high() / d.low());
115+
}
116+
117+
// d.high() != 0
118+
if n.low() == 0 {
119+
// K 0
120+
// ---
121+
// K 0
122+
123+
if let Some(rem) = rem {
124+
*rem = U64 {
125+
low: 0,
126+
high: n.high() % d.high(),
127+
}[..];
128+
}
129+
return u64::from(n.high() / d.high());
130+
}
131+
132+
// n.low() != 0
133+
// K K
134+
// ---
135+
// K 0
136+
137+
if d.high().is_power_of_two() {
138+
if let Some(rem) = rem {
139+
*rem = U64 {
140+
low: n.low(),
141+
high: n.high() & (d.high() - 1),
142+
}[..];
143+
}
144+
145+
return u64::from(n.high() >> d.high().trailing_zeros());
146+
}
147+
148+
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
149+
150+
// D > N
151+
if sr > u32_bits - 2 {
152+
if let Some(rem) = rem {
153+
*rem = n;
154+
}
155+
return 0;
156+
}
157+
158+
sr = sr + 1;
159+
160+
// 1 <= sr <= u32_bits - 1
161+
// q = n << (u64_bits - sr);
162+
q.low = 0;
163+
q.high = n.low() << (u32_bits - sr);
164+
// r = n >> sr
165+
r.high = n.high() >> sr;
166+
r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr);
167+
} else
168+
// d.low() != 0
169+
{
170+
if d.high() == 0 {
171+
// K X
172+
// ---
173+
// 0 K
174+
if d.low().is_power_of_two() {
175+
if let Some(rem) = rem {
176+
*rem = u64::from(n.low() & (d.low() - 1));
177+
}
178+
179+
if d.low() == 1 {
180+
return n;
181+
} else {
182+
let sr = d.low().trailing_zeros();
183+
return U64 {
184+
low: (n.high() << (u32_bits - sr)) | (n.low() >> sr),
185+
high: n.high() >> sr,
186+
}[..];
187+
};
188+
}
189+
190+
sr = 1 + u32_bits + d.low().leading_zeros() - n.high().leading_zeros();
191+
192+
// 2 <= sr <= u64_bits - 1
193+
// q = n << (u64_bits - sr)
194+
// r = n >> sr;
195+
if sr == u32_bits {
196+
q.low = 0;
197+
q.high = n.low();
198+
r.high = 0;
199+
r.low = n.high();
200+
} else if sr < u32_bits
201+
// 2 <= sr <= u32_bits - 1
202+
{
203+
q.low = 0;
204+
q.high = n.low() << (u32_bits - sr);
205+
r.high = n.high() >> sr;
206+
r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr);
207+
} else
208+
// u32_bits + 1 <= sr <= u64_bits - 1
209+
{
210+
q.low = n.low() << (u64_bits - sr);
211+
q.high = (n.high() << (u64_bits - sr)) | (n.low() >> (sr - u32_bits));
212+
r.high = 0;
213+
r.low = n.high() >> (sr - u32_bits);
214+
}
215+
216+
} else
217+
// d.high() != 0
218+
{
219+
// K X
220+
// ---
221+
// K K
222+
223+
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
224+
225+
// D > N
226+
if sr > u32_bits - 1 {
227+
if let Some(rem) = rem {
228+
*rem = n;
229+
return 0;
230+
}
231+
}
232+
233+
sr += 1;
234+
235+
// 1 <= sr <= u32_bits
236+
// q = n << (u64_bits - sr)
237+
q.low = 0;
238+
if sr == u32_bits {
239+
q.high = n.low();
240+
r.high = 0;
241+
r.low = n.high();
242+
} else {
243+
q.high = n.low() << (u32_bits - sr);
244+
r.high = n.high() >> sr;
245+
r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr);
246+
}
247+
}
248+
}
249+
250+
// Not a special case
251+
// q and r are initialized with
252+
// q = n << (u64_bits - sr)
253+
// r = n >> sr
254+
// 1 <= sr <= u64_bits - 1
255+
let mut carry = 0;
256+
257+
for _ in 0..sr {
258+
// r:q = ((r:q) << 1) | carry
259+
r[..] = (r[..] << 1) | (q[..] >> 63);
260+
q[..] = (q[..] << 1) | carry as u64;
261+
262+
// carry = 0
263+
// if r >= d {
264+
// r -= d;
265+
// carry = 1;
266+
// }
267+
268+
let s = (d.wrapping_sub(r[..]).wrapping_sub(1)) as i64 >> (u64_bits - 1);
269+
carry = (s & 1) as u32;
270+
r[..] -= d & s as u64;
271+
}
272+
273+
q[..] = (q[..] << 1) | carry as u64;
274+
if let Some(rem) = rem {
275+
*rem = r[..];
276+
}
277+
q[..]
278+
}

0 commit comments

Comments
 (0)