Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add __powitf2 symbol for f128 integer exponentiation #614

Merged
merged 3 commits into from
Sep 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ of being added to Rust.
- [ ] floatunsitf.c
- [ ] floatuntitf.c
- [x] multf3.c
- [ ] powitf2.c
- [x] powitf2.c
- [x] subtf3.c
- [x] truncdfhf2.c
- [x] truncsfhf2.c
Expand Down
1 change: 0 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,6 @@ mod c {
("__floatsitf", "floatsitf.c"),
("__floatunditf", "floatunditf.c"),
("__floatunsitf", "floatunsitf.c"),
("__powitf2", "powitf2.c"),
("__fe_getround", "fp_mode.c"),
("__fe_raise_inexact", "fp_mode.c"),
]);
Expand Down
9 changes: 9 additions & 0 deletions src/float/pow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,13 @@ intrinsics! {
pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 {
pow(a, b)
}

#[avr_skip]
#[ppc_alias = __powikf2]
#[cfg(f128_enabled)]
// FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly.
#[cfg(not(target_env = "msvc"))]
pub extern "C" fn __powitf2(a: f128, b: i32) -> f128 {
pow(a, b)
}
}
31 changes: 28 additions & 3 deletions testcrate/benches/float_pow.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![cfg_attr(f128_enabled, feature(f128))]

use compiler_builtins::float::pow;
use criterion::{criterion_group, criterion_main, Criterion};
use criterion::{criterion_main, Criterion};
use testcrate::float_bench;

float_bench! {
Expand All @@ -20,5 +22,28 @@ float_bench! {
asm: [],
}

criterion_group!(float_add, powi_f32, powi_f64);
criterion_main!(float_add);
// FIXME(f16_f128): can be changed to only `f128_enabled` once `__multf3` and `__divtf3` are
// distributed by nightly.
#[cfg(all(f128_enabled, not(feature = "no-sys-f128")))]
float_bench! {
name: powi_f128,
sig: (a: f128, b: i32) -> f128,
crate_fn: pow::__powitf2,
crate_fn_ppc: pow::__powikf2,
sys_fn: __powitf2,
sys_fn_ppc: __powikf2,
sys_available: not(feature = "no-sys-f128"),
asm: []
}

pub fn float_pow() {
let mut criterion = Criterion::default().configure_from_args();

powi_f32(&mut criterion);
powi_f64(&mut criterion);

#[cfg(all(f128_enabled, not(feature = "no-sys-f128")))]
powi_f128(&mut criterion);
}

criterion_main!(float_pow);
2 changes: 2 additions & 0 deletions testcrate/src/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,3 +360,5 @@ impl_testio!(int i16, i32, i64, i128);
impl_testio!(int u16, u32, u64, u128);
impl_testio!((float, int)(f32, i32));
impl_testio!((float, int)(f64, i32));
#[cfg(f128_enabled)]
impl_testio!((float, int)(f128, i32));
72 changes: 72 additions & 0 deletions testcrate/tests/float_pow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#![allow(unused_macros)]
#![cfg_attr(f128_enabled, feature(f128))]
#![cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]

use testcrate::*;

// This is approximate because of issues related to
// https://github.com/rust-lang/rust/issues/73920.
// TODO how do we resolve this indeterminacy?
macro_rules! pow {
($($f:ty, $tolerance:expr, $fn:ident, $sys_available:meta);*;) => {
$(
#[test]
// FIXME(apfloat): We skip tests if system symbols aren't available rather
// than providing a fallback, since `rustc_apfloat` does not provide `pow`.
#[cfg($sys_available)]
fn $fn() {
use compiler_builtins::float::pow::$fn;
use compiler_builtins::float::Float;
fuzz_float_2(N, |x: $f, y: $f| {
if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) {
let n = y.to_bits() & !<$f as Float>::SIGNIFICAND_MASK;
let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS;
let n = n as i32;
let tmp0: $f = x.powi(n);
let tmp1: $f = $fn(x, n);
let (a, b) = if tmp0 < tmp1 {
(tmp0, tmp1)
} else {
(tmp1, tmp0)
};

let good = if a == b {
// handles infinity equality
true
} else if a < $tolerance {
b < $tolerance
} else {
let quo = b / a;
(quo < (1. + $tolerance)) && (quo > (1. - $tolerance))
};

assert!(
good,
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
stringify!($fn), x, n, tmp0, tmp1
);
}
});
}
)*
};
}

pow! {
f32, 1e-4, __powisf2, all();
f64, 1e-12, __powidf2, all();
}

#[cfg(f128_enabled)]
// FIXME(f16_f128): MSVC cannot build these until `__divtf3` is available in nightly.
#[cfg(not(target_env = "msvc"))]
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
pow! {
f128, 1e-36, __powitf2, not(feature = "no-sys-f128");
}

#[cfg(f128_enabled)]
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
pow! {
f128, 1e-36, __powikf2, not(feature = "no-sys-f128");
}
56 changes: 0 additions & 56 deletions testcrate/tests/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,59 +207,3 @@ fn bswap() {
);
}
}

// This is approximate because of issues related to
// https://github.com/rust-lang/rust/issues/73920.
// TODO how do we resolve this indeterminacy?
macro_rules! pow {
($($f:ty, $tolerance:expr, $fn:ident);*;) => {
$(
#[test]
fn $fn() {
use compiler_builtins::float::pow::$fn;
use compiler_builtins::float::Float;
fuzz_float_2(N, |x: $f, y: $f| {
if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) {
let n = y.to_bits() & !<$f as Float>::SIGNIFICAND_MASK;
let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS;
let n = n as i32;
let tmp0: $f = x.powi(n);
let tmp1: $f = $fn(x, n);
let (a, b) = if tmp0 < tmp1 {
(tmp0, tmp1)
} else {
(tmp1, tmp0)
};
let good = {
if a == b {
// handles infinity equality
true
} else if a < $tolerance {
b < $tolerance
} else {
let quo = b / a;
(quo < (1. + $tolerance)) && (quo > (1. - $tolerance))
}
};
if !good {
panic!(
"{}({}, {}): std: {}, builtins: {}",
stringify!($fn), x, n, tmp0, tmp1
);
}
}
});
}
)*
};
}

#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
mod float_pow {
use super::*;

pow! {
f32, 1e-4, __powisf2;
f64, 1e-12, __powidf2;
}
}
Loading