about summary refs log tree commit diff
path: root/compiler/rustc_const_eval/src
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-10-15 12:33:35 -0400
committerGitHub <noreply@github.com>2024-10-15 12:33:35 -0400
commit2f3f001423286560e9a0b28bb9ef19c51c61f88e (patch)
treec00e5ee0bafafc2f07bb9702f056fb2ef0f592da /compiler/rustc_const_eval/src
parent34636e6e7c704918eb4713270619f949b0f7c79f (diff)
parentc09ed3e767a73d83673790f74c357432fa44d320 (diff)
downloadrust-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')
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs27
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs80
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs3
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),