Skip to content

Commit c09ed3e

Browse files
committedOct 15, 2024·
Make some float methods unstable const fn
Some float methods are now `const fn` under the `const_float_methods` 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.
1 parent b73e613 commit c09ed3e

File tree

14 files changed

+498
-243
lines changed

14 files changed

+498
-243
lines changed
 

‎compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
use std::assert_matches::assert_matches;
66

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

442+
sym::minnumf16 => self.float_min_intrinsic::<Half>(args, dest)?,
443+
sym::minnumf32 => self.float_min_intrinsic::<Single>(args, dest)?,
444+
sym::minnumf64 => self.float_min_intrinsic::<Double>(args, dest)?,
445+
sym::minnumf128 => self.float_min_intrinsic::<Quad>(args, dest)?,
446+
447+
sym::maxnumf16 => self.float_max_intrinsic::<Half>(args, dest)?,
448+
sym::maxnumf32 => self.float_max_intrinsic::<Single>(args, dest)?,
449+
sym::maxnumf64 => self.float_max_intrinsic::<Double>(args, dest)?,
450+
sym::maxnumf128 => self.float_max_intrinsic::<Quad>(args, dest)?,
451+
452+
sym::copysignf16 => self.float_copysign_intrinsic::<Half>(args, dest)?,
453+
sym::copysignf32 => self.float_copysign_intrinsic::<Single>(args, dest)?,
454+
sym::copysignf64 => self.float_copysign_intrinsic::<Double>(args, dest)?,
455+
sym::copysignf128 => self.float_copysign_intrinsic::<Quad>(args, dest)?,
456+
457+
sym::fabsf16 => self.float_abs_intrinsic::<Half>(args, dest)?,
458+
sym::fabsf32 => self.float_abs_intrinsic::<Single>(args, dest)?,
459+
sym::fabsf64 => self.float_abs_intrinsic::<Double>(args, dest)?,
460+
sym::fabsf128 => self.float_abs_intrinsic::<Quad>(args, dest)?,
461+
441462
// Unsupported intrinsic: skip the return_to_block below.
442463
_ => return interp_ok(false),
443464
}
@@ -697,4 +718,63 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
697718
let rhs_bytes = get_bytes(self, rhs)?;
698719
interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes))
699720
}
721+
722+
fn float_min_intrinsic<F>(
723+
&mut self,
724+
args: &[OpTy<'tcx, M::Provenance>],
725+
dest: &MPlaceTy<'tcx, M::Provenance>,
726+
) -> InterpResult<'tcx, ()>
727+
where
728+
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
729+
{
730+
let a: F = self.read_scalar(&args[0])?.to_float()?;
731+
let b: F = self.read_scalar(&args[1])?.to_float()?;
732+
let res = self.adjust_nan(a.min(b), &[a, b]);
733+
self.write_scalar(res, dest)?;
734+
interp_ok(())
735+
}
736+
737+
fn float_max_intrinsic<F>(
738+
&mut self,
739+
args: &[OpTy<'tcx, M::Provenance>],
740+
dest: &MPlaceTy<'tcx, M::Provenance>,
741+
) -> InterpResult<'tcx, ()>
742+
where
743+
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
744+
{
745+
let a: F = self.read_scalar(&args[0])?.to_float()?;
746+
let b: F = self.read_scalar(&args[1])?.to_float()?;
747+
let res = self.adjust_nan(a.max(b), &[a, b]);
748+
self.write_scalar(res, dest)?;
749+
interp_ok(())
750+
}
751+
752+
fn float_copysign_intrinsic<F>(
753+
&mut self,
754+
args: &[OpTy<'tcx, M::Provenance>],
755+
dest: &MPlaceTy<'tcx, M::Provenance>,
756+
) -> InterpResult<'tcx, ()>
757+
where
758+
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
759+
{
760+
let a: F = self.read_scalar(&args[0])?.to_float()?;
761+
let b: F = self.read_scalar(&args[1])?.to_float()?;
762+
// bitwise, no NaN adjustments
763+
self.write_scalar(a.copy_sign(b), dest)?;
764+
interp_ok(())
765+
}
766+
767+
fn float_abs_intrinsic<F>(
768+
&mut self,
769+
args: &[OpTy<'tcx, M::Provenance>],
770+
dest: &MPlaceTy<'tcx, M::Provenance>,
771+
) -> InterpResult<'tcx, ()>
772+
where
773+
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
774+
{
775+
let x: F = self.read_scalar(&args[0])?.to_float()?;
776+
// bitwise, no NaN adjustments
777+
self.write_scalar(x.abs(), dest)?;
778+
interp_ok(())
779+
}
700780
}

‎library/core/src/intrinsics.rs

Lines changed: 239 additions & 148 deletions
Large diffs are not rendered by default.

‎library/core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
#![feature(const_char_encode_utf16)]
121121
#![feature(const_eval_select)]
122122
#![feature(const_exact_div)]
123+
#![feature(const_float_methods)]
123124
#![feature(const_fmt_arguments_new)]
124125
#![feature(const_hash)]
125126
#![feature(const_heap)]

‎library/core/src/num/f128.rs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ impl f128 {
471471
#[inline]
472472
#[must_use]
473473
#[unstable(feature = "f128", issue = "116909")]
474-
pub fn is_sign_positive(self) -> bool {
474+
pub const fn is_sign_positive(self) -> bool {
475475
!self.is_sign_negative()
476476
}
477477

@@ -497,7 +497,7 @@ impl f128 {
497497
#[inline]
498498
#[must_use]
499499
#[unstable(feature = "f128", issue = "116909")]
500-
pub fn is_sign_negative(self) -> bool {
500+
pub const fn is_sign_negative(self) -> bool {
501501
// IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
502502
// applies to zeros and NaNs as well.
503503
// SAFETY: This is just transmuting to get the sign bit, it's fine.
@@ -538,7 +538,7 @@ impl f128 {
538538
#[inline]
539539
#[unstable(feature = "f128", issue = "116909")]
540540
// #[unstable(feature = "float_next_up_down", issue = "91399")]
541-
pub fn next_up(self) -> Self {
541+
pub const fn next_up(self) -> Self {
542542
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
543543
// denormals to zero. This is in general unsound and unsupported, but here
544544
// we do our best to still produce the correct result on such targets.
@@ -592,7 +592,7 @@ impl f128 {
592592
#[inline]
593593
#[unstable(feature = "f128", issue = "116909")]
594594
// #[unstable(feature = "float_next_up_down", issue = "91399")]
595-
pub fn next_down(self) -> Self {
595+
pub const fn next_down(self) -> Self {
596596
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
597597
// denormals to zero. This is in general unsound and unsupported, but here
598598
// we do our best to still produce the correct result on such targets.
@@ -627,8 +627,9 @@ impl f128 {
627627
/// ```
628628
#[inline]
629629
#[unstable(feature = "f128", issue = "116909")]
630+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
630631
#[must_use = "this returns the result of the operation, without modifying the original"]
631-
pub fn recip(self) -> Self {
632+
pub const fn recip(self) -> Self {
632633
1.0 / self
633634
}
634635

@@ -647,8 +648,9 @@ impl f128 {
647648
/// ```
648649
#[inline]
649650
#[unstable(feature = "f128", issue = "116909")]
651+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
650652
#[must_use = "this returns the result of the operation, without modifying the original"]
651-
pub fn to_degrees(self) -> Self {
653+
pub const fn to_degrees(self) -> Self {
652654
// Use a literal for better precision.
653655
const PIS_IN_180: f128 = 57.2957795130823208767981548141051703324054724665643215491602_f128;
654656
self * PIS_IN_180
@@ -670,8 +672,9 @@ impl f128 {
670672
/// ```
671673
#[inline]
672674
#[unstable(feature = "f128", issue = "116909")]
675+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
673676
#[must_use = "this returns the result of the operation, without modifying the original"]
674-
pub fn to_radians(self) -> f128 {
677+
pub const fn to_radians(self) -> f128 {
675678
// Use a literal for better precision.
676679
const RADS_PER_DEG: f128 =
677680
0.0174532925199432957692369076848861271344287188854172545609719_f128;
@@ -698,8 +701,9 @@ impl f128 {
698701
/// ```
699702
#[inline]
700703
#[unstable(feature = "f128", issue = "116909")]
704+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
701705
#[must_use = "this returns the result of the comparison, without modifying either input"]
702-
pub fn max(self, other: f128) -> f128 {
706+
pub const fn max(self, other: f128) -> f128 {
703707
intrinsics::maxnumf128(self, other)
704708
}
705709

@@ -723,8 +727,9 @@ impl f128 {
723727
/// ```
724728
#[inline]
725729
#[unstable(feature = "f128", issue = "116909")]
730+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
726731
#[must_use = "this returns the result of the comparison, without modifying either input"]
727-
pub fn min(self, other: f128) -> f128 {
732+
pub const fn min(self, other: f128) -> f128 {
728733
intrinsics::minnumf128(self, other)
729734
}
730735

@@ -757,7 +762,7 @@ impl f128 {
757762
#[unstable(feature = "f128", issue = "116909")]
758763
// #[unstable(feature = "float_minimum_maximum", issue = "91079")]
759764
#[must_use = "this returns the result of the comparison, without modifying either input"]
760-
pub fn maximum(self, other: f128) -> f128 {
765+
pub const fn maximum(self, other: f128) -> f128 {
761766
if self > other {
762767
self
763768
} else if other > self {
@@ -798,7 +803,7 @@ impl f128 {
798803
#[unstable(feature = "f128", issue = "116909")]
799804
// #[unstable(feature = "float_minimum_maximum", issue = "91079")]
800805
#[must_use = "this returns the result of the comparison, without modifying either input"]
801-
pub fn minimum(self, other: f128) -> f128 {
806+
pub const fn minimum(self, other: f128) -> f128 {
802807
if self < other {
803808
self
804809
} else if other < self {
@@ -1269,9 +1274,20 @@ impl f128 {
12691274
/// ```
12701275
#[inline]
12711276
#[unstable(feature = "f128", issue = "116909")]
1277+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
12721278
#[must_use = "method returns a new number and does not mutate the original value"]
1273-
pub fn clamp(mut self, min: f128, max: f128) -> f128 {
1274-
assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}");
1279+
pub const fn clamp(mut self, min: f128, max: f128) -> f128 {
1280+
#[inline] // inline to avoid LLVM crash
1281+
const fn assert_at_const(min: f128, max: f128) {
1282+
// Note that we cannot format in constant expressions.
1283+
assert!(min <= max, "min > max, or either was NaN");
1284+
}
1285+
#[inline] // inline to avoid codegen regression
1286+
fn assert_at_rt(min: f128, max: f128) {
1287+
assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}");
1288+
}
1289+
// FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly.
1290+
intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt);
12751291
if self < min {
12761292
self = min;
12771293
}

‎library/core/src/num/f16.rs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ impl f16 {
459459
#[inline]
460460
#[must_use]
461461
#[unstable(feature = "f16", issue = "116909")]
462-
pub fn is_sign_positive(self) -> bool {
462+
pub const fn is_sign_positive(self) -> bool {
463463
!self.is_sign_negative()
464464
}
465465

@@ -488,7 +488,7 @@ impl f16 {
488488
#[inline]
489489
#[must_use]
490490
#[unstable(feature = "f16", issue = "116909")]
491-
pub fn is_sign_negative(self) -> bool {
491+
pub const fn is_sign_negative(self) -> bool {
492492
// IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
493493
// applies to zeros and NaNs as well.
494494
// SAFETY: This is just transmuting to get the sign bit, it's fine.
@@ -529,7 +529,7 @@ impl f16 {
529529
#[inline]
530530
#[unstable(feature = "f16", issue = "116909")]
531531
// #[unstable(feature = "float_next_up_down", issue = "91399")]
532-
pub fn next_up(self) -> Self {
532+
pub const fn next_up(self) -> Self {
533533
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
534534
// denormals to zero. This is in general unsound and unsupported, but here
535535
// we do our best to still produce the correct result on such targets.
@@ -583,7 +583,7 @@ impl f16 {
583583
#[inline]
584584
#[unstable(feature = "f16", issue = "116909")]
585585
// #[unstable(feature = "float_next_up_down", issue = "91399")]
586-
pub fn next_down(self) -> Self {
586+
pub const fn next_down(self) -> Self {
587587
// Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
588588
// denormals to zero. This is in general unsound and unsupported, but here
589589
// we do our best to still produce the correct result on such targets.
@@ -618,8 +618,9 @@ impl f16 {
618618
/// ```
619619
#[inline]
620620
#[unstable(feature = "f16", issue = "116909")]
621+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
621622
#[must_use = "this returns the result of the operation, without modifying the original"]
622-
pub fn recip(self) -> Self {
623+
pub const fn recip(self) -> Self {
623624
1.0 / self
624625
}
625626

@@ -638,8 +639,9 @@ impl f16 {
638639
/// ```
639640
#[inline]
640641
#[unstable(feature = "f16", issue = "116909")]
642+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
641643
#[must_use = "this returns the result of the operation, without modifying the original"]
642-
pub fn to_degrees(self) -> Self {
644+
pub const fn to_degrees(self) -> Self {
643645
// Use a literal for better precision.
644646
const PIS_IN_180: f16 = 57.2957795130823208767981548141051703_f16;
645647
self * PIS_IN_180
@@ -661,8 +663,9 @@ impl f16 {
661663
/// ```
662664
#[inline]
663665
#[unstable(feature = "f16", issue = "116909")]
666+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
664667
#[must_use = "this returns the result of the operation, without modifying the original"]
665-
pub fn to_radians(self) -> f16 {
668+
pub const fn to_radians(self) -> f16 {
666669
// Use a literal for better precision.
667670
const RADS_PER_DEG: f16 = 0.017453292519943295769236907684886_f16;
668671
self * RADS_PER_DEG
@@ -687,8 +690,9 @@ impl f16 {
687690
/// ```
688691
#[inline]
689692
#[unstable(feature = "f16", issue = "116909")]
693+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
690694
#[must_use = "this returns the result of the comparison, without modifying either input"]
691-
pub fn max(self, other: f16) -> f16 {
695+
pub const fn max(self, other: f16) -> f16 {
692696
intrinsics::maxnumf16(self, other)
693697
}
694698

@@ -711,8 +715,9 @@ impl f16 {
711715
/// ```
712716
#[inline]
713717
#[unstable(feature = "f16", issue = "116909")]
718+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
714719
#[must_use = "this returns the result of the comparison, without modifying either input"]
715-
pub fn min(self, other: f16) -> f16 {
720+
pub const fn min(self, other: f16) -> f16 {
716721
intrinsics::minnumf16(self, other)
717722
}
718723

@@ -744,7 +749,7 @@ impl f16 {
744749
#[unstable(feature = "f16", issue = "116909")]
745750
// #[unstable(feature = "float_minimum_maximum", issue = "91079")]
746751
#[must_use = "this returns the result of the comparison, without modifying either input"]
747-
pub fn maximum(self, other: f16) -> f16 {
752+
pub const fn maximum(self, other: f16) -> f16 {
748753
if self > other {
749754
self
750755
} else if other > self {
@@ -784,7 +789,7 @@ impl f16 {
784789
#[unstable(feature = "f16", issue = "116909")]
785790
// #[unstable(feature = "float_minimum_maximum", issue = "91079")]
786791
#[must_use = "this returns the result of the comparison, without modifying either input"]
787-
pub fn minimum(self, other: f16) -> f16 {
792+
pub const fn minimum(self, other: f16) -> f16 {
788793
if self < other {
789794
self
790795
} else if other < self {
@@ -1244,9 +1249,20 @@ impl f16 {
12441249
/// ```
12451250
#[inline]
12461251
#[unstable(feature = "f16", issue = "116909")]
1252+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
12471253
#[must_use = "method returns a new number and does not mutate the original value"]
1248-
pub fn clamp(mut self, min: f16, max: f16) -> f16 {
1249-
assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}");
1254+
pub const fn clamp(mut self, min: f16, max: f16) -> f16 {
1255+
#[inline] // inline to avoid LLVM crash
1256+
const fn assert_at_const(min: f16, max: f16) {
1257+
// Note that we cannot format in constant expressions.
1258+
assert!(min <= max, "min > max, or either was NaN");
1259+
}
1260+
#[inline] // inline to avoid codegen regression
1261+
fn assert_at_rt(min: f16, max: f16) {
1262+
assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}");
1263+
}
1264+
// FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly.
1265+
intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt);
12501266
if self < min {
12511267
self = min;
12521268
}

‎library/core/src/num/f32.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -828,8 +828,9 @@ impl f32 {
828828
/// ```
829829
#[must_use = "this returns the result of the operation, without modifying the original"]
830830
#[stable(feature = "rust1", since = "1.0.0")]
831+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
831832
#[inline]
832-
pub fn recip(self) -> f32 {
833+
pub const fn recip(self) -> f32 {
833834
1.0 / self
834835
}
835836

@@ -845,8 +846,9 @@ impl f32 {
845846
#[must_use = "this returns the result of the operation, \
846847
without modifying the original"]
847848
#[stable(feature = "f32_deg_rad_conversions", since = "1.7.0")]
849+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
848850
#[inline]
849-
pub fn to_degrees(self) -> f32 {
851+
pub const fn to_degrees(self) -> f32 {
850852
// Use a constant for better precision.
851853
const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32;
852854
self * PIS_IN_180
@@ -864,8 +866,9 @@ impl f32 {
864866
#[must_use = "this returns the result of the operation, \
865867
without modifying the original"]
866868
#[stable(feature = "f32_deg_rad_conversions", since = "1.7.0")]
869+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
867870
#[inline]
868-
pub fn to_radians(self) -> f32 {
871+
pub const fn to_radians(self) -> f32 {
869872
const RADS_PER_DEG: f32 = consts::PI / 180.0;
870873
self * RADS_PER_DEG
871874
}
@@ -885,8 +888,9 @@ impl f32 {
885888
/// ```
886889
#[must_use = "this returns the result of the comparison, without modifying either input"]
887890
#[stable(feature = "rust1", since = "1.0.0")]
891+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
888892
#[inline]
889-
pub fn max(self, other: f32) -> f32 {
893+
pub const fn max(self, other: f32) -> f32 {
890894
intrinsics::maxnumf32(self, other)
891895
}
892896

@@ -905,8 +909,9 @@ impl f32 {
905909
/// ```
906910
#[must_use = "this returns the result of the comparison, without modifying either input"]
907911
#[stable(feature = "rust1", since = "1.0.0")]
912+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
908913
#[inline]
909-
pub fn min(self, other: f32) -> f32 {
914+
pub const fn min(self, other: f32) -> f32 {
910915
intrinsics::minnumf32(self, other)
911916
}
912917

@@ -933,7 +938,7 @@ impl f32 {
933938
#[must_use = "this returns the result of the comparison, without modifying either input"]
934939
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
935940
#[inline]
936-
pub fn maximum(self, other: f32) -> f32 {
941+
pub const fn maximum(self, other: f32) -> f32 {
937942
if self > other {
938943
self
939944
} else if other > self {
@@ -968,7 +973,7 @@ impl f32 {
968973
#[must_use = "this returns the result of the comparison, without modifying either input"]
969974
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
970975
#[inline]
971-
pub fn minimum(self, other: f32) -> f32 {
976+
pub const fn minimum(self, other: f32) -> f32 {
972977
if self < other {
973978
self
974979
} else if other < self {
@@ -1401,9 +1406,19 @@ impl f32 {
14011406
/// ```
14021407
#[must_use = "method returns a new number and does not mutate the original value"]
14031408
#[stable(feature = "clamp", since = "1.50.0")]
1409+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
14041410
#[inline]
1405-
pub fn clamp(mut self, min: f32, max: f32) -> f32 {
1406-
assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}");
1411+
pub const fn clamp(mut self, min: f32, max: f32) -> f32 {
1412+
const fn assert_at_const(min: f32, max: f32) {
1413+
// Note that we cannot format in constant expressions.
1414+
assert!(min <= max, "min > max, or either was NaN");
1415+
}
1416+
#[inline] // inline to avoid codegen regression
1417+
fn assert_at_rt(min: f32, max: f32) {
1418+
assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}");
1419+
}
1420+
// FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly.
1421+
intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt);
14071422
if self < min {
14081423
self = min;
14091424
}

‎library/core/src/num/f64.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -845,8 +845,9 @@ impl f64 {
845845
/// ```
846846
#[must_use = "this returns the result of the operation, without modifying the original"]
847847
#[stable(feature = "rust1", since = "1.0.0")]
848+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
848849
#[inline]
849-
pub fn recip(self) -> f64 {
850+
pub const fn recip(self) -> f64 {
850851
1.0 / self
851852
}
852853

@@ -862,8 +863,9 @@ impl f64 {
862863
#[must_use = "this returns the result of the operation, \
863864
without modifying the original"]
864865
#[stable(feature = "rust1", since = "1.0.0")]
866+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
865867
#[inline]
866-
pub fn to_degrees(self) -> f64 {
868+
pub const fn to_degrees(self) -> f64 {
867869
// The division here is correctly rounded with respect to the true
868870
// value of 180/π. (This differs from f32, where a constant must be
869871
// used to ensure a correctly rounded result.)
@@ -882,8 +884,9 @@ impl f64 {
882884
#[must_use = "this returns the result of the operation, \
883885
without modifying the original"]
884886
#[stable(feature = "rust1", since = "1.0.0")]
887+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
885888
#[inline]
886-
pub fn to_radians(self) -> f64 {
889+
pub const fn to_radians(self) -> f64 {
887890
const RADS_PER_DEG: f64 = consts::PI / 180.0;
888891
self * RADS_PER_DEG
889892
}
@@ -903,8 +906,9 @@ impl f64 {
903906
/// ```
904907
#[must_use = "this returns the result of the comparison, without modifying either input"]
905908
#[stable(feature = "rust1", since = "1.0.0")]
909+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
906910
#[inline]
907-
pub fn max(self, other: f64) -> f64 {
911+
pub const fn max(self, other: f64) -> f64 {
908912
intrinsics::maxnumf64(self, other)
909913
}
910914

@@ -923,8 +927,9 @@ impl f64 {
923927
/// ```
924928
#[must_use = "this returns the result of the comparison, without modifying either input"]
925929
#[stable(feature = "rust1", since = "1.0.0")]
930+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
926931
#[inline]
927-
pub fn min(self, other: f64) -> f64 {
932+
pub const fn min(self, other: f64) -> f64 {
928933
intrinsics::minnumf64(self, other)
929934
}
930935

@@ -951,7 +956,7 @@ impl f64 {
951956
#[must_use = "this returns the result of the comparison, without modifying either input"]
952957
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
953958
#[inline]
954-
pub fn maximum(self, other: f64) -> f64 {
959+
pub const fn maximum(self, other: f64) -> f64 {
955960
if self > other {
956961
self
957962
} else if other > self {
@@ -986,7 +991,7 @@ impl f64 {
986991
#[must_use = "this returns the result of the comparison, without modifying either input"]
987992
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
988993
#[inline]
989-
pub fn minimum(self, other: f64) -> f64 {
994+
pub const fn minimum(self, other: f64) -> f64 {
990995
if self < other {
991996
self
992997
} else if other < self {
@@ -1401,9 +1406,19 @@ impl f64 {
14011406
/// ```
14021407
#[must_use = "method returns a new number and does not mutate the original value"]
14031408
#[stable(feature = "clamp", since = "1.50.0")]
1409+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
14041410
#[inline]
1405-
pub fn clamp(mut self, min: f64, max: f64) -> f64 {
1406-
assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}");
1411+
pub const fn clamp(mut self, min: f64, max: f64) -> f64 {
1412+
const fn assert_at_const(min: f64, max: f64) {
1413+
// Note that we cannot format in constant expressions.
1414+
assert!(min <= max, "min > max, or either was NaN");
1415+
}
1416+
#[inline] // inline to avoid codegen regression
1417+
fn assert_at_rt(min: f64, max: f64) {
1418+
assert!(min <= max, "min > max, or either was NaN. min = {min:?}, max = {max:?}");
1419+
}
1420+
// FIXME(const-hack): We would prefer to have streamlined panics when formatters become const-friendly.
1421+
intrinsics::const_eval_select((min, max), assert_at_const, assert_at_rt);
14071422
if self < min {
14081423
self = min;
14091424
}

‎library/std/src/f128.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,9 @@ impl f128 {
210210
#[inline]
211211
#[rustc_allow_incoherent_impl]
212212
#[unstable(feature = "f128", issue = "116909")]
213+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
213214
#[must_use = "method returns a new number and does not mutate the original value"]
214-
pub fn abs(self) -> Self {
215+
pub const fn abs(self) -> Self {
215216
// FIXME(f16_f128): replace with `intrinsics::fabsf128` when available
216217
// We don't do this now because LLVM has lowering bugs for f128 math.
217218
Self::from_bits(self.to_bits() & !(1 << 127))
@@ -240,8 +241,9 @@ impl f128 {
240241
#[inline]
241242
#[rustc_allow_incoherent_impl]
242243
#[unstable(feature = "f128", issue = "116909")]
244+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
243245
#[must_use = "method returns a new number and does not mutate the original value"]
244-
pub fn signum(self) -> f128 {
246+
pub const fn signum(self) -> f128 {
245247
if self.is_nan() { Self::NAN } else { 1.0_f128.copysign(self) }
246248
}
247249

@@ -278,8 +280,9 @@ impl f128 {
278280
#[inline]
279281
#[rustc_allow_incoherent_impl]
280282
#[unstable(feature = "f128", issue = "116909")]
283+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
281284
#[must_use = "method returns a new number and does not mutate the original value"]
282-
pub fn copysign(self, sign: f128) -> f128 {
285+
pub const fn copysign(self, sign: f128) -> f128 {
283286
unsafe { intrinsics::copysignf128(self, sign) }
284287
}
285288

‎library/std/src/f16.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,9 @@ impl f16 {
210210
#[inline]
211211
#[rustc_allow_incoherent_impl]
212212
#[unstable(feature = "f16", issue = "116909")]
213+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
213214
#[must_use = "method returns a new number and does not mutate the original value"]
214-
pub fn abs(self) -> Self {
215+
pub const fn abs(self) -> Self {
215216
// FIXME(f16_f128): replace with `intrinsics::fabsf16` when available
216217
Self::from_bits(self.to_bits() & !(1 << 15))
217218
}
@@ -239,8 +240,9 @@ impl f16 {
239240
#[inline]
240241
#[rustc_allow_incoherent_impl]
241242
#[unstable(feature = "f16", issue = "116909")]
243+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
242244
#[must_use = "method returns a new number and does not mutate the original value"]
243-
pub fn signum(self) -> f16 {
245+
pub const fn signum(self) -> f16 {
244246
if self.is_nan() { Self::NAN } else { 1.0_f16.copysign(self) }
245247
}
246248

@@ -277,8 +279,9 @@ impl f16 {
277279
#[inline]
278280
#[rustc_allow_incoherent_impl]
279281
#[unstable(feature = "f16", issue = "116909")]
282+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
280283
#[must_use = "method returns a new number and does not mutate the original value"]
281-
pub fn copysign(self, sign: f16) -> f16 {
284+
pub const fn copysign(self, sign: f16) -> f16 {
282285
unsafe { intrinsics::copysignf16(self, sign) }
283286
}
284287

‎library/std/src/f32.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,9 @@ impl f32 {
194194
#[rustc_allow_incoherent_impl]
195195
#[must_use = "method returns a new number and does not mutate the original value"]
196196
#[stable(feature = "rust1", since = "1.0.0")]
197+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
197198
#[inline]
198-
pub fn abs(self) -> f32 {
199+
pub const fn abs(self) -> f32 {
199200
unsafe { intrinsics::fabsf32(self) }
200201
}
201202

@@ -218,8 +219,9 @@ impl f32 {
218219
#[rustc_allow_incoherent_impl]
219220
#[must_use = "method returns a new number and does not mutate the original value"]
220221
#[stable(feature = "rust1", since = "1.0.0")]
222+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
221223
#[inline]
222-
pub fn signum(self) -> f32 {
224+
pub const fn signum(self) -> f32 {
223225
if self.is_nan() { Self::NAN } else { 1.0_f32.copysign(self) }
224226
}
225227

@@ -253,7 +255,8 @@ impl f32 {
253255
#[must_use = "method returns a new number and does not mutate the original value"]
254256
#[inline]
255257
#[stable(feature = "copysign", since = "1.35.0")]
256-
pub fn copysign(self, sign: f32) -> f32 {
258+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
259+
pub const fn copysign(self, sign: f32) -> f32 {
257260
unsafe { intrinsics::copysignf32(self, sign) }
258261
}
259262

‎library/std/src/f64.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,9 @@ impl f64 {
194194
#[rustc_allow_incoherent_impl]
195195
#[must_use = "method returns a new number and does not mutate the original value"]
196196
#[stable(feature = "rust1", since = "1.0.0")]
197+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
197198
#[inline]
198-
pub fn abs(self) -> f64 {
199+
pub const fn abs(self) -> f64 {
199200
unsafe { intrinsics::fabsf64(self) }
200201
}
201202

@@ -218,8 +219,9 @@ impl f64 {
218219
#[rustc_allow_incoherent_impl]
219220
#[must_use = "method returns a new number and does not mutate the original value"]
220221
#[stable(feature = "rust1", since = "1.0.0")]
222+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
221223
#[inline]
222-
pub fn signum(self) -> f64 {
224+
pub const fn signum(self) -> f64 {
223225
if self.is_nan() { Self::NAN } else { 1.0_f64.copysign(self) }
224226
}
225227

@@ -252,8 +254,9 @@ impl f64 {
252254
#[rustc_allow_incoherent_impl]
253255
#[must_use = "method returns a new number and does not mutate the original value"]
254256
#[stable(feature = "copysign", since = "1.35.0")]
257+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
255258
#[inline]
256-
pub fn copysign(self, sign: f64) -> f64 {
259+
pub const fn copysign(self, sign: f64) -> f64 {
257260
unsafe { intrinsics::copysignf64(self, sign) }
258261
}
259262

‎library/std/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@
288288
#![feature(cfg_target_thread_local)]
289289
#![feature(cfi_encoding)]
290290
#![feature(concat_idents)]
291+
#![feature(const_float_methods)]
291292
#![feature(decl_macro)]
292293
#![feature(deprecated_suggestion)]
293294
#![feature(doc_cfg)]

‎src/tools/miri/src/intrinsics/mod.rs

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -145,20 +145,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
145145
this.write_scalar(Scalar::from_bool(branch), dest)?;
146146
}
147147

148-
// Floating-point operations
149-
"fabsf32" => {
150-
let [f] = check_arg_count(args)?;
151-
let f = this.read_scalar(f)?.to_f32()?;
152-
// This is a "bitwise" operation, so there's no NaN non-determinism.
153-
this.write_scalar(Scalar::from_f32(f.abs()), dest)?;
154-
}
155-
"fabsf64" => {
156-
let [f] = check_arg_count(args)?;
157-
let f = this.read_scalar(f)?.to_f64()?;
158-
// This is a "bitwise" operation, so there's no NaN non-determinism.
159-
this.write_scalar(Scalar::from_f64(f.abs()), dest)?;
160-
}
161-
162148
"floorf32" | "ceilf32" | "truncf32" | "roundf32" | "rintf32" => {
163149
let [f] = check_arg_count(args)?;
164150
let f = this.read_scalar(f)?.to_f32()?;
@@ -249,31 +235,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
249235
this.write_scalar(res, dest)?;
250236
}
251237

252-
"minnumf32" | "maxnumf32" | "copysignf32" => {
253-
let [a, b] = check_arg_count(args)?;
254-
let a = this.read_scalar(a)?.to_f32()?;
255-
let b = this.read_scalar(b)?.to_f32()?;
256-
let res = match intrinsic_name {
257-
"minnumf32" => this.adjust_nan(a.min(b), &[a, b]),
258-
"maxnumf32" => this.adjust_nan(a.max(b), &[a, b]),
259-
"copysignf32" => a.copy_sign(b), // bitwise, no NaN adjustments
260-
_ => bug!(),
261-
};
262-
this.write_scalar(Scalar::from_f32(res), dest)?;
263-
}
264-
"minnumf64" | "maxnumf64" | "copysignf64" => {
265-
let [a, b] = check_arg_count(args)?;
266-
let a = this.read_scalar(a)?.to_f64()?;
267-
let b = this.read_scalar(b)?.to_f64()?;
268-
let res = match intrinsic_name {
269-
"minnumf64" => this.adjust_nan(a.min(b), &[a, b]),
270-
"maxnumf64" => this.adjust_nan(a.max(b), &[a, b]),
271-
"copysignf64" => a.copy_sign(b), // bitwise, no NaN adjustments
272-
_ => bug!(),
273-
};
274-
this.write_scalar(Scalar::from_f64(res), dest)?;
275-
}
276-
277238
"fmaf32" => {
278239
let [a, b, c] = check_arg_count(args)?;
279240
let a = this.read_scalar(a)?.to_f32()?;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//@ run-pass
2+
//! Tests the float intrinsics: min, max, abs, copysign
3+
4+
#![feature(const_float_methods)]
5+
#![feature(f16, f128)]
6+
7+
const F16_MIN: f16 = 1.0_f16.min(0.5_f16);
8+
const F16_MAX: f16 = 1.0_f16.max(0.5_f16);
9+
const F16_ABS: f16 = (-1.0_f16).abs();
10+
const F16_COPYSIGN: f16 = 1.0_f16.copysign(-2.0_f16);
11+
12+
const F32_MIN: f32 = 1.0_f32.min(0.5_f32);
13+
const F32_MAX: f32 = 1.0_f32.max(0.5_f32);
14+
const F32_ABS: f32 = (-1.0_f32).abs();
15+
const F32_COPYSIGN: f32 = 1.0_f32.copysign(-2.0_f32);
16+
17+
const F64_MIN: f64 = 1.0_f64.min(0.5_f64);
18+
const F64_MAX: f64 = 1.0_f64.max(0.5_f64);
19+
const F64_ABS: f64 = (-1.0_f64).abs();
20+
const F64_COPYSIGN: f64 = 1.0_f64.copysign(-2.0_f64);
21+
22+
const F128_MIN: f128 = 1.0_f128.min(0.5_f128);
23+
const F128_MAX: f128 = 1.0_f128.max(0.5_f128);
24+
const F128_ABS: f128 = (-1.0_f128).abs();
25+
const F128_COPYSIGN: f128 = 1.0_f128.copysign(-2.0_f128);
26+
27+
fn main() {
28+
assert_eq!(F16_MIN, 0.5);
29+
assert_eq!(F16_MAX, 1.0);
30+
assert_eq!(F16_ABS, 1.0);
31+
assert_eq!(F16_COPYSIGN, -1.0);
32+
33+
assert_eq!(F32_MIN, 0.5);
34+
assert_eq!(F32_MAX, 1.0);
35+
assert_eq!(F32_ABS, 1.0);
36+
assert_eq!(F32_COPYSIGN, -1.0);
37+
38+
assert_eq!(F64_MIN, 0.5);
39+
assert_eq!(F64_MAX, 1.0);
40+
assert_eq!(F64_ABS, 1.0);
41+
assert_eq!(F64_COPYSIGN, -1.0);
42+
43+
assert_eq!(F128_MIN, 0.5);
44+
assert_eq!(F128_MAX, 1.0);
45+
assert_eq!(F128_ABS, 1.0);
46+
assert_eq!(F128_COPYSIGN, -1.0);
47+
}

0 commit comments

Comments
 (0)
Please sign in to comment.