add gamma function shims

This commit is contained in:
Ralf Jung 2023-08-10 19:31:08 +02:00
parent 2e14f25c9b
commit 9281ddc644
3 changed files with 42 additions and 2 deletions

View File

@ -1,4 +1,5 @@
#![feature(rustc_private)]
#![feature(float_gamma)]
#![feature(map_try_insert)]
#![feature(never_type)]
#![feature(try_blocks)]

View File

@ -815,6 +815,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
| "atanf"
| "log1pf"
| "expm1f"
| "tgammaf"
=> {
let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
// FIXME: Using host floats.
@ -830,6 +831,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"atanf" => f.atan(),
"log1pf" => f.ln_1p(),
"expm1f" => f.exp_m1(),
"tgammaf" => f.gamma(),
_ => bug!(),
};
this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?;
@ -866,6 +868,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
| "atan"
| "log1p"
| "expm1"
| "tgamma"
=> {
let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
// FIXME: Using host floats.
@ -881,6 +884,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"atan" => f.atan(),
"log1p" => f.ln_1p(),
"expm1" => f.exp_m1(),
"tgamma" => f.gamma(),
_ => bug!(),
};
this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?;
@ -917,6 +921,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let res = x.scalbn(exp);
this.write_scalar(Scalar::from_f64(res), dest)?;
}
"lgammaf_r" => {
let [x, signp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
// FIXME: Using host floats.
let x = f32::from_bits(this.read_scalar(x)?.to_u32()?);
let signp = this.deref_pointer(signp)?;
let (res, sign) = x.ln_gamma();
this.write_int(sign, &signp)?;
this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?;
}
"lgamma_r" => {
let [x, signp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
// FIXME: Using host floats.
let x = f64::from_bits(this.read_scalar(x)?.to_u64()?);
let signp = this.deref_pointer(signp)?;
let (res, sign) = x.ln_gamma();
this.write_int(sign, &signp)?;
this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?;
}
// Architecture-specific shims
"llvm.x86.addcarry.64" if this.tcx.sess.target.arch == "x86_64" => {

View File

@ -1,5 +1,4 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
// SPDX-FileCopyrightText: The Rust Project Developers (see https://thanks.rust-lang.org)
#![feature(float_gamma)]
macro_rules! assert_approx_eq {
($a:expr, $b:expr) => {{
@ -130,4 +129,20 @@ pub fn main() {
);
assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32);
assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64);
assert_approx_eq!(5.0f32.gamma(), 24.0);
assert_approx_eq!(5.0f64.gamma(), 24.0);
// These fail even on the host, precision seems to be terrible.
//assert_approx_eq!(-0.5f32.gamma(), -2.0 * f32::consts::PI.sqrt());
//assert_approx_eq!(-0.5f64.gamma(), -2.0 * f64::consts::PI.sqrt());
assert_eq!(2.0f32.ln_gamma(), (0.0, 1));
assert_eq!(2.0f64.ln_gamma(), (0.0, 1));
// Gamma(-0.5) = -2*sqrt(π)
let (val, sign) = (-0.5f32).ln_gamma();
assert_approx_eq!(val, (2.0 * f32::consts::PI.sqrt()).ln());
assert_eq!(sign, -1);
let (val, sign) = (-0.5f64).ln_gamma();
assert_approx_eq!(val, (2.0 * f64::consts::PI.sqrt()).ln());
assert_eq!(sign, -1);
}