diff --git a/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs b/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs index 09762f1a451b6..874a68fe5b872 100644 --- a/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs +++ b/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs @@ -160,20 +160,6 @@ pub(crate) fn neg_f128(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { fx.bcx.ins().bitcast(types::F128, MemFlagsData::new(), bits) } -pub(crate) fn abs_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { - let bits = fx.bcx.ins().bitcast(types::I16, MemFlagsData::new(), value); - let bits = fx.bcx.ins().band_imm_u(bits, 0x7fff); - fx.bcx.ins().bitcast(types::F16, MemFlagsData::new(), bits) -} - -pub(crate) fn abs_f128(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { - let bits = fx.bcx.ins().bitcast(types::I128, MemFlagsData::new(), value); - let (low, high) = fx.bcx.ins().isplit(bits); - let high = fx.bcx.ins().band_imm_u(high, 0x7fff_ffff_ffff_ffff_u64 as i64); - let bits = fx.bcx.ins().iconcat(low, high); - fx.bcx.ins().bitcast(types::F128, MemFlagsData::new(), bits) -} - pub(crate) fn codegen_cast( fx: &mut FunctionCx<'_, '_, '_>, from: Value, diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index cf1c1f027e7f5..12e488530e668 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -349,11 +349,6 @@ fn codegen_float_intrinsic_call<'tcx>( sym::fmuladdf64 => ("fma", 3, fx.tcx.types.f64, types::F64), sym::fmuladdf128 => return false, // has a fallback - sym::copysignf16 => return false, // has a fallback - sym::copysignf32 => ("copysignf", 2, fx.tcx.types.f32, types::F32), - sym::copysignf64 => ("copysign", 2, fx.tcx.types.f64, types::F64), - sym::copysignf128 => return false, // has a fallback - sym::floorf16 => return false, // has a fallback via f32 sym::floorf32 => ("floorf", 1, fx.tcx.types.f32, types::F32), sym::floorf64 => ("floor", 1, fx.tcx.types.f64, types::F64), @@ -417,7 +412,6 @@ fn codegen_float_intrinsic_call<'tcx>( sym::fmaf32 | sym::fmaf64 | sym::fmuladdf32 | sym::fmuladdf64 => { fx.bcx.ins().fma(args[0], args[1], args[2]) } - sym::copysignf32 | sym::copysignf64 => fx.bcx.ins().fcopysign(args[0], args[1]), sym::floorf32 | sym::floorf64 => fx.bcx.ins().floor(args[0]), sym::ceilf32 | sym::ceilf64 => fx.bcx.ins().ceil(args[0]), sym::truncf32 | sym::truncf64 => fx.bcx.ins().trunc(args[0]), @@ -455,6 +449,13 @@ fn codegen_float_intrinsic_call<'tcx>( true } +/// Used to distinguish fallbacks of float intrinsics. For some we have a codegen fallback, +/// while for others we fallback to an external libcall. +enum IntrinsicFallback { + Fallback(&'static str), + Codegen(Value), +} + fn codegen_regular_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, instance: Instance<'tcx>, @@ -1163,6 +1164,66 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, old); } + sym::copysign + | sym::minimum + | sym::maximum + | sym::minimum_number_nsz + | sym::maximum_number_nsz => { + intrinsic_args!(fx, args => (arg1, arg2); intrinsic); + let layout = arg1.layout(); + let ty::Float(float_ty) = layout.ty.kind() else { + span_bug!( + source_info.span, + "expected float type for fabs intrinsic: {:?}", + layout.ty + ); + }; + use FloatTy::*; + use IntrinsicFallback::*; + let x = arg1.load_scalar(fx); + let y = arg2.load_scalar(fx); + let res = match (intrinsic, float_ty) { + (sym::copysign, F32 | F64) => Codegen(fx.bcx.ins().fcopysign(x, y)), + + (sym::minimum, F32 | F64) => Codegen(fx.bcx.ins().fmin(x, y)), + (sym::maximum, F32 | F64) => Codegen(fx.bcx.ins().fmax(x, y)), + // FIXME(bytecodealliance/wasmtime#8312): Use `fmin`/`fmax` directly for `f16` and + // `f128` once the lowerings have been implemented in Cranelift. + (sym::minimum, F128) => Codegen(codegen_f16_f128::fmin_f128(fx, x, y)), + (sym::maximum, F128) => Codegen(codegen_f16_f128::fmax_f128(fx, x, y)), + (sym::minimum, F16) => { + Codegen(codegen_f16_f128::maybe_with_f16_to_f32_pair(fx, x, y, |fx, x, y| { + fx.bcx.ins().fmin(x, y) + })) + } + (sym::maximum, F16) => { + Codegen(codegen_f16_f128::maybe_with_f16_to_f32_pair(fx, x, y, |fx, x, y| { + fx.bcx.ins().fmax(x, y) + })) + } + + (sym::minimum_number_nsz, _) => Codegen(crate::num::codegen_float_min(fx, x, y)), + (sym::maximum_number_nsz, _) => Codegen(crate::num::codegen_float_max(fx, x, y)), + + (sym::copysign, F128) | (_, F16) => { + // We use the intrinsic fallback bodies for the rest + return Err(Instance::new_raw(instance.def_id(), instance.args)); + } + + _ => unreachable!(), + }; + let val = match res { + Codegen(val) => val, + Fallback(name) => { + let ty = fx.clif_type(layout.ty).unwrap(); + let arg = AbiParam::new(ty); + fx.lib_call(name, vec![arg, arg], vec![arg], &[x, y])[0] + } + }; + let val = CValue::by_val(val, layout); + ret.write_cvalue(fx, val); + } + sym::fabs | sym::exp | sym::exp2 @@ -1176,24 +1237,16 @@ fn codegen_regular_intrinsic_call<'tcx>( let ty::Float(float_ty) = layout.ty.kind() else { span_bug!( source_info.span, - "expected float type for fabs intrinsic: {:?}", + "expected float type for {:?} intrinsic: {:?}", + intrinsic, layout.ty ); }; - enum IntrinsicFallback { - Fallback(&'static str), - Codegen(Value), - } use FloatTy::*; use IntrinsicFallback::*; let x = arg.load_scalar(fx); let res = match (intrinsic, float_ty) { (sym::fabs, F32 | F64) => Codegen(fx.bcx.ins().fabs(x)), - // FIXME(bytecodealliance/wasmtime#8312): Use `fabsf16` once Cranelift - // backend lowerings are implemented. - (sym::fabs, F16) => Codegen(codegen_f16_f128::abs_f16(fx, x)), - (sym::fabs, F128) => Codegen(codegen_f16_f128::abs_f128(fx, x)), - (sym::exp, F32) => Fallback("expf"), (sym::exp, F64) => Fallback("exp"), (sym::exp, F128) => Fallback("expf128"), @@ -1222,8 +1275,10 @@ fn codegen_regular_intrinsic_call<'tcx>( (sym::cos, F64) => Fallback("cos"), (sym::cos, F128) => Fallback("cosf128"), - (_, F16) => { - // We implement fallbacks for other f16 intrinsics via f32 + (sym::fabs, F128) | (_, F16) => { + // FIXME(bytecodealliance/wasmtime#8312): Use the native operations once + // Cranelift backend lowerings for `f16` are implemented. + // We use the intrinsic fallback bodies for the rest return Err(Instance::new_raw(instance.def_id(), instance.args)); } @@ -1240,160 +1295,6 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, val); } - sym::minimumf16 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - let val = codegen_f16_f128::maybe_with_f16_to_f32_pair(fx, a, b, |fx, a, b| { - fx.bcx.ins().fmin(a, b) - }); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); - ret.write_cvalue(fx, val); - } - sym::minimumf32 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - let val = fx.bcx.ins().fmin(a, b); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32)); - ret.write_cvalue(fx, val); - } - sym::minimumf64 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - let val = fx.bcx.ins().fmin(a, b); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); - ret.write_cvalue(fx, val); - } - sym::minimumf128 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - // FIXME(bytecodealliance/wasmtime#8312): Use `fmin` once Cranelift - // backend lowerings are implemented. - let val = codegen_f16_f128::fmin_f128(fx, a, b); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f128)); - ret.write_cvalue(fx, val); - } - sym::maximumf16 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - let val = codegen_f16_f128::maybe_with_f16_to_f32_pair(fx, a, b, |fx, a, b| { - fx.bcx.ins().fmax(a, b) - }); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); - ret.write_cvalue(fx, val); - } - sym::maximumf32 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - let val = fx.bcx.ins().fmax(a, b); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32)); - ret.write_cvalue(fx, val); - } - sym::maximumf64 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - let val = fx.bcx.ins().fmax(a, b); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); - ret.write_cvalue(fx, val); - } - sym::maximumf128 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - // FIXME(bytecodealliance/wasmtime#8312): Use `fmax` once Cranelift - // backend lowerings are implemented. - let val = codegen_f16_f128::fmax_f128(fx, a, b); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f128)); - ret.write_cvalue(fx, val); - } - - sym::minimum_number_nsz_f16 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - let val = crate::num::codegen_float_min(fx, a, b); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); - ret.write_cvalue(fx, val); - } - sym::minimum_number_nsz_f32 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - let val = crate::num::codegen_float_min(fx, a, b); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32)); - ret.write_cvalue(fx, val); - } - sym::minimum_number_nsz_f64 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - let val = crate::num::codegen_float_min(fx, a, b); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); - ret.write_cvalue(fx, val); - } - sym::minimum_number_nsz_f128 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - let val = crate::num::codegen_float_min(fx, a, b); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f128)); - ret.write_cvalue(fx, val); - } - sym::maximum_number_nsz_f16 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - let val = crate::num::codegen_float_max(fx, a, b); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); - ret.write_cvalue(fx, val); - } - sym::maximum_number_nsz_f32 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - let val = crate::num::codegen_float_max(fx, a, b); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32)); - ret.write_cvalue(fx, val); - } - sym::maximum_number_nsz_f64 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - let val = crate::num::codegen_float_max(fx, a, b); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); - ret.write_cvalue(fx, val); - } - sym::maximum_number_nsz_f128 => { - intrinsic_args!(fx, args => (a, b); intrinsic); - let a = a.load_scalar(fx); - let b = b.load_scalar(fx); - - let val = crate::num::codegen_float_max(fx, a, b); - let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f128)); - ret.write_cvalue(fx, val); - } - sym::catch_unwind => { let ret_block = fx.get_block(destination.unwrap()); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 5550d22b33aa3..6bd7571cd8f09 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -37,20 +37,20 @@ use crate::context::CodegenCx; use crate::intrinsic::simd::generic_simd_intrinsic; use crate::type_of::LayoutGccExt; -fn float_intrinsic<'gcc, 'tcx>( +// GCC doesn't have the intrinsic we want so we use the compiler-builtins one +fn binop_libcall<'gcc, 'tcx>( cx: &CodegenCx<'gcc, 'tcx>, typ: Type<'gcc>, name: &str, -) -> Option> { - // GCC doesn't have the intrinsic we want so we use the compiler-builtins one - Some(cx.context.new_function( +) -> Function<'gcc> { + cx.context.new_function( None, FunctionType::Extern, typ, &[cx.context.new_parameter(None, typ, "a"), cx.context.new_parameter(None, typ, "b")], name, false, - )) + ) } fn get_simple_intrinsic<'gcc, 'tcx>( @@ -69,19 +69,11 @@ fn get_simple_intrinsic<'gcc, 'tcx>( // FIXME: calling `fma` from libc without FMA target feature uses expensive software emulation sym::fmuladdf32 => "fmaf", // FIXME: use gcc intrinsic analogous to llvm.fmuladd.f32 sym::fmuladdf64 => "fma", // FIXME: use gcc intrinsic analogous to llvm.fmuladd.f64 - sym::minimumf32 => return float_intrinsic(cx, cx.type_f32(), "fminimumf"), - sym::minimumf64 => return float_intrinsic(cx, cx.type_f64(), "fminimum"), - sym::minimumf128 => return float_intrinsic(cx, cx.type_f128(), "fminimumf128"), - sym::maximumf32 => return float_intrinsic(cx, cx.type_f32(), "fmaximumf"), - sym::maximumf64 => return float_intrinsic(cx, cx.type_f64(), "fmaximum"), - sym::maximumf128 => return float_intrinsic(cx, cx.type_f128(), "fmaximumf128"), - sym::copysignf32 => "copysignf", - sym::copysignf64 => "copysign", sym::floorf32 => "floorf", sym::floorf64 => "floor", sym::ceilf32 => "ceilf", sym::ceilf64 => "ceil", - sym::powf128 => return float_intrinsic(cx, cx.type_f128(), "powf128"), + sym::powf128 => return Some(binop_libcall(cx, cx.type_f128(), "powf128")), sym::truncf32 => "truncf", sym::truncf64 => "trunc", // We match the LLVM backend and lower this to `rint`. @@ -101,31 +93,32 @@ fn get_simple_function_f128<'gcc, 'tcx>( name: Symbol, ) -> Function<'gcc> { let f128_type = cx.type_f128(); - let func_name = match name { - sym::ceilf128 => "ceilf128", - sym::cos => "cosf128", - sym::fabs => "fabsf128", - sym::exp => "expf128", - sym::exp2 => "exp2f128", - sym::floorf128 => "floorf128", - sym::log => "logf128", - sym::log2 => "log2f128", - sym::log10 => "log10f128", - sym::truncf128 => "truncf128", - sym::roundf128 => "roundf128", - sym::round_ties_even_f128 => "roundevenf128", - sym::sin => "sinf128", - sym::sqrtf128 => "sqrtf128", - _ => span_bug!(span, "used get_simple_function_f128 for non-unary f128 intrinsic"), + let (func_name, args): (&str, &[gccjit::Type<'_>]) = match name { + sym::copysign => ("copysignf128", &[f128_type, f128_type]), + sym::ceilf128 => ("ceilf128", &[f128_type]), + sym::cos => ("cosf128", &[f128_type]), + sym::fabs => ("fabsf128", &[f128_type]), + sym::exp => ("expf128", &[f128_type]), + sym::exp2 => ("exp2f128", &[f128_type]), + sym::floorf128 => ("floorf128", &[f128_type]), + sym::log => ("logf128", &[f128_type]), + sym::log2 => ("log2f128", &[f128_type]), + sym::log10 => ("log10f128", &[f128_type]), + sym::truncf128 => ("truncf128", &[f128_type]), + sym::roundf128 => ("roundf128", &[f128_type]), + sym::round_ties_even_f128 => ("roundevenf128", &[f128_type]), + sym::sin => ("sinf128", &[f128_type]), + sym::sqrtf128 => ("sqrtf128", &[f128_type]), + sym::minimum => ("fminimumf128", &[f128_type, f128_type]), + sym::maximum => ("fmaximumf128", &[f128_type, f128_type]), + _ => span_bug!(span, "used get_simple_function_f128 for unsupported f128 intrinsic"), }; - cx.context.new_function( - None, - FunctionType::Extern, - f128_type, - &[cx.context.new_parameter(None, f128_type, "a")], - func_name, - false, - ) + let args: Vec<_> = args + .iter() + .enumerate() + .map(|(index, typ)| cx.context.new_parameter(None, *typ, format!("param{}", index))) + .collect(); + cx.context.new_function(None, FunctionType::Extern, f128_type, &args, func_name, false) } fn f16_builtin<'gcc, 'tcx>( @@ -136,7 +129,7 @@ fn f16_builtin<'gcc, 'tcx>( let f32_type = cx.type_f32(); let builtin_name = match name { sym::ceilf16 => "__builtin_ceilf", - sym::copysignf16 => "__builtin_copysignf", + sym::copysign => "__builtin_copysignf", sym::cos => "cosf", sym::exp => "expf", sym::exp2 => "exp2f", @@ -189,34 +182,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc &args.iter().map(|arg| arg.immediate()).collect::>(), ) } - // FIXME(antoyo): We can probably remove these and use the fallback intrinsic implementation. - sym::minimumf32 | sym::minimumf64 | sym::maximumf32 | sym::maximumf64 => { - let (ty, func_name) = match name { - sym::minimumf32 => (self.cx.float_type, "fminimumf"), - sym::maximumf32 => (self.cx.float_type, "fmaximumf"), - sym::minimumf64 => (self.cx.double_type, "fminimum"), - sym::maximumf64 => (self.cx.double_type, "fmaximum"), - _ => unreachable!(), - }; - let func = self.cx.context.new_function( - None, - FunctionType::Extern, - ty, - &[ - self.cx.context.new_parameter(None, ty, "a"), - self.cx.context.new_parameter(None, ty, "b"), - ], - func_name, - false, - ); - self.cx.context.new_call( - self.location, - func, - &args.iter().map(|arg| arg.immediate()).collect::>(), - ) - } sym::ceilf16 - | sym::copysignf16 | sym::floorf16 | sym::powf16 | sym::roundf16 @@ -238,25 +204,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc &args.iter().map(|arg| arg.immediate()).collect::>(), ) } - sym::copysignf128 if self.cx.supports_f128_type => { - let f128_type = self.cx.type_f128(); - let func = self.cx.context.new_function( - None, - FunctionType::Extern, - f128_type, - &[ - self.cx.context.new_parameter(None, f128_type, "a"), - self.cx.context.new_parameter(None, f128_type, "b"), - ], - "copysignf128", - false, - ); - self.cx.context.new_call( - self.location, - func, - &args.iter().map(|arg| arg.immediate()).collect::>(), - ) - } sym::fmaf128 => { let f128_type = self.cx.type_f128(); let func = self.cx.context.new_function( @@ -412,23 +359,41 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } } } - sym::fabs + sym::copysign + | sym::fabs + | sym::minimum + | sym::maximum | sym::exp | sym::exp2 | sym::log | sym::log10 | sym::log2 | sym::sin - | sym::cos => 'float_unop: { + | sym::cos => 'float_op: { let ty = args[0].layout.ty; let ty::Float(float_ty) = *ty.kind() else { - span_bug!(span, "expected float type for fabs intrinsic: {:?}", ty); + span_bug!(span, "expected float type for {:?} intrinsic: {:?}", name, ty); }; use ty::FloatTy::*; let func = match (name, float_ty) { + (sym::copysign, F32) => self.context.get_builtin_function("copysignf"), + (sym::copysign, F64) => self.context.get_builtin_function("copysign"), + (sym::fabs, F32) => self.context.get_builtin_function("fabsf"), (sym::fabs, F64) => self.context.get_builtin_function("fabs"), + // FIXME(antoyo): We can probably remove these and use the fallback intrinsic implementation. + (sym::minimum, F32) => binop_libcall(self, self.type_f32(), "fminimumf"), + (sym::minimum, F64) => binop_libcall(self, self.type_f64(), "fminimum"), + (sym::maximum, F32) => binop_libcall(self, self.type_f32(), "fmaximumf"), + (sym::maximum, F64) => binop_libcall(self, self.type_f64(), "fmaximum"), + + // `f16` has no builtin for these, use the intrinsic fallback bodies instead. + (sym::minimum | sym::maximum, F16) => { + let fallback = Instance::new_raw(instance.def_id(), instance.args); + return IntrinsicResult::Fallback(fallback); + } + (sym::exp, F32) => self.context.get_builtin_function("expf"), (sym::exp, F64) => self.context.get_builtin_function("exp"), @@ -452,7 +417,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc (_, F32 | F64) => unreachable!(), - (_, F16) => break 'float_unop f16_builtin(self, name, args), + (_, F16) => break 'float_op f16_builtin(self, name, args), (_, F128) => { if !self.cx.supports_f128_type { // Fall back to default body diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index c4ff1eee56750..29f636246a7c2 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -81,25 +81,6 @@ fn call_simple_intrinsic<'ll, 'tcx>( sym::fmuladdf64 => ("llvm.fmuladd", &[bx.type_f64()]), sym::fmuladdf128 => ("llvm.fmuladd", &[bx.type_f128()]), - sym::minimumf16 => ("llvm.minimum", &[bx.type_f16()]), - sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]), - // FIXME: LLVM currently mis-compile those intrinsics, re-enable them - // when llvm/llvm-project#{139380,139381,140445} are fixed. - //sym::minimumf64 => ("llvm.minimum", &[bx.type_f64()]), - //sym::minimumf128 => ("llvm.minimum", &[cx.type_f128()]), - // - sym::maximumf16 => ("llvm.maximum", &[bx.type_f16()]), - sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]), - // FIXME: LLVM currently mis-compile those intrinsics, re-enable them - // when llvm/llvm-project#{139380,139381,140445} are fixed. - //sym::maximumf64 => ("llvm.maximum", &[bx.type_f64()]), - //sym::maximumf128 => ("llvm.maximum", &[cx.type_f128()]), - // - sym::copysignf16 => ("llvm.copysign", &[bx.type_f16()]), - sym::copysignf32 => ("llvm.copysign", &[bx.type_f32()]), - sym::copysignf64 => ("llvm.copysign", &[bx.type_f64()]), - sym::copysignf128 => ("llvm.copysign", &[bx.type_f128()]), - sym::floorf16 => ("llvm.floor", &[bx.type_f16()]), sym::floorf32 => ("llvm.floor", &[bx.type_f32()]), sym::floorf64 => ("llvm.floor", &[bx.type_f64()]), @@ -193,17 +174,8 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let llval = match name { _ if simple.is_some() => simple.unwrap(), // Need at least LLVM 22 for `min/maximumnum` to not crash LLVM. - sym::minimum_number_nsz_f16 - | sym::minimum_number_nsz_f32 - | sym::minimum_number_nsz_f64 - | sym::minimum_number_nsz_f128 - | sym::maximum_number_nsz_f16 - | sym::maximum_number_nsz_f32 - | sym::maximum_number_nsz_f64 - | sym::maximum_number_nsz_f128 - if llvm_version >= (22, 0, 0) => - { - let intrinsic_name = if name.as_str().starts_with("min") { + sym::minimum_number_nsz | sym::maximum_number_nsz if llvm_version >= (22, 0, 0) => { + let intrinsic_name = if name == sym::minimum_number_nsz { "llvm.minimumnum" } else { "llvm.maximumnum" @@ -567,14 +539,17 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } - sym::fabs + sym::copysign + | sym::fabs | sym::exp | sym::exp2 | sym::log | sym::log10 | sym::log2 | sym::sin - | sym::cos => { + | sym::cos + | sym::minimum + | sym::maximum => { let ty = args[0].layout.ty; let ty::Float(f) = ty.kind() else { span_bug!( @@ -586,6 +561,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { }; let llty = self.type_float_from_ty(*f); let llvm_name = match name { + sym::copysign => "llvm.copysign", sym::fabs => "llvm.fabs", sym::exp => "llvm.exp", sym::exp2 => "llvm.exp2", @@ -594,6 +570,18 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { sym::log2 => "llvm.log2", sym::sin => "llvm.sin", sym::cos => "llvm.cos", + + // FIXME: LLVM currently mis-compiles `llvm.minimum`/`llvm.maximum` for `f64` and + // `f128`; use the fallback bodies for those until + // llvm/llvm-project#{139380,139381,140445} are fixed. + sym::minimum | sym::maximum + if matches!(f, ty::FloatTy::F64 | ty::FloatTy::F128) => + { + let fallback = ty::Instance::new_raw(instance.def_id(), instance.args); + return IntrinsicResult::Fallback(fallback); + } + sym::minimum => "llvm.minimum", + sym::maximum => "llvm.maximum", _ => bug!(), }; self.call_intrinsic( diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 775e1dcf2ffea..39555b919bcb6 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -352,7 +352,7 @@ impl CodegenBackend for LlvmCodegenBackend { sym::sqrtf16, sym::powif16, sym::fmaf16, - sym::copysignf16, sym::copysignf32, sym::copysignf64, sym::copysignf128, + sym::copysign, ]; if llvm_util::get_version() >= (22, 0, 0) { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 00057dc503827..cda876b8a311c 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -568,54 +568,36 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?; } - sym::minimum_number_nsz_f16 => { - self.float_minmax_intrinsic::(args, MinMax::MinimumNumberNsz, dest)? - } - sym::minimum_number_nsz_f32 => { - self.float_minmax_intrinsic::(args, MinMax::MinimumNumberNsz, dest)? - } - sym::minimum_number_nsz_f64 => { - self.float_minmax_intrinsic::(args, MinMax::MinimumNumberNsz, dest)? - } - sym::minimum_number_nsz_f128 => { - self.float_minmax_intrinsic::(args, MinMax::MinimumNumberNsz, dest)? - } - - sym::minimumf16 => self.float_minmax_intrinsic::(args, MinMax::Minimum, dest)?, - sym::minimumf32 => { - self.float_minmax_intrinsic::(args, MinMax::Minimum, dest)? - } - sym::minimumf64 => { - self.float_minmax_intrinsic::(args, MinMax::Minimum, dest)? - } - sym::minimumf128 => self.float_minmax_intrinsic::(args, MinMax::Minimum, dest)?, - - sym::maximum_number_nsz_f16 => { - self.float_minmax_intrinsic::(args, MinMax::MaximumNumberNsz, dest)? - } - sym::maximum_number_nsz_f32 => { - self.float_minmax_intrinsic::(args, MinMax::MaximumNumberNsz, dest)? - } - sym::maximum_number_nsz_f64 => { - self.float_minmax_intrinsic::(args, MinMax::MaximumNumberNsz, dest)? - } - sym::maximum_number_nsz_f128 => { - self.float_minmax_intrinsic::(args, MinMax::MaximumNumberNsz, dest)? - } - - sym::maximumf16 => self.float_minmax_intrinsic::(args, MinMax::Maximum, dest)?, - sym::maximumf32 => { - self.float_minmax_intrinsic::(args, MinMax::Maximum, dest)? - } - sym::maximumf64 => { - self.float_minmax_intrinsic::(args, MinMax::Maximum, dest)? + sym::minimum + | sym::maximum + | sym::minimum_number_nsz + | sym::maximum_number_nsz + | sym::copysign => { + let arg1 = self.read_immediate(&args[0])?; + let arg2 = self.read_immediate(&args[1])?; + let ty::Float(float_ty) = arg1.layout.ty.kind() else { + span_bug!( + self.cur_span(), + "non-float type for float intrinsic: {}", + arg1.layout.ty, + ); + }; + let out_val = match float_ty { + FloatTy::F16 => { + self.binop_float_intrinsic::(intrinsic_name, arg1, arg2)? + } + FloatTy::F32 => { + self.binop_float_intrinsic::(intrinsic_name, arg1, arg2)? + } + FloatTy::F64 => { + self.binop_float_intrinsic::(intrinsic_name, arg1, arg2)? + } + FloatTy::F128 => { + self.binop_float_intrinsic::(intrinsic_name, arg1, arg2)? + } + }; + self.write_scalar(out_val, dest)?; } - sym::maximumf128 => self.float_minmax_intrinsic::(args, MinMax::Maximum, dest)?, - - sym::copysignf16 => self.float_copysign_intrinsic::(args, dest)?, - sym::copysignf32 => self.float_copysign_intrinsic::(args, dest)?, - sym::copysignf64 => self.float_copysign_intrinsic::(args, dest)?, - sym::copysignf128 => self.float_copysign_intrinsic::(args, dest)?, sym::fabs => { let arg = self.read_immediate(&args[0])?; @@ -1207,17 +1189,34 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - fn float_minmax( + fn binop_float_intrinsic( &self, - a: Scalar, - b: Scalar, - op: MinMax, + name: Symbol, + arg1: ImmTy<'tcx, M::Provenance>, + arg2: ImmTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Scalar> where F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, { - let a: F = a.to_float()?; - let b: F = b.to_float()?; + let x: F = arg1.to_scalar().to_float()?; + let y: F = arg2.to_scalar().to_float()?; + match name { + // bitwise, no NaN adjustments + sym::copysign => interp_ok(x.copy_sign(y).into()), + + sym::minimum => self.float_minmax(x, y, MinMax::Minimum), + sym::maximum => self.float_minmax(x, y, MinMax::Maximum), + sym::minimum_number_nsz => self.float_minmax(x, y, MinMax::MinimumNumberNsz), + sym::maximum_number_nsz => self.float_minmax(x, y, MinMax::MaximumNumberNsz), + + _ => bug!("not a unary float intrinsic: {}", name), + } + } + + fn float_minmax(&self, a: F, b: F, op: MinMax) -> InterpResult<'tcx, Scalar> + where + F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, + { let res = if matches!(op, MinMax::MinimumNumberNsz | MinMax::MaximumNumberNsz) && a == b { // They are definitely not NaN (those are never equal), but they could be `+0` and `-0`. // Let the machine decide which one to return. @@ -1235,36 +1234,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(res.into()) } - fn float_minmax_intrinsic( - &mut self, - args: &[OpTy<'tcx, M::Provenance>], - op: MinMax, - dest: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ()> - where - F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, - { - let res = - self.float_minmax::(self.read_scalar(&args[0])?, self.read_scalar(&args[1])?, op)?; - self.write_scalar(res, dest)?; - interp_ok(()) - } - - fn float_copysign_intrinsic( - &mut self, - args: &[OpTy<'tcx, M::Provenance>], - dest: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, ()> - where - F: rustc_apfloat::Float + rustc_apfloat::FloatConvert + Into>, - { - 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_round( &mut self, x: Scalar, diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs index 2ddb20fe8c987..f2d0182d1950a 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs @@ -824,10 +824,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let left = left.to_scalar(); let right = right.to_scalar(); interp_ok(match float_ty { - FloatTy::F16 => self.float_minmax::(left, right, op)?, - FloatTy::F32 => self.float_minmax::(left, right, op)?, - FloatTy::F64 => self.float_minmax::(left, right, op)?, - FloatTy::F128 => self.float_minmax::(left, right, op)?, + FloatTy::F16 => self.float_minmax::(left.to_float()?, right.to_float()?, op)?, + FloatTy::F32 => self.float_minmax::(left.to_float()?, right.to_float()?, op)?, + FloatTy::F64 => self.float_minmax::(left.to_float()?, right.to_float()?, op)?, + FloatTy::F128 => self.float_minmax::(left.to_float()?, right.to_float()?, op)?, }) } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 30d7127ccd8fa..784a9e3903a1b 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -91,10 +91,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::contract_check_ensures | sym::contract_check_requires | sym::contract_checks - | sym::copysignf16 - | sym::copysignf32 - | sym::copysignf64 - | sym::copysignf128 + | sym::copysign | sym::cos | sym::ctlz | sym::ctpop @@ -132,22 +129,10 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::log | sym::log2 | sym::log10 - | sym::maximum_number_nsz_f16 - | sym::maximum_number_nsz_f32 - | sym::maximum_number_nsz_f64 - | sym::maximum_number_nsz_f128 - | sym::maximumf16 - | sym::maximumf32 - | sym::maximumf64 - | sym::maximumf128 - | sym::minimum_number_nsz_f16 - | sym::minimum_number_nsz_f32 - | sym::minimum_number_nsz_f64 - | sym::minimum_number_nsz_f128 - | sym::minimumf16 - | sym::minimumf32 - | sym::minimumf64 - | sym::minimumf128 + | sym::maximum + | sym::maximum_number_nsz + | sym::minimum + | sym::minimum_number_nsz | sym::mul_with_overflow | sym::needs_drop | sym::non_exhaustive @@ -448,34 +433,11 @@ pub(crate) fn check_intrinsic_type( | sym::sin | sym::cos => (1, 0, vec![param(0)], param(0)), - 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), - sym::minimum_number_nsz_f128 => { - (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128) - } - - sym::minimumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), - sym::minimumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - sym::minimumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - sym::minimumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), - - sym::maximum_number_nsz_f16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), - sym::maximum_number_nsz_f32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - sym::maximum_number_nsz_f64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - sym::maximum_number_nsz_f128 => { - (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128) - } - - sym::maximumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), - sym::maximumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - sym::maximumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - sym::maximumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), - - sym::copysignf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16), - sym::copysignf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32), - sym::copysignf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64), - sym::copysignf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128), + sym::copysign + | sym::minimum + | sym::maximum + | sym::minimum_number_nsz + | sym::maximum_number_nsz => (1, 0, vec![param(0), param(0)], param(0)), sym::floorf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), sym::floorf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7665df4a4e5ae..f755c034c66a0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -722,10 +722,7 @@ symbols! { copy, copy_closures, copy_nonoverlapping, - copysignf16, - copysignf32, - copysignf64, - copysignf128, + copysign, core, core_panic, core_panic_2015_macro, @@ -1263,14 +1260,8 @@ symbols! { masked, match_beginning_vert, match_default_bindings, - maximum_number_nsz_f16, - maximum_number_nsz_f32, - maximum_number_nsz_f64, - maximum_number_nsz_f128, - maximumf16, - maximumf32, - maximumf64, - maximumf128, + maximum, + maximum_number_nsz, may_dangle, may_unwind, maybe_dangling, @@ -1303,14 +1294,8 @@ symbols! { min_generic_const_args, min_specialization, min_type_alias_impl_trait, - minimum_number_nsz_f16, - minimum_number_nsz_f32, - minimum_number_nsz_f64, - minimum_number_nsz_f128, - minimumf16, - minimumf32, - minimumf64, - minimumf128, + minimum, + minimum_number_nsz, mips, mips32r6, mips64, diff --git a/library/core/src/intrinsics/bounds.rs b/library/core/src/intrinsics/bounds.rs index 085e131035c52..ed017450d6d14 100644 --- a/library/core/src/intrinsics/bounds.rs +++ b/library/core/src/intrinsics/bounds.rs @@ -44,71 +44,49 @@ impl ChangePointee for *const T { /// /// # Safety /// Must actually *be* such a type. -#[rustc_const_unstable(feature = "core_intrinsics", issue = "none")] -pub const unsafe trait FloatPrimitive: Sized + Copy { - type UInt: const core::ops::BitOr - + const core::ops::BitAnd - + const core::ops::Not; +pub unsafe trait FloatPrimitive: + Sized + Copy + PartialOrd + core::ops::Add +{ + type UInt: core::ops::BitOr + + core::ops::BitAnd + + core::ops::Not; const SIGN_MASK: Self::UInt; fn to_bits(self) -> Self::UInt; fn from_bits(bits: Self::UInt) -> Self; + fn is_nan(self) -> bool; + fn is_sign_positive(self) -> bool; + fn is_sign_negative(self) -> bool; } -#[rustc_const_unstable(feature = "core_intrinsics", issue = "none")] -const unsafe impl FloatPrimitive for f16 { - type UInt = u16; - const SIGN_MASK: Self::UInt = f16::SIGN_MASK; - #[inline] - fn to_bits(self) -> Self::UInt { - f16::to_bits(self) - } - #[inline] - fn from_bits(bits: Self::UInt) -> Self { - f16::from_bits(bits) - } -} - -#[rustc_const_unstable(feature = "core_intrinsics", issue = "none")] -const unsafe impl FloatPrimitive for f32 { - type UInt = u32; - const SIGN_MASK: Self::UInt = f32::SIGN_MASK; - #[inline] - fn to_bits(self) -> Self::UInt { - f32::to_bits(self) - } - #[inline] - fn from_bits(bits: Self::UInt) -> Self { - f32::from_bits(bits) - } -} - -#[rustc_const_unstable(feature = "core_intrinsics", issue = "none")] -const unsafe impl FloatPrimitive for f64 { - type UInt = u64; - const SIGN_MASK: Self::UInt = f64::SIGN_MASK; - #[inline] - fn to_bits(self) -> Self::UInt { - f64::to_bits(self) - } - #[inline] - fn from_bits(bits: Self::UInt) -> Self { - f64::from_bits(bits) - } -} - -#[rustc_const_unstable(feature = "core_intrinsics", issue = "none")] -const unsafe impl FloatPrimitive for f128 { - type UInt = u128; - const SIGN_MASK: Self::UInt = f128::SIGN_MASK; - #[inline] - fn to_bits(self) -> Self::UInt { - f128::to_bits(self) - } - #[inline] - fn from_bits(bits: Self::UInt) -> Self { - f128::from_bits(bits) - } -} +macro_rules! impl_float_primitive { + ($($float:ident => $bits:ident),+) => {$( + unsafe impl FloatPrimitive for $float { + type UInt = $bits; + const SIGN_MASK: Self::UInt = $float::SIGN_MASK; + #[inline] + fn to_bits(self) -> Self::UInt { + $float::to_bits(self) + } + #[inline] + fn from_bits(bits: Self::UInt) -> Self { + $float::from_bits(bits) + } + #[inline] + fn is_nan(self) -> bool { + $float::is_nan(self) + } + #[inline] + fn is_sign_positive(self) -> bool { + $float::is_sign_positive(self) + } + #[inline] + fn is_sign_negative(self) -> bool { + $float::is_sign_negative(self) + } + } + )+}; +} +impl_float_primitive!(f16 => u16, f32 => u32, f64 => u64, f128 => u128); /// Built-in integer types (i8, i16, .., i128, isize, u8, u16, .., u128, usize). /// diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index a99633456de0b..b6232d05af8a1 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3178,7 +3178,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize); #[rustc_intrinsic] pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize); -/// Returns the minimum of two `f16` values, ignoring NaN. +/// Returns the minimum of two floating-point values, ignoring NaN. /// /// This behaves like IEEE 754-2019 minimumNumber, *except* that it does not order signed /// zeros deterministically. In particular: @@ -3191,36 +3191,13 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize); /// Therefore, implementations must not require the user to uphold /// any safety invariants. /// -/// The stabilized version of this intrinsic is [`f16::min`]. -#[rustc_nounwind] -#[rustc_intrinsic] -pub const fn minimum_number_nsz_f16(x: f16, y: f16) -> f16 { - if x.is_nan() || y <= x { - y - } else { - // Either y > x or y is a NaN. - x - } -} - -/// Returns the minimum of two `f32` values, ignoring NaN. -/// -/// This behaves like IEEE 754-2019 minimumNumber, *except* that it does not order signed -/// zeros deterministically. In particular: -/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If -/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` -/// and `-0.0`), either input may be returned non-deterministically. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is [`f32::min`]. +/// The stabilized versions of this intrinsic are available on the float primitives via the +/// `min` method. For example, [`f32::min`]. #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn minimum_number_nsz_f32(x: f32, y: f32) -> f32 { +#[rustc_do_not_const_check] +pub const fn minimum_number_nsz(x: T, y: T) -> T { if x.is_nan() || y <= x { y } else { @@ -3229,9 +3206,9 @@ pub const fn minimum_number_nsz_f32(x: f32, y: f32) -> f32 { } } -/// Returns the minimum of two `f64` values, ignoring NaN. +/// Returns the maximum of two floating-point values, ignoring NaN. /// -/// This behaves like IEEE 754-2019 minimumNumber, *except* that it does not order signed +/// This behaves like IEEE 754-2019 maximumNumber, *except* that it does not order signed /// zeros deterministically. In particular: /// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If /// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` @@ -3242,120 +3219,22 @@ pub const fn minimum_number_nsz_f32(x: f32, y: f32) -> f32 { /// Therefore, implementations must not require the user to uphold /// any safety invariants. /// -/// The stabilized version of this intrinsic is [`f64::min`]. +/// The stabilized versions of this intrinsic are available on the float primitives via the +/// `max` method. For example, [`f32::max`]. #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn minimum_number_nsz_f64(x: f64, y: f64) -> f64 { - if x.is_nan() || y <= x { - y - } else { - // Either y > x or y is a NaN. - x - } -} - -/// Returns the minimum of two `f128` values, ignoring NaN. -/// -/// This behaves like IEEE 754-2019 minimumNumber, *except* that it does not order signed -/// zeros deterministically. In particular: -/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If -/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` -/// and `-0.0`), either input may be returned non-deterministically. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is [`f128::min`]. -#[rustc_nounwind] -#[rustc_intrinsic] -pub const fn minimum_number_nsz_f128(x: f128, y: f128) -> f128 { - if x.is_nan() || y <= x { - y - } else { - // Either y > x or y is a NaN. - x - } -} - -/// Returns the minimum of two `f16` values, propagating NaN. -/// -/// This behaves like IEEE 754-2019 minimum. In particular: -/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules. -/// For this operation, -0.0 is considered to be strictly less than +0.0. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -#[rustc_nounwind] -#[rustc_intrinsic] -pub const fn minimumf16(x: f16, y: f16) -> f16 { - if x < y { - x - } else if y < x { - y - } else if x == y { - if x.is_sign_negative() && y.is_sign_positive() { x } else { y } - } else { - // At least one input is NaN. Use `+` to perform NaN propagation and quieting. - x + y - } -} - -/// Returns the minimum of two `f32` values, propagating NaN. -/// -/// This behaves like IEEE 754-2019 minimum. In particular: -/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules. -/// For this operation, -0.0 is considered to be strictly less than +0.0. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -#[rustc_nounwind] -#[rustc_intrinsic] -pub const fn minimumf32(x: f32, y: f32) -> f32 { - if x < y { - x - } else if y < x { +#[rustc_do_not_const_check] +pub const fn maximum_number_nsz(x: T, y: T) -> T { + if x.is_nan() || y >= x { y - } else if x == y { - if x.is_sign_negative() && y.is_sign_positive() { x } else { y } } else { - // At least one input is NaN. Use `+` to perform NaN propagation and quieting. - x + y - } -} - -/// Returns the minimum of two `f64` values, propagating NaN. -/// -/// This behaves like IEEE 754-2019 minimum. In particular: -/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules. -/// For this operation, -0.0 is considered to be strictly less than +0.0. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -#[rustc_nounwind] -#[rustc_intrinsic] -pub const fn minimumf64(x: f64, y: f64) -> f64 { - if x < y { + // Either y < x or y is a NaN. x - } else if y < x { - y - } else if x == y { - if x.is_sign_negative() && y.is_sign_positive() { x } else { y } - } else { - // At least one input is NaN. Use `+` to perform NaN propagation and quieting. - x + y } } -/// Returns the minimum of two `f128` values, propagating NaN. +/// Returns the minimum of two floating-point values, propagating NaN. /// /// This behaves like IEEE 754-2019 minimum. In particular: /// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules. @@ -3366,8 +3245,10 @@ pub const fn minimumf64(x: f64, y: f64) -> f64 { /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[rustc_nounwind] +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn minimumf128(x: f128, y: f128) -> f128 { +#[rustc_do_not_const_check] +pub const fn minimum(x: T, y: T) -> T { if x < y { x } else if y < x { @@ -3380,181 +3261,7 @@ pub const fn minimumf128(x: f128, y: f128) -> f128 { } } -/// Returns the maximum of two `f16` values, ignoring NaN. -/// -/// This behaves like IEEE 754-2019 maximumNumber, *except* that it does not order signed -/// zeros deterministically. In particular: -/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If -/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` -/// and `-0.0`), either input may be returned non-deterministically. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is [`f16::max`]. -#[rustc_nounwind] -#[rustc_intrinsic] -pub const fn maximum_number_nsz_f16(x: f16, y: f16) -> f16 { - if x.is_nan() || y >= x { - y - } else { - // Either y < x or y is a NaN. - x - } -} - -/// Returns the maximum of two `f32` values, ignoring NaN. -/// -/// This behaves like IEEE 754-2019 maximumNumber, *except* that it does not order signed -/// zeros deterministically. In particular: -/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If -/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` -/// and `-0.0`), either input may be returned non-deterministically. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is [`f32::max`]. -#[rustc_nounwind] -#[rustc_intrinsic_const_stable_indirect] -#[rustc_intrinsic] -pub const fn maximum_number_nsz_f32(x: f32, y: f32) -> f32 { - if x.is_nan() || y >= x { - y - } else { - // Either y < x or y is a NaN. - x - } -} - -/// Returns the maximum of two `f64` values, ignoring NaN. -/// -/// This behaves like IEEE 754-2019 maximumNumber, *except* that it does not order signed -/// zeros deterministically. In particular: -/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If -/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` -/// and `-0.0`), either input may be returned non-deterministically. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is [`f64::max`]. -#[rustc_nounwind] -#[rustc_intrinsic_const_stable_indirect] -#[rustc_intrinsic] -pub const fn maximum_number_nsz_f64(x: f64, y: f64) -> f64 { - if x.is_nan() || y >= x { - y - } else { - // Either y < x or y is a NaN. - x - } -} - -/// Returns the maximum of two `f128` values, ignoring NaN. -/// -/// This behaves like IEEE 754-2019 maximumNumber, *except* that it does not order signed -/// zeros deterministically. In particular: -/// If one of the arguments is NaN (quiet or signaling), then the other argument is returned. If -/// both arguments are NaN, returns NaN. If the inputs compare equal (such as for the case of `+0.0` -/// and `-0.0`), either input may be returned non-deterministically. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -/// -/// The stabilized version of this intrinsic is [`f128::max`]. -#[rustc_nounwind] -#[rustc_intrinsic] -pub const fn maximum_number_nsz_f128(x: f128, y: f128) -> f128 { - if x.is_nan() || y >= x { - y - } else { - // Either y < x or y is a NaN. - x - } -} - -/// Returns the maximum of two `f16` values, propagating NaN. -/// -/// This behaves like IEEE 754-2019 maximum. In particular: -/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules. -/// For this operation, -0.0 is considered to be strictly less than +0.0. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -#[rustc_nounwind] -#[rustc_intrinsic] -pub const fn maximumf16(x: f16, y: f16) -> f16 { - if x > y { - x - } else if y > x { - y - } else if x == y { - if x.is_sign_positive() && y.is_sign_negative() { x } else { y } - } else { - x + y - } -} - -/// Returns the maximum of two `f32` values, propagating NaN. -/// -/// This behaves like IEEE 754-2019 maximum. In particular: -/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules. -/// For this operation, -0.0 is considered to be strictly less than +0.0. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -#[rustc_nounwind] -#[rustc_intrinsic] -pub const fn maximumf32(x: f32, y: f32) -> f32 { - if x > y { - x - } else if y > x { - y - } else if x == y { - if x.is_sign_positive() && y.is_sign_negative() { x } else { y } - } else { - x + y - } -} - -/// Returns the maximum of two `f64` values, propagating NaN. -/// -/// This behaves like IEEE 754-2019 maximum. In particular: -/// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules. -/// For this operation, -0.0 is considered to be strictly less than +0.0. -/// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. -#[rustc_nounwind] -#[rustc_intrinsic] -pub const fn maximumf64(x: f64, y: f64) -> f64 { - if x > y { - x - } else if y > x { - y - } else if x == y { - if x.is_sign_positive() && y.is_sign_negative() { x } else { y } - } else { - x + y - } -} - -/// Returns the maximum of two `f128` values, propagating NaN. +/// Returns the maximum of two floating-point values, propagating NaN. /// /// This behaves like IEEE 754-2019 maximum. In particular: /// If one of the arguments is NaN, then a NaN is returned using the usual NaN propagation rules. @@ -3565,8 +3272,10 @@ pub const fn maximumf64(x: f64, y: f64) -> f64 { /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[rustc_nounwind] +#[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn maximumf128(x: f128, y: f128) -> f128 { +#[rustc_do_not_const_check] +pub const fn maximum(x: T, y: T) -> T { if x > y { x } else if y > x { @@ -3574,6 +3283,7 @@ pub const fn maximumf128(x: f128, y: f128) -> f128 { } else if x == y { if x.is_sign_positive() && y.is_sign_negative() { x } else { y } } else { + // At least one input is NaN. Use `+` to perform NaN propagation and quieting. x + y } } @@ -3583,57 +3293,26 @@ pub const fn maximumf128(x: f128, y: f128) -> f128 { /// The stabilized versions of this intrinsic are available on the float /// primitives via the `abs` method. For example, [`f32::abs`]. #[rustc_nounwind] -#[rustc_const_unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[miri::intrinsic_fallback_is_spec] -pub const fn fabs(x: T) -> T { +#[rustc_do_not_const_check] +pub const fn fabs(x: T) -> T { T::from_bits(x.to_bits() & !T::SIGN_MASK) } -/// 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) -#[inline] -#[rustc_nounwind] -#[rustc_intrinsic] -pub const fn copysignf16(x: f16, y: f16) -> f16 { - f16::from_bits((x.to_bits() & !f16::SIGN_MASK) | (y.to_bits() & f16::SIGN_MASK)) -} - -/// 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) -#[inline] -#[rustc_nounwind] -#[rustc_intrinsic_const_stable_indirect] -#[rustc_intrinsic] -pub const fn copysignf32(x: f32, y: f32) -> f32 { - f32::from_bits((x.to_bits() & !f32::SIGN_MASK) | (y.to_bits() & f32::SIGN_MASK)) -} -/// Copies the sign from `y` to `x` for `f64` values. +/// Copies the sign from `y` to `x` for floating-point values. /// -/// The stabilized version of this intrinsic is -/// [`f64::copysign`](../../std/primitive.f64.html#method.copysign) +/// The stabilized versions of this intrinsic are available on the float +/// primitives via the `copysign` method. For example, [`f32::copysign`]. #[inline] #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn copysignf64(x: f64, y: f64) -> f64 { - f64::from_bits((x.to_bits() & !f64::SIGN_MASK) | (y.to_bits() & f64::SIGN_MASK)) -} - -/// 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) -#[inline] -#[rustc_nounwind] -#[rustc_intrinsic] -pub const fn copysignf128(x: f128, y: f128) -> f128 { - f128::from_bits((x.to_bits() & !f128::SIGN_MASK) | (y.to_bits() & f128::SIGN_MASK)) +#[rustc_do_not_const_check] +#[miri::intrinsic_fallback_is_spec] +pub const fn copysign(x: T, y: T) -> T { + T::from_bits((x.to_bits() & !T::SIGN_MASK) | (y.to_bits() & T::SIGN_MASK)) } /// Generates the LLVM body for the automatic differentiation of `f` using Enzyme, diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 93dd52198f488..e2d662a760de5 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -859,7 +859,7 @@ impl f128 { #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn max(self, other: f128) -> f128 { - intrinsics::maximum_number_nsz_f128(self, other) + intrinsics::maximum_number_nsz(self, other) } /// Returns the minimum of the two numbers, ignoring NaN. @@ -890,7 +890,7 @@ impl f128 { #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn min(self, other: f128) -> f128 { - intrinsics::minimum_number_nsz_f128(self, other) + intrinsics::minimum_number_nsz(self, other) } /// Returns the maximum of the two numbers, propagating NaN. @@ -922,7 +922,7 @@ impl f128 { // #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn maximum(self, other: f128) -> f128 { - intrinsics::maximumf128(self, other) + intrinsics::maximum(self, other) } /// Returns the minimum of the two numbers, propagating NaN. @@ -954,7 +954,7 @@ impl f128 { // #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn minimum(self, other: f128) -> f128 { - intrinsics::minimumf128(self, other) + intrinsics::minimum(self, other) } /// Calculates the midpoint (average) between `self` and `rhs`. @@ -1679,7 +1679,7 @@ impl f128 { #[rustc_const_unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn copysign(self, sign: f128) -> f128 { - intrinsics::copysignf128(self, sign) + intrinsics::copysign(self, sign) } /// Float addition that allows optimizations based on algebraic rules. diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index cb79c0736c608..cf469410f06c3 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -855,7 +855,7 @@ impl f16 { #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn max(self, other: f16) -> f16 { - intrinsics::maximum_number_nsz_f16(self, other) + intrinsics::maximum_number_nsz(self, other) } /// Returns the minimum of the two numbers, ignoring NaN. @@ -886,7 +886,7 @@ impl f16 { #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn min(self, other: f16) -> f16 { - intrinsics::minimum_number_nsz_f16(self, other) + intrinsics::minimum_number_nsz(self, other) } /// Returns the maximum of the two numbers, propagating NaN. @@ -918,7 +918,7 @@ impl f16 { // #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn maximum(self, other: f16) -> f16 { - intrinsics::maximumf16(self, other) + intrinsics::maximum(self, other) } /// Returns the minimum of the two numbers, propagating NaN. @@ -950,7 +950,7 @@ impl f16 { // #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[must_use = "this returns the result of the comparison, without modifying either input"] pub const fn minimum(self, other: f16) -> f16 { - intrinsics::minimumf16(self, other) + intrinsics::minimum(self, other) } /// Calculates the midpoint (average) between `self` and `rhs`. @@ -1665,7 +1665,7 @@ impl f16 { #[rustc_const_unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub const fn copysign(self, sign: f16) -> f16 { - intrinsics::copysignf16(self, sign) + intrinsics::copysign(self, sign) } /// Float addition that allows optimizations based on algebraic rules. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 8a02aa7517474..66347beefff7d 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1056,7 +1056,7 @@ impl f32 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn max(self, other: f32) -> f32 { - intrinsics::maximum_number_nsz_f32(self, other) + intrinsics::maximum_number_nsz(self, other) } /// Returns the minimum of the two numbers, ignoring NaN. @@ -1083,7 +1083,7 @@ impl f32 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn min(self, other: f32) -> f32 { - intrinsics::minimum_number_nsz_f32(self, other) + intrinsics::minimum_number_nsz(self, other) } /// Returns the maximum of the two numbers, propagating NaN. @@ -1110,7 +1110,7 @@ impl f32 { #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] pub const fn maximum(self, other: f32) -> f32 { - intrinsics::maximumf32(self, other) + intrinsics::maximum(self, other) } /// Returns the minimum of the two numbers, propagating NaN. @@ -1137,7 +1137,7 @@ impl f32 { #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] pub const fn minimum(self, other: f32) -> f32 { - intrinsics::minimumf32(self, other) + intrinsics::minimum(self, other) } /// Calculates the midpoint (average) between `self` and `rhs`. @@ -1822,7 +1822,7 @@ impl f32 { #[stable(feature = "copysign", since = "1.35.0")] #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] pub const fn copysign(self, sign: f32) -> f32 { - intrinsics::copysignf32(self, sign) + intrinsics::copysign(self, sign) } /// Float addition that allows optimizations based on algebraic rules. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index e0bb0e35415b6..ab6ea8ba4724f 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1056,7 +1056,7 @@ impl f64 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn max(self, other: f64) -> f64 { - intrinsics::maximum_number_nsz_f64(self, other) + intrinsics::maximum_number_nsz(self, other) } /// Returns the minimum of the two numbers, ignoring NaN. @@ -1083,7 +1083,7 @@ impl f64 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn min(self, other: f64) -> f64 { - intrinsics::minimum_number_nsz_f64(self, other) + intrinsics::minimum_number_nsz(self, other) } /// Returns the maximum of the two numbers, propagating NaN. @@ -1110,7 +1110,7 @@ impl f64 { #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] pub const fn maximum(self, other: f64) -> f64 { - intrinsics::maximumf64(self, other) + intrinsics::maximum(self, other) } /// Returns the minimum of the two numbers, propagating NaN. @@ -1137,7 +1137,7 @@ impl f64 { #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] pub const fn minimum(self, other: f64) -> f64 { - intrinsics::minimumf64(self, other) + intrinsics::minimum(self, other) } /// Calculates the midpoint (average) between `self` and `rhs`. @@ -1800,7 +1800,7 @@ impl f64 { #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")] #[inline] pub const fn copysign(self, sign: f64) -> f64 { - intrinsics::copysignf64(self, sign) + intrinsics::copysign(self, sign) } /// Float addition that allows optimizations based on algebraic rules. diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index 7d6bb117bd39a..8d4a7bc5ce0fb 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -419,7 +419,6 @@ generate! { max_by, max_by_key, max_value, - maximum, mem_align_of, mem_replace, mem_size_of, @@ -428,7 +427,6 @@ generate! { min_by, min_by_key, min_value, - minimum, mode, module_name_repetitions, msrv, diff --git a/tests/codegen-llvm/force-intrinsic-fallback.rs b/tests/codegen-llvm/force-intrinsic-fallback.rs index 1fb80b4e83f12..a81cea3edc520 100644 --- a/tests/codegen-llvm/force-intrinsic-fallback.rs +++ b/tests/codegen-llvm/force-intrinsic-fallback.rs @@ -10,15 +10,15 @@ // With the flag, the fallback body is called instead. #[no_mangle] -pub fn call_minimumf32(x: f32, y: f32) -> f32 { - // CHECK-LABEL: @call_minimumf32 +pub fn call_minimum_f32(x: f32, y: f32) -> f32 { + // CHECK-LABEL: @call_minimum_f32 // NORMAL: call float @llvm.minimum.f32 - // NORMAL-NOT: minimumf32 + // NORMAL-NOT: intrinsics{{.*}}minimum // FALLBACK-NOT: @llvm.minimum - // FALLBACK: call {{.*}}minimumf32 - core::intrinsics::minimumf32(x, y) + // FALLBACK: call {{.*}}intrinsics{{.*}}minimum + core::intrinsics::minimum(x, y) } // Codegen backends can return a list of `replaced_intrinsics`, for which codegen of the fallback is diff --git a/tests/ui/consts/const-float-intrinsics.rs b/tests/ui/consts/const-float-intrinsics.rs new file mode 100644 index 0000000000000..6c38d3fca4027 --- /dev/null +++ b/tests/ui/consts/const-float-intrinsics.rs @@ -0,0 +1,30 @@ +//@ 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 bodies are never const-checked and never run by +// const-eval, which has to implement each of these intrinsics itself. + +#![feature(core_intrinsics, f16, f128)] + +use std::intrinsics::{copysign, fabs, maximum, maximum_number_nsz, minimum, minimum_number_nsz}; + +macro_rules! check { + ($ty:ident) => { + const _: () = { + assert!(fabs(-2.5 as $ty) == 2.5); + assert!(copysign(2.5 as $ty, -1.0) == -2.5); + + assert!(minimum(1.0 as $ty, 2.0) == 1.0); + assert!(maximum(1.0 as $ty, 2.0) == 2.0); + assert!(minimum_number_nsz($ty::NAN, 2.0) == 2.0); + assert!(maximum_number_nsz($ty::NAN, 2.0) == 2.0); + }; + }; +} + +check!(f16); +check!(f32); +check!(f64); +check!(f128); + +fn main() {} diff --git a/tests/ui/intrinsics/bad-intrinsic-monomorphization-bounds.stderr b/tests/ui/intrinsics/bad-intrinsic-monomorphization-bounds.stderr index 148e6ea1e6aca..37a10e8fe35d1 100644 --- a/tests/ui/intrinsics/bad-intrinsic-monomorphization-bounds.stderr +++ b/tests/ui/intrinsics/bad-intrinsic-monomorphization-bounds.stderr @@ -14,19 +14,20 @@ LL | pub struct Foo(i64); | ^^^^^^^^^^^^^^ help: the following other types implement trait `intrinsics::bounds::FloatPrimitive` --> $SRC_DIR/core/src/intrinsics/bounds.rs:LL:COL + | + = note: `f128` | = note: `f16` - ::: $SRC_DIR/core/src/intrinsics/bounds.rs:LL:COL | = note: `f32` - ::: $SRC_DIR/core/src/intrinsics/bounds.rs:LL:COL | = note: `f64` ::: $SRC_DIR/core/src/intrinsics/bounds.rs:LL:COL | - = note: `f128` + = note: in this macro invocation note: required by a bound in `fadd_fast` --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL + = note: this error originates in the macro `impl_float_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error