commit
bb2c81b700
|
@ -170,11 +170,11 @@ features = ["c"]
|
||||||
- [x] lshrdi3.c
|
- [x] lshrdi3.c
|
||||||
- [x] moddi3.c
|
- [x] moddi3.c
|
||||||
- [x] modsi3.c
|
- [x] modsi3.c
|
||||||
- [ ] muldf3.c
|
- [x] muldf3.c
|
||||||
- [x] muldi3.c
|
- [x] muldi3.c
|
||||||
- [x] mulodi4.c
|
- [x] mulodi4.c
|
||||||
- [x] mulosi4.c
|
- [x] mulosi4.c
|
||||||
- [ ] mulsf3.c
|
- [x] mulsf3.c
|
||||||
- [x] powidf2.c
|
- [x] powidf2.c
|
||||||
- [x] powisf2.c
|
- [x] powisf2.c
|
||||||
- [ ] subdf3.c
|
- [ ] subdf3.c
|
||||||
|
|
230
build.rs
230
build.rs
|
@ -121,6 +121,10 @@ mod tests {
|
||||||
Subdf3,
|
Subdf3,
|
||||||
Subsf3,
|
Subsf3,
|
||||||
|
|
||||||
|
// float/mul.rs
|
||||||
|
Mulsf3,
|
||||||
|
Muldf3,
|
||||||
|
|
||||||
// int/mul.rs
|
// int/mul.rs
|
||||||
Muldi3,
|
Muldi3,
|
||||||
Mulodi4,
|
Mulodi4,
|
||||||
|
@ -3221,6 +3225,181 @@ fn subsf3() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
|
pub struct Mulsf3 {
|
||||||
|
a: u32, // f32
|
||||||
|
b: u32, // f32
|
||||||
|
c: u32, // f32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCase for Mulsf3 {
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"mulsf3"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate<R>(rng: &mut R) -> Option<Self>
|
||||||
|
where
|
||||||
|
R: Rng,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let a = gen_large_f32(rng);
|
||||||
|
let b = gen_large_f32(rng);
|
||||||
|
let c = a * b;
|
||||||
|
// TODO accept NaNs. We don't do that right now because we can't check
|
||||||
|
// for NaN-ness on the thumb targets (due to missing intrinsics)
|
||||||
|
if a.is_nan() || b.is_nan() || c.is_nan() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(
|
||||||
|
Mulsf3 {
|
||||||
|
a: to_u32(a),
|
||||||
|
b: to_u32(b),
|
||||||
|
c: to_u32(c),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_string(&self, buffer: &mut String) {
|
||||||
|
writeln!(
|
||||||
|
buffer,
|
||||||
|
"(({a}, {b}), {c}),",
|
||||||
|
a = self.a,
|
||||||
|
b = self.b,
|
||||||
|
c = self.c
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prologue() -> &'static str {
|
||||||
|
r#"
|
||||||
|
#[cfg(all(target_arch = "arm",
|
||||||
|
not(any(target_env = "gnu", target_env = "musl")),
|
||||||
|
target_os = "linux",
|
||||||
|
test))]
|
||||||
|
use core::mem;
|
||||||
|
#[cfg(not(all(target_arch = "arm",
|
||||||
|
not(any(target_env = "gnu", target_env = "musl")),
|
||||||
|
target_os = "linux",
|
||||||
|
test)))]
|
||||||
|
use std::mem;
|
||||||
|
use compiler_builtins::float::mul::__mulsf3;
|
||||||
|
|
||||||
|
fn mk_f32(x: u32) -> f32 {
|
||||||
|
unsafe { mem::transmute(x) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_u32(x: f32) -> u32 {
|
||||||
|
unsafe { mem::transmute(x) }
|
||||||
|
}
|
||||||
|
|
||||||
|
static TEST_CASES: &[((u32, u32), u32)] = &[
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn epilogue() -> &'static str {
|
||||||
|
"
|
||||||
|
];
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mulsf3() {
|
||||||
|
for &((a, b), c) in TEST_CASES {
|
||||||
|
let c_ = __mulsf3(mk_f32(a), mk_f32(b));
|
||||||
|
assert_eq!(((a, b), c), ((a, b), to_u32(c_)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
|
pub struct Muldf3 {
|
||||||
|
a: u64, // f64
|
||||||
|
b: u64, // f64
|
||||||
|
c: u64, // f64
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCase for Muldf3 {
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"muldf3"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate<R>(rng: &mut R) -> Option<Self>
|
||||||
|
where
|
||||||
|
R: Rng,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let a = gen_large_f64(rng);
|
||||||
|
let b = gen_large_f64(rng);
|
||||||
|
let c = a * b;
|
||||||
|
// TODO accept NaNs. We don't do that right now because we can't check
|
||||||
|
// for NaN-ness on the thumb targets (due to missing intrinsics)
|
||||||
|
if a.is_nan() || b.is_nan() || c.is_nan() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(
|
||||||
|
Muldf3 {
|
||||||
|
a: to_u64(a),
|
||||||
|
b: to_u64(b),
|
||||||
|
c: to_u64(c),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_string(&self, buffer: &mut String) {
|
||||||
|
writeln!(
|
||||||
|
buffer,
|
||||||
|
"(({a}, {b}), {c}),",
|
||||||
|
a = self.a,
|
||||||
|
b = self.b,
|
||||||
|
c = self.c
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prologue() -> &'static str {
|
||||||
|
r#"
|
||||||
|
#[cfg(all(target_arch = "arm",
|
||||||
|
not(any(target_env = "gnu", target_env = "musl")),
|
||||||
|
target_os = "linux",
|
||||||
|
test))]
|
||||||
|
use core::mem;
|
||||||
|
#[cfg(not(all(target_arch = "arm",
|
||||||
|
not(any(target_env = "gnu", target_env = "musl")),
|
||||||
|
target_os = "linux",
|
||||||
|
test)))]
|
||||||
|
use std::mem;
|
||||||
|
use compiler_builtins::float::mul::__muldf3;
|
||||||
|
|
||||||
|
fn mk_f64(x: u64) -> f64 {
|
||||||
|
unsafe { mem::transmute(x) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_u64(x: f64) -> u64 {
|
||||||
|
unsafe { mem::transmute(x) }
|
||||||
|
}
|
||||||
|
|
||||||
|
static TEST_CASES: &[((u64, u64), u64)] = &[
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn epilogue() -> &'static str {
|
||||||
|
"
|
||||||
|
];
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn muldf3() {
|
||||||
|
for &((a, b), c) in TEST_CASES {
|
||||||
|
let c_ = __muldf3(mk_f64(a), mk_f64(b));
|
||||||
|
assert_eq!(((a, b), c), ((a, b), to_u64(c_)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Eq, Hash, PartialEq)]
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
pub struct Udivdi3 {
|
pub struct Udivdi3 {
|
||||||
a: u64,
|
a: u64,
|
||||||
|
@ -3899,6 +4078,57 @@ macro_rules! panic {
|
||||||
gen_float!(gen_f32, f32, u32, 32, 23);
|
gen_float!(gen_f32, f32, u32, 32, 23);
|
||||||
gen_float!(gen_f64, f64, u64, 64, 52);
|
gen_float!(gen_f64, f64, u64, 64, 52);
|
||||||
|
|
||||||
|
macro_rules! gen_large_float {
|
||||||
|
($name:ident,
|
||||||
|
$fty:ident,
|
||||||
|
$uty:ident,
|
||||||
|
$bits:expr,
|
||||||
|
$significand_bits:expr) => {
|
||||||
|
pub fn $name<R>(rng: &mut R) -> $fty
|
||||||
|
where
|
||||||
|
R: Rng,
|
||||||
|
{
|
||||||
|
const BITS: u8 = $bits;
|
||||||
|
const SIGNIFICAND_BITS: u8 = $significand_bits;
|
||||||
|
|
||||||
|
const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1;
|
||||||
|
const SIGN_MASK: $uty = (1 << (BITS - 1));
|
||||||
|
const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK);
|
||||||
|
|
||||||
|
fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty {
|
||||||
|
unsafe {
|
||||||
|
mem::transmute(((sign as $uty) << (BITS - 1)) |
|
||||||
|
((exponent & EXPONENT_MASK) <<
|
||||||
|
SIGNIFICAND_BITS) |
|
||||||
|
(significand & SIGNIFICAND_MASK))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rng.gen_weighted_bool(10) {
|
||||||
|
// Special values
|
||||||
|
*rng.choose(&[-0.0,
|
||||||
|
0.0,
|
||||||
|
::std::$fty::NAN,
|
||||||
|
::std::$fty::INFINITY,
|
||||||
|
-::std::$fty::INFINITY])
|
||||||
|
.unwrap()
|
||||||
|
} else if rng.gen_weighted_bool(10) {
|
||||||
|
// NaN patterns
|
||||||
|
mk_f32(rng.gen(), rng.gen(), 0)
|
||||||
|
} else if rng.gen() {
|
||||||
|
// Denormalized
|
||||||
|
mk_f32(rng.gen(), 0, rng.gen())
|
||||||
|
} else {
|
||||||
|
// Random anything
|
||||||
|
rng.gen::<$fty>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_large_float!(gen_large_f32, f32, u32, 32, 23);
|
||||||
|
gen_large_float!(gen_large_f64, f64, u64, 64, 52);
|
||||||
|
|
||||||
pub fn gen_u128<R>(rng: &mut R) -> u128
|
pub fn gen_u128<R>(rng: &mut R) -> u128
|
||||||
where
|
where
|
||||||
R: Rng,
|
R: Rng,
|
||||||
|
|
|
@ -7,6 +7,7 @@ pub mod conv;
|
||||||
pub mod add;
|
pub mod add;
|
||||||
pub mod pow;
|
pub mod pow;
|
||||||
pub mod sub;
|
pub mod sub;
|
||||||
|
pub mod mul;
|
||||||
|
|
||||||
/// Trait for some basic operations on floats
|
/// Trait for some basic operations on floats
|
||||||
pub trait Float:
|
pub trait Float:
|
||||||
|
|
|
@ -0,0 +1,191 @@
|
||||||
|
use int::{CastInto, Int, WideInt};
|
||||||
|
use float::Float;
|
||||||
|
|
||||||
|
fn mul<F: Float>(a: F, b: F) -> F
|
||||||
|
where
|
||||||
|
u32: CastInto<F::Int>,
|
||||||
|
F::Int: CastInto<u32>,
|
||||||
|
i32: CastInto<F::Int>,
|
||||||
|
F::Int: CastInto<i32>,
|
||||||
|
F::Int: WideInt,
|
||||||
|
{
|
||||||
|
let one = F::Int::ONE;
|
||||||
|
let zero = F::Int::ZERO;
|
||||||
|
|
||||||
|
let bits = F::BITS;
|
||||||
|
let significand_bits = F::SIGNIFICAND_BITS;
|
||||||
|
let max_exponent = F::EXPONENT_MAX;
|
||||||
|
|
||||||
|
let exponent_bias = F::EXPONENT_BIAS;
|
||||||
|
|
||||||
|
let implicit_bit = F::IMPLICIT_BIT;
|
||||||
|
let significand_mask = F::SIGNIFICAND_MASK;
|
||||||
|
let sign_bit = F::SIGN_MASK as F::Int;
|
||||||
|
let abs_mask = sign_bit - one;
|
||||||
|
let exponent_mask = F::EXPONENT_MASK;
|
||||||
|
let inf_rep = exponent_mask;
|
||||||
|
let quiet_bit = implicit_bit >> 1;
|
||||||
|
let qnan_rep = exponent_mask | quiet_bit;
|
||||||
|
let exponent_bits = F::EXPONENT_BITS;
|
||||||
|
|
||||||
|
let a_rep = a.repr();
|
||||||
|
let b_rep = b.repr();
|
||||||
|
|
||||||
|
let a_exponent = (a_rep >> significand_bits) & max_exponent.cast();
|
||||||
|
let b_exponent = (b_rep >> significand_bits) & max_exponent.cast();
|
||||||
|
let product_sign = (a_rep ^ b_rep) & sign_bit;
|
||||||
|
|
||||||
|
let mut a_significand = a_rep & significand_mask;
|
||||||
|
let mut b_significand = b_rep & significand_mask;
|
||||||
|
let mut scale = 0;
|
||||||
|
|
||||||
|
// Detect if a or b is zero, denormal, infinity, or NaN.
|
||||||
|
if a_exponent.wrapping_sub(one) >= (max_exponent - 1).cast()
|
||||||
|
|| b_exponent.wrapping_sub(one) >= (max_exponent - 1).cast()
|
||||||
|
{
|
||||||
|
let a_abs = a_rep & abs_mask;
|
||||||
|
let b_abs = b_rep & abs_mask;
|
||||||
|
|
||||||
|
// NaN + anything = qNaN
|
||||||
|
if a_abs > inf_rep {
|
||||||
|
return F::from_repr(a_rep | quiet_bit);
|
||||||
|
}
|
||||||
|
// anything + NaN = qNaN
|
||||||
|
if b_abs > inf_rep {
|
||||||
|
return F::from_repr(b_rep | quiet_bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if a_abs == inf_rep {
|
||||||
|
if b_abs != zero {
|
||||||
|
// infinity * non-zero = +/- infinity
|
||||||
|
return F::from_repr(a_abs | product_sign);
|
||||||
|
} else {
|
||||||
|
// infinity * zero = NaN
|
||||||
|
return F::from_repr(qnan_rep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if b_abs == inf_rep {
|
||||||
|
if a_abs != zero {
|
||||||
|
// infinity * non-zero = +/- infinity
|
||||||
|
return F::from_repr(b_abs | product_sign);
|
||||||
|
} else {
|
||||||
|
// infinity * zero = NaN
|
||||||
|
return F::from_repr(qnan_rep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// zero * anything = +/- zero
|
||||||
|
if a_abs == zero {
|
||||||
|
return F::from_repr(product_sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
// anything * zero = +/- zero
|
||||||
|
if b_abs == zero {
|
||||||
|
return F::from_repr(product_sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
// one or both of a or b is denormal, the other (if applicable) is a
|
||||||
|
// normal number. Renormalize one or both of a and b, and set scale to
|
||||||
|
// include the necessary exponent adjustment.
|
||||||
|
if a_abs < implicit_bit {
|
||||||
|
let (exponent, significand) = F::normalize(a_significand);
|
||||||
|
scale += exponent;
|
||||||
|
a_significand = significand;
|
||||||
|
}
|
||||||
|
|
||||||
|
if b_abs < implicit_bit {
|
||||||
|
let (exponent, significand) = F::normalize(b_significand);
|
||||||
|
scale += exponent;
|
||||||
|
b_significand = significand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or in the implicit significand bit. (If we fell through from the
|
||||||
|
// denormal path it was already set by normalize( ), but setting it twice
|
||||||
|
// won't hurt anything.)
|
||||||
|
a_significand |= implicit_bit;
|
||||||
|
b_significand |= implicit_bit;
|
||||||
|
|
||||||
|
// Get the significand of a*b. Before multiplying the significands, shift
|
||||||
|
// one of them left to left-align it in the field. Thus, the product will
|
||||||
|
// have (exponentBits + 2) integral digits, all but two of which must be
|
||||||
|
// zero. Normalizing this result is just a conditional left-shift by one
|
||||||
|
// and bumping the exponent accordingly.
|
||||||
|
let (mut product_high, mut product_low) =
|
||||||
|
<F::Int as WideInt>::wide_mul(a_significand, b_significand << exponent_bits);
|
||||||
|
|
||||||
|
let a_exponent_i32: i32 = a_exponent.cast();
|
||||||
|
let b_exponent_i32: i32 = b_exponent.cast();
|
||||||
|
let mut product_exponent: i32 = a_exponent_i32
|
||||||
|
.wrapping_add(b_exponent_i32)
|
||||||
|
.wrapping_add(scale)
|
||||||
|
.wrapping_sub(exponent_bias as i32);
|
||||||
|
|
||||||
|
// Normalize the significand, adjust exponent if needed.
|
||||||
|
if (product_high & implicit_bit) != zero {
|
||||||
|
product_exponent = product_exponent.wrapping_add(1);
|
||||||
|
} else {
|
||||||
|
<F::Int as WideInt>::wide_shift_left(&mut product_high, &mut product_low, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have overflowed the type, return +/- infinity.
|
||||||
|
if product_exponent >= max_exponent as i32 {
|
||||||
|
return F::from_repr(inf_rep | product_sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
if product_exponent <= 0 {
|
||||||
|
// Result is denormal before rounding
|
||||||
|
//
|
||||||
|
// If the result is so small that it just underflows to zero, return
|
||||||
|
// a zero of the appropriate sign. Mathematically there is no need to
|
||||||
|
// handle this case separately, but we make it a special case to
|
||||||
|
// simplify the shift logic.
|
||||||
|
let shift = one.wrapping_sub(product_exponent.cast()).cast();
|
||||||
|
if shift >= bits as i32 {
|
||||||
|
return F::from_repr(product_sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, shift the significand of the result so that the round
|
||||||
|
// bit is the high bit of productLo.
|
||||||
|
<F::Int as WideInt>::wide_shift_right_with_sticky(
|
||||||
|
&mut product_high,
|
||||||
|
&mut product_low,
|
||||||
|
shift,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Result is normal before rounding; insert the exponent.
|
||||||
|
product_high &= significand_mask;
|
||||||
|
product_high |= product_exponent.cast() << significand_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the sign of the result:
|
||||||
|
product_high |= product_sign;
|
||||||
|
|
||||||
|
// Final rounding. The final result may overflow to infinity, or underflow
|
||||||
|
// to zero, but those are the correct results in those cases. We use the
|
||||||
|
// default IEEE-754 round-to-nearest, ties-to-even rounding mode.
|
||||||
|
if product_low > sign_bit {
|
||||||
|
product_high += one;
|
||||||
|
}
|
||||||
|
|
||||||
|
if product_low == sign_bit {
|
||||||
|
product_high += product_high & one;
|
||||||
|
}
|
||||||
|
|
||||||
|
return F::from_repr(product_high);
|
||||||
|
}
|
||||||
|
|
||||||
|
intrinsics! {
|
||||||
|
#[aapcs_on_arm]
|
||||||
|
#[arm_aeabi_alias = __aeabi_fmul]
|
||||||
|
pub extern "C" fn __mulsf3(a: f32, b: f32) -> f32 {
|
||||||
|
mul(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aapcs_on_arm]
|
||||||
|
#[arm_aeabi_alias = __aeabi_dmul]
|
||||||
|
pub extern "C" fn __muldf3(a: f64, b: f64) -> f64 {
|
||||||
|
mul(a, b)
|
||||||
|
}
|
||||||
|
}
|
|
@ -249,3 +249,48 @@ cast_into!(u64);
|
||||||
cast_into!(i64);
|
cast_into!(i64);
|
||||||
cast_into!(u128);
|
cast_into!(u128);
|
||||||
cast_into!(i128);
|
cast_into!(i128);
|
||||||
|
|
||||||
|
pub trait WideInt: Int {
|
||||||
|
type Output: Int;
|
||||||
|
|
||||||
|
fn wide_mul(self, other: Self) -> (Self, Self);
|
||||||
|
fn wide_shift_left(&mut self, low: &mut Self, count: i32);
|
||||||
|
fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_wide_int {
|
||||||
|
($ty:ty, $tywide:ty, $bits:expr) => {
|
||||||
|
impl WideInt for $ty {
|
||||||
|
type Output = $ty;
|
||||||
|
|
||||||
|
fn wide_mul(self, other: Self) -> (Self, Self) {
|
||||||
|
let product = (self as $tywide).wrapping_mul(other as $tywide);
|
||||||
|
((product >> ($bits as $ty)) as $ty, product as $ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wide_shift_left(&mut self, low: &mut Self, count: i32) {
|
||||||
|
*self = (*self << count) | (*low >> ($bits - count));
|
||||||
|
*low = *low << count;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32) {
|
||||||
|
if count < $bits {
|
||||||
|
let sticky = *low << ($bits - count);
|
||||||
|
*low = *self << ($bits - count) | *low >> count | sticky;
|
||||||
|
*self = *self >> count;
|
||||||
|
} else if count < 2*$bits {
|
||||||
|
let sticky = *self << (2*$bits - count) | *low;
|
||||||
|
*low = *self >> (count - $bits ) | sticky;
|
||||||
|
*self = 0;
|
||||||
|
} else {
|
||||||
|
let sticky = *self | *low;
|
||||||
|
*self = sticky;
|
||||||
|
*self = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_wide_int!(u32, u64, 32);
|
||||||
|
impl_wide_int!(u64, u128, 64);
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#![feature(compiler_builtins_lib)]
|
||||||
|
#![feature(i128_type)]
|
||||||
|
#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")),
|
||||||
|
target_os = "linux", test),
|
||||||
|
no_std)]
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/muldf3.rs"));
|
|
@ -0,0 +1,7 @@
|
||||||
|
#![feature(compiler_builtins_lib)]
|
||||||
|
#![feature(i128_type)]
|
||||||
|
#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")),
|
||||||
|
target_os = "linux", test),
|
||||||
|
no_std)]
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/mulsf3.rs"));
|
Loading…
Reference in New Issue