Skip to content

Commit 1d7bbe8

Browse files
author
Jorge Aparicio
committed
port udivmoddi4 and __aeabi_uldivmod
1 parent 1c9c2b4 commit 1d7bbe8

File tree

4 files changed

+299
-3
lines changed

4 files changed

+299
-3
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"

src/arm.rs

+17
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
use core::mem;
2+
3+
#[repr(C)]
4+
pub struct u64x2 {
5+
a: u64,
6+
b: u64,
7+
}
8+
9+
#[no_mangle]
10+
pub unsafe extern "aapcs" fn __aeabi_uldivmod(num: u64, den: u64) -> u64x2 {
11+
12+
let mut rem = mem::uninitialized();
13+
let quot = ::__udivmoddi4(num, den, &mut rem);
14+
15+
u64x2 { a: quot, b: rem }
16+
}
17+
118
extern "C" {
219
fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
320
fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;

src/lib.rs

+259-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
#[cfg(test)]
1010
extern crate core;
11+
#[cfg(test)]
12+
#[macro_use]
13+
extern crate quickcheck;
1114

1215
use core::mem;
1316

@@ -17,13 +20,13 @@ pub mod arm;
1720
#[cfg(test)]
1821
mod test;
1922

20-
const CHAR_BITS: usize = 8;
23+
const U8_BITS: usize = 8;
2124

2225
macro_rules! absv_i2 {
2326
($intrinsic:ident : $ty:ty) => {
2427
#[no_mangle]
2528
pub extern "C" fn $intrinsic(x: $ty) -> $ty {
26-
let n = mem::size_of::<$ty>() * CHAR_BITS;
29+
let n = mem::size_of::<$ty>() * U8_BITS;
2730
if x == 1 << (n - 1) {
2831
panic!();
2932
}
@@ -38,3 +41,257 @@ absv_i2!(__absvsi2: i32);
3841
absv_i2!(__absvdi2: i64);
3942
// TODO(rust-lang/35118)?
4043
// absv_i2!(__absvti2, i128);
44+
45+
#[no_mangle]
46+
pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 {
47+
#[cfg(target_endian = "little")]
48+
#[repr(C)]
49+
#[derive(Debug)]
50+
struct words {
51+
low: u32,
52+
high: u32,
53+
}
54+
55+
#[cfg(target_endian = "big")]
56+
#[repr(C)]
57+
#[derive(Debug)]
58+
struct words {
59+
high: u32,
60+
low: u32,
61+
}
62+
63+
impl words {
64+
fn all(&mut self) -> &mut u64 {
65+
unsafe { mem::transmute(self) }
66+
}
67+
68+
fn u64(&self) -> u64 {
69+
unsafe { *(self as *const _ as *const u64) }
70+
}
71+
}
72+
73+
impl From<u64> for words {
74+
fn from(x: u64) -> words {
75+
unsafe { mem::transmute(x) }
76+
}
77+
}
78+
79+
let u32_bits = (mem::size_of::<u32>() * U8_BITS) as u32;
80+
let u64_bits = (mem::size_of::<u64>() * U8_BITS) as u32;
81+
82+
let n = words::from(a);
83+
let d = words::from(b);
84+
85+
// NOTE X is unknown, K != 0
86+
if n.high == 0 {
87+
return if d.high == 0 {
88+
// 0 X
89+
// ---
90+
// 0 X
91+
92+
if let Some(rem) = unsafe { rem.as_mut() } {
93+
*rem = u64::from(n.low % d.low);
94+
}
95+
u64::from(n.low / d.low)
96+
} else
97+
// d.high != 0
98+
{
99+
// 0 X
100+
// ---
101+
// K X
102+
103+
if let Some(rem) = unsafe { rem.as_mut() } {
104+
*rem = u64::from(n.low);
105+
}
106+
0
107+
};
108+
}
109+
110+
let mut sr;
111+
// NOTE IMO it should be possible to leave these "uninitialized" (just declare them here)
112+
// because these variables get initialized below, but if I do that the compiler complains about
113+
// them being used before being initialized.
114+
let mut q = words { low: 0, high: 0 };
115+
let mut r = words { low: 0, high: 0 };
116+
117+
// n.high != 0
118+
if d.low == 0 {
119+
if d.high == 0 {
120+
// K X
121+
// ---
122+
// 0 0
123+
124+
// NOTE copied verbatim from compiler-rt, but does division by zero even make sense?
125+
if let Some(rem) = unsafe { rem.as_mut() } {
126+
*rem = u64::from(n.high % d.low);
127+
}
128+
return u64::from(n.high / d.low);
129+
}
130+
131+
// d.high != 0
132+
if n.low == 0 {
133+
// K 0
134+
// ---
135+
// K 0
136+
137+
if let Some(rem) = unsafe { rem.as_mut() } {
138+
*rem = words {
139+
low: 0,
140+
high: n.high % d.high,
141+
}
142+
.u64();
143+
}
144+
return u64::from(n.high / d.high);
145+
}
146+
147+
// n.low != 0
148+
// K K
149+
// ---
150+
// K 0
151+
152+
if d.high.is_power_of_two() {
153+
if let Some(rem) = unsafe { rem.as_mut() } {
154+
*rem = words {
155+
low: n.low,
156+
high: n.high & (d.high - 1),
157+
}
158+
.u64()
159+
}
160+
161+
return u64::from(n.high >> d.high.trailing_zeros());
162+
}
163+
164+
sr = d.high.leading_zeros().wrapping_sub(n.high.leading_zeros());
165+
166+
// D > N
167+
if sr > u32_bits - 2 {
168+
if let Some(rem) = unsafe { rem.as_mut() } {
169+
*rem = n.u64();
170+
}
171+
return 0;
172+
}
173+
174+
sr = sr + 1;
175+
176+
// 1 <= sr <= u32_bits - 1
177+
// *q.all() = n.u64() << (u64_bits - sr);
178+
q.low = 0;
179+
q.high = n.low << (u32_bits - sr);
180+
// *r.all() = n.u64() >> sr
181+
r.high = n.high >> sr;
182+
r.low = (n.high << (u32_bits - sr)) | (n.low >> sr);
183+
} else
184+
// d.low != 0
185+
{
186+
if d.high == 0 {
187+
// K X
188+
// ---
189+
// 0 K
190+
if d.low.is_power_of_two() {
191+
if let Some(rem) = unsafe { rem.as_mut() } {
192+
*rem = u64::from(n.low & (d.low - 1));
193+
}
194+
195+
return if d.low == 1 {
196+
n.u64()
197+
} else {
198+
let sr = d.low.trailing_zeros();
199+
words {
200+
low: (n.high << (u32_bits - sr)) | (n.low >> sr),
201+
high: n.high >> sr,
202+
}
203+
.u64()
204+
};
205+
}
206+
207+
sr = 1 + u32_bits + d.low.leading_zeros() - n.high.leading_zeros();
208+
209+
// 2 <= sr <= u64_bits - 1
210+
// *q.all() = n.u64() << (u64_bits - sr)
211+
// *r.all() = n.u64() >> sr;
212+
if sr == u32_bits {
213+
q.low = 0;
214+
q.high = n.low;
215+
r.high = 0;
216+
r.low = n.high;
217+
} else if sr < u32_bits
218+
// 2 <= sr <= u32_bits - 1
219+
{
220+
q.low = 0;
221+
q.high = n.low << (u32_bits - sr);
222+
r.high = n.high >> sr;
223+
r.low = (n.high << (u32_bits - sr)) | (n.low >> sr);
224+
} else
225+
// u32_bits + 1 <= sr <= u64_bits - 1
226+
{
227+
q.low = n.low << (u64_bits - sr);
228+
q.high = (n.high << (u64_bits - sr)) | (n.low >> (sr - u32_bits));
229+
r.high = 0;
230+
r.low = n.high >> (sr - u32_bits);
231+
}
232+
233+
} else
234+
// d.high != 0
235+
{
236+
// K X
237+
// ---
238+
// K K
239+
240+
sr = d.high.leading_zeros().wrapping_sub(n.high.leading_zeros());
241+
242+
// D > N
243+
if sr > u32_bits - 1 {
244+
if let Some(rem) = unsafe { rem.as_mut() } {
245+
*rem = a;
246+
return 0;
247+
}
248+
}
249+
250+
sr += 1;
251+
252+
// 1 <= sr <= u32_bits
253+
// *q.all() = n.u64() << (u64_bits - sr)
254+
q.low = 0;
255+
if sr == u32_bits {
256+
q.high = n.low;
257+
r.high = 0;
258+
r.low = n.high;
259+
} else {
260+
q.high = n.low << (u32_bits - sr);
261+
r.high = n.high >> sr;
262+
r.low = (n.high << (u32_bits - sr)) | (n.low >> sr);
263+
}
264+
}
265+
}
266+
267+
// Not a special case
268+
// q and r are initialized with
269+
// *q.all() = n.u64() << (u64_bits - sr)
270+
// *.r.all() = n.u64() >> sr
271+
// 1 <= sr <= u64_bits - 1
272+
let mut carry = 0;
273+
274+
for _ in 0..sr {
275+
// r:q = ((r:q) << 1) | carry
276+
r.high = (r.high << 1) | (r.low >> (u32_bits - 1));
277+
r.low = (r.low << 1) | (q.high >> (u32_bits - 1));
278+
q.high = (q.high << 1) | (q.low >> (u32_bits - 1));
279+
q.low = (q.low << 1) | carry;
280+
281+
// carry = 0
282+
// if r.u64() >= d.u64() {
283+
// *r.all() -= d.u64();
284+
// carry = 1;
285+
// }
286+
287+
let s = (d.u64().wrapping_sub(r.u64()).wrapping_sub(1)) as i64 >> (u64_bits - 1);
288+
carry = (s & 1) as u32;
289+
*r.all() -= d.u64() & s as u64;
290+
}
291+
292+
*q.all() = (q.u64() << 1) | carry as u64;
293+
if let Some(rem) = unsafe { rem.as_mut() } {
294+
*rem = r.u64();
295+
}
296+
q.u64()
297+
}

src/test.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use std::panic;
1+
use std::{mem, panic};
2+
3+
use quickcheck::TestResult;
24

35
macro_rules! absv_i2 {
46
($intrinsic:ident: $ty:ident) => {
@@ -23,3 +25,20 @@ absv_i2!(__absvsi2: i32);
2325
absv_i2!(__absvdi2: i64);
2426
// TODO(rust-lang/35118)?
2527
// absv_i2!(__absvti2: i128);
28+
29+
quickcheck! {
30+
fn udivmoddi4(a: (u32, u32), b: (u32, u32)) -> TestResult {
31+
let (a, b) = unsafe {
32+
(mem::transmute(a), mem::transmute(b))
33+
};
34+
35+
if b == 0 {
36+
TestResult::discard()
37+
} else {
38+
let mut r = 0;
39+
let q = ::__udivmoddi4(a, b, &mut r);
40+
41+
TestResult::from_bool(q * b + r == a)
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)