diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 454347a5e041e..68630ee36ccc2 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -606,6 +606,26 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { ) } + sym::scalbn => { + let ty = args[0].layout.ty; + let ty::Float(f) = ty.kind() else { + span_bug!( + span, + "the `{}` intrinsic requires a floating-point argument, got {:?}", + name, + ty + ); + }; + let llty = self.type_float_from_ty(*f); + + // For our floats (that use a radix of 2), scalbn corresponds to ldexp. + self.call_intrinsic( + "llvm.ldexp", + &[llty, self.type_i32()], + &args.iter().map(|arg| arg.immediate()).collect::>(), + ) + } + sym::raw_eq => { use BackendRepr::*; let tp_ty = fn_args.type_at(0); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index b8b372ad1dab1..0df6b849f5f6b 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -618,7 +618,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sym::copysignf64 => self.float_copysign_intrinsic::(args, dest)?, sym::copysignf128 => self.float_copysign_intrinsic::(args, dest)?, - sym::fabs => { + sym::fabs | sym::ilogb => { let arg = self.read_immediate(&args[0])?; let ty::Float(float_ty) = arg.layout.ty.kind() else { span_bug!( @@ -636,6 +636,27 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_scalar(out_val, dest)?; } + sym::scalbn => { + let arg = self.read_immediate(&args[0])?; + let exp = self.read_immediate(&args[1])?; + + let ty::Float(float_ty) = arg.layout.ty.kind() else { + span_bug!( + self.cur_span(), + "non-float type for float intrinsic: {}", + arg.layout.ty, + ); + }; + + let res = match float_ty { + FloatTy::F16 => self.scalbn_intrinsic::(arg, exp)?, + FloatTy::F32 => self.scalbn_intrinsic::(arg, exp)?, + FloatTy::F64 => self.scalbn_intrinsic::(arg, exp)?, + FloatTy::F128 => self.scalbn_intrinsic::(arg, exp)?, + }; + self.write_scalar(res, dest)?; + } + sym::floorf16 => self.float_round_intrinsic::( args, dest, @@ -1219,12 +1240,29 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { { let x: F = arg.to_scalar().to_float()?; match name { - // bitwise, no NaN adjustments + // fabs and ilogb are both bitwise, no NaN adjustments. sym::fabs => interp_ok(x.abs().into()), + sym::ilogb => interp_ok(Scalar::from_i32(x.ilogb())), _ => bug!("not a unary float intrinsic: {}", name), } } + fn scalbn_intrinsic( + &self, + arg: ImmTy<'tcx, M::Provenance>, + exp: ImmTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, Scalar> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { + let arg: F = arg.to_scalar().to_float()?; + let exp: i32 = exp.to_scalar().to_i32()?; + + let res = arg.scalbn(exp); + let res = self.adjust_nan(res, &[arg]); + interp_ok(res.into()) + } + fn float_minmax( &self, a: Scalar, diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index bcab1457e0655..1f6e16a698223 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -127,6 +127,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::frem_algebraic | sym::fsub_algebraic | sym::gpu_launch_sized_workgroup_mem + | sym::ilogb | sym::integer_max | sym::integer_min | sym::is_val_statically_known @@ -185,6 +186,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::rustc_peek | sym::saturating_add | sym::saturating_sub + | sym::scalbn | sym::select_unpredictable | sym::sin | sym::size_of @@ -469,6 +471,9 @@ pub(crate) fn check_intrinsic_type( | sym::sin | sym::cos => (1, 0, vec![param(0)], param(0)), + sym::scalbn => (1, 0, vec![param(0), tcx.types.i32], param(0)), + sym::ilogb => (1, 0, vec![param(0)], tcx.types.i32), + sym::minimum_number_nsz_f16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), sym::minimum_number_nsz_f32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), sym::minimum_number_nsz_f64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b490362a34ee4..e2d8763544edc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1126,6 +1126,7 @@ symbols! { if_let_rescope, if_while_or_patterns, ignore, + ilogb, immediate_abort: "immediate-abort", impl_header_lifetime_elision, impl_lint_pass, @@ -1922,6 +1923,7 @@ symbols! { sanitizer_runtime, saturating_add, saturating_sub, + scalbn, sdylib, search_unbox, section, diff --git a/library/compiler-builtins/compiler-builtins/src/math/mod.rs b/library/compiler-builtins/compiler-builtins/src/math/mod.rs index 03a564ca0e543..93bcaa0410c50 100644 --- a/library/compiler-builtins/compiler-builtins/src/math/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/math/mod.rs @@ -35,9 +35,11 @@ pub mod full_availability { fn fminimum_numf16(x: f16, y: f16) -> f16; fn fminimumf16(x: f16, y: f16) -> f16; fn fmodf16(x: f16, y: f16) -> f16; + fn ilogbf16(x: f16) -> i32; fn rintf16(x: f16) -> f16; fn roundevenf16(x: f16) -> f16; fn roundf16(x: f16) -> f16; + fn scalbnf16(x: f16, n: i32) -> f16; fn sqrtf16(x: f16) -> f16; fn truncf16(x: f16) -> f16; } @@ -58,8 +60,10 @@ pub mod full_availability { fn fmaxf(x: f32, y: f32) -> f32; fn fminf(x: f32, y: f32) -> f32; fn fmodf(x: f32, y: f32) -> f32; + fn ilogbf(x: f32) -> i32; fn rintf(x: f32) -> f32; fn roundf(x: f32) -> f32; + fn scalbnf(x: f32, n: i32) -> f32; fn sqrtf(x: f32) -> f32; fn truncf(x: f32) -> f32; @@ -74,8 +78,10 @@ pub mod full_availability { fn fmax(x: f64, y: f64) -> f64; fn fmin(x: f64, y: f64) -> f64; fn fmod(x: f64, y: f64) -> f64; + fn ilogb(x: f64) -> i32; fn rint(x: f64) -> f64; fn round(x: f64) -> f64; + fn scalbn(x: f64, n: i32) -> f64; fn sqrt(x: f64) -> f64; fn trunc(x: f64) -> f64; } @@ -110,9 +116,11 @@ pub mod full_availability { fn fminimum_numf128(x: f128, y: f128) -> f128; fn fminimumf128(x: f128, y: f128) -> f128; fn fmodf128(x: f128, y: f128) -> f128; + fn ilogbf128(x: f128) -> i32; fn rintf128(x: f128) -> f128; fn roundevenf128(x: f128) -> f128; fn roundf128(x: f128) -> f128; + fn scalbnf128(x: f128, n: i32) -> f128; fn sqrtf128(x: f128) -> f128; fn truncf128(x: f128) -> f128; } diff --git a/library/core/src/intrinsics/macros.rs b/library/core/src/intrinsics/macros.rs index 5abad0e2c9726..778a3bce3e34c 100644 --- a/library/core/src/intrinsics/macros.rs +++ b/library/core/src/intrinsics/macros.rs @@ -24,6 +24,34 @@ macro_rules! intrinsic_dispatch_on_type { $($arg:ident: $arg_ty:ty),* $(,)? ) -> $ret_ty:ty; $($concrete:ty => $body:block)* + ) => { + intrinsic_dispatch_on_type! { + @declare [] $(#[$attr])* + $vis fn $name<$generic: $bound>($($arg: $arg_ty),*) -> $ret_ty; + $($concrete => $body)* + } + }; + + ( + $(#[$attr:meta])* + $vis:vis const fn $name:ident<$generic:ident: $bound:path>( + $($arg:ident: $arg_ty:ty),* $(,)? + ) -> $ret_ty:ty; + $($concrete:ty => $body:block)* + ) => { + intrinsic_dispatch_on_type! { + @declare [const] $(#[$attr])* + $vis fn $name<$generic: $bound>($($arg: $arg_ty),*) -> $ret_ty; + $($concrete => $body)* + } + }; + + ( + @declare [$($constness:tt)?] $(#[$attr:meta])* + $vis:vis fn $name:ident<$generic:ident: $bound:path>( + $($arg:ident: $arg_ty:ty),* + ) -> $ret_ty:ty; + $($concrete:ty => $body:block)* ) => { mod $name { use super::*; @@ -39,7 +67,7 @@ macro_rules! intrinsic_dispatch_on_type { } $(#[$attr])* - $vis fn $name<$generic: $name::Dispatch>($($arg: $arg_ty),*) -> $ret_ty { + $vis $($constness)? fn $name<$generic: $name::Dispatch>($($arg: $arg_ty),*) -> $ret_ty { <$generic as $name::Dispatch>::dispatch($($arg),*) } }; diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index ecc8b66ec5785..43b205db868e5 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1356,6 +1356,45 @@ intrinsic_dispatch_on_type! { f128 => { libm::maybe_available::log2f128(x) } } +intrinsic_dispatch_on_type! { + /// Calculates `x * 2.0^exp` efficiently. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + #[inline] + #[rustc_intrinsic] + // The fallback bodies call into `libm`, which is not available at compile time. This is fine + // because const-eval implements this intrinsic itself and never runs the fallback body. + #[rustc_do_not_const_check] + pub const fn scalbn(x: T, exp: i32) -> T; + + f16 => { libm::scalbnf16(x, exp) } + f32 => { libm::scalbnf(x, exp) } + f64 => { libm::scalbn(x, exp) } + f128 => { libm::scalbnf128(x, exp) } +} + +intrinsic_dispatch_on_type! { + /// Returns the order of magnitude of `x` (in base 2). + /// + /// When `x` is NaN or `0.0`, the return value is implementation-defined, and may be different + /// between const eval and runtime. When `x` is an infinity, the return value is [`i32::MAX`]. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + #[inline] + #[rustc_intrinsic] + // The fallback bodies call into `libm`, which is not available at compile time. This is fine + // because const-eval implements this intrinsic itself and never runs the fallback body. + #[rustc_do_not_const_check] + pub const fn ilogb(x: T) -> i32; + + f16 => { libm::ilogbf16(x) } + f32 => { libm::ilogbf(x) } + f64 => { libm::ilogb(x) } + f128 => { libm::ilogbf128(x) } +} + /// Returns `a * b + c` without rounding the intermediate result for `f16` values. /// /// The stabilized version of this intrinsic is diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index db05d7fdc5087..6f4b23b32fb41 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1682,6 +1682,30 @@ impl f128 { intrinsics::copysignf128(self, sign) } + /// Placeholder. + #[inline] + #[unstable(feature = "float_exponent_methods", issue = "163184")] + #[rustc_const_unstable(feature = "float_exponent_methods", issue = "163184")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub const fn scalbn(self, exponent: i32) -> f128 { + intrinsics::scalbn(self, exponent) + } + + /// Placeholder. + #[inline] + #[unstable(feature = "float_exponent_methods", issue = "163184")] + #[rustc_const_unstable(feature = "float_exponent_methods", issue = "163184")] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn ilogb(self) -> Option { + if self.is_nan() { + None + } else if self == 0.0 { + Some(i32::MIN) + } else { + Some(intrinsics::ilogb(self)) + } + } + /// Float addition that allows optimizations based on algebraic rules. /// /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 273ef3688ca5f..c780d8558d407 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1668,6 +1668,30 @@ impl f16 { intrinsics::copysignf16(self, sign) } + /// Placeholder. + #[inline] + #[unstable(feature = "float_exponent_methods", issue = "163184")] + #[rustc_const_unstable(feature = "float_exponent_methods", issue = "163184")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub const fn scalbn(self, exponent: i32) -> f16 { + intrinsics::scalbn(self, exponent) + } + + /// Placeholder. + #[inline] + #[unstable(feature = "float_exponent_methods", issue = "163184")] + #[rustc_const_unstable(feature = "float_exponent_methods", issue = "163184")] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn ilogb(self) -> Option { + if self.is_nan() { + None + } else if self == 0.0 { + Some(i32::MIN) + } else { + Some(intrinsics::ilogb(self)) + } + } + /// Float addition that allows optimizations based on algebraic rules. /// /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index d3dea38dc2fcf..9a83d9227bef4 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1825,6 +1825,65 @@ impl f32 { intrinsics::copysignf32(self, sign) } + /// Calculates `self * 2.powi(exponent)` efficiently and accurately. + /// + /// Because of how floating point numbers are represented, this operation can be performed + /// using only bitwise operations. This is much faster than `powi` and does not run + /// into floating point precision issues. + /// + /// ``` + /// #![feature(float_exponent_methods)] + /// + /// assert_eq!(3.0_f32.scalbn(4), 3.0 * 2.0_f32.powi(4)); // = 3 * 16 = 48 + /// assert_eq!(3.0_f32.scalbn(-1), 3.0 * 2.0_f32.powi(-1)); // = 3 * 0.5 = 1.5 + /// + /// assert_eq!(f32::INFINITY.scalbn(4), f32::INFINITY); + /// assert_eq!(f32::NEG_INFINITY.scalbn(4), f32::NEG_INFINITY); + /// + /// assert!(f32::NAN.scalbn(4).is_nan()); + /// ``` + #[inline] + #[unstable(feature = "float_exponent_methods", issue = "163184")] + #[rustc_const_unstable(feature = "float_exponent_methods", issue = "163184")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub const fn scalbn(self, exponent: i32) -> f32 { + intrinsics::scalbn(self, exponent) + } + + /// Returns the exponent of `self`. + /// + /// Return `None` when `self` is NaN, [`i32::MIN`] when `self` is zero, + /// and [`i32::MAX`] when `self` is an infinity. + /// + /// ``` + /// #![feature(float_exponent_methods)] + /// + /// assert_eq!(8.0_f32.ilogb(), Some(3)); + /// assert_eq!((-8.0_f32).ilogb(), Some(3)); + /// + /// assert_eq!(15.0_f32.ilogb(), Some(3)); + /// assert_eq!(16.0_f32.ilogb(), Some(4)); + /// + /// assert_eq!(0.5_f32.ilogb(), Some(-1)); + /// + /// assert_eq!(f32::INFINITY.ilogb(), Some(i32::MAX)); + /// assert_eq!(0.0_f32.ilogb(), Some(i32::MIN)); + /// assert_eq!(f32::NAN.ilogb(), None); + /// ``` + #[inline] + #[unstable(feature = "float_exponent_methods", issue = "163184")] + #[rustc_const_unstable(feature = "float_exponent_methods", issue = "163184")] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn ilogb(self) -> Option { + if self.is_nan() { + None + } else if self == 0.0 { + Some(i32::MIN) + } else { + Some(intrinsics::ilogb(self)) + } + } + /// Float addition that allows optimizations based on algebraic rules. /// /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 7c5082749cd11..bd7ad7b9e17e1 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1803,6 +1803,30 @@ impl f64 { intrinsics::copysignf64(self, sign) } + /// Placeholder. + #[inline] + #[unstable(feature = "float_exponent_methods", issue = "163184")] + #[rustc_const_unstable(feature = "float_exponent_methods", issue = "163184")] + #[must_use = "method returns a new number and does not mutate the original value"] + pub const fn scalbn(self, exponent: i32) -> f64 { + intrinsics::scalbn(self, exponent) + } + + /// Placeholder. + #[inline] + #[unstable(feature = "float_exponent_methods", issue = "163184")] + #[rustc_const_unstable(feature = "float_exponent_methods", issue = "163184")] + #[must_use = "this returns the result of the operation, without modifying the original"] + pub const fn ilogb(self) -> Option { + if self.is_nan() { + None + } else if self == 0.0 { + Some(i32::MIN) + } else { + Some(intrinsics::ilogb(self)) + } + } + /// Float addition that allows optimizations based on algebraic rules. /// /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. diff --git a/library/core/src/num/imp/libm.rs b/library/core/src/num/imp/libm.rs index a8d6bdc0b5d7c..11e670ddaeb0e 100644 --- a/library/core/src/num/imp/libm.rs +++ b/library/core/src/num/imp/libm.rs @@ -54,6 +54,10 @@ unsafe extern "C" { pub(crate) safe fn fmodf(x: f32, y: f32) -> f32; pub(crate) safe fn fmodf128(x: f128, y: f128) -> f128; pub(crate) safe fn fmodf16(x: f16, y: f16) -> f16; + pub(crate) safe fn ilogb(x: f64) -> i32; + pub(crate) safe fn ilogbf(x: f32) -> i32; + pub(crate) safe fn ilogbf128(x: f128) -> i32; + pub(crate) safe fn ilogbf16(x: f16) -> i32; pub(crate) safe fn rint(x: f64) -> f64; pub(crate) safe fn rintf(x: f32) -> f32; pub(crate) safe fn rintf128(x: f128) -> f128; @@ -66,6 +70,10 @@ unsafe extern "C" { pub(crate) safe fn roundf(x: f32) -> f32; pub(crate) safe fn roundf128(x: f128) -> f128; pub(crate) safe fn roundf16(x: f16) -> f16; + pub(crate) safe fn scalbn(x: f64, e: i32) -> f64; + pub(crate) safe fn scalbnf(x: f32, e: i32) -> f32; + pub(crate) safe fn scalbnf128(x: f128, e: i32) -> f128; + pub(crate) safe fn scalbnf16(x: f16, e: i32) -> f16; pub(crate) safe fn sqrt(x: f64) -> f64; pub(crate) safe fn sqrtf(x: f32) -> f32; pub(crate) safe fn sqrtf128(x: f128) -> f128; diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 69bc6edd1b833..7f67f3f8e2315 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -59,6 +59,7 @@ #![feature(f128)] #![feature(float_conversions)] #![feature(float_exact_integer_constants)] +#![feature(float_exponent_methods)] #![feature(float_gamma)] #![feature(float_minimum_maximum)] #![feature(flt2dec)] diff --git a/library/coretests/tests/num/floats.rs b/library/coretests/tests/num/floats.rs index 7093687f04b15..111f6e0139f3a 100644 --- a/library/coretests/tests/num/floats.rs +++ b/library/coretests/tests/num/floats.rs @@ -1242,6 +1242,67 @@ float_test! { } } +float_test! { + name: scalbn, + attrs: { + f16: #[cfg(target_has_reliable_f16)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { + assert_biteq!(flt(3.0).scalbn(4), 48.0); + assert_biteq!(flt(-3.0).scalbn(4), -48.0); + + assert_biteq!(flt(0.0).scalbn(4), 0.0); + assert_biteq!(flt(-0.0).scalbn(4), -0.0); + + assert_biteq!(Float::ONE.scalbn(0), Float::ONE); + assert_biteq!(Float::ONE.scalbn(1), 2.0); + assert_biteq!(Float::ONE.scalbn(-1), 0.5); + assert_biteq!(Float::ONE.scalbn(10), 1024.0); + assert_biteq!(Float::ONE.scalbn(-10), 1.0 / 1024.0); + + assert_biteq!(Float::MAX.scalbn(1), Float::INFINITY); + assert_biteq!(Float::MAX.scalbn(0), Float::MAX); + assert_biteq!(Float::TINY.scalbn(-1), Float::ZERO); + assert_biteq!((-Float::TINY).scalbn(-1), -Float::ZERO); + + assert_biteq!(Float::ONE.scalbn(i32::MAX), Float::INFINITY); + assert_biteq!(Float::ONE.scalbn(i32::MIN), Float::ZERO); + + assert_biteq!(Float::NAN.scalbn(100), Float::NAN); + } +} + +float_test! { + name: ilogb, + attrs: { + f16: #[cfg(target_has_reliable_f16)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { + assert_eq_const_safe!(Option: flt(32.0).ilogb(), Some(5)); + + assert_eq_const_safe!(Option: Float::ONE.ilogb(), Some(0)); + assert_eq_const_safe!(Option: flt(2.0).ilogb(), Some(1)); + assert_eq_const_safe!(Option: flt(4.0).ilogb(), Some(2)); + assert_eq_const_safe!(Option: flt(0.5).ilogb(), Some(-1)); + assert_eq_const_safe!(Option: flt(0.25).ilogb(), Some(-2)); + + assert_eq_const_safe!(Option: Float::INFINITY.ilogb(), Some(i32::MAX)); + assert_eq_const_safe!(Option: Float::NEG_INFINITY.ilogb(), Some(i32::MAX)); + + // The return value of the intrinsic for 0.0 is implementation-defined, + // we guarantee that the method returns i32::MIN. + assert_eq_const_safe!(Option: Float::ZERO.ilogb(), Some(i32::MIN)); + assert_eq_const_safe!(Option: (-Float::ZERO).ilogb(), Some(i32::MIN)); + + // The return value of the intrinsic for NaN is implementation-defined, we + // guarantee that the method returns None. + assert_eq_const_safe!(Option: Float::NAN.ilogb(), None); + + } +} + float_test! { name: next_up, attrs: { diff --git a/tests/ui/consts/const-float-intrinsics.rs b/tests/ui/consts/const-float-intrinsics.rs new file mode 100644 index 0000000000000..347473facfa22 --- /dev/null +++ b/tests/ui/consts/const-float-intrinsics.rs @@ -0,0 +1,28 @@ +//@ check-pass + +// Check that the float intrinsics carrying `#[rustc_do_not_const_check]` can actually be called in +// a const context, for every float width. Their fallback bodies call into `libm`, but const-eval +// overrides them. + +#![feature(core_intrinsics, f16, f128)] + +use std::intrinsics::{ilogb, scalbn}; + +macro_rules! check { + ($ty:ident) => { + const _: () = { + assert!(scalbn(3.0 as $ty, 2i32) == 12.0); + assert!(scalbn(1024 as $ty, -10i32) == 1.0); + assert!(ilogb(1.0 as $ty) == 0); + assert!(ilogb(4.0 as $ty) == 2); + assert!(ilogb(0.25 as $ty) == -2); + }; + }; +} + +check!(f16); +check!(f32); +check!(f64); +check!(f128); + +fn main() {}