Skip to content

Commit

Permalink
Auto merge of rust-lang#130568 - eduardosm:const-float-methods, r=<try>
Browse files Browse the repository at this point in the history
Make some float methods unstable `const fn`

Some float methods are now `const fn` under the `const_float_methods` feature gate.

I also made some unstable methods `const fn`, keeping their constness under their respective feature gate.

In order to support `min`, `max`, `abs` and `copysign`, the implementation of some intrinsics had to be moved from Miri to rustc_const_eval (cc `@RalfJung).`

Tracking issue: rust-lang#130843

```rust
impl <float> {
    // #[feature(const_float_methods)]
    pub const fn recip(self) -> Self;
    pub const fn to_degrees(self) -> Self;
    pub const fn to_radians(self) -> Self;
    pub const fn max(self, other: Self) -> Self;
    pub const fn min(self, other: Self) -> Self;
    pub const fn clamp(self, min: Self, max: Self) -> Self;
    pub const fn abs(self) -> Self;
    pub const fn signum(self) -> Self;
    pub const fn copysign(self, sign: Self) -> Self;

    // #[feature(float_minimum_maximum)]
    pub const fn maximum(self, other: Self) -> Self;
    pub const fn minimum(self, other: Self) -> Self;

    // Only f16/f128 (f32/f64 already const)
    pub const fn is_sign_positive(self) -> bool;
    pub const fn is_sign_negative(self) -> bool;
    pub const fn next_up(self) -> Self;
    pub const fn next_down(self) -> Self;
}
```

r? libs-api

try-job: dist-s390x-linux
  • Loading branch information
bors committed Oct 15, 2024
2 parents 9322d18 + 029a881 commit b181e49
Show file tree
Hide file tree
Showing 18 changed files with 515 additions and 266 deletions.
27 changes: 10 additions & 17 deletions compiler/rustc_const_eval/src/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,19 +334,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
{
use rustc_type_ir::TyKind::*;

fn adjust_nan<
'tcx,
M: Machine<'tcx>,
F1: rustc_apfloat::Float + FloatConvert<F2>,
F2: rustc_apfloat::Float,
>(
ecx: &InterpCx<'tcx, M>,
f1: F1,
f2: F2,
) -> F2 {
if f2.is_nan() { M::generate_nan(ecx, &[f1]) } else { f2 }
}

match *dest_ty.kind() {
// float -> uint
Uint(t) => {
Expand All @@ -367,11 +354,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
// float -> float
Float(fty) => match fty {
FloatTy::F16 => Scalar::from_f16(adjust_nan(self, f, f.convert(&mut false).value)),
FloatTy::F32 => Scalar::from_f32(adjust_nan(self, f, f.convert(&mut false).value)),
FloatTy::F64 => Scalar::from_f64(adjust_nan(self, f, f.convert(&mut false).value)),
FloatTy::F16 => {
Scalar::from_f16(self.adjust_nan(f.convert(&mut false).value, &[f]))
}
FloatTy::F32 => {
Scalar::from_f32(self.adjust_nan(f.convert(&mut false).value, &[f]))
}
FloatTy::F64 => {
Scalar::from_f64(self.adjust_nan(f.convert(&mut false).value, &[f]))
}
FloatTy::F128 => {
Scalar::from_f128(adjust_nan(self, f, f.convert(&mut false).value))
Scalar::from_f128(self.adjust_nan(f.convert(&mut false).value, &[f]))
}
},
// That's it.
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>> {
Frame::generate_stacktrace_from_stack(self.stack())
}

pub fn adjust_nan<F1, F2>(&self, f: F2, inputs: &[F1]) -> F2
where
F1: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F2>,
F2: rustc_apfloat::Float,
{
if f.is_nan() { M::generate_nan(self, inputs) } else { f }
}
}

#[doc(hidden)]
Expand Down
80 changes: 80 additions & 0 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use std::assert_matches::assert_matches;

use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_hir::def_id::DefId;
use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
use rustc_middle::ty::layout::{LayoutOf as _, TyAndLayout, ValidityRequirement};
Expand Down Expand Up @@ -438,6 +439,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?;
}

sym::minnumf16 => self.float_min_intrinsic::<Half>(args, dest)?,
sym::minnumf32 => self.float_min_intrinsic::<Single>(args, dest)?,
sym::minnumf64 => self.float_min_intrinsic::<Double>(args, dest)?,
sym::minnumf128 => self.float_min_intrinsic::<Quad>(args, dest)?,

sym::maxnumf16 => self.float_max_intrinsic::<Half>(args, dest)?,
sym::maxnumf32 => self.float_max_intrinsic::<Single>(args, dest)?,
sym::maxnumf64 => self.float_max_intrinsic::<Double>(args, dest)?,
sym::maxnumf128 => self.float_max_intrinsic::<Quad>(args, dest)?,

sym::copysignf16 => self.float_copysign_intrinsic::<Half>(args, dest)?,
sym::copysignf32 => self.float_copysign_intrinsic::<Single>(args, dest)?,
sym::copysignf64 => self.float_copysign_intrinsic::<Double>(args, dest)?,
sym::copysignf128 => self.float_copysign_intrinsic::<Quad>(args, dest)?,

sym::fabsf16 => self.float_abs_intrinsic::<Half>(args, dest)?,
sym::fabsf32 => self.float_abs_intrinsic::<Single>(args, dest)?,
sym::fabsf64 => self.float_abs_intrinsic::<Double>(args, dest)?,
sym::fabsf128 => self.float_abs_intrinsic::<Quad>(args, dest)?,

// Unsupported intrinsic: skip the return_to_block below.
_ => return interp_ok(false),
}
Expand Down Expand Up @@ -697,4 +718,63 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let rhs_bytes = get_bytes(self, rhs)?;
interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes))
}

fn float_min_intrinsic<F>(
&mut self,
args: &[OpTy<'tcx, M::Provenance>],
dest: &MPlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx, ()>
where
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
{
let a: F = self.read_scalar(&args[0])?.to_float()?;
let b: F = self.read_scalar(&args[1])?.to_float()?;
let res = self.adjust_nan(a.min(b), &[a, b]);
self.write_scalar(res, dest)?;
interp_ok(())
}

fn float_max_intrinsic<F>(
&mut self,
args: &[OpTy<'tcx, M::Provenance>],
dest: &MPlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx, ()>
where
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
{
let a: F = self.read_scalar(&args[0])?.to_float()?;
let b: F = self.read_scalar(&args[1])?.to_float()?;
let res = self.adjust_nan(a.max(b), &[a, b]);
self.write_scalar(res, dest)?;
interp_ok(())
}

fn float_copysign_intrinsic<F>(
&mut self,
args: &[OpTy<'tcx, M::Provenance>],
dest: &MPlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx, ()>
where
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
{
let a: F = self.read_scalar(&args[0])?.to_float()?;
let b: F = self.read_scalar(&args[1])?.to_float()?;
// bitwise, no NaN adjustments
self.write_scalar(a.copy_sign(b), dest)?;
interp_ok(())
}

fn float_abs_intrinsic<F>(
&mut self,
args: &[OpTy<'tcx, M::Provenance>],
dest: &MPlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx, ()>
where
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
{
let x: F = self.read_scalar(&args[0])?.to_float()?;
// bitwise, no NaN adjustments
self.write_scalar(x.abs(), dest)?;
interp_ok(())
}
}
3 changes: 1 addition & 2 deletions compiler/rustc_const_eval/src/interpret/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
use rustc_middle::mir::BinOp::*;

// Performs appropriate non-deterministic adjustments of NaN results.
let adjust_nan =
|f: F| -> F { if f.is_nan() { M::generate_nan(self, &[l, r]) } else { f } };
let adjust_nan = |f: F| -> F { self.adjust_nan(f, &[l, r]) };

match bin_op {
Eq => ImmTy::from_bool(l == r, *self.tcx),
Expand Down
Loading

0 comments on commit b181e49

Please sign in to comment.