intrinsics: try to return everything via {u,i}128ret to match LLVM
on suggestion by nagisa.
This commit is contained in:
parent
92163f1c5e
commit
d71223a6c5
@ -19,7 +19,7 @@
|
||||
#![feature(staged_api)]
|
||||
#![cfg_attr(any(target_pointer_width="32", target_pointer_width="16", target_os="windows",
|
||||
target_arch="mips64"),
|
||||
feature(core_intrinsics, core_float))]
|
||||
feature(core_intrinsics, core_float, repr_simd))]
|
||||
#![feature(associated_consts)]
|
||||
#![cfg_attr(not(stage0), feature(i128_type))]
|
||||
|
||||
@ -46,6 +46,29 @@ pub mod reimpls {
|
||||
#[cfg(not(stage0))]
|
||||
type i128_ = i128;
|
||||
|
||||
// Unfortunately, every tool on Windows expects different
|
||||
// calling conventions to be met for int128. We need to
|
||||
// match here what LLVM expects from us. This is only
|
||||
// required for the return type!
|
||||
#[cfg(not(stage0))]
|
||||
#[cfg(windows)]
|
||||
#[repr(simd)]
|
||||
pub struct u64x2(u64, u64);
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[cfg(windows)]
|
||||
type u128ret = u64x2;
|
||||
|
||||
#[cfg(any(not(windows),stage0))]
|
||||
type u128ret = u128_;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[cfg(windows)]
|
||||
type i128ret = u64x2;
|
||||
|
||||
#[cfg(any(not(windows),stage0))]
|
||||
type i128ret = i128_;
|
||||
|
||||
macro_rules! ashl {
|
||||
($a:expr, $b:expr, $ty:ty) => {{
|
||||
let (a, b) = ($a, $b);
|
||||
@ -114,24 +137,27 @@ pub mod reimpls {
|
||||
|
||||
|
||||
#[export_name="__lshrti3"]
|
||||
pub extern "C" fn lshr(a: u128_, b: u128_) -> u128_ {
|
||||
lshr!(a, b, u128_)
|
||||
pub extern "C" fn lshr(a: u128_, b: u128_) -> u128ret {
|
||||
lshr!(a, b, u128_).to_ret()
|
||||
}
|
||||
|
||||
#[export_name="__udivmodti4"]
|
||||
pub extern "C" fn u128_div_mod_export(n: u128_, d: u128_, rem: *mut u128_) -> u128ret {
|
||||
u128_div_mod(n, d, rem).to_ret()
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[export_name="__udivmodti4"]
|
||||
pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ {
|
||||
pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128ret {
|
||||
unsafe {
|
||||
if !rem.is_null() {
|
||||
*rem = unchecked_rem(n, d);
|
||||
}
|
||||
unchecked_div(n, d)
|
||||
unchecked_div(n, d).to_ret()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[export_name="__udivmodti4"]
|
||||
pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ {
|
||||
pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128 {
|
||||
// Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide
|
||||
unsafe {
|
||||
// special cases, X is unknown, K != 0
|
||||
@ -297,43 +323,50 @@ pub mod reimpls {
|
||||
}
|
||||
|
||||
#[export_name="__umodti3"]
|
||||
pub extern "C" fn u128_mod(a: u128_, b: u128_) -> u128_ {
|
||||
pub extern "C" fn u128_mod(a: u128_, b: u128_) -> u128ret {
|
||||
unsafe {
|
||||
let mut r = ::core::mem::zeroed();
|
||||
u128_div_mod(a, b, &mut r);
|
||||
r
|
||||
r.to_ret()
|
||||
}
|
||||
}
|
||||
|
||||
#[export_name="__modti3"]
|
||||
pub extern "C" fn i128_mod(a: i128_, b: i128_) -> i128_ {
|
||||
pub extern "C" fn i128_mod(a: i128_, b: i128_) -> i128ret {
|
||||
let b = b.uabs();
|
||||
let sa = a.signum();
|
||||
let a = a.uabs();
|
||||
unsafe {
|
||||
(unsafe {
|
||||
let mut r = ::core::mem::zeroed();
|
||||
u128_div_mod(a, b, &mut r);
|
||||
if sa == -1 { (r as i128_).unchecked_neg() } else { r as i128_ }
|
||||
}
|
||||
}).to_ret()
|
||||
}
|
||||
|
||||
#[export_name="__divti3"]
|
||||
pub extern "C" fn i128_div(a: i128_, b: i128_) -> i128_ {
|
||||
pub extern "C" fn i128_div(a: i128_, b: i128_) -> i128ret {
|
||||
let sa = a.signum();
|
||||
let sb = b.signum();
|
||||
let a = a.uabs();
|
||||
let b = b.uabs();
|
||||
let sr = sa.wrapping_mul(sb); // sign of quotient
|
||||
if sr == -1 {
|
||||
(if sr == -1 {
|
||||
(u128_div_mod(a, b, ptr::null_mut()) as i128_).unchecked_neg()
|
||||
} else {
|
||||
u128_div_mod(a, b, ptr::null_mut()) as i128_
|
||||
}
|
||||
}).to_ret()
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[export_name="__udivti3"]
|
||||
pub extern "C" fn u128_div(a: u128_, b: u128_) -> u128_ {
|
||||
u128_div_mod(a, b, ptr::null_mut())
|
||||
pub extern "C" fn u128_div(a: u128_, b: u128_) -> u128ret {
|
||||
(a / b).to_ret()
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[export_name="__udivti3"]
|
||||
pub extern "C" fn u128_div(a: u128_, b: u128_) -> u128ret {
|
||||
u128_div_mod(a, b, ptr::null_mut()).to_ret()
|
||||
}
|
||||
|
||||
macro_rules! mulo {
|
||||
@ -345,13 +378,13 @@ pub mod reimpls {
|
||||
if b != 0 && b != 1 {
|
||||
*overflow = 1;
|
||||
}
|
||||
return result;
|
||||
return result.to_ret();
|
||||
}
|
||||
if b == <$ty>::min_value() {
|
||||
if a != 0 && a != 1 {
|
||||
*overflow = 1;
|
||||
}
|
||||
return result;
|
||||
return result.to_ret();
|
||||
}
|
||||
|
||||
let sa = a.signum();
|
||||
@ -359,7 +392,7 @@ pub mod reimpls {
|
||||
let sb = b.signum();
|
||||
let abs_b = b.iabs();
|
||||
if abs_a < 2 || abs_b < 2 {
|
||||
return result;
|
||||
return result.to_ret();
|
||||
}
|
||||
unsafe {
|
||||
if sa == sb {
|
||||
@ -372,27 +405,30 @@ pub mod reimpls {
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
result.to_ret()
|
||||
}}
|
||||
}
|
||||
|
||||
// FIXME: i32 here should be c_int.
|
||||
#[export_name="__muloti4"]
|
||||
pub extern "C" fn i128_mul_oflow(a: i128_, b: i128_, o: &mut i32) -> i128_ {
|
||||
pub extern "C" fn i128_mul_oflow(a: i128_, b: i128_, o: &mut i32) -> i128ret {
|
||||
mulo!(a, b, o, i128_)
|
||||
}
|
||||
|
||||
pub trait LargeInt {
|
||||
type LowHalf;
|
||||
type HighHalf;
|
||||
type Ret;
|
||||
|
||||
fn low(self) -> Self::LowHalf;
|
||||
fn high(self) -> Self::HighHalf;
|
||||
fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self;
|
||||
fn to_ret(self) -> Self::Ret;
|
||||
}
|
||||
impl LargeInt for u64 {
|
||||
type LowHalf = u32;
|
||||
type HighHalf = u32;
|
||||
type Ret = u64;
|
||||
|
||||
fn low(self) -> u32 {
|
||||
self as u32
|
||||
@ -403,10 +439,14 @@ pub mod reimpls {
|
||||
fn from_parts(low: u32, high: u32) -> u64 {
|
||||
low as u64 | (high as u64).wrapping_shl(32)
|
||||
}
|
||||
fn to_ret(self) -> u64 {
|
||||
self
|
||||
}
|
||||
}
|
||||
impl LargeInt for i64 {
|
||||
type LowHalf = u32;
|
||||
type HighHalf = i32;
|
||||
type Ret = i64;
|
||||
|
||||
fn low(self) -> u32 {
|
||||
self as u32
|
||||
@ -417,11 +457,15 @@ pub mod reimpls {
|
||||
fn from_parts(low: u32, high: i32) -> i64 {
|
||||
low as i64 | (high as i64).wrapping_shl(32)
|
||||
}
|
||||
fn to_ret(self) -> i64 {
|
||||
self
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
impl LargeInt for u128 {
|
||||
type LowHalf = u64;
|
||||
type HighHalf = u64;
|
||||
type Ret = u128ret;
|
||||
|
||||
fn low(self) -> u64 {
|
||||
self as u64
|
||||
@ -433,11 +477,20 @@ pub mod reimpls {
|
||||
#[repr(C, packed)] struct Parts(u64, u64);
|
||||
unsafe { ::core::mem::transmute(Parts(low, high)) }
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
fn to_ret(self) -> u128ret {
|
||||
self
|
||||
}
|
||||
#[cfg(windows)]
|
||||
fn to_ret(self) -> u128ret {
|
||||
u64x2(self.low(), self.high())
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
impl LargeInt for i128 {
|
||||
type LowHalf = u64;
|
||||
type HighHalf = i64;
|
||||
type Ret = i128ret;
|
||||
|
||||
fn low(self) -> u64 {
|
||||
self as u64
|
||||
@ -448,6 +501,14 @@ pub mod reimpls {
|
||||
fn from_parts(low: u64, high: i64) -> i128 {
|
||||
u128::from_parts(low, high as u64) as i128
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
fn to_ret(self) -> u128ret {
|
||||
self
|
||||
}
|
||||
#[cfg(windows)]
|
||||
fn to_ret(self) -> i128ret {
|
||||
u64x2(self.low(), self.high() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! mul {
|
||||
@ -481,14 +542,14 @@ pub mod reimpls {
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[export_name="__multi3"]
|
||||
pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128_ {
|
||||
(a as i64).wrapping_mul(b as i64) as i128_
|
||||
pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128ret {
|
||||
((a as i64).wrapping_mul(b as i64) as i128_).to_ret()
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[export_name="__multi3"]
|
||||
pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128_ {
|
||||
mul!(a, b, i128_, i64)
|
||||
pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128ret {
|
||||
mul!(a, b, i128_, i64).to_ret()
|
||||
}
|
||||
|
||||
trait AbsExt: Sized {
|
||||
@ -566,11 +627,11 @@ pub mod reimpls {
|
||||
let exponent = $from.get_exponent();
|
||||
let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK;
|
||||
let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT;
|
||||
if sign == -1.0 || exponent < 0 { return 0; }
|
||||
if sign == -1.0 || exponent < 0 { return (0 as u128_).to_ret(); }
|
||||
if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 {
|
||||
return !0;
|
||||
return (!(0 as u128_)).to_ret();
|
||||
}
|
||||
if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 {
|
||||
(if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 {
|
||||
(mantissa as $outty)
|
||||
.wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32)
|
||||
.wrapping_sub(exponent) as u32)
|
||||
@ -578,17 +639,17 @@ pub mod reimpls {
|
||||
(mantissa as $outty)
|
||||
.wrapping_shl(exponent.wrapping_sub(
|
||||
<$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32)
|
||||
}
|
||||
}).to_ret()
|
||||
} }
|
||||
}
|
||||
|
||||
#[export_name="__fixunsdfti"]
|
||||
pub extern "C" fn f64_as_u128(a: f64) -> u128_ {
|
||||
pub extern "C" fn f64_as_u128(a: f64) -> u128ret {
|
||||
float_as_unsigned!(a, f64, u128_)
|
||||
}
|
||||
|
||||
#[export_name="__fixunssfti"]
|
||||
pub extern "C" fn f32_as_u128(a: f32) -> u128_ {
|
||||
pub extern "C" fn f32_as_u128(a: f32) -> u128ret {
|
||||
float_as_unsigned!(a, f32, u128_)
|
||||
}
|
||||
|
||||
@ -601,9 +662,9 @@ pub mod reimpls {
|
||||
let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK;
|
||||
let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT;
|
||||
|
||||
if exponent < 0 { return 0; }
|
||||
if exponent < 0 { return (0 as i128_).to_ret(); }
|
||||
if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 {
|
||||
return if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() };
|
||||
return (if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() }).to_ret();
|
||||
}
|
||||
let r = if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 {
|
||||
(mantissa as $outty)
|
||||
@ -614,17 +675,17 @@ pub mod reimpls {
|
||||
.wrapping_shl(exponent.wrapping_sub(
|
||||
<$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32)
|
||||
};
|
||||
if sign >= 0.0 { r } else { r.unchecked_neg() }
|
||||
(if sign >= 0.0 { r } else { r.unchecked_neg() }).to_ret()
|
||||
}}
|
||||
}
|
||||
|
||||
#[export_name="__fixdfti"]
|
||||
pub extern "C" fn f64_as_i128(a: f64) -> i128_ {
|
||||
pub extern "C" fn f64_as_i128(a: f64) -> i128ret {
|
||||
float_as_signed!(a, f64, i128_)
|
||||
}
|
||||
|
||||
#[export_name="__fixsfti"]
|
||||
pub extern "C" fn f32_as_i128(a: f32) -> i128_ {
|
||||
pub extern "C" fn f32_as_i128(a: f32) -> i128ret {
|
||||
float_as_signed!(a, f32, i128_)
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user