diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 7b795b96c242c..6160e51fb300f 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -438,21 +438,54 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?; } - sym::minnumf16 | sym::maxnumf16 => { - let is_max = intrinsic_name == sym::maxnumf16; - self.float_min_max_intrinsic::(is_max, args, dest)?; + sym::minnumf16 | sym::maxnumf16 | sym::copysignf16 => { + let op = match intrinsic_name { + sym::minnumf16 => FloatBinOp::Min, + sym::maxnumf16 => FloatBinOp::Max, + sym::copysignf16 => FloatBinOp::Copysign, + _ => bug!(), + }; + self.float_bin_op_intrinsic::(op, args, dest)?; + } + sym::minnumf32 | sym::maxnumf32 | sym::copysignf32 => { + let op = match intrinsic_name { + sym::minnumf32 => FloatBinOp::Min, + sym::maxnumf32 => FloatBinOp::Max, + sym::copysignf32 => FloatBinOp::Copysign, + _ => bug!(), + }; + self.float_bin_op_intrinsic::(op, args, dest)?; + } + sym::minnumf64 | sym::maxnumf64 | sym::copysignf64 => { + let op = match intrinsic_name { + sym::minnumf64 => FloatBinOp::Min, + sym::maxnumf64 => FloatBinOp::Max, + sym::copysignf64 => FloatBinOp::Copysign, + _ => bug!(), + }; + self.float_bin_op_intrinsic::(op, args, dest)?; + } + sym::minnumf128 | sym::maxnumf128 | sym::copysignf128 => { + let op = match intrinsic_name { + sym::minnumf128 => FloatBinOp::Min, + sym::maxnumf128 => FloatBinOp::Max, + sym::copysignf128 => FloatBinOp::Copysign, + _ => bug!(), + }; + self.float_bin_op_intrinsic::(op, args, dest)?; + } + + sym::fabsf16 => { + self.float_abs_intrinsic::(args, dest)?; } - sym::minnumf32 | sym::maxnumf32 => { - let is_max = intrinsic_name == sym::maxnumf32; - self.float_min_max_intrinsic::(is_max, args, dest)?; + sym::fabsf32 => { + self.float_abs_intrinsic::(args, dest)?; } - sym::minnumf64 | sym::maxnumf64 => { - let is_max = intrinsic_name == sym::maxnumf64; - self.float_min_max_intrinsic::(is_max, args, dest)?; + sym::fabsf64 => { + self.float_abs_intrinsic::(args, dest)?; } - sym::minnumf128 | sym::maxnumf128 => { - let is_max = intrinsic_name == sym::maxnumf128; - self.float_min_max_intrinsic::(is_max, args, dest)?; + sym::fabsf128 => { + self.float_abs_intrinsic::(args, dest)?; } // Unsupported intrinsic: skip the return_to_block below. @@ -715,9 +748,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes)) } - fn float_min_max_intrinsic( + fn float_bin_op_intrinsic( &mut self, - is_max: bool, + op: FloatBinOp, args: &[OpTy<'tcx, M::Provenance>], dest: &MPlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ()> @@ -726,10 +759,34 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { { let a: F = self.read_scalar(&args[0])?.to_float()?; let b: F = self.read_scalar(&args[1])?.to_float()?; - let res = if is_max { a.max(b) } else { a.min(b) }; - self.write_scalar(adjust_nan(self, res, &[a, b]), dest)?; + let res = match op { + FloatBinOp::Min => adjust_nan(self, a.min(b), &[a, b]), + FloatBinOp::Max => adjust_nan(self, a.max(b), &[a, b]), + FloatBinOp::Copysign => a.copy_sign(b), // bitwise, no NaN adjustments + }; + self.write_scalar(res, dest)?; interp_ok(()) } + + fn float_abs_intrinsic( + &mut self, + args: &[OpTy<'tcx, M::Provenance>], + dest: &MPlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ()> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { + let x: F = self.read_scalar(&args[0])?.to_float()?; + // bitwise, no NaN adjustments + self.write_scalar(x.abs(), dest)?; + interp_ok(()) + } +} + +enum FloatBinOp { + Min, + Max, + Copysign, } // Performs appropriate non-deterministic adjustments of NaN results. diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 8e8f92ddc6ba6..78f49f5db34f1 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1795,56 +1795,6 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn fmaf128(a: f128, b: f128, c: f128) -> f128; - /// Returns the absolute value of an `f16`. - /// - /// The stabilized version of this intrinsic is - /// [`f16::abs`](../../std/primitive.f16.html#method.abs) - #[rustc_nounwind] - pub fn fabsf16(x: f16) -> f16; - /// Returns the absolute value of an `f32`. - /// - /// The stabilized version of this intrinsic is - /// [`f32::abs`](../../std/primitive.f32.html#method.abs) - #[rustc_nounwind] - pub fn fabsf32(x: f32) -> f32; - /// Returns the absolute value of an `f64`. - /// - /// The stabilized version of this intrinsic is - /// [`f64::abs`](../../std/primitive.f64.html#method.abs) - #[rustc_nounwind] - pub fn fabsf64(x: f64) -> f64; - /// Returns the absolute value of an `f128`. - /// - /// The stabilized version of this intrinsic is - /// [`f128::abs`](../../std/primitive.f128.html#method.abs) - #[rustc_nounwind] - pub fn fabsf128(x: f128) -> f128; - - /// Copies the sign from `y` to `x` for `f16` values. - /// - /// The stabilized version of this intrinsic is - /// [`f16::copysign`](../../std/primitive.f16.html#method.copysign) - #[rustc_nounwind] - pub fn copysignf16(x: f16, y: f16) -> f16; - /// Copies the sign from `y` to `x` for `f32` values. - /// - /// The stabilized version of this intrinsic is - /// [`f32::copysign`](../../std/primitive.f32.html#method.copysign) - #[rustc_nounwind] - pub fn copysignf32(x: f32, y: f32) -> f32; - /// Copies the sign from `y` to `x` for `f64` values. - /// - /// The stabilized version of this intrinsic is - /// [`f64::copysign`](../../std/primitive.f64.html#method.copysign) - #[rustc_nounwind] - pub fn copysignf64(x: f64, y: f64) -> f64; - /// Copies the sign from `y` to `x` for `f128` values. - /// - /// The stabilized version of this intrinsic is - /// [`f128::copysign`](../../std/primitive.f128.html#method.copysign) - #[rustc_nounwind] - pub fn copysignf128(x: f128, y: f128) -> f128; - /// Returns the largest integer less than or equal to an `f16`. /// /// The stabilized version of this intrinsic is @@ -3539,6 +3489,105 @@ pub const fn maxnumf128(_x: f128, _y: f128) -> f128 { unimplemented!(); } +/// Returns the absolute value of an `f16`. +/// +/// The stabilized version of this intrinsic is +/// [`f16::abs`](../../std/primitive.f16.html#method.abs) +#[rustc_nounwind] +// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_const_unstable(feature = "f16", issue = "116909")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn fabsf16(_x: f16) -> f16 { + unimplemented!(); +} + +/// Returns the absolute value of an `f32`. +/// +/// The stabilized version of this intrinsic is +/// [`f32::abs`](../../std/primitive.f32.html#method.abs) +#[rustc_nounwind] +#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn fabsf32(_x: f32) -> f32 { + unimplemented!(); +} + +/// Returns the absolute value of an `f64`. +/// +/// The stabilized version of this intrinsic is +/// [`f64::abs`](../../std/primitive.f64.html#method.abs) +#[rustc_nounwind] +#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn fabsf64(_x: f64) -> f64 { + unimplemented!(); +} + +/// Returns the absolute value of an `f128`. +/// +/// The stabilized version of this intrinsic is +/// [`f128::abs`](../../std/primitive.f128.html#method.abs) +#[rustc_nounwind] +// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_const_unstable(feature = "f128", issue = "116909")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn fabsf128(_x: f128) -> f128 { + unimplemented!(); +} + +/// Copies the sign from `y` to `x` for `f16` values. +/// +/// The stabilized version of this intrinsic is +/// [`f16::copysign`](../../std/primitive.f16.html#method.copysign) +#[rustc_nounwind] +// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_const_unstable(feature = "f16", issue = "116909")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 { + unimplemented!(); +} + +/// Copies the sign from `y` to `x` for `f32` values. +/// +/// The stabilized version of this intrinsic is +/// [`f32::copysign`](../../std/primitive.f32.html#method.copysign) +#[rustc_nounwind] +#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 { + unimplemented!(); +} +/// Copies the sign from `y` to `x` for `f64` values. +/// +/// The stabilized version of this intrinsic is +/// [`f64::copysign`](../../std/primitive.f64.html#method.copysign) +#[rustc_nounwind] +#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 { + unimplemented!(); +} + +/// Copies the sign from `y` to `x` for `f128` values. +/// +/// The stabilized version of this intrinsic is +/// [`f128::copysign`](../../std/primitive.f128.html#method.copysign) +#[rustc_nounwind] +// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[rustc_const_unstable(feature = "f128", issue = "116909")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn copysignf128(_x: f128, _y: f128) -> f128 { + unimplemented!(); +} + /// Inform Miri that a given pointer definitely has a certain alignment. #[cfg(miri)] pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize) { diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs index b436fe9929c36..6ba85063875df 100644 --- a/library/std/src/f128.rs +++ b/library/std/src/f128.rs @@ -210,8 +210,10 @@ impl f128 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn abs(self) -> Self { + pub const fn abs(self) -> Self { // FIXME(f16_f128): replace with `intrinsics::fabsf128` when available // We don't do this now because LLVM has lowering bugs for f128 math. Self::from_bits(self.to_bits() & !(1 << 127)) @@ -240,8 +242,10 @@ impl f128 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn signum(self) -> f128 { + pub const fn signum(self) -> f128 { if self.is_nan() { Self::NAN } else { 1.0_f128.copysign(self) } } @@ -278,8 +282,10 @@ impl f128 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn copysign(self, sign: f128) -> f128 { + pub const fn copysign(self, sign: f128) -> f128 { unsafe { intrinsics::copysignf128(self, sign) } } diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs index b2cd5fae9d04a..24937c45d872d 100644 --- a/library/std/src/f16.rs +++ b/library/std/src/f16.rs @@ -210,8 +210,10 @@ impl f16 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn abs(self) -> Self { + pub const fn abs(self) -> Self { // FIXME(f16_f128): replace with `intrinsics::fabsf16` when available Self::from_bits(self.to_bits() & !(1 << 15)) } @@ -239,8 +241,10 @@ impl f16 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn signum(self) -> f16 { + pub const fn signum(self) -> f16 { if self.is_nan() { Self::NAN } else { 1.0_f16.copysign(self) } } @@ -277,8 +281,10 @@ impl f16 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + // #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] - pub fn copysign(self, sign: f16) -> f16 { + pub const fn copysign(self, sign: f16) -> f16 { unsafe { intrinsics::copysignf16(self, sign) } } diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index fa0b3ef6484f7..30cf4e1f756e0 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -194,8 +194,9 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn abs(self) -> f32 { + pub const fn abs(self) -> f32 { unsafe { intrinsics::fabsf32(self) } } @@ -218,8 +219,9 @@ impl f32 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn signum(self) -> f32 { + pub const fn signum(self) -> f32 { if self.is_nan() { Self::NAN } else { 1.0_f32.copysign(self) } } @@ -253,7 +255,8 @@ impl f32 { #[must_use = "method returns a new number and does not mutate the original value"] #[inline] #[stable(feature = "copysign", since = "1.35.0")] - pub fn copysign(self, sign: f32) -> f32 { + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] + pub const fn copysign(self, sign: f32) -> f32 { unsafe { intrinsics::copysignf32(self, sign) } } diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 9fa43a6742ea6..51d5476b372d2 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -194,8 +194,9 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn abs(self) -> f64 { + pub const fn abs(self) -> f64 { unsafe { intrinsics::fabsf64(self) } } @@ -218,8 +219,9 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn signum(self) -> f64 { + pub const fn signum(self) -> f64 { if self.is_nan() { Self::NAN } else { 1.0_f64.copysign(self) } } @@ -252,8 +254,9 @@ impl f64 { #[rustc_allow_incoherent_impl] #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "copysign", since = "1.35.0")] + #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] #[inline] - pub fn copysign(self, sign: f64) -> f64 { + pub const fn copysign(self, sign: f64) -> f64 { unsafe { intrinsics::copysignf64(self, sign) } } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 65a9aa66c7cc6..1c14e0691e566 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -288,6 +288,7 @@ #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] #![feature(concat_idents)] +#![feature(const_float_methods)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] @@ -297,7 +298,9 @@ #![feature(dropck_eyepatch)] #![feature(extended_varargs_abi_support)] #![feature(f128)] +#![feature(f128_const)] #![feature(f16)] +#![feature(f16_const)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] #![feature(lang_items)] diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 04b77d9766bc3..a3facafa665e8 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -145,20 +145,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_bool(branch), dest)?; } - // Floating-point operations - "fabsf32" => { - let [f] = check_arg_count(args)?; - let f = this.read_scalar(f)?.to_f32()?; - // This is a "bitwise" operation, so there's no NaN non-determinism. - this.write_scalar(Scalar::from_f32(f.abs()), dest)?; - } - "fabsf64" => { - let [f] = check_arg_count(args)?; - let f = this.read_scalar(f)?.to_f64()?; - // This is a "bitwise" operation, so there's no NaN non-determinism. - this.write_scalar(Scalar::from_f64(f.abs()), dest)?; - } - "floorf32" | "ceilf32" | "truncf32" | "roundf32" | "rintf32" => { let [f] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; @@ -249,21 +235,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } - "copysignf32" => { - let [a, b] = check_arg_count(args)?; - let a = this.read_scalar(a)?.to_f32()?; - let b = this.read_scalar(b)?.to_f32()?; - let res = a.copy_sign(b); // bitwise, no NaN adjustments - this.write_scalar(Scalar::from_f32(res), dest)?; - } - "copysignf64" => { - let [a, b] = check_arg_count(args)?; - let a = this.read_scalar(a)?.to_f64()?; - let b = this.read_scalar(b)?.to_f64()?; - let res = a.copy_sign(b); // bitwise, no NaN adjustments - this.write_scalar(Scalar::from_f64(res), dest)?; - } - "fmaf32" => { let [a, b, c] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f32()?; diff --git a/tests/ui/consts/const-eval/float_min_max.rs b/tests/ui/consts/const-eval/float_methods.rs similarity index 51% rename from tests/ui/consts/const-eval/float_min_max.rs rename to tests/ui/consts/const-eval/float_methods.rs index 38644c5d0711c..c7d4b6ee5bbee 100644 --- a/tests/ui/consts/const-eval/float_min_max.rs +++ b/tests/ui/consts/const-eval/float_methods.rs @@ -5,26 +5,42 @@ const F16_MIN: f16 = 1.0_f16.min(0.5_f16); const F16_MAX: f16 = 1.0_f16.max(0.5_f16); +const F16_ABS: f16 = (-1.0_f16).abs(); +const F16_COPYSIGN: f16 = 1.0_f16.copysign(-2.0_f16); const F32_MIN: f32 = 1.0_f32.min(0.5_f32); const F32_MAX: f32 = 1.0_f32.max(0.5_f32); +const F32_ABS: f32 = (-1.0_f32).abs(); +const F32_COPYSIGN: f32 = 1.0_f32.copysign(-2.0_f32); const F64_MIN: f64 = 1.0_f64.min(0.5_f64); const F64_MAX: f64 = 1.0_f64.max(0.5_f64); +const F64_ABS: f64 = (-1.0_f64).abs(); +const F64_COPYSIGN: f64 = 1.0_f64.copysign(-2.0_f64); const F128_MIN: f128 = 1.0_f128.min(0.5_f128); const F128_MAX: f128 = 1.0_f128.max(0.5_f128); +const F128_ABS: f128 = (-1.0_f128).abs(); +const F128_COPYSIGN: f128 = 1.0_f128.copysign(-2.0_f128); fn main() { assert_eq!(F16_MIN, 0.5); assert_eq!(F16_MAX, 1.0); + assert_eq!(F16_ABS, 1.0); + assert_eq!(F16_COPYSIGN, -1.0); assert_eq!(F32_MIN, 0.5); assert_eq!(F32_MAX, 1.0); + assert_eq!(F32_ABS, 1.0); + assert_eq!(F32_COPYSIGN, -1.0); assert_eq!(F64_MIN, 0.5); assert_eq!(F64_MAX, 1.0); + assert_eq!(F64_ABS, 1.0); + assert_eq!(F64_COPYSIGN, -1.0); assert_eq!(F128_MIN, 0.5); assert_eq!(F128_MAX, 1.0); + assert_eq!(F128_ABS, 1.0); + assert_eq!(F128_COPYSIGN, -1.0); }