diff options
| author | Michael Goulet <michael@errs.io> | 2024-10-15 12:33:35 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-15 12:33:35 -0400 |
| commit | 2f3f001423286560e9a0b28bb9ef19c51c61f88e (patch) | |
| tree | c00e5ee0bafafc2f07bb9702f056fb2ef0f592da /compiler/rustc_const_eval/src | |
| parent | 34636e6e7c704918eb4713270619f949b0f7c79f (diff) | |
| parent | c09ed3e767a73d83673790f74c357432fa44d320 (diff) | |
| download | rust-2f3f001423286560e9a0b28bb9ef19c51c61f88e.tar.gz rust-2f3f001423286560e9a0b28bb9ef19c51c61f88e.zip | |
Rollup merge of #130568 - eduardosm:const-float-methods, r=RalfJung,tgross35
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: https://github.com/rust-lang/rust/issues/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
Diffstat (limited to 'compiler/rustc_const_eval/src')
4 files changed, 99 insertions, 19 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 30b5a8d70bc..1def3d08328 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -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) => { @@ -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. diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 5165f95afd5..02dd7821ef6 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -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)] diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 52780cc6a3a..540898ec645 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -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}; @@ -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), } @@ -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(()) + } } diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 52cd9b898bb..b28ac68ac54 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -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), |
