2016-07-24 21:42:11 -05:00
|
|
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2016-09-28 15:55:26 -05:00
|
|
|
#![feature(compiler_builtins)]
|
2016-07-24 21:42:11 -05:00
|
|
|
#![no_std]
|
2016-09-28 15:55:26 -05:00
|
|
|
#![compiler_builtins]
|
2016-09-13 14:27:26 -05:00
|
|
|
#![unstable(feature = "compiler_builtins_lib",
|
|
|
|
reason = "internal implementation detail of rustc right now",
|
|
|
|
issue = "0")]
|
2016-07-24 21:42:11 -05:00
|
|
|
#![crate_name = "compiler_builtins"]
|
|
|
|
#![crate_type = "rlib"]
|
2016-09-13 14:27:26 -05:00
|
|
|
#![feature(staged_api)]
|
2016-12-04 00:58:49 -06:00
|
|
|
#![cfg_attr(any(target_pointer_width="32", target_pointer_width="16", target_os="windows",
|
|
|
|
target_arch="mips64"),
|
2016-12-11 21:56:00 -06:00
|
|
|
feature(core_intrinsics, core_float, repr_simd))]
|
2016-10-02 15:01:57 -05:00
|
|
|
#![feature(associated_consts)]
|
|
|
|
#![cfg_attr(not(stage0), feature(i128_type))]
|
|
|
|
|
|
|
|
#![allow(non_camel_case_types, unused_variables)]
|
|
|
|
|
2016-12-04 00:58:49 -06:00
|
|
|
#[cfg(any(target_pointer_width="32", target_pointer_width="16", target_os="windows",
|
|
|
|
target_arch="mips64"))]
|
2016-10-02 15:01:57 -05:00
|
|
|
pub mod reimpls {
|
2016-11-24 17:08:40 -06:00
|
|
|
|
2016-10-02 15:01:57 -05:00
|
|
|
#![allow(unused_comparisons)]
|
2016-11-24 17:08:40 -06:00
|
|
|
|
|
|
|
use core::intrinsics::unchecked_div;
|
|
|
|
use core::intrinsics::unchecked_rem;
|
|
|
|
use core::ptr;
|
|
|
|
|
2016-10-02 15:01:57 -05:00
|
|
|
// C API is expected to tolerate some amount of size mismatch in ABI. Hopefully the amount of
|
|
|
|
// handling is sufficient for bootstrapping.
|
|
|
|
#[cfg(stage0)]
|
|
|
|
type u128_ = u64;
|
|
|
|
#[cfg(stage0)]
|
|
|
|
type i128_ = i64;
|
|
|
|
#[cfg(not(stage0))]
|
|
|
|
type u128_ = u128;
|
|
|
|
#[cfg(not(stage0))]
|
|
|
|
type i128_ = i128;
|
|
|
|
|
2016-12-11 21:56:00 -06:00
|
|
|
// 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_;
|
|
|
|
|
2016-10-02 15:01:57 -05:00
|
|
|
macro_rules! ashl {
|
|
|
|
($a:expr, $b:expr, $ty:ty) => {{
|
|
|
|
let (a, b) = ($a, $b);
|
|
|
|
let bits = (::core::mem::size_of::<$ty>() * 8) as $ty;
|
2016-12-08 12:02:22 -06:00
|
|
|
let half_bits = bits >> 1;
|
2016-10-02 15:01:57 -05:00
|
|
|
if b & half_bits != 0 {
|
2016-12-08 12:02:22 -06:00
|
|
|
<$ty>::from_parts(0, a.low().wrapping_shl(
|
|
|
|
b.wrapping_sub(half_bits) as u32))
|
2016-10-02 15:01:57 -05:00
|
|
|
} else if b == 0 {
|
|
|
|
a
|
|
|
|
} else {
|
2016-12-08 12:02:22 -06:00
|
|
|
<$ty>::from_parts(a.low().wrapping_shl(b as u32),
|
|
|
|
a.high().wrapping_shl(b as u32)
|
|
|
|
| a.low()
|
|
|
|
.wrapping_shr(half_bits.wrapping_sub(b) as u32))
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[export_name="__ashlti3"]
|
2016-12-07 09:28:45 -06:00
|
|
|
pub extern "C" fn shl(a: u128_, b: u128_) -> u128_ {
|
2016-10-02 15:01:57 -05:00
|
|
|
ashl!(a, b, u128_)
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! ashr {
|
|
|
|
($a: expr, $b: expr, $ty:ty) => {{
|
|
|
|
let (a, b) = ($a, $b);
|
|
|
|
let bits = (::core::mem::size_of::<$ty>() * 8) as $ty;
|
2016-12-05 17:48:54 -06:00
|
|
|
let half_bits = bits >> 1;
|
2016-10-02 15:01:57 -05:00
|
|
|
if b & half_bits != 0 {
|
2016-12-08 12:02:22 -06:00
|
|
|
<$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32)
|
|
|
|
as <$ty as LargeInt>::LowHalf,
|
|
|
|
a.high().wrapping_shr(half_bits.wrapping_sub(1) as u32))
|
2016-10-02 15:01:57 -05:00
|
|
|
} else if b == 0 {
|
|
|
|
a
|
|
|
|
} else {
|
|
|
|
let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf;
|
2016-12-08 12:02:22 -06:00
|
|
|
<$ty>::from_parts(high_unsigned.wrapping_shl(half_bits.wrapping_sub(b) as u32)
|
|
|
|
| a.low().wrapping_shr(b as u32),
|
|
|
|
a.high().wrapping_shr(b as u32))
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[export_name="__ashrti3"]
|
2016-12-07 09:28:45 -06:00
|
|
|
pub extern "C" fn shr(a: i128_, b: i128_) -> i128_ {
|
2016-10-02 15:01:57 -05:00
|
|
|
ashr!(a, b, i128_)
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! lshr {
|
|
|
|
($a: expr, $b: expr, $ty:ty) => {{
|
|
|
|
let (a, b) = ($a, $b);
|
|
|
|
let bits = (::core::mem::size_of::<$ty>() * 8) as $ty;
|
2016-12-05 17:48:54 -06:00
|
|
|
let half_bits = bits >> 1;
|
2016-10-02 15:01:57 -05:00
|
|
|
if b & half_bits != 0 {
|
2016-12-08 12:02:22 -06:00
|
|
|
<$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32), 0)
|
2016-10-02 15:01:57 -05:00
|
|
|
} else if b == 0 {
|
|
|
|
a
|
|
|
|
} else {
|
2016-12-08 12:02:22 -06:00
|
|
|
<$ty>::from_parts(a.high().wrapping_shl(half_bits.wrapping_sub(b) as u32)
|
|
|
|
| a.low().wrapping_shr(b as u32),
|
|
|
|
a.high().wrapping_shr(b as u32))
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[export_name="__lshrti3"]
|
2016-12-11 21:56:00 -06:00
|
|
|
pub extern "C" fn lshr(a: u128_, b: u128_) -> u128ret {
|
|
|
|
lshr!(a, b, u128_).to_ret()
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[export_name="__udivmodti4"]
|
2016-12-11 21:56:00 -06:00
|
|
|
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)]
|
|
|
|
pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128ret {
|
2016-10-02 15:01:57 -05:00
|
|
|
unsafe {
|
|
|
|
if !rem.is_null() {
|
2016-11-24 17:08:40 -06:00
|
|
|
*rem = unchecked_rem(n, d);
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
2016-12-11 21:56:00 -06:00
|
|
|
unchecked_div(n, d).to_ret()
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(stage0))]
|
2016-12-11 21:56:00 -06:00
|
|
|
pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128 {
|
2016-11-24 17:08:40 -06:00
|
|
|
// Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide
|
2016-10-02 15:01:57 -05:00
|
|
|
unsafe {
|
2016-11-24 17:08:40 -06:00
|
|
|
// special cases, X is unknown, K != 0
|
2016-10-02 15:01:57 -05:00
|
|
|
if n.high() == 0 {
|
|
|
|
if d.high() == 0 {
|
|
|
|
// 0 X
|
|
|
|
// ---
|
|
|
|
// 0 X
|
|
|
|
if !rem.is_null() {
|
2016-11-24 17:08:40 -06:00
|
|
|
*rem = u128::from(unchecked_rem(n.low(), d.low()));
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
2016-11-24 17:08:40 -06:00
|
|
|
return u128::from(unchecked_div(n.low(), d.low()));
|
2016-10-02 15:01:57 -05:00
|
|
|
} else {
|
|
|
|
// 0 X
|
|
|
|
// ---
|
|
|
|
// K X
|
|
|
|
if !rem.is_null() {
|
|
|
|
*rem = n;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut sr;
|
|
|
|
let mut q;
|
|
|
|
let mut r;
|
|
|
|
|
|
|
|
if d.low() == 0 {
|
|
|
|
if d.high() == 0 {
|
|
|
|
// K X
|
|
|
|
// ---
|
|
|
|
// 0 0
|
2016-11-24 17:08:40 -06:00
|
|
|
if !rem.is_null() {
|
|
|
|
*rem = u128::from(unchecked_rem(n.high(), d.low()));
|
|
|
|
}
|
|
|
|
return u128::from(unchecked_div(n.high(), d.low()));
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if n.low() == 0 {
|
|
|
|
// K 0
|
|
|
|
// ---
|
|
|
|
// K 0
|
|
|
|
if !rem.is_null() {
|
2016-11-24 17:08:40 -06:00
|
|
|
*rem = u128::from_parts(0, unchecked_rem(n.high(), d.high()));
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
2016-11-24 17:08:40 -06:00
|
|
|
return u128::from(unchecked_div(n.high(), d.high()));
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// K K
|
|
|
|
// ---
|
|
|
|
// K 0
|
|
|
|
|
|
|
|
if d.high().is_power_of_two() {
|
|
|
|
if !rem.is_null() {
|
2016-12-08 12:02:22 -06:00
|
|
|
*rem = u128::from_parts(n.low(),
|
|
|
|
n.high() & (d.high().wrapping_sub(1)));
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
2016-12-08 12:02:22 -06:00
|
|
|
return u128::from(n.high().wrapping_shr(d.high().trailing_zeros()));
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
|
2016-11-24 17:08:40 -06:00
|
|
|
// K K
|
|
|
|
// ---
|
|
|
|
// K 0
|
2016-10-02 15:01:57 -05:00
|
|
|
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
|
|
|
|
|
|
|
|
// D > N
|
|
|
|
if sr > 64 - 2 {
|
|
|
|
if !rem.is_null() {
|
|
|
|
*rem = n;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-08 12:02:22 -06:00
|
|
|
sr = sr.wrapping_add(1);
|
2016-10-02 15:01:57 -05:00
|
|
|
|
2016-11-24 17:08:40 -06:00
|
|
|
// 1 <= sr <= u64::bits() - 1
|
2016-12-08 12:02:22 -06:00
|
|
|
q = n.wrapping_shl(64u32.wrapping_sub(sr));
|
|
|
|
r = n.wrapping_shr(sr);
|
2016-10-02 15:01:57 -05:00
|
|
|
} else {
|
|
|
|
if d.high() == 0 {
|
|
|
|
// K X
|
|
|
|
// ---
|
|
|
|
// 0 K
|
|
|
|
if d.low().is_power_of_two() {
|
|
|
|
if !rem.is_null() {
|
2016-12-08 12:02:22 -06:00
|
|
|
*rem = u128::from(n.low() & (d.low().wrapping_sub(1)));
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if d.low() == 1 {
|
|
|
|
return n;
|
|
|
|
} else {
|
|
|
|
let sr = d.low().trailing_zeros();
|
2016-12-08 12:02:22 -06:00
|
|
|
return n.wrapping_shr(sr);
|
2016-10-02 15:01:57 -05:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-12-08 12:02:22 -06:00
|
|
|
sr = (1 + 64u32)
|
|
|
|
.wrapping_add(d.low().leading_zeros())
|
|
|
|
.wrapping_sub(n.high().leading_zeros());
|
2016-10-02 15:01:57 -05:00
|
|
|
|
|
|
|
// 2 <= sr <= u64::bits() - 1
|
2016-12-08 12:02:22 -06:00
|
|
|
q = n.wrapping_shl(128u32.wrapping_sub(sr));
|
|
|
|
r = n.wrapping_shr(sr);
|
2016-11-24 17:08:40 -06:00
|
|
|
// FIXME the C compiler-rt implementation has something here
|
|
|
|
// that looks like a speed optimisation.
|
|
|
|
// It would be worth a try to port it to Rust too and
|
|
|
|
// compare the speed.
|
2016-10-02 15:01:57 -05:00
|
|
|
} else {
|
|
|
|
// K X
|
|
|
|
// ---
|
|
|
|
// K K
|
|
|
|
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
|
|
|
|
|
|
|
|
// D > N
|
|
|
|
if sr > 64 - 1 {
|
|
|
|
if !rem.is_null() {
|
|
|
|
*rem = n;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-08 12:02:22 -06:00
|
|
|
sr = sr.wrapping_add(1);
|
2016-10-02 15:01:57 -05:00
|
|
|
|
|
|
|
// 1 <= sr <= u32::bits()
|
2016-12-08 12:02:22 -06:00
|
|
|
q = n.wrapping_shl(128u32.wrapping_sub(sr));
|
|
|
|
r = n.wrapping_shr(sr);
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not a special case
|
|
|
|
// q and r are initialized with
|
|
|
|
// q = n << (u64::bits() - sr)
|
|
|
|
// r = n >> sr
|
|
|
|
// 1 <= sr <= u64::bits() - 1
|
|
|
|
let mut carry = 0;
|
|
|
|
|
2016-12-07 09:28:45 -06:00
|
|
|
// FIXME: replace this with a for loop
|
|
|
|
// (atm not doable as this generates call to
|
|
|
|
// eh_personality when optimisations are turned off,
|
|
|
|
// which in turn gives a linker error in later
|
|
|
|
// compilation steps)
|
|
|
|
while sr > 0 {
|
2016-10-02 15:01:57 -05:00
|
|
|
// r:q = ((r:q) << 1) | carry
|
2016-12-08 12:02:22 -06:00
|
|
|
r = r.wrapping_shl(1) | q.wrapping_shr(128 - 1);
|
|
|
|
q = q.wrapping_shl(1) | carry as u128;
|
2016-10-02 15:01:57 -05:00
|
|
|
|
|
|
|
// carry = 0
|
|
|
|
// if r >= d {
|
|
|
|
// r -= d;
|
|
|
|
// carry = 1;
|
|
|
|
// }
|
2016-12-08 12:02:22 -06:00
|
|
|
let s = ((d.wrapping_sub(r).wrapping_sub(1)) as i128).wrapping_shr(128 - 1);
|
2016-10-02 15:01:57 -05:00
|
|
|
carry = (s & 1) as u64;
|
2016-12-08 12:02:22 -06:00
|
|
|
r = r.wrapping_sub(d & s as u128);
|
|
|
|
sr = sr.wrapping_sub(1);
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if !rem.is_null() {
|
|
|
|
*rem = r;
|
|
|
|
}
|
2016-12-08 12:02:22 -06:00
|
|
|
(q.wrapping_shl(1)) | carry as u128
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[export_name="__umodti3"]
|
2016-12-11 21:56:00 -06:00
|
|
|
pub extern "C" fn u128_mod(a: u128_, b: u128_) -> u128ret {
|
2016-10-02 15:01:57 -05:00
|
|
|
unsafe {
|
|
|
|
let mut r = ::core::mem::zeroed();
|
|
|
|
u128_div_mod(a, b, &mut r);
|
2016-12-11 21:56:00 -06:00
|
|
|
r.to_ret()
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[export_name="__modti3"]
|
2016-12-11 21:56:00 -06:00
|
|
|
pub extern "C" fn i128_mod(a: i128_, b: i128_) -> i128ret {
|
2016-11-24 19:33:35 -06:00
|
|
|
let b = b.uabs();
|
2016-10-02 15:01:57 -05:00
|
|
|
let sa = a.signum();
|
2016-11-24 19:33:35 -06:00
|
|
|
let a = a.uabs();
|
2016-12-11 21:56:00 -06:00
|
|
|
(unsafe {
|
2016-10-02 15:01:57 -05:00
|
|
|
let mut r = ::core::mem::zeroed();
|
2016-11-24 19:33:35 -06:00
|
|
|
u128_div_mod(a, b, &mut r);
|
2016-12-08 12:02:22 -06:00
|
|
|
if sa == -1 { (r as i128_).unchecked_neg() } else { r as i128_ }
|
2016-12-11 21:56:00 -06:00
|
|
|
}).to_ret()
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[export_name="__divti3"]
|
2016-12-11 21:56:00 -06:00
|
|
|
pub extern "C" fn i128_div(a: i128_, b: i128_) -> i128ret {
|
2016-10-02 15:01:57 -05:00
|
|
|
let sa = a.signum();
|
|
|
|
let sb = b.signum();
|
2016-11-24 19:33:35 -06:00
|
|
|
let a = a.uabs();
|
|
|
|
let b = b.uabs();
|
2016-12-08 12:02:22 -06:00
|
|
|
let sr = sa.wrapping_mul(sb); // sign of quotient
|
2016-12-11 21:56:00 -06:00
|
|
|
(if sr == -1 {
|
2016-12-08 12:02:22 -06:00
|
|
|
(u128_div_mod(a, b, ptr::null_mut()) as i128_).unchecked_neg()
|
2016-11-24 17:08:40 -06:00
|
|
|
} else {
|
2016-11-24 19:33:35 -06:00
|
|
|
u128_div_mod(a, b, ptr::null_mut()) as i128_
|
2016-12-11 21:56:00 -06:00
|
|
|
}).to_ret()
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
|
2016-12-11 21:56:00 -06:00
|
|
|
#[cfg(stage0)]
|
|
|
|
#[export_name="__udivti3"]
|
|
|
|
pub extern "C" fn u128_div(a: u128_, b: u128_) -> u128ret {
|
|
|
|
(a / b).to_ret()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(stage0))]
|
2016-10-02 15:01:57 -05:00
|
|
|
#[export_name="__udivti3"]
|
2016-12-11 21:56:00 -06:00
|
|
|
pub extern "C" fn u128_div(a: u128_, b: u128_) -> u128ret {
|
|
|
|
u128_div_mod(a, b, ptr::null_mut()).to_ret()
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! mulo {
|
|
|
|
($a:expr, $b:expr, $o: expr, $ty: ty) => {{
|
|
|
|
let (a, b, overflow) = ($a, $b, $o);
|
|
|
|
*overflow = 0;
|
|
|
|
let result = a.wrapping_mul(b);
|
|
|
|
if a == <$ty>::min_value() {
|
|
|
|
if b != 0 && b != 1 {
|
|
|
|
*overflow = 1;
|
|
|
|
}
|
2016-12-11 21:56:00 -06:00
|
|
|
return result.to_ret();
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
if b == <$ty>::min_value() {
|
|
|
|
if a != 0 && a != 1 {
|
|
|
|
*overflow = 1;
|
|
|
|
}
|
2016-12-11 21:56:00 -06:00
|
|
|
return result.to_ret();
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
|
2016-11-24 17:08:40 -06:00
|
|
|
let sa = a.signum();
|
2016-11-24 19:33:35 -06:00
|
|
|
let abs_a = a.iabs();
|
2016-11-24 17:08:40 -06:00
|
|
|
let sb = b.signum();
|
2016-11-24 19:33:35 -06:00
|
|
|
let abs_b = b.iabs();
|
2016-10-02 15:01:57 -05:00
|
|
|
if abs_a < 2 || abs_b < 2 {
|
2016-12-11 21:56:00 -06:00
|
|
|
return result.to_ret();
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
2016-11-24 17:08:40 -06:00
|
|
|
unsafe {
|
2016-10-02 15:01:57 -05:00
|
|
|
if sa == sb {
|
2016-11-24 17:08:40 -06:00
|
|
|
if abs_a > unchecked_div(<$ty>::max_value(), abs_b) {
|
2016-10-02 15:01:57 -05:00
|
|
|
*overflow = 1;
|
|
|
|
}
|
|
|
|
} else {
|
2016-12-08 12:02:22 -06:00
|
|
|
if abs_a > unchecked_div(<$ty>::min_value(), abs_b.unchecked_neg()) {
|
2016-10-02 15:01:57 -05:00
|
|
|
*overflow = 1;
|
|
|
|
}
|
|
|
|
}
|
2016-11-24 17:08:40 -06:00
|
|
|
}
|
2016-12-11 21:56:00 -06:00
|
|
|
result.to_ret()
|
2016-10-02 15:01:57 -05:00
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: i32 here should be c_int.
|
|
|
|
#[export_name="__muloti4"]
|
2016-12-11 21:56:00 -06:00
|
|
|
pub extern "C" fn i128_mul_oflow(a: i128_, b: i128_, o: &mut i32) -> i128ret {
|
2016-11-24 17:08:40 -06:00
|
|
|
mulo!(a, b, o, i128_)
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub trait LargeInt {
|
|
|
|
type LowHalf;
|
|
|
|
type HighHalf;
|
2016-12-11 21:56:00 -06:00
|
|
|
type Ret;
|
2016-10-02 15:01:57 -05:00
|
|
|
|
|
|
|
fn low(self) -> Self::LowHalf;
|
|
|
|
fn high(self) -> Self::HighHalf;
|
|
|
|
fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self;
|
2016-12-11 21:56:00 -06:00
|
|
|
fn to_ret(self) -> Self::Ret;
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
impl LargeInt for u64 {
|
|
|
|
type LowHalf = u32;
|
|
|
|
type HighHalf = u32;
|
2016-12-11 21:56:00 -06:00
|
|
|
type Ret = u64;
|
2016-10-02 15:01:57 -05:00
|
|
|
|
|
|
|
fn low(self) -> u32 {
|
|
|
|
self as u32
|
|
|
|
}
|
|
|
|
fn high(self) -> u32 {
|
2016-12-08 12:02:22 -06:00
|
|
|
(self.wrapping_shr(32)) as u32
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
fn from_parts(low: u32, high: u32) -> u64 {
|
2016-12-08 12:02:22 -06:00
|
|
|
low as u64 | (high as u64).wrapping_shl(32)
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
2016-12-11 21:56:00 -06:00
|
|
|
fn to_ret(self) -> u64 {
|
|
|
|
self
|
|
|
|
}
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
impl LargeInt for i64 {
|
|
|
|
type LowHalf = u32;
|
|
|
|
type HighHalf = i32;
|
2016-12-11 21:56:00 -06:00
|
|
|
type Ret = i64;
|
2016-10-02 15:01:57 -05:00
|
|
|
|
|
|
|
fn low(self) -> u32 {
|
|
|
|
self as u32
|
|
|
|
}
|
|
|
|
fn high(self) -> i32 {
|
2016-12-08 12:02:22 -06:00
|
|
|
self.wrapping_shr(32) as i32
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
fn from_parts(low: u32, high: i32) -> i64 {
|
2016-12-08 12:02:22 -06:00
|
|
|
low as i64 | (high as i64).wrapping_shl(32)
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
2016-12-11 21:56:00 -06:00
|
|
|
fn to_ret(self) -> i64 {
|
|
|
|
self
|
|
|
|
}
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
#[cfg(not(stage0))]
|
|
|
|
impl LargeInt for u128 {
|
|
|
|
type LowHalf = u64;
|
|
|
|
type HighHalf = u64;
|
2016-12-11 21:56:00 -06:00
|
|
|
type Ret = u128ret;
|
2016-10-02 15:01:57 -05:00
|
|
|
|
|
|
|
fn low(self) -> u64 {
|
|
|
|
self as u64
|
|
|
|
}
|
|
|
|
fn high(self) -> u64 {
|
2016-11-24 17:08:40 -06:00
|
|
|
unsafe { *(&self as *const u128 as *const u64).offset(1) }
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
fn from_parts(low: u64, high: u64) -> u128 {
|
|
|
|
#[repr(C, packed)] struct Parts(u64, u64);
|
|
|
|
unsafe { ::core::mem::transmute(Parts(low, high)) }
|
|
|
|
}
|
2016-12-11 21:56:00 -06:00
|
|
|
#[cfg(not(windows))]
|
|
|
|
fn to_ret(self) -> u128ret {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
|
|
fn to_ret(self) -> u128ret {
|
|
|
|
u64x2(self.low(), self.high())
|
|
|
|
}
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
#[cfg(not(stage0))]
|
|
|
|
impl LargeInt for i128 {
|
|
|
|
type LowHalf = u64;
|
|
|
|
type HighHalf = i64;
|
2016-12-11 21:56:00 -06:00
|
|
|
type Ret = i128ret;
|
2016-10-02 15:01:57 -05:00
|
|
|
|
|
|
|
fn low(self) -> u64 {
|
|
|
|
self as u64
|
|
|
|
}
|
|
|
|
fn high(self) -> i64 {
|
2016-11-24 17:08:40 -06:00
|
|
|
unsafe { *(&self as *const i128 as *const i64).offset(1) }
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
fn from_parts(low: u64, high: i64) -> i128 {
|
|
|
|
u128::from_parts(low, high as u64) as i128
|
|
|
|
}
|
2016-12-11 21:56:00 -06:00
|
|
|
#[cfg(not(windows))]
|
|
|
|
fn to_ret(self) -> u128ret {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
|
|
fn to_ret(self) -> i128ret {
|
|
|
|
u64x2(self.low(), self.high() as u64)
|
|
|
|
}
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! mul {
|
2016-11-24 17:08:40 -06:00
|
|
|
($a:expr, $b:expr, $ty: ty, $tyh: ty) => {{
|
2016-10-02 15:01:57 -05:00
|
|
|
let (a, b) = ($a, $b);
|
2016-12-08 12:02:22 -06:00
|
|
|
let half_bits = ((::core::mem::size_of::<$tyh>() * 8) / 2) as u32;
|
|
|
|
let lower_mask = (!0u64).wrapping_shr(half_bits);
|
|
|
|
let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask);
|
|
|
|
let mut t = low.wrapping_shr(half_bits);
|
2016-10-02 15:01:57 -05:00
|
|
|
low &= lower_mask;
|
2016-12-08 12:02:22 -06:00
|
|
|
t = t.wrapping_add(a.low().wrapping_shr(half_bits)
|
|
|
|
.wrapping_mul(b.low() & lower_mask));
|
|
|
|
low = low.wrapping_add((t & lower_mask).wrapping_shl(half_bits));
|
|
|
|
let mut high = t.wrapping_shr(half_bits) as $tyh;
|
|
|
|
t = low.wrapping_shr(half_bits);
|
2016-10-02 15:01:57 -05:00
|
|
|
low &= lower_mask;
|
2016-12-08 12:02:22 -06:00
|
|
|
t = t.wrapping_add(b.low().wrapping_shr(half_bits)
|
|
|
|
.wrapping_mul(a.low() & lower_mask));
|
|
|
|
low = low.wrapping_add((t & lower_mask).wrapping_shl(half_bits));
|
|
|
|
high = high.wrapping_add(t.wrapping_shr(half_bits) as $tyh);
|
|
|
|
high = high.wrapping_add(a.low().wrapping_shr(half_bits)
|
|
|
|
.wrapping_mul(b.low().wrapping_shr(half_bits)) as $tyh);
|
2016-11-19 18:26:51 -06:00
|
|
|
high = high
|
|
|
|
.wrapping_add(a.high()
|
2016-11-24 17:08:40 -06:00
|
|
|
.wrapping_mul(b.low() as $tyh))
|
|
|
|
.wrapping_add((a.low() as $tyh)
|
|
|
|
.wrapping_mul(b.high()));
|
2016-10-02 15:01:57 -05:00
|
|
|
<$ty>::from_parts(low, high)
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2016-11-24 17:08:40 -06:00
|
|
|
#[cfg(stage0)]
|
|
|
|
#[export_name="__multi3"]
|
2016-12-11 21:56:00 -06:00
|
|
|
pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128ret {
|
|
|
|
((a as i64).wrapping_mul(b as i64) as i128_).to_ret()
|
2016-11-24 17:08:40 -06:00
|
|
|
}
|
2016-10-02 15:01:57 -05:00
|
|
|
|
2016-11-24 17:08:40 -06:00
|
|
|
#[cfg(not(stage0))]
|
2016-10-02 15:01:57 -05:00
|
|
|
#[export_name="__multi3"]
|
2016-12-11 21:56:00 -06:00
|
|
|
pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128ret {
|
|
|
|
mul!(a, b, i128_, i64).to_ret()
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
|
2016-11-24 19:33:35 -06:00
|
|
|
trait AbsExt: Sized {
|
2016-12-07 09:28:45 -06:00
|
|
|
fn uabs(self) -> u128_;
|
2016-11-24 19:33:35 -06:00
|
|
|
fn iabs(self) -> i128_;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AbsExt for i128_ {
|
2016-12-07 09:28:45 -06:00
|
|
|
fn uabs(self) -> u128_ {
|
|
|
|
self.iabs() as u128_
|
|
|
|
}
|
2016-11-24 19:33:35 -06:00
|
|
|
fn iabs(self) -> i128_ {
|
|
|
|
((self ^ self).wrapping_sub(self))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-08 12:02:22 -06:00
|
|
|
trait NegExt: Sized {
|
|
|
|
fn unchecked_neg(self) -> i128_;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl NegExt for i128_ {
|
|
|
|
fn unchecked_neg(self) -> i128_ {
|
|
|
|
(!self).wrapping_add(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-02 15:01:57 -05:00
|
|
|
trait FloatStuff: Sized {
|
|
|
|
type ToBytes;
|
|
|
|
|
|
|
|
const MANTISSA_BITS: u32;
|
|
|
|
const MAX_EXP: i32;
|
|
|
|
const EXP_MASK: Self::ToBytes;
|
|
|
|
const MANTISSA_MASK: Self::ToBytes;
|
2016-11-24 17:08:40 -06:00
|
|
|
const MANTISSA_LEAD_BIT: Self::ToBytes;
|
2016-10-02 15:01:57 -05:00
|
|
|
|
|
|
|
fn to_bytes(self) -> Self::ToBytes;
|
|
|
|
fn get_exponent(self) -> i32;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FloatStuff for f32 {
|
|
|
|
type ToBytes = u32;
|
|
|
|
const MANTISSA_BITS: u32 = 23;
|
|
|
|
const MAX_EXP: i32 = 127;
|
|
|
|
const EXP_MASK: u32 = 0x7F80_0000;
|
2016-11-24 17:08:40 -06:00
|
|
|
const MANTISSA_MASK: u32 = 0x007F_FFFF;
|
|
|
|
const MANTISSA_LEAD_BIT: u32 = 0x0080_0000;
|
2016-10-02 15:01:57 -05:00
|
|
|
|
|
|
|
fn to_bytes(self) -> u32 { unsafe { ::core::mem::transmute(self) } }
|
|
|
|
fn get_exponent(self) -> i32 {
|
2016-12-08 12:02:22 -06:00
|
|
|
((self.to_bytes() & Self::EXP_MASK).wrapping_shr(Self::MANTISSA_BITS) as i32)
|
|
|
|
.wrapping_sub(Self::MAX_EXP)
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FloatStuff for f64 {
|
|
|
|
type ToBytes = u64;
|
|
|
|
const MANTISSA_BITS: u32 = 52;
|
|
|
|
const MAX_EXP: i32 = 1023;
|
|
|
|
const EXP_MASK: u64 = 0x7FF0_0000_0000_0000;
|
|
|
|
const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF;
|
2016-11-24 17:08:40 -06:00
|
|
|
const MANTISSA_LEAD_BIT: u64 = 0x0010_0000_0000_0000;
|
2016-10-02 15:01:57 -05:00
|
|
|
|
|
|
|
fn to_bytes(self) -> u64 { unsafe { ::core::mem::transmute(self) } }
|
|
|
|
fn get_exponent(self) -> i32 {
|
2016-12-08 12:02:22 -06:00
|
|
|
((self.to_bytes() & Self::EXP_MASK).wrapping_shr(Self::MANTISSA_BITS) as i32)
|
|
|
|
.wrapping_sub(Self::MAX_EXP)
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! float_as_unsigned {
|
|
|
|
($from: expr, $fromty: ty, $outty: ty) => { {
|
|
|
|
use core::num::Float;
|
|
|
|
let repr = $from.to_bytes();
|
|
|
|
let sign = $from.signum();
|
|
|
|
let exponent = $from.get_exponent();
|
2016-11-24 17:08:40 -06:00
|
|
|
let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK;
|
|
|
|
let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT;
|
2016-12-11 21:56:00 -06:00
|
|
|
if sign == -1.0 || exponent < 0 { return (0 as u128_).to_ret(); }
|
2016-10-02 15:01:57 -05:00
|
|
|
if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 {
|
2016-12-11 21:56:00 -06:00
|
|
|
return (!(0 as u128_)).to_ret();
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
2016-12-11 21:56:00 -06:00
|
|
|
(if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 {
|
2016-12-08 12:02:22 -06:00
|
|
|
(mantissa as $outty)
|
2016-12-08 13:02:20 -06:00
|
|
|
.wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32)
|
|
|
|
.wrapping_sub(exponent) as u32)
|
2016-10-02 15:01:57 -05:00
|
|
|
} else {
|
2016-12-08 12:02:22 -06:00
|
|
|
(mantissa as $outty)
|
2016-12-08 13:02:20 -06:00
|
|
|
.wrapping_shl(exponent.wrapping_sub(
|
|
|
|
<$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32)
|
2016-12-11 21:56:00 -06:00
|
|
|
}).to_ret()
|
2016-10-02 15:01:57 -05:00
|
|
|
} }
|
|
|
|
}
|
|
|
|
|
|
|
|
#[export_name="__fixunsdfti"]
|
2016-12-11 21:56:00 -06:00
|
|
|
pub extern "C" fn f64_as_u128(a: f64) -> u128ret {
|
2016-10-02 15:01:57 -05:00
|
|
|
float_as_unsigned!(a, f64, u128_)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[export_name="__fixunssfti"]
|
2016-12-11 21:56:00 -06:00
|
|
|
pub extern "C" fn f32_as_u128(a: f32) -> u128ret {
|
2016-10-02 15:01:57 -05:00
|
|
|
float_as_unsigned!(a, f32, u128_)
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! float_as_signed {
|
|
|
|
($from: expr, $fromty: ty, $outty: ty) => {{
|
|
|
|
use core::num::Float;
|
|
|
|
let repr = $from.to_bytes();
|
|
|
|
let sign = $from.signum();
|
|
|
|
let exponent = $from.get_exponent();
|
2016-11-24 17:08:40 -06:00
|
|
|
let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK;
|
|
|
|
let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT;
|
2016-10-02 15:01:57 -05:00
|
|
|
|
2016-12-11 21:56:00 -06:00
|
|
|
if exponent < 0 { return (0 as i128_).to_ret(); }
|
2016-10-02 15:01:57 -05:00
|
|
|
if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 {
|
2016-12-11 21:56:00 -06:00
|
|
|
return (if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() }).to_ret();
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
let r = if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 {
|
2016-12-08 12:02:22 -06:00
|
|
|
(mantissa as $outty)
|
2016-12-08 13:02:20 -06:00
|
|
|
.wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32)
|
|
|
|
.wrapping_sub(exponent) as u32)
|
2016-10-02 15:01:57 -05:00
|
|
|
} else {
|
2016-12-08 12:02:22 -06:00
|
|
|
(mantissa as $outty)
|
2016-12-08 13:02:20 -06:00
|
|
|
.wrapping_shl(exponent.wrapping_sub(
|
|
|
|
<$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32)
|
2016-10-02 15:01:57 -05:00
|
|
|
};
|
2016-12-11 21:56:00 -06:00
|
|
|
(if sign >= 0.0 { r } else { r.unchecked_neg() }).to_ret()
|
2016-10-02 15:01:57 -05:00
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[export_name="__fixdfti"]
|
2016-12-11 21:56:00 -06:00
|
|
|
pub extern "C" fn f64_as_i128(a: f64) -> i128ret {
|
2016-10-02 15:01:57 -05:00
|
|
|
float_as_signed!(a, f64, i128_)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[export_name="__fixsfti"]
|
2016-12-11 21:56:00 -06:00
|
|
|
pub extern "C" fn f32_as_i128(a: f32) -> i128ret {
|
2016-10-02 15:01:57 -05:00
|
|
|
float_as_signed!(a, f32, i128_)
|
|
|
|
}
|
|
|
|
|
2016-12-13 21:19:45 -06:00
|
|
|
// LLVM expectations for ABI on windows are pure madness.
|
|
|
|
|
|
|
|
#[cfg(not(stage0))]
|
|
|
|
#[cfg_attr(windows, export_name="__floattidf")]
|
|
|
|
pub extern "C" fn i128_as_f64_win(alow: u64, ahigh: i64) -> f64 {
|
|
|
|
i128_as_f64(i128_::from_parts(alow, ahigh))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(stage0))]
|
|
|
|
#[cfg_attr(windows, export_name="__floattisf")]
|
|
|
|
pub extern "C" fn i128_as_f32_win(alow: u64, ahigh: i64) -> f32 {
|
|
|
|
i128_as_f32(i128_::from_parts(alow, ahigh))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(stage0))]
|
|
|
|
#[cfg_attr(windows, export_name="__floatuntidf")]
|
|
|
|
pub extern "C" fn u128_as_f64_win(alow: u64, ahigh: u64) -> f64 {
|
|
|
|
u128_as_f64(u128_::from_parts(alow, ahigh))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(stage0))]
|
|
|
|
#[cfg_attr(windows, export_name="__floatuntisf")]
|
|
|
|
pub extern "C" fn u128_as_f32_win(alow: u64, ahigh: u64) -> f32 {
|
|
|
|
u128_as_f32(u128_::from_parts(alow, ahigh))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg_attr(any(not(windows),stage0),export_name="__floattidf")]
|
2016-12-07 09:28:45 -06:00
|
|
|
pub extern "C" fn i128_as_f64(a: i128_) -> f64 {
|
2016-10-02 15:01:57 -05:00
|
|
|
match a.signum() {
|
2016-11-24 19:33:35 -06:00
|
|
|
1 => u128_as_f64(a.uabs()),
|
2016-10-02 15:01:57 -05:00
|
|
|
0 => 0.0,
|
2016-12-07 09:56:26 -06:00
|
|
|
_ => -u128_as_f64(a.uabs()),
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-13 21:19:45 -06:00
|
|
|
#[cfg_attr(any(not(windows),stage0),export_name="__floattisf")]
|
2016-12-07 09:28:45 -06:00
|
|
|
pub extern "C" fn i128_as_f32(a: i128_) -> f32 {
|
2016-10-02 15:01:57 -05:00
|
|
|
match a.signum() {
|
2016-11-24 19:33:35 -06:00
|
|
|
1 => u128_as_f32(a.uabs()),
|
2016-10-02 15:01:57 -05:00
|
|
|
0 => 0.0,
|
2016-12-07 09:56:26 -06:00
|
|
|
_ => -u128_as_f32(a.uabs()),
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-13 21:19:45 -06:00
|
|
|
#[cfg_attr(any(not(windows),stage0),export_name="__floatuntidf")]
|
2016-12-07 09:28:45 -06:00
|
|
|
pub extern "C" fn u128_as_f64(mut a: u128_) -> f64 {
|
2016-10-02 15:01:57 -05:00
|
|
|
use ::core::f64::MANTISSA_DIGITS;
|
|
|
|
if a == 0 { return 0.0; }
|
2016-12-08 12:02:22 -06:00
|
|
|
let sd = 128u32.wrapping_sub(a.leading_zeros());
|
|
|
|
let mut e = sd.wrapping_sub(1);
|
2016-10-02 15:01:57 -05:00
|
|
|
const MD1 : u32 = MANTISSA_DIGITS + 1;
|
|
|
|
const MD2 : u32 = MANTISSA_DIGITS + 2;
|
|
|
|
|
2016-12-08 12:02:22 -06:00
|
|
|
// SNAP: replace this with !0u128
|
|
|
|
let negn :u128_ = !0;
|
|
|
|
|
2016-10-02 15:01:57 -05:00
|
|
|
if sd > MANTISSA_DIGITS {
|
|
|
|
a = match sd {
|
2016-12-08 12:02:22 -06:00
|
|
|
MD1 => a.wrapping_shl(1),
|
2016-10-02 15:01:57 -05:00
|
|
|
MD2 => a,
|
2016-12-08 12:02:22 -06:00
|
|
|
_ => a.wrapping_shr(sd.wrapping_sub(MANTISSA_DIGITS + 2)) |
|
|
|
|
(if (a & (negn.wrapping_shr(128 + MANTISSA_DIGITS + 2)
|
|
|
|
.wrapping_sub(sd as u128_))) == 0 { 0 } else { 1 })
|
2016-10-02 15:01:57 -05:00
|
|
|
};
|
|
|
|
a |= if (a & 4) == 0 { 0 } else { 1 };
|
2016-12-08 12:02:22 -06:00
|
|
|
a = a.wrapping_add(1);
|
|
|
|
a = a.wrapping_shr(2);
|
2016-10-02 15:01:57 -05:00
|
|
|
if a & (1 << MANTISSA_DIGITS) != 0 {
|
2016-12-08 12:02:22 -06:00
|
|
|
a = a.wrapping_shr(1);
|
|
|
|
e = e.wrapping_add(1);
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
} else {
|
2016-12-08 12:02:22 -06:00
|
|
|
a = a.wrapping_shl(MANTISSA_DIGITS.wrapping_sub(sd));
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
unsafe {
|
2016-12-08 12:02:22 -06:00
|
|
|
::core::mem::transmute((e as u64).wrapping_add(1023).wrapping_shl(52)
|
|
|
|
| (a as u64 & 0x000f_ffff_ffff_ffff))
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-13 21:19:45 -06:00
|
|
|
#[cfg_attr(any(not(windows),stage0),export_name="__floatuntisf")]
|
2016-12-07 09:28:45 -06:00
|
|
|
pub extern "C" fn u128_as_f32(mut a: u128_) -> f32 {
|
2016-10-02 15:01:57 -05:00
|
|
|
use ::core::f32::MANTISSA_DIGITS;
|
|
|
|
if a == 0 { return 0.0; }
|
2016-12-08 12:02:22 -06:00
|
|
|
let sd = 128u32.wrapping_sub(a.leading_zeros());
|
|
|
|
let mut e = sd.wrapping_sub(1);
|
2016-10-02 15:01:57 -05:00
|
|
|
const MD1 : u32 = MANTISSA_DIGITS + 1;
|
|
|
|
const MD2 : u32 = MANTISSA_DIGITS + 2;
|
|
|
|
|
2016-12-08 12:02:22 -06:00
|
|
|
// SNAP: replace this with !0u128
|
|
|
|
let negn :u128_ = !0;
|
|
|
|
|
2016-10-02 15:01:57 -05:00
|
|
|
if sd > MANTISSA_DIGITS {
|
|
|
|
a = match sd {
|
2016-12-08 12:02:22 -06:00
|
|
|
MD1 => a.wrapping_shl(1),
|
2016-10-02 15:01:57 -05:00
|
|
|
MD2 => a,
|
2016-12-08 12:02:22 -06:00
|
|
|
_ => a.wrapping_shr(sd.wrapping_sub(MANTISSA_DIGITS + 2)) |
|
|
|
|
(if (a & (negn.wrapping_shr(128 + MANTISSA_DIGITS + 2)
|
|
|
|
.wrapping_sub(sd as u128_))) == 0 { 0 } else { 1 })
|
2016-10-02 15:01:57 -05:00
|
|
|
};
|
|
|
|
a |= if (a & 4) == 0 { 0 } else { 1 };
|
2016-12-08 12:02:22 -06:00
|
|
|
a = a.wrapping_add(1);
|
|
|
|
a = a.wrapping_shr(2);
|
2016-10-02 15:01:57 -05:00
|
|
|
if a & (1 << MANTISSA_DIGITS) != 0 {
|
2016-12-08 12:02:22 -06:00
|
|
|
a = a.wrapping_shr(1);
|
|
|
|
e = e.wrapping_add(1);
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
} else {
|
2016-12-08 12:02:22 -06:00
|
|
|
a = a.wrapping_shl(MANTISSA_DIGITS.wrapping_sub(sd));
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
unsafe {
|
2016-12-08 12:02:22 -06:00
|
|
|
::core::mem::transmute((e as u32).wrapping_add(127).wrapping_shl(23)
|
|
|
|
| (a as u32 & 0x007f_ffff))
|
2016-10-02 15:01:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|