Skip to content

Commit b46719e

Browse files
committed
Auto merge of #67 - japaric:gcc_s, r=japaric
test our implementations against gcc_s if it exposes the same intrinsics that we implement -- gcc_s doesn't implement all the intrinsics for all the architectures. closes #65 r? @Amanieu Tested on Linux x86_64 and against the x86_64 and the arm-gnueabi targets. Unclear whether this works on osx or windows.
2 parents 9e50598 + dafe47b commit b46719e

File tree

10 files changed

+292
-27
lines changed

10 files changed

+292
-27
lines changed

Cargo.toml

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
[package]
22
authors = ["Jorge Aparicio <[email protected]>"]
3+
build = "build.rs"
34
name = "rustc_builtins"
45
version = "0.1.0"
56

67
[dependencies]
7-
rlibc = { git = "https://github.com/alexcrichton/rlibc", optional = true }
8+
9+
[dependencies.rlibc]
10+
git = "https://github.com/alexcrichton/rlibc"
11+
optional = true
812

913
[dev-dependencies]
1014
quickcheck = "0.3.1"
15+
rand = "0.3.14"
16+
17+
[dev-dependencies.gcc_s]
18+
path = "gcc_s"
1119

1220
[features]
1321
default = ["rlibc/weak"]
22+
23+
[workspace]

build.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use std::env;
2+
3+
fn main() {
4+
if env::var("TARGET").unwrap().ends_with("gnueabihf") {
5+
println!("cargo:rustc-cfg=gnueabihf")
6+
}
7+
}

gcc_s/Cargo.toml

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
authors = ["Jorge Aparicio <[email protected]>"]
3+
name = "gcc_s"
4+
version = "0.1.0"
5+
6+
[dependencies]
7+
libloading = "0.3.0"

gcc_s/src/lib.rs

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#![feature(drop_types_in_const)]
2+
3+
extern crate libloading;
4+
5+
use std::sync::{Once, ONCE_INIT};
6+
7+
use libloading::Library;
8+
9+
static mut GCC_S: Option<Library> = None;
10+
11+
#[cfg(not(windows))]
12+
fn gcc_s() -> &'static Library {
13+
#[cfg(not(target_os = "macos"))]
14+
const LIBGCC_S: &'static str = "libgcc_s.so.1";
15+
16+
#[cfg(target_os = "macos")]
17+
const LIBGCC_S: &'static str = "libgcc_s.1.dylib";
18+
19+
unsafe {
20+
static INIT: Once = ONCE_INIT;
21+
22+
INIT.call_once(|| {
23+
GCC_S = Some(Library::new(LIBGCC_S).unwrap());
24+
});
25+
GCC_S.as_ref().unwrap()
26+
}
27+
}
28+
29+
#[cfg(windows)]
30+
macro_rules! declare {
31+
($symbol:ident: fn($($i:ty),+) -> $o:ty) => {
32+
pub fn $symbol() -> Option<unsafe extern fn($($i),+) -> $o> {
33+
None
34+
}
35+
}
36+
}
37+
38+
#[cfg(not(windows))]
39+
macro_rules! declare {
40+
($symbol:ident: fn($($i:ty),+) -> $o:ty) => {
41+
pub fn $symbol() -> Option<unsafe extern fn($($i),+) -> $o> {
42+
unsafe {
43+
gcc_s().get(concat!("__", stringify!($symbol)).as_bytes()).ok().map(|s| *s)
44+
}
45+
}
46+
}
47+
}
48+
49+
declare!(ashldi3: fn(u64, u32) -> u64);
50+
declare!(ashrdi3: fn(i64, u32) -> i64);
51+
declare!(divdi3: fn(i64, i64) -> i64);
52+
declare!(divmoddi4: fn(i64, i64, &mut i64) -> i64);
53+
declare!(divmodsi4: fn(i32, i32, &mut i32) -> i32);
54+
declare!(divsi3: fn(i32, i32) -> i32);
55+
declare!(lshrdi3: fn(u64, u32) -> u64);
56+
declare!(moddi3: fn(i64, i64) -> i64);
57+
declare!(modsi3: fn(i32, i32) -> i32);
58+
declare!(muldi3: fn(u64, u64) -> u64);
59+
declare!(mulodi4: fn(i64, i64, &mut i32) -> i64);
60+
declare!(mulosi4: fn(i32, i32, &mut i32) -> i32);
61+
declare!(udivdi3: fn(u64, u64) -> u64);
62+
declare!(udivmoddi4: fn(u64, u64, Option<&mut u64>) -> u64);
63+
declare!(udivmodsi4: fn(u32, u32, Option<&mut u32>) -> u32);
64+
declare!(udivsi3: fn(u32, u32) -> u32);
65+
declare!(umoddi3: fn(u64, u64) -> u64);
66+
declare!(umodsi3: fn(u32, u32) -> u32);
67+
declare!(addsf3: fn(f32, f32) -> f32);
68+
declare!(adddf3: fn(f64, f64) -> f64);

src/float/add.rs

+24-5
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,12 @@ pub extern fn __aeabi_fadd(a: f32, b: f32) -> f32 {
199199
#[cfg(test)]
200200
mod tests {
201201
use core::{f32, f64};
202-
use qc::{U32, U64};
202+
203203
use float::Float;
204+
use qc::{U32, U64};
205+
206+
use gcc_s;
207+
use rand;
204208

205209
// NOTE The tests below have special handing for NaN values.
206210
// Because NaN != NaN, the floating-point representations must be used
@@ -213,15 +217,30 @@ mod tests {
213217
fn addsf3(a: U32, b: U32) -> bool {
214218
let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0));
215219
let x = super::__addsf3(a, b);
216-
let y = a + b;
217-
x.eq_repr(y)
220+
221+
match gcc_s::addsf3() {
222+
// NOTE(cfg) for some reason, on hard float targets, our implementation doesn't
223+
// match the output of its gcc_s counterpart. Until we investigate further, we'll
224+
// just avoid testing against gcc_s on those targets. Do note that our
225+
// implementation matches the output of the FPU instruction on *hard* float targets
226+
// and matches its gcc_s counterpart on *soft* float targets.
227+
#[cfg(not(gnueabihf))]
228+
Some(addsf3) if rand::random() => x.eq_repr(unsafe { addsf3(a, b) }),
229+
_ => x.eq_repr(a + b),
230+
}
218231
}
219232

220233
fn adddf3(a: U64, b: U64) -> bool {
221234
let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0));
222235
let x = super::__adddf3(a, b);
223-
let y = a + b;
224-
x.eq_repr(y)
236+
237+
match gcc_s::adddf3() {
238+
// NOTE(cfg) See NOTE above
239+
#[cfg(not(gnueabihf))]
240+
Some(adddf3) if rand::random() => x.eq_repr(unsafe { adddf3(a, b) }),
241+
_ => x.eq_repr(a + b),
242+
243+
}
225244
}
226245
}
227246

src/int/mul.rs

+32-3
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,18 @@ mulo!(__mulodi4: i64);
7474
mod tests {
7575
use qc::{I32, I64, U64};
7676

77+
use gcc_s;
78+
use rand;
79+
7780
quickcheck! {
7881
fn muldi(a: U64, b: U64) -> bool {
7982
let (a, b) = (a.0, b.0);
8083
let r = super::__muldi3(a, b);
81-
r == a.wrapping_mul(b)
84+
85+
match gcc_s::muldi3() {
86+
Some(muldi3) if rand::random() => r == unsafe { muldi3(a, b) },
87+
_ => r == a.wrapping_mul(b),
88+
}
8289
}
8390

8491
fn mulosi(a: I32, b: I32) -> bool {
@@ -88,7 +95,18 @@ mod tests {
8895
if overflow != 0 && overflow != 1 {
8996
return false;
9097
}
91-
(r, overflow != 0) == a.overflowing_mul(b)
98+
99+
match gcc_s::mulosi4() {
100+
Some(mulosi4) if rand::random() => {
101+
let mut gcc_s_overflow = 2;
102+
let gcc_s_r = unsafe {
103+
mulosi4(a, b, &mut gcc_s_overflow)
104+
};
105+
106+
(r, overflow) == (gcc_s_r, gcc_s_overflow)
107+
},
108+
_ => (r, overflow != 0) == a.overflowing_mul(b),
109+
}
92110
}
93111

94112
fn mulodi(a: I64, b: I64) -> bool {
@@ -98,7 +116,18 @@ mod tests {
98116
if overflow != 0 && overflow != 1 {
99117
return false;
100118
}
101-
(r, overflow != 0) == a.overflowing_mul(b)
119+
120+
match gcc_s::mulodi4() {
121+
Some(mulodi4) if rand::random() => {
122+
let mut gcc_s_overflow = 2;
123+
let gcc_s_r = unsafe {
124+
mulodi4(a, b, &mut gcc_s_overflow)
125+
};
126+
127+
(r, overflow) == (gcc_s_r, gcc_s_overflow)
128+
},
129+
_ => (r, overflow != 0) == a.overflowing_mul(b),
130+
}
102131
}
103132
}
104133
}

src/int/sdiv.rs

+56-7
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,26 @@ divmod!(__divmoddi4, __divdi3: i64);
5252

5353
#[cfg(test)]
5454
mod tests {
55-
use quickcheck::TestResult;
5655
use qc::{U32, U64};
5756

57+
use gcc_s;
58+
use quickcheck::TestResult;
59+
use rand;
60+
5861
quickcheck!{
5962
fn divdi3(n: U64, d: U64) -> TestResult {
6063
let (n, d) = (n.0 as i64, d.0 as i64);
6164
if d == 0 {
6265
TestResult::discard()
6366
} else {
6467
let q = super::__divdi3(n, d);
65-
TestResult::from_bool(q == n / d)
68+
69+
match gcc_s::divdi3() {
70+
Some(divdi3) if rand::random() => {
71+
TestResult::from_bool(q == unsafe { divdi3(n, d) })
72+
},
73+
_ => TestResult::from_bool(q == n / d),
74+
}
6675
}
6776
}
6877

@@ -72,7 +81,13 @@ mod tests {
7281
TestResult::discard()
7382
} else {
7483
let r = super::__moddi3(n, d);
75-
TestResult::from_bool(r == n % d)
84+
85+
match gcc_s::moddi3() {
86+
Some(moddi3) if rand::random() => {
87+
TestResult::from_bool(r == unsafe { moddi3(n, d) })
88+
},
89+
_ => TestResult::from_bool(r == n % d),
90+
}
7691
}
7792
}
7893

@@ -83,7 +98,18 @@ mod tests {
8398
} else {
8499
let mut r = 0;
85100
let q = super::__divmoddi4(n, d, &mut r);
86-
TestResult::from_bool(q == n / d && r == n % d)
101+
102+
match gcc_s::divmoddi4() {
103+
Some(divmoddi4) if rand::random() => {
104+
let mut gcc_s_r = 0;
105+
let gcc_s_q = unsafe {
106+
divmoddi4(n, d, &mut gcc_s_r)
107+
};
108+
109+
TestResult::from_bool(q == gcc_s_q && r == gcc_s_r)
110+
},
111+
_ => TestResult::from_bool(q == n / d && r == n % d),
112+
}
87113
}
88114
}
89115

@@ -93,7 +119,13 @@ mod tests {
93119
TestResult::discard()
94120
} else {
95121
let q = super::__divsi3(n, d);
96-
TestResult::from_bool(q == n / d)
122+
123+
match gcc_s::divsi3() {
124+
Some(divsi3) if rand::random() => {
125+
TestResult::from_bool(q == unsafe { divsi3(n, d)})
126+
},
127+
_ => TestResult::from_bool(q == n / d),
128+
}
97129
}
98130
}
99131

@@ -103,7 +135,13 @@ mod tests {
103135
TestResult::discard()
104136
} else {
105137
let r = super::__modsi3(n, d);
106-
TestResult::from_bool(r == n % d)
138+
139+
match gcc_s::modsi3() {
140+
Some(modsi3) if rand::random() => {
141+
TestResult::from_bool(r == unsafe { modsi3(n, d) })
142+
},
143+
_ => TestResult::from_bool(r == n % d),
144+
}
107145
}
108146
}
109147

@@ -114,7 +152,18 @@ mod tests {
114152
} else {
115153
let mut r = 0;
116154
let q = super::__divmodsi4(n, d, &mut r);
117-
TestResult::from_bool(q == n / d && r == n % d)
155+
156+
match gcc_s::divmodsi4() {
157+
Some(divmodsi4) if rand::random() => {
158+
let mut gcc_s_r = 0;
159+
let gcc_s_q = unsafe {
160+
divmodsi4(n, d, &mut gcc_s_r)
161+
};
162+
163+
TestResult::from_bool(q == gcc_s_q && r == gcc_s_r)
164+
},
165+
_ => TestResult::from_bool(q == n / d && r == n % d),
166+
}
118167
}
119168
}
120169
}

src/int/shift.rs

+25-4
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,12 @@ lshr!(__lshrdi3: u64);
6060

6161
#[cfg(test)]
6262
mod tests {
63-
use quickcheck::TestResult;
6463
use qc::{I64, U64};
6564

65+
use gcc_s;
66+
use quickcheck::TestResult;
67+
use rand;
68+
6669
// NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64)
6770
quickcheck! {
6871
fn ashldi(a: U64, b: u32) -> TestResult {
@@ -71,7 +74,13 @@ mod tests {
7174
TestResult::discard()
7275
} else {
7376
let r = super::__ashldi3(a, b);
74-
TestResult::from_bool(r == a << b)
77+
78+
match gcc_s::ashldi3() {
79+
Some(ashldi3) if rand::random() => {
80+
TestResult::from_bool(r == unsafe { ashldi3(a, b) })
81+
},
82+
_ => TestResult::from_bool(r == a << b),
83+
}
7584
}
7685
}
7786

@@ -81,7 +90,13 @@ mod tests {
8190
TestResult::discard()
8291
} else {
8392
let r = super::__ashrdi3(a, b);
84-
TestResult::from_bool(r == a >> b)
93+
94+
match gcc_s::ashrdi3() {
95+
Some(ashrdi3) if rand::random() => {
96+
TestResult::from_bool(r == unsafe { ashrdi3(a, b) })
97+
},
98+
_ => TestResult::from_bool(r == a >> b),
99+
}
85100
}
86101
}
87102

@@ -91,7 +106,13 @@ mod tests {
91106
TestResult::discard()
92107
} else {
93108
let r = super::__lshrdi3(a, b);
94-
TestResult::from_bool(r == a >> b)
109+
110+
match gcc_s::lshrdi3() {
111+
Some(lshrdi3) if rand::random() => {
112+
TestResult::from_bool(r == unsafe { lshrdi3(a, b) })
113+
},
114+
_ => TestResult::from_bool(r == a >> b),
115+
}
95116
}
96117
}
97118
}

0 commit comments

Comments
 (0)