Skip to content

Commit 4ab4465

Browse files
author
Jorge Aparicio
authored
Merge pull request #25 from japaric/udivmoddi4
port udivmoddi4 and __aeabi_uldivmod
2 parents c4142ed + eb20684 commit 4ab4465

File tree

6 files changed

+392
-8
lines changed

6 files changed

+392
-8
lines changed

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@
22
authors = ["Jorge Aparicio <[email protected]>"]
33
name = "rustc_builtins"
44
version = "0.1.0"
5+
6+
[dev-dependencies]
7+
quickcheck = "0.3.1"

ci/install.sh

+4-4
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,19 @@ install_c_toolchain() {
4949
;;
5050
mips-unknown-linux-gnu)
5151
apt-get install -y --no-install-recommends \
52-
gcc-mips-linux-gnu libc6-dev-mips-cross
52+
gcc gcc-mips-linux-gnu libc6-dev libc6-dev-mips-cross
5353
;;
5454
mipsel-unknown-linux-gnu)
5555
apt-get install -y --no-install-recommends \
56-
gcc-mipsel-linux-gnu libc6-dev-mipsel-cross
56+
gcc gcc-mipsel-linux-gnu libc6-dev libc6-dev-mipsel-cross
5757
;;
5858
powerpc64-unknown-linux-gnu)
5959
apt-get install -y --no-install-recommends \
60-
gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross
60+
gcc gcc-powerpc64-linux-gnu libc6-dev libc6-dev-ppc64-cross
6161
;;
6262
powerpc64le-unknown-linux-gnu)
6363
apt-get install -y --no-install-recommends \
64-
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross
64+
gcc gcc-powerpc64le-linux-gnu libc6-dev libc6-dev-ppc64el-cross
6565
;;
6666
esac
6767
}

src/arm.rs

+34
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,37 @@
1+
use core::intrinsics;
2+
3+
// NOTE This function and the one below are implemented using assembly because they using a custom
4+
// calling convention which can't be implemented using a normal Rust function
5+
// TODO use `global_asm!`
6+
#[naked]
7+
#[no_mangle]
8+
pub unsafe extern "aapcs" fn __aeabi_uidivmod() {
9+
asm!("push { lr }
10+
sub sp, sp, #4
11+
mov r2, sp
12+
bl __udivmodsi4
13+
ldr r1, [sp]
14+
add sp, sp, #4
15+
pop { pc }");
16+
intrinsics::unreachable();
17+
}
18+
19+
// TODO use `global_asm!`
20+
#[naked]
21+
#[no_mangle]
22+
pub unsafe extern "aapcs" fn __aeabi_uldivmod() {
23+
asm!("push {r11, lr}
24+
sub sp, sp, #16
25+
add r12, sp, #8
26+
str r12, [sp]
27+
bl __udivmoddi4
28+
ldr r2, [sp, #8]
29+
ldr r3, [sp, #12]
30+
add sp, sp, #16
31+
pop {r11, pc}");
32+
intrinsics::unreachable();
33+
}
34+
135
extern "C" {
236
fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
337
fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;

src/div.rs

+271
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
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+
panic!("Division by zero");
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 << 1) | carry
53+
}
54+
55+
/// Returns `n / d` and sets `*rem = n % d`
56+
#[no_mangle]
57+
pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 {
58+
let d = __udivsi3(a, b);
59+
if let Some(rem) = rem {
60+
*rem = a - (d * b);
61+
}
62+
return d;
63+
}
64+
65+
/// Returns `n / d` and sets `*rem = n % d`
66+
#[no_mangle]
67+
pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
68+
let u32_bits = u32::bits() as u32;
69+
let u64_bits = u64::bits() as u32;
70+
71+
// NOTE X is unknown, K != 0
72+
if n.high() == 0 {
73+
if d.high() == 0 {
74+
// 0 X
75+
// ---
76+
// 0 X
77+
78+
if let Some(rem) = rem {
79+
*rem = u64::from(n.low() % d.low());
80+
}
81+
return u64::from(n.low() / d.low());
82+
} else
83+
// d.high() != 0
84+
{
85+
// 0 X
86+
// ---
87+
// K X
88+
89+
if let Some(rem) = rem {
90+
*rem = u64::from(n.low());
91+
}
92+
return 0;
93+
};
94+
}
95+
96+
let mut sr;
97+
let mut q = U64 { low: 0, high: 0 };
98+
let mut r = U64 { low: 0, high: 0 };
99+
100+
// n.high() != 0
101+
if d.low() == 0 {
102+
if d.high() == 0 {
103+
// K X
104+
// ---
105+
// 0 0
106+
107+
panic!("Division by zero");
108+
}
109+
110+
// d.high() != 0
111+
if n.low() == 0 {
112+
// K 0
113+
// ---
114+
// K 0
115+
116+
if let Some(rem) = rem {
117+
*rem = U64 {
118+
low: 0,
119+
high: n.high() % d.high(),
120+
}[..];
121+
}
122+
return u64::from(n.high() / d.high());
123+
}
124+
125+
// n.low() != 0
126+
// K K
127+
// ---
128+
// K 0
129+
130+
if d.high().is_power_of_two() {
131+
if let Some(rem) = rem {
132+
*rem = U64 {
133+
low: n.low(),
134+
high: n.high() & (d.high() - 1),
135+
}[..];
136+
}
137+
138+
return u64::from(n.high() >> d.high().trailing_zeros());
139+
}
140+
141+
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
142+
143+
// D > N
144+
if sr > u32_bits - 2 {
145+
if let Some(rem) = rem {
146+
*rem = n;
147+
}
148+
return 0;
149+
}
150+
151+
sr = sr + 1;
152+
153+
// 1 <= sr <= u32_bits - 1
154+
// q = n << (u64_bits - sr);
155+
q.low = 0;
156+
q.high = n.low() << (u32_bits - sr);
157+
// r = n >> sr
158+
r.high = n.high() >> sr;
159+
r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr);
160+
} else
161+
// d.low() != 0
162+
{
163+
if d.high() == 0 {
164+
// K X
165+
// ---
166+
// 0 K
167+
if d.low().is_power_of_two() {
168+
if let Some(rem) = rem {
169+
*rem = u64::from(n.low() & (d.low() - 1));
170+
}
171+
172+
if d.low() == 1 {
173+
return n;
174+
} else {
175+
let sr = d.low().trailing_zeros();
176+
return U64 {
177+
low: (n.high() << (u32_bits - sr)) | (n.low() >> sr),
178+
high: n.high() >> sr,
179+
}[..];
180+
};
181+
}
182+
183+
sr = 1 + u32_bits + d.low().leading_zeros() - n.high().leading_zeros();
184+
185+
// 2 <= sr <= u64_bits - 1
186+
// q = n << (u64_bits - sr)
187+
// r = n >> sr;
188+
if sr == u32_bits {
189+
q.low = 0;
190+
q.high = n.low();
191+
r.high = 0;
192+
r.low = n.high();
193+
} else if sr < u32_bits
194+
// 2 <= sr <= u32_bits - 1
195+
{
196+
q.low = 0;
197+
q.high = n.low() << (u32_bits - sr);
198+
r.high = n.high() >> sr;
199+
r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr);
200+
} else
201+
// u32_bits + 1 <= sr <= u64_bits - 1
202+
{
203+
q.low = n.low() << (u64_bits - sr);
204+
q.high = (n.high() << (u64_bits - sr)) | (n.low() >> (sr - u32_bits));
205+
r.high = 0;
206+
r.low = n.high() >> (sr - u32_bits);
207+
}
208+
209+
} else
210+
// d.high() != 0
211+
{
212+
// K X
213+
// ---
214+
// K K
215+
216+
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
217+
218+
// D > N
219+
if sr > u32_bits - 1 {
220+
if let Some(rem) = rem {
221+
*rem = n;
222+
return 0;
223+
}
224+
}
225+
226+
sr += 1;
227+
228+
// 1 <= sr <= u32_bits
229+
// q = n << (u64_bits - sr)
230+
q.low = 0;
231+
if sr == u32_bits {
232+
q.high = n.low();
233+
r.high = 0;
234+
r.low = n.high();
235+
} else {
236+
q.high = n.low() << (u32_bits - sr);
237+
r.high = n.high() >> sr;
238+
r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr);
239+
}
240+
}
241+
}
242+
243+
// Not a special case
244+
// q and r are initialized with
245+
// q = n << (u64_bits - sr)
246+
// r = n >> sr
247+
// 1 <= sr <= u64_bits - 1
248+
let mut carry = 0;
249+
250+
for _ in 0..sr {
251+
// r:q = ((r:q) << 1) | carry
252+
r[..] = (r[..] << 1) | (q[..] >> 63);
253+
q[..] = (q[..] << 1) | carry as u64;
254+
255+
// carry = 0
256+
// if r >= d {
257+
// r -= d;
258+
// carry = 1;
259+
// }
260+
261+
let s = (d.wrapping_sub(r[..]).wrapping_sub(1)) as i64 >> (u64_bits - 1);
262+
carry = (s & 1) as u32;
263+
r[..] -= d & s as u64;
264+
}
265+
266+
q[..] = (q[..] << 1) | carry as u64;
267+
if let Some(rem) = rem {
268+
*rem = r[..];
269+
}
270+
q[..]
271+
}

0 commit comments

Comments
 (0)