Auto merge of #141 - rust-lang-nursery:aapcs, r=alexcrichton
use AAPCS calling convention on all aeabi intrinsics also, on ARM, inline(always) the actual implementation of the intrinsics so we end with code like this: ``` 00000000 <__aeabi_dadd>: (implementation here) ``` instead of "trampolines" like this: ``` 00000000 <__aeabi_dadd>: (shuffle registers) (call __adddf3) 00000000 <__adddf3>: (implementation here) ``` closes #116 cc #66 r? @alexcrichton cc @mattico
This commit is contained in:
commit
9aa3a257d6
40
src/arm.rs
40
src/arm.rs
|
@ -62,44 +62,44 @@ pub unsafe fn __aeabi_ldivmod() {
|
||||||
|
|
||||||
// TODO: These aeabi_* functions should be defined as aliases
|
// TODO: These aeabi_* functions should be defined as aliases
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub extern "C" fn __aeabi_dadd(a: f64, b: f64) -> f64 {
|
pub extern "aapcs" fn __aeabi_dadd(a: f64, b: f64) -> f64 {
|
||||||
::float::add::__adddf3(a, b)
|
::float::add::__adddf3(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub extern "C" fn __aeabi_fadd(a: f32, b: f32) -> f32 {
|
pub extern "aapcs" fn __aeabi_fadd(a: f32, b: f32) -> f32 {
|
||||||
::float::add::__addsf3(a, b)
|
::float::add::__addsf3(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
|
#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 {
|
pub extern "aapcs" fn __aeabi_idiv(a: i32, b: i32) -> i32 {
|
||||||
::int::sdiv::__divsi3(a, b)
|
::int::sdiv::__divsi3(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub extern "C" fn __aeabi_lasr(a: i64, b: u32) -> i64 {
|
pub extern "aapcs" fn __aeabi_lasr(a: i64, b: u32) -> i64 {
|
||||||
::int::shift::__ashrdi3(a, b)
|
::int::shift::__ashrdi3(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub extern "C" fn __aeabi_llsl(a: u64, b: u32) -> u64 {
|
pub extern "aapcs" fn __aeabi_llsl(a: u64, b: u32) -> u64 {
|
||||||
::int::shift::__ashldi3(a, b)
|
::int::shift::__ashldi3(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub extern "C" fn __aeabi_llsr(a: u64, b: u32) -> u64 {
|
pub extern "aapcs" fn __aeabi_llsr(a: u64, b: u32) -> u64 {
|
||||||
::int::shift::__lshrdi3(a, b)
|
::int::shift::__lshrdi3(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub extern "C" fn __aeabi_lmul(a: u64, b: u64) -> u64 {
|
pub extern "aapcs" fn __aeabi_lmul(a: u64, b: u64) -> u64 {
|
||||||
::int::mul::__muldi3(a, b)
|
::int::mul::__muldi3(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
|
#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 {
|
pub extern "aapcs" fn __aeabi_uidiv(a: u32, b: u32) -> u32 {
|
||||||
::int::udiv::__udivsi3(a, b)
|
::int::udiv::__udivsi3(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,55 +113,55 @@ extern "C" {
|
||||||
// FIXME: The `*4` and `*8` variants should be defined as aliases.
|
// FIXME: The `*4` and `*8` variants should be defined as aliases.
|
||||||
|
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) {
|
pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) {
|
||||||
memcpy(dest, src, n);
|
memcpy(dest, src, n);
|
||||||
}
|
}
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub unsafe extern "C" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) {
|
pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) {
|
||||||
memcpy(dest, src, n);
|
memcpy(dest, src, n);
|
||||||
}
|
}
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub unsafe extern "C" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) {
|
pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) {
|
||||||
memcpy(dest, src, n);
|
memcpy(dest, src, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub unsafe extern "C" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) {
|
pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) {
|
||||||
memmove(dest, src, n);
|
memmove(dest, src, n);
|
||||||
}
|
}
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub unsafe extern "C" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) {
|
pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) {
|
||||||
memmove(dest, src, n);
|
memmove(dest, src, n);
|
||||||
}
|
}
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub unsafe extern "C" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) {
|
pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) {
|
||||||
memmove(dest, src, n);
|
memmove(dest, src, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note the different argument order
|
// Note the different argument order
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub unsafe extern "C" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) {
|
pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) {
|
||||||
memset(dest, c, n);
|
memset(dest, c, n);
|
||||||
}
|
}
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub unsafe extern "C" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) {
|
pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) {
|
||||||
memset(dest, c, n);
|
memset(dest, c, n);
|
||||||
}
|
}
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub unsafe extern "C" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) {
|
pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) {
|
||||||
memset(dest, c, n);
|
memset(dest, c, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub unsafe extern "C" fn __aeabi_memclr(dest: *mut u8, n: usize) {
|
pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) {
|
||||||
memset(dest, 0, n);
|
memset(dest, 0, n);
|
||||||
}
|
}
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub unsafe extern "C" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
|
pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
|
||||||
memset(dest, 0, n);
|
memset(dest, 0, n);
|
||||||
}
|
}
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub unsafe extern "C" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
|
pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
|
||||||
memset(dest, 0, n);
|
memset(dest, 0, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,11 @@ use core::num::Wrapping;
|
||||||
use float::Float;
|
use float::Float;
|
||||||
|
|
||||||
macro_rules! add {
|
macro_rules! add {
|
||||||
($intrinsic:ident: $ty:ty) => {
|
($abi:tt, $intrinsic:ident: $ty:ty) => {
|
||||||
/// Returns `a + b`
|
/// Returns `a + b`
|
||||||
#[allow(unused_parens)]
|
#[allow(unused_parens)]
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty {
|
pub extern $abi fn $intrinsic(a: $ty, b: $ty) -> $ty {
|
||||||
let one = Wrapping(1 as <$ty as Float>::Int);
|
let one = Wrapping(1 as <$ty as Float>::Int);
|
||||||
let zero = Wrapping(0 as <$ty as Float>::Int);
|
let zero = Wrapping(0 as <$ty as Float>::Int);
|
||||||
|
|
||||||
|
@ -181,8 +181,17 @@ macro_rules! add {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add!(__addsf3: f32);
|
#[cfg(target_arch = "arm")]
|
||||||
add!(__adddf3: f64);
|
add!("aapcs", __addsf3: f32);
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "arm"))]
|
||||||
|
add!("C", __addsf3: f32);
|
||||||
|
|
||||||
|
#[cfg(target_arch = "arm")]
|
||||||
|
add!("aapcs", __adddf3: f64);
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "arm"))]
|
||||||
|
add!("C", __adddf3: f64);
|
||||||
|
|
||||||
// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabi*, our implementation doesn't
|
// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabi*, our implementation doesn't
|
||||||
// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll
|
// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll
|
||||||
|
@ -194,14 +203,14 @@ mod tests {
|
||||||
use qc::{F32, F64};
|
use qc::{F32, F64};
|
||||||
|
|
||||||
check! {
|
check! {
|
||||||
fn __addsf3(f: extern fn(f32, f32) -> f32,
|
fn __addsf3(f: extern "C" fn(f32, f32) -> f32,
|
||||||
a: F32,
|
a: F32,
|
||||||
b: F32)
|
b: F32)
|
||||||
-> Option<F32> {
|
-> Option<F32> {
|
||||||
Some(F32(f(a.0, b.0)))
|
Some(F32(f(a.0, b.0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __adddf3(f: extern fn(f64, f64) -> f64,
|
fn __adddf3(f: extern "C" fn(f64, f64) -> f64,
|
||||||
a: F64,
|
a: F64,
|
||||||
b: F64) -> Option<F64> {
|
b: F64) -> Option<F64> {
|
||||||
Some(F64(f(a.0, b.0)))
|
Some(F64(f(a.0, b.0)))
|
||||||
|
|
|
@ -34,13 +34,13 @@ mod tests {
|
||||||
use qc::{I32, F32, F64};
|
use qc::{I32, F32, F64};
|
||||||
|
|
||||||
check! {
|
check! {
|
||||||
fn __powisf2(f: extern fn(f32, i32) -> f32,
|
fn __powisf2(f: extern "C" fn(f32, i32) -> f32,
|
||||||
a: F32,
|
a: F32,
|
||||||
b: I32) -> Option<F32> {
|
b: I32) -> Option<F32> {
|
||||||
Some(F32(f(a.0, b.0)))
|
Some(F32(f(a.0, b.0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __powidf2(f: extern fn(f64, i32) -> f64,
|
fn __powidf2(f: extern "C" fn(f64, i32) -> f64,
|
||||||
a: F64,
|
a: F64,
|
||||||
b: I32) -> Option<F64> {
|
b: I32) -> Option<F64> {
|
||||||
Some(F64(f(a.0, b.0)))
|
Some(F64(f(a.0, b.0)))
|
||||||
|
|
|
@ -2,10 +2,11 @@ use int::LargeInt;
|
||||||
use int::Int;
|
use int::Int;
|
||||||
|
|
||||||
macro_rules! mul {
|
macro_rules! mul {
|
||||||
($intrinsic:ident: $ty:ty) => {
|
($(#[$attr:meta])+ |
|
||||||
|
$abi:tt, $intrinsic:ident: $ty:ty) => {
|
||||||
/// Returns `a * b`
|
/// Returns `a * b`
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
$(#[$attr])+
|
||||||
pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty {
|
pub extern $abi fn $intrinsic(a: $ty, b: $ty) -> $ty {
|
||||||
let half_bits = <$ty>::bits() / 4;
|
let half_bits = <$ty>::bits() / 4;
|
||||||
let lower_mask = !0 >> half_bits;
|
let lower_mask = !0 >> half_bits;
|
||||||
let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask);
|
let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask);
|
||||||
|
@ -73,9 +74,17 @@ macro_rules! mulo {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(all(feature = "c", target_arch = "x86")))]
|
#[cfg(not(all(feature = "c", target_arch = "x86")))]
|
||||||
mul!(__muldi3: u64);
|
mul!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)]
|
||||||
|
#[cfg_attr(all(not(test), target_arch = "arm"), inline(always))]
|
||||||
|
| "C", __muldi3: u64);
|
||||||
|
|
||||||
mul!(__multi3: i128);
|
#[cfg(not(target_arch = "arm"))]
|
||||||
|
mul!(#[cfg_attr(not(test), no_mangle)]
|
||||||
|
| "C", __multi3: i128);
|
||||||
|
|
||||||
|
#[cfg(target_arch = "arm")]
|
||||||
|
mul!(#[cfg_attr(not(test), no_mangle)]
|
||||||
|
| "aapcs", __multi3: i128);
|
||||||
|
|
||||||
mulo!(__mulosi4: i32);
|
mulo!(__mulosi4: i32);
|
||||||
mulo!(__mulodi4: i64);
|
mulo!(__mulodi4: i64);
|
||||||
|
@ -90,12 +99,12 @@ mod tests {
|
||||||
use qc::{I32, I64, U64};
|
use qc::{I32, I64, U64};
|
||||||
|
|
||||||
check! {
|
check! {
|
||||||
fn __muldi3(f: extern fn(u64, u64) -> u64, a: U64, b: U64)
|
fn __muldi3(f: extern "C" fn(u64, u64) -> u64, a: U64, b: U64)
|
||||||
-> Option<u64> {
|
-> Option<u64> {
|
||||||
Some(f(a.0, b.0))
|
Some(f(a.0, b.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __mulosi4(f: extern fn(i32, i32, &mut i32) -> i32,
|
fn __mulosi4(f: extern "C" fn(i32, i32, &mut i32) -> i32,
|
||||||
a: I32,
|
a: I32,
|
||||||
b: I32) -> Option<(i32, i32)> {
|
b: I32) -> Option<(i32, i32)> {
|
||||||
let (a, b) = (a.0, b.0);
|
let (a, b) = (a.0, b.0);
|
||||||
|
@ -107,7 +116,7 @@ mod tests {
|
||||||
Some((r, overflow))
|
Some((r, overflow))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __mulodi4(f: extern fn(i64, i64, &mut i32) -> i64,
|
fn __mulodi4(f: extern "C" fn(i64, i64, &mut i32) -> i64,
|
||||||
a: I64,
|
a: I64,
|
||||||
b: I64) -> Option<(i64, i32)> {
|
b: I64) -> Option<(i64, i32)> {
|
||||||
let (a, b) = (a.0, b.0);
|
let (a, b) = (a.0, b.0);
|
||||||
|
@ -130,11 +139,11 @@ mod tests_i128 {
|
||||||
use qc::I128;
|
use qc::I128;
|
||||||
|
|
||||||
check! {
|
check! {
|
||||||
fn __multi3(f: extern fn(i128, i128) -> i128, a: I128, b: I128)
|
fn __multi3(f: extern "C" fn(i128, i128) -> i128, a: I128, b: I128)
|
||||||
-> Option<i128> {
|
-> Option<i128> {
|
||||||
Some(f(a.0, b.0))
|
Some(f(a.0, b.0))
|
||||||
}
|
}
|
||||||
fn __muloti4(f: extern fn(i128, i128, &mut i32) -> i128,
|
fn __muloti4(f: extern "C" fn(i128, i128, &mut i32) -> i128,
|
||||||
a: I128,
|
a: I128,
|
||||||
b: I128) -> Option<(i128, i32)> {
|
b: I128) -> Option<(i128, i32)> {
|
||||||
let (a, b) = (a.0, b.0);
|
let (a, b) = (a.0, b.0);
|
||||||
|
|
|
@ -40,10 +40,10 @@ macro_rules! mod_ {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! divmod {
|
macro_rules! divmod {
|
||||||
($intrinsic:ident, $div:ident: $ty:ty) => {
|
($abi:tt, $intrinsic:ident, $div:ident: $ty:ty) => {
|
||||||
/// Returns `a / b` and sets `*rem = n % d`
|
/// Returns `a / b` and sets `*rem = n % d`
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub extern "C" fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty {
|
pub extern $abi fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty {
|
||||||
#[cfg(all(feature = "c", any(target_arch = "x86")))]
|
#[cfg(all(feature = "c", any(target_arch = "x86")))]
|
||||||
extern {
|
extern {
|
||||||
fn $div(a: $ty, b: $ty) -> $ty;
|
fn $div(a: $ty, b: $ty) -> $ty;
|
||||||
|
@ -86,16 +86,20 @@ mod_!(__modti3: i128, u128);
|
||||||
mod_!(__modti3: i128, u128, ::U64x2, ::sconv);
|
mod_!(__modti3: i128, u128, ::U64x2, ::sconv);
|
||||||
|
|
||||||
#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))]
|
#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))]
|
||||||
divmod!(__divmodsi4, __divsi3: i32);
|
divmod!("C", __divmodsi4, __divsi3: i32);
|
||||||
|
|
||||||
divmod!(__divmoddi4, __divdi3: i64);
|
#[cfg(target_arch = "arm")]
|
||||||
|
divmod!("aapcs", __divmoddi4, __divdi3: i64);
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "arm"))]
|
||||||
|
divmod!("C", __divmoddi4, __divdi3: i64);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use qc::{U32, U64};
|
use qc::{U32, U64};
|
||||||
|
|
||||||
check! {
|
check! {
|
||||||
fn __divdi3(f: extern fn(i64, i64) -> i64, n: U64, d: U64) -> Option<i64> {
|
fn __divdi3(f: extern "C" fn(i64, i64) -> i64, n: U64, d: U64) -> Option<i64> {
|
||||||
let (n, d) = (n.0 as i64, d.0 as i64);
|
let (n, d) = (n.0 as i64, d.0 as i64);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
None
|
None
|
||||||
|
@ -104,7 +108,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __moddi3(f: extern fn(i64, i64) -> i64, n: U64, d: U64) -> Option<i64> {
|
fn __moddi3(f: extern "C" fn(i64, i64) -> i64, n: U64, d: U64) -> Option<i64> {
|
||||||
let (n, d) = (n.0 as i64, d.0 as i64);
|
let (n, d) = (n.0 as i64, d.0 as i64);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
None
|
None
|
||||||
|
@ -113,7 +117,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __divmoddi4(f: extern fn(i64, i64, &mut i64) -> i64,
|
#[cfg(target_arch = "arm")]
|
||||||
|
fn __divmoddi4(f: extern "aapcs" fn(i64, i64, &mut i64) -> i64,
|
||||||
n: U64,
|
n: U64,
|
||||||
d: U64) -> Option<(i64, i64)> {
|
d: U64) -> Option<(i64, i64)> {
|
||||||
let (n, d) = (n.0 as i64, d.0 as i64);
|
let (n, d) = (n.0 as i64, d.0 as i64);
|
||||||
|
@ -126,7 +131,21 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __divsi3(f: extern fn(i32, i32) -> i32,
|
#[cfg(not(target_arch = "arm"))]
|
||||||
|
fn __divmoddi4(f: extern "C" fn(i64, i64, &mut i64) -> i64,
|
||||||
|
n: U64,
|
||||||
|
d: U64) -> Option<(i64, i64)> {
|
||||||
|
let (n, d) = (n.0 as i64, d.0 as i64);
|
||||||
|
if d == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let mut r = 0;
|
||||||
|
let q = f(n, d, &mut r);
|
||||||
|
Some((q, r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn __divsi3(f: extern "C" fn(i32, i32) -> i32,
|
||||||
n: U32,
|
n: U32,
|
||||||
d: U32) -> Option<i32> {
|
d: U32) -> Option<i32> {
|
||||||
let (n, d) = (n.0 as i32, d.0 as i32);
|
let (n, d) = (n.0 as i32, d.0 as i32);
|
||||||
|
@ -137,7 +156,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __modsi3(f: extern fn(i32, i32) -> i32,
|
fn __modsi3(f: extern "C" fn(i32, i32) -> i32,
|
||||||
n: U32,
|
n: U32,
|
||||||
d: U32) -> Option<i32> {
|
d: U32) -> Option<i32> {
|
||||||
let (n, d) = (n.0 as i32, d.0 as i32);
|
let (n, d) = (n.0 as i32, d.0 as i32);
|
||||||
|
@ -148,7 +167,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __divmodsi4(f: extern fn(i32, i32, &mut i32) -> i32,
|
fn __divmodsi4(f: extern "C" fn(i32, i32, &mut i32) -> i32,
|
||||||
n: U32,
|
n: U32,
|
||||||
d: U32) -> Option<(i32, i32)> {
|
d: U32) -> Option<(i32, i32)> {
|
||||||
let (n, d) = (n.0 as i32, d.0 as i32);
|
let (n, d) = (n.0 as i32, d.0 as i32);
|
||||||
|
@ -172,7 +191,7 @@ mod tests_i128 {
|
||||||
use qc::U128;
|
use qc::U128;
|
||||||
check! {
|
check! {
|
||||||
|
|
||||||
fn __divti3(f: extern fn(i128, i128) -> i128, n: U128, d: U128) -> Option<i128> {
|
fn __divti3(f: extern "C" fn(i128, i128) -> i128, n: U128, d: U128) -> Option<i128> {
|
||||||
let (n, d) = (n.0 as i128, d.0 as i128);
|
let (n, d) = (n.0 as i128, d.0 as i128);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
None
|
None
|
||||||
|
@ -181,7 +200,7 @@ mod tests_i128 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __modti3(f: extern fn(i128, i128) -> i128, n: U128, d: U128) -> Option<i128> {
|
fn __modti3(f: extern "C" fn(i128, i128) -> i128, n: U128, d: U128) -> Option<i128> {
|
||||||
let (n, d) = (n.0 as i128, d.0 as i128);
|
let (n, d) = (n.0 as i128, d.0 as i128);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
None
|
None
|
||||||
|
|
|
@ -4,6 +4,8 @@ macro_rules! ashl {
|
||||||
($intrinsic:ident: $ty:ty) => {
|
($intrinsic:ident: $ty:ty) => {
|
||||||
/// Returns `a << b`, requires `b < $ty::bits()`
|
/// Returns `a << b`, requires `b < $ty::bits()`
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
|
#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)]
|
||||||
|
#[cfg_attr(all(not(test), target_arch = "arm"), inline(always))]
|
||||||
pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty {
|
pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty {
|
||||||
let half_bits = <$ty>::bits() / 2;
|
let half_bits = <$ty>::bits() / 2;
|
||||||
if b & half_bits != 0 {
|
if b & half_bits != 0 {
|
||||||
|
@ -21,6 +23,8 @@ macro_rules! ashr {
|
||||||
($intrinsic:ident: $ty:ty) => {
|
($intrinsic:ident: $ty:ty) => {
|
||||||
/// Returns arithmetic `a >> b`, requires `b < $ty::bits()`
|
/// Returns arithmetic `a >> b`, requires `b < $ty::bits()`
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
|
#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)]
|
||||||
|
#[cfg_attr(all(not(test), target_arch = "arm"), inline(always))]
|
||||||
pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty {
|
pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty {
|
||||||
let half_bits = <$ty>::bits() / 2;
|
let half_bits = <$ty>::bits() / 2;
|
||||||
if b & half_bits != 0 {
|
if b & half_bits != 0 {
|
||||||
|
@ -75,7 +79,7 @@ mod tests {
|
||||||
|
|
||||||
// NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64)
|
// NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64)
|
||||||
check! {
|
check! {
|
||||||
fn __ashldi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option<u64> {
|
fn __ashldi3(f: extern "C" fn(u64, u32) -> u64, a: U64, b: u32) -> Option<u64> {
|
||||||
let a = a.0;
|
let a = a.0;
|
||||||
if b >= 64 {
|
if b >= 64 {
|
||||||
None
|
None
|
||||||
|
@ -84,7 +88,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __ashrdi3(f: extern fn(i64, u32) -> i64, a: I64, b: u32) -> Option<i64> {
|
fn __ashrdi3(f: extern "C" fn(i64, u32) -> i64, a: I64, b: u32) -> Option<i64> {
|
||||||
let a = a.0;
|
let a = a.0;
|
||||||
if b >= 64 {
|
if b >= 64 {
|
||||||
None
|
None
|
||||||
|
@ -93,7 +97,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __lshrdi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option<u64> {
|
fn __lshrdi3(f: extern "C" fn(u64, u32) -> u64, a: U64, b: u32) -> Option<u64> {
|
||||||
let a = a.0;
|
let a = a.0;
|
||||||
if b >= 64 {
|
if b >= 64 {
|
||||||
None
|
None
|
||||||
|
@ -114,7 +118,7 @@ mod tests_i128 {
|
||||||
|
|
||||||
// NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64)
|
// NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64)
|
||||||
check! {
|
check! {
|
||||||
fn __ashlti3(f: extern fn(u128, u32) -> u128, a: U128, b: u32) -> Option<u128> {
|
fn __ashlti3(f: extern "C" fn(u128, u32) -> u128, a: U128, b: u32) -> Option<u128> {
|
||||||
let a = a.0;
|
let a = a.0;
|
||||||
if b >= 64 {
|
if b >= 64 {
|
||||||
None
|
None
|
||||||
|
@ -123,7 +127,7 @@ mod tests_i128 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __ashrti3(f: extern fn(i128, u32) -> i128, a: I128, b: u32) -> Option<i128> {
|
fn __ashrti3(f: extern "C" fn(i128, u32) -> i128, a: I128, b: u32) -> Option<i128> {
|
||||||
let a = a.0;
|
let a = a.0;
|
||||||
if b >= 64 {
|
if b >= 64 {
|
||||||
None
|
None
|
||||||
|
@ -132,7 +136,7 @@ mod tests_i128 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __lshrti3(f: extern fn(u128, u32) -> u128, a: U128, b: u32) -> Option<u128> {
|
fn __lshrti3(f: extern "C" fn(u128, u32) -> u128, a: U128, b: u32) -> Option<u128> {
|
||||||
let a = a.0;
|
let a = a.0;
|
||||||
if b >= 128 {
|
if b >= 128 {
|
||||||
None
|
None
|
||||||
|
|
|
@ -3,7 +3,8 @@ use int::{Int, LargeInt};
|
||||||
|
|
||||||
/// Returns `n / d`
|
/// Returns `n / d`
|
||||||
#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
|
#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)]
|
||||||
|
#[cfg_attr(all(not(test), target_arch = "arm"), inline(always))]
|
||||||
pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
|
pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
|
||||||
// Special cases
|
// Special cases
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
|
@ -79,15 +80,15 @@ pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 {
|
||||||
#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
|
#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 {
|
pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 {
|
||||||
#[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))]
|
#[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn __udivsi3(n: u32, d: u32) -> u32;
|
fn __udivsi3(n: u32, d: u32) -> u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
let q = match () {
|
let q = match () {
|
||||||
#[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))]
|
#[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))]
|
||||||
() => unsafe { __udivsi3(n, d) },
|
() => unsafe { __udivsi3(n, d) },
|
||||||
#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))]
|
#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
|
||||||
() => __udivsi3(n, d),
|
() => __udivsi3(n, d),
|
||||||
};
|
};
|
||||||
if let Some(rem) = rem {
|
if let Some(rem) = rem {
|
||||||
|
@ -317,7 +318,7 @@ mod tests {
|
||||||
use qc::{U32, U64};
|
use qc::{U32, U64};
|
||||||
|
|
||||||
check! {
|
check! {
|
||||||
fn __udivdi3(f: extern fn(u64, u64) -> u64, n: U64, d: U64) -> Option<u64> {
|
fn __udivdi3(f: extern "C" fn(u64, u64) -> u64, n: U64, d: U64) -> Option<u64> {
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
None
|
None
|
||||||
|
@ -326,7 +327,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __umoddi3(f: extern fn(u64, u64) -> u64, n: U64, d: U64) -> Option<u64> {
|
fn __umoddi3(f: extern "C" fn(u64, u64) -> u64, n: U64, d: U64) -> Option<u64> {
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
None
|
None
|
||||||
|
@ -335,7 +336,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __udivmoddi4(f: extern fn(u64, u64, Option<&mut u64>) -> u64,
|
fn __udivmoddi4(f: extern "C" fn(u64, u64, Option<&mut u64>) -> u64,
|
||||||
n: U64,
|
n: U64,
|
||||||
d: U64) -> Option<(u64, u64)> {
|
d: U64) -> Option<(u64, u64)> {
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
|
@ -348,7 +349,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __udivsi3(f: extern fn(u32, u32) -> u32, n: U32, d: U32) -> Option<u32> {
|
fn __udivsi3(f: extern "C" fn(u32, u32) -> u32, n: U32, d: U32) -> Option<u32> {
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
None
|
None
|
||||||
|
@ -357,7 +358,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __umodsi3(f: extern fn(u32, u32) -> u32, n: U32, d: U32) -> Option<u32> {
|
fn __umodsi3(f: extern "C" fn(u32, u32) -> u32, n: U32, d: U32) -> Option<u32> {
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
if d == 0 {
|
if d == 0 {
|
||||||
None
|
None
|
||||||
|
@ -366,7 +367,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __udivmodsi4(f: extern fn(u32, u32, Option<&mut u32>) -> u32,
|
fn __udivmodsi4(f: extern "C" fn(u32, u32, Option<&mut u32>) -> u32,
|
||||||
n: U32,
|
n: U32,
|
||||||
d: U32) -> Option<(u32, u32)> {
|
d: U32) -> Option<(u32, u32)> {
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
|
@ -390,7 +391,7 @@ mod tests_i128 {
|
||||||
use qc::U128;
|
use qc::U128;
|
||||||
|
|
||||||
check! {
|
check! {
|
||||||
fn __udivti3(f: extern fn(u128, u128) -> u128,
|
fn __udivti3(f: extern "C" fn(u128, u128) -> u128,
|
||||||
n: U128,
|
n: U128,
|
||||||
d: U128) -> Option<u128> {
|
d: U128) -> Option<u128> {
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
|
@ -401,7 +402,7 @@ mod tests_i128 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __umodti3(f: extern fn(u128, u128) -> u128,
|
fn __umodti3(f: extern "C" fn(u128, u128) -> u128,
|
||||||
n: U128,
|
n: U128,
|
||||||
d: U128) -> Option<u128> {
|
d: U128) -> Option<u128> {
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
|
@ -412,7 +413,7 @@ mod tests_i128 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __udivmodti4(f: extern fn(u128, u128, Option<&mut u128>) -> u128,
|
fn __udivmodti4(f: extern "C" fn(u128, u128, Option<&mut u128>) -> u128,
|
||||||
n: U128,
|
n: U128,
|
||||||
d: U128) -> Option<u128> {
|
d: U128) -> Option<u128> {
|
||||||
let (n, d) = (n.0, d.0);
|
let (n, d) = (n.0, d.0);
|
||||||
|
|
|
@ -28,6 +28,10 @@
|
||||||
// NOTE cfg(all(feature = "c", ..)) indicate that compiler-rt provides an arch optimized
|
// NOTE cfg(all(feature = "c", ..)) indicate that compiler-rt provides an arch optimized
|
||||||
// implementation of that intrinsic and we'll prefer to use that
|
// implementation of that intrinsic and we'll prefer to use that
|
||||||
|
|
||||||
|
// NOTE(aapcs, aeabi, arm) ARM targets use intrinsics named __aeabi_* instead of the intrinsics
|
||||||
|
// that follow "x86 naming convention" (e.g. addsf3). Those aeabi intrinsics must adhere to the
|
||||||
|
// AAPCS calling convention (`extern "aapcs"`) because that's how LLVM will call them.
|
||||||
|
|
||||||
// TODO(rust-lang/rust#37029) use e.g. checked_div(_).unwrap_or_else(|| abort())
|
// TODO(rust-lang/rust#37029) use e.g. checked_div(_).unwrap_or_else(|| abort())
|
||||||
macro_rules! udiv {
|
macro_rules! udiv {
|
||||||
($a:expr, $b:expr) => {
|
($a:expr, $b:expr) => {
|
||||||
|
|
|
@ -240,7 +240,8 @@ arbitrary_float!(F64: f64);
|
||||||
// fails.
|
// fails.
|
||||||
macro_rules! check {
|
macro_rules! check {
|
||||||
($(
|
($(
|
||||||
fn $name:ident($f:ident: extern fn($($farg:ty),*) -> $fret:ty,
|
$(#[$cfg:meta])*
|
||||||
|
fn $name:ident($f:ident: extern $abi:tt fn($($farg:ty),*) -> $fret:ty,
|
||||||
$($arg:ident: $t:ty),*)
|
$($arg:ident: $t:ty),*)
|
||||||
-> Option<$ret:ty>
|
-> Option<$ret:ty>
|
||||||
{
|
{
|
||||||
|
@ -248,7 +249,8 @@ macro_rules! check {
|
||||||
}
|
}
|
||||||
)*) => (
|
)*) => (
|
||||||
$(
|
$(
|
||||||
fn $name($f: extern fn($($farg),*) -> $fret,
|
$(#[$cfg])*
|
||||||
|
fn $name($f: extern $abi fn($($farg),*) -> $fret,
|
||||||
$($arg: $t),*) -> Option<$ret> {
|
$($arg: $t),*) -> Option<$ret> {
|
||||||
$($code)*
|
$($code)*
|
||||||
}
|
}
|
||||||
|
@ -260,6 +262,7 @@ macro_rules! check {
|
||||||
use quickcheck::TestResult;
|
use quickcheck::TestResult;
|
||||||
|
|
||||||
$(
|
$(
|
||||||
|
$(#[$cfg])*
|
||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
fn my_check($($arg:$t),*) -> TestResult {
|
fn my_check($($arg:$t),*) -> TestResult {
|
||||||
|
|
Loading…
Reference in New Issue