Skip to content

Commit 8603e64

Browse files
author
Jorge Aparicio
authored
Merge pull request #44 from Amanieu/sdiv
Add signed division functions
2 parents 6508c55 + b9e916c commit 8603e64

File tree

6 files changed

+259
-18
lines changed

6 files changed

+259
-18
lines changed

README.md

+12-12
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ See [rust-lang/rust#35437][0].
4040
- [x] arm/aeabi_uidivmod.S
4141
- [x] arm/aeabi_uldivmod.S
4242
- [ ] arm/divdf3vfp.S
43-
- [ ] arm/divmodsi4.S
43+
- [ ] arm/divmodsi4.S (generic version is done)
4444
- [ ] arm/divsf3vfp.S
45-
- [ ] arm/divsi3.S
45+
- [ ] arm/divsi3.S (generic version is done)
4646
- [ ] arm/eqdf2vfp.S
4747
- [ ] arm/eqsf2vfp.S
4848
- [ ] arm/extendsfdf2vfp.S
@@ -62,7 +62,7 @@ See [rust-lang/rust#35437][0].
6262
- [ ] arm/lesf2vfp.S
6363
- [ ] arm/ltdf2vfp.S
6464
- [ ] arm/ltsf2vfp.S
65-
- [ ] arm/modsi3.S
65+
- [ ] arm/modsi3.S (generic version is done)
6666
- [ ] arm/muldf3vfp.S
6767
- [ ] arm/mulsf3vfp.S
6868
- [ ] arm/nedf2vfp.S
@@ -73,17 +73,19 @@ See [rust-lang/rust#35437][0].
7373
- [ ] arm/subdf3vfp.S
7474
- [ ] arm/subsf3vfp.S
7575
- [ ] arm/truncdfsf2vfp.S
76-
- [ ] arm/udivmodsi4.S
77-
- [ ] arm/udivsi3.S
78-
- [ ] arm/umodsi3.S
76+
- [ ] arm/udivmodsi4.S (generic version is done)
77+
- [ ] arm/udivsi3.S (generic version is done)
78+
- [ ] arm/umodsi3.S (generic version is done)
7979
- [ ] arm/unorddf2vfp.S
8080
- [ ] arm/unordsf2vfp.S
8181
- [x] ashldi3.c
8282
- [x] ashrdi3.c
8383
- [ ] divdf3.c
84-
- [ ] divdi3.c
84+
- [x] divdi3.c
85+
- [x] divmoddi4.c
86+
- [x] divmodsi4.c
8587
- [ ] divsf3.c
86-
- [ ] divsi3.c
88+
- [x] divsi3.c
8789
- [ ] extendhfsf2.c
8890
- [ ] extendsfdf2.c
8991
- [ ] fixdfdi.c
@@ -113,8 +115,8 @@ See [rust-lang/rust#35437][0].
113115
- [ ] i386/udivdi3.S
114116
- [ ] i386/umoddi3.S
115117
- [x] lshrdi3.c
116-
- [ ] moddi3.c
117-
- [ ] modsi3.c
118+
- [x] moddi3.c
119+
- [x] modsi3.c
118120
- [ ] muldf3.c
119121
- [x] muldi3.c
120122
- [x] mulodi4.c
@@ -251,8 +253,6 @@ These builtins are never called by LLVM.
251253
- ~~ctzdi2.c~~
252254
- ~~ctzsi2.c~~
253255
- ~~ctzti2.c~~
254-
- ~~divmoddi4.c~~
255-
- ~~divmodsi4.c~~
256256
- ~~ffsdi2.c~~
257257
- ~~ffsti2.c~~
258258
- ~~mulvdi3.c~~

src/arm.rs

+120-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use core::intrinsics;
22

3-
// NOTE This function and the one below are implemented using assembly because they using a custom
3+
// NOTE This function and the ones below are implemented using assembly because they using a custom
44
// calling convention which can't be implemented using a normal Rust function
55
#[naked]
66
#[cfg_attr(not(test), no_mangle)]
@@ -30,6 +30,44 @@ pub unsafe fn __aeabi_uldivmod() {
3030
intrinsics::unreachable();
3131
}
3232

33+
#[naked]
34+
#[cfg_attr(not(test), no_mangle)]
35+
pub unsafe fn __aeabi_idivmod() {
36+
asm!("push {r0, r1, r4, lr}
37+
bl __divsi3
38+
pop {r1, r2}
39+
muls r2, r2, r0
40+
subs r1, r1, r2
41+
pop {r4, pc}");
42+
intrinsics::unreachable();
43+
}
44+
45+
#[naked]
46+
#[cfg_attr(not(test), no_mangle)]
47+
pub unsafe fn __aeabi_ldivmod() {
48+
asm!("push {r4, lr}
49+
sub sp, sp, #16
50+
add r4, sp, #8
51+
str r4, [sp]
52+
bl __divmoddi4
53+
ldr r2, [sp, #8]
54+
ldr r3, [sp, #12]
55+
add sp, sp, #16
56+
pop {r4, pc}");
57+
intrinsics::unreachable();
58+
}
59+
60+
// TODO: These two functions should be defined as aliases
61+
#[cfg_attr(not(test), no_mangle)]
62+
pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 {
63+
::udiv::__udivsi3(a, b)
64+
}
65+
66+
#[cfg_attr(not(test), no_mangle)]
67+
pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 {
68+
::sdiv::__divsi3(a, b)
69+
}
70+
3371
extern "C" {
3472
fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
3573
fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
@@ -90,3 +128,84 @@ pub unsafe extern "C" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
90128
pub unsafe extern "C" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
91129
memset(dest, 0, n);
92130
}
131+
132+
133+
#[cfg(test)]
134+
mod tests {
135+
use quickcheck::TestResult;
136+
use qc::{U32, U64};
137+
138+
quickcheck!{
139+
fn uldivmod(n: U64, d: U64) -> TestResult {
140+
let (n, d) = (n.0, d.0);
141+
if d == 0 {
142+
TestResult::discard()
143+
} else {
144+
let q: u64;
145+
let r: u64;
146+
unsafe {
147+
// The inline asm is a bit tricky here, LLVM will allocate
148+
// both r0 and r1 when we specify a 64-bit value for {r0}.
149+
asm!("bl __aeabi_uldivmod"
150+
: "={r0}" (q), "={r2}" (r)
151+
: "{r0}" (n), "{r2}" (d)
152+
: "r12", "lr", "flags");
153+
}
154+
TestResult::from_bool(q == n / d && r == n % d)
155+
}
156+
}
157+
158+
fn uidivmod(n: U32, d: U32) -> TestResult {
159+
let (n, d) = (n.0, d.0);
160+
if d == 0 {
161+
TestResult::discard()
162+
} else {
163+
let q: u32;
164+
let r: u32;
165+
unsafe {
166+
asm!("bl __aeabi_uidivmod"
167+
: "={r0}" (q), "={r1}" (r)
168+
: "{r0}" (n), "{r1}" (d)
169+
: "r2", "r3", "r12", "lr", "flags");
170+
}
171+
TestResult::from_bool(q == n / d && r == n % d)
172+
}
173+
}
174+
175+
fn ldivmod(n: U64, d: U64) -> TestResult {
176+
let (n, d) = (n.0 as i64, d.0 as i64);
177+
if d == 0 {
178+
TestResult::discard()
179+
} else {
180+
let q: i64;
181+
let r: i64;
182+
unsafe {
183+
// The inline asm is a bit tricky here, LLVM will allocate
184+
// both r0 and r1 when we specify a 64-bit value for {r0}.
185+
asm!("bl __aeabi_ldivmod"
186+
: "={r0}" (q), "={r2}" (r)
187+
: "{r0}" (n), "{r2}" (d)
188+
: "r12", "lr", "flags");
189+
}
190+
TestResult::from_bool(q == n / d && r == n % d)
191+
}
192+
}
193+
194+
fn idivmod(n: U32, d: U32) -> TestResult {
195+
let (n, d) = (n.0 as i32, d.0 as i32);
196+
if d == 0 {
197+
TestResult::discard()
198+
} else {
199+
let q: i32;
200+
let r: i32;
201+
unsafe {
202+
asm!("bl __aeabi_idivmod"
203+
: "={r0}" (q), "={r1}" (r)
204+
: "{r0}" (n), "{r1}" (d)
205+
: "r2", "r3", "r12", "lr", "flags");
206+
}
207+
TestResult::from_bool(q == n / d && r == n % d)
208+
}
209+
}
210+
}
211+
}

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub mod arm;
2727
pub mod x86_64;
2828

2929
pub mod udiv;
30+
pub mod sdiv;
3031
pub mod mul;
3132
pub mod shift;
3233

src/mul.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ macro_rules! mul {
44
($intrinsic:ident: $ty:ty) => {
55
/// Returns `a * b`
66
#[cfg_attr(not(test), no_mangle)]
7-
pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty {
7+
pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty {
88
let half_bits = <$ty>::bits() / 4;
99
let lower_mask = !0 >> half_bits;
1010
let mut low = (a.low() & lower_mask) * (b.low() & lower_mask);
@@ -29,7 +29,7 @@ macro_rules! mulo {
2929
($intrinsic:ident: $ty:ty) => {
3030
/// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows
3131
#[cfg_attr(not(test), no_mangle)]
32-
pub extern fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty {
32+
pub extern "C" fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty {
3333
*overflow = 0;
3434
let result = a.wrapping_mul(b);
3535
if a == <$ty>::min_value() {

src/sdiv.rs

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
use Int;
2+
3+
macro_rules! div {
4+
($intrinsic:ident: $ty:ty, $uty:ty) => {
5+
/// Returns `a / b`
6+
#[cfg_attr(not(test), no_mangle)]
7+
pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty {
8+
let s_a = a >> (<$ty>::bits() - 1);
9+
let s_b = b >> (<$ty>::bits() - 1);
10+
let a = (a ^ s_a) - s_a;
11+
let b = (b ^ s_b) - s_b;
12+
let s = s_a ^ s_b;
13+
let r = (a as $uty) / (b as $uty);
14+
(r as $ty ^ s) - s
15+
}
16+
}
17+
}
18+
19+
macro_rules! mod_ {
20+
($intrinsic:ident: $ty:ty, $uty:ty) => {
21+
/// Returns `a % b`
22+
#[cfg_attr(not(test), no_mangle)]
23+
pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty {
24+
let s = b >> (<$ty>::bits() - 1);
25+
let b = (b ^ s) - s;
26+
let s = a >> (<$ty>::bits() - 1);
27+
let a = (a ^ s) - s;
28+
let r = (a as $uty) % (b as $uty);
29+
(r as $ty ^ s) - s
30+
}
31+
}
32+
}
33+
34+
macro_rules! divmod {
35+
($intrinsic:ident, $div:ident: $ty:ty) => {
36+
/// Returns `a / b` and sets `*rem = n % d`
37+
#[cfg_attr(not(test), no_mangle)]
38+
pub extern "C" fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty {
39+
let r = $div(a, b);
40+
*rem = a - (r * b);
41+
r
42+
}
43+
}
44+
}
45+
46+
div!(__divsi3: i32, u32);
47+
div!(__divdi3: i64, u64);
48+
mod_!(__modsi3: i32, u32);
49+
mod_!(__moddi3: i64, u64);
50+
divmod!(__divmodsi4, __divsi3: i32);
51+
divmod!(__divmoddi4, __divdi3: i64);
52+
53+
#[cfg(test)]
54+
mod tests {
55+
use quickcheck::TestResult;
56+
use qc::{U32, U64};
57+
58+
quickcheck!{
59+
fn divdi3(n: U64, d: U64) -> TestResult {
60+
let (n, d) = (n.0 as i64, d.0 as i64);
61+
if d == 0 {
62+
TestResult::discard()
63+
} else {
64+
let q = super::__divdi3(n, d);
65+
TestResult::from_bool(q == n / d)
66+
}
67+
}
68+
69+
fn moddi3(n: U64, d: U64) -> TestResult {
70+
let (n, d) = (n.0 as i64, d.0 as i64);
71+
if d == 0 {
72+
TestResult::discard()
73+
} else {
74+
let r = super::__moddi3(n, d);
75+
TestResult::from_bool(r == n % d)
76+
}
77+
}
78+
79+
fn divmoddi4(n: U64, d: U64) -> TestResult {
80+
let (n, d) = (n.0 as i64, d.0 as i64);
81+
if d == 0 {
82+
TestResult::discard()
83+
} else {
84+
let mut r = 0;
85+
let q = super::__divmoddi4(n, d, &mut r);
86+
TestResult::from_bool(q == n / d && r == n % d)
87+
}
88+
}
89+
90+
fn divsi3(n: U32, d: U32) -> TestResult {
91+
let (n, d) = (n.0 as i32, d.0 as i32);
92+
if d == 0 {
93+
TestResult::discard()
94+
} else {
95+
let q = super::__divsi3(n, d);
96+
TestResult::from_bool(q == n / d)
97+
}
98+
}
99+
100+
fn modsi3(n: U32, d: U32) -> TestResult {
101+
let (n, d) = (n.0 as i32, d.0 as i32);
102+
if d == 0 {
103+
TestResult::discard()
104+
} else {
105+
let r = super::__modsi3(n, d);
106+
TestResult::from_bool(r == n % d)
107+
}
108+
}
109+
110+
fn divmodsi4(n: U32, d: U32) -> TestResult {
111+
let (n, d) = (n.0 as i32, d.0 as i32);
112+
if d == 0 {
113+
TestResult::discard()
114+
} else {
115+
let mut r = 0;
116+
let q = super::__divmodsi4(n, d, &mut r);
117+
TestResult::from_bool(q == n / d && r == n % d)
118+
}
119+
}
120+
}
121+
}

src/shift.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ macro_rules! ashl {
44
($intrinsic:ident: $ty:ty) => {
55
/// Returns `a << b`, requires `b < $ty::bits()`
66
#[cfg_attr(not(test), no_mangle)]
7-
pub extern fn $intrinsic(a: $ty, b: u32) -> $ty {
7+
pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty {
88
let half_bits = <$ty>::bits() / 2;
99
if b & half_bits != 0 {
1010
<$ty>::from_parts(0, a.low() << (b - half_bits))
@@ -21,7 +21,7 @@ macro_rules! ashr {
2121
($intrinsic:ident: $ty:ty) => {
2222
/// Returns arithmetic `a >> b`, requires `b < $ty::bits()`
2323
#[cfg_attr(not(test), no_mangle)]
24-
pub extern fn $intrinsic(a: $ty, b: u32) -> $ty {
24+
pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty {
2525
let half_bits = <$ty>::bits() / 2;
2626
if b & half_bits != 0 {
2727
<$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf,
@@ -41,7 +41,7 @@ macro_rules! lshr {
4141
($intrinsic:ident: $ty:ty) => {
4242
/// Returns logical `a >> b`, requires `b < $ty::bits()`
4343
#[cfg_attr(not(test), no_mangle)]
44-
pub extern fn $intrinsic(a: $ty, b: u32) -> $ty {
44+
pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty {
4545
let half_bits = <$ty>::bits() / 2;
4646
if b & half_bits != 0 {
4747
<$ty>::from_parts(a.high() >> (b - half_bits), 0)

0 commit comments

Comments
 (0)