Skip to content

Commit f308845

Browse files
committed
Use intrinsics for {f16,f32,f64,f64}::{minimum,maximum} operations
1 parent 7e552b4 commit f308845

File tree

12 files changed

+351
-68
lines changed

12 files changed

+351
-68
lines changed

compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs

+37
Original file line numberDiff line numberDiff line change
@@ -1109,6 +1109,43 @@ fn codegen_regular_intrinsic_call<'tcx>(
11091109
ret.write_cvalue(fx, old);
11101110
}
11111111

1112+
sym::minimumf32 => {
1113+
intrinsic_args!(fx, args => (a, b); intrinsic);
1114+
let a = a.load_scalar(fx);
1115+
let b = b.load_scalar(fx);
1116+
1117+
let val = fx.bcx.ins().fmin(a, b);
1118+
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
1119+
ret.write_cvalue(fx, val);
1120+
}
1121+
sym::minimumf64 => {
1122+
intrinsic_args!(fx, args => (a, b); intrinsic);
1123+
let a = a.load_scalar(fx);
1124+
let b = b.load_scalar(fx);
1125+
1126+
let val = fx.bcx.ins().fmin(a, b);
1127+
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
1128+
ret.write_cvalue(fx, val);
1129+
}
1130+
sym::maximumf32 => {
1131+
intrinsic_args!(fx, args => (a, b); intrinsic);
1132+
let a = a.load_scalar(fx);
1133+
let b = b.load_scalar(fx);
1134+
1135+
let val = fx.bcx.ins().fmax(a, b);
1136+
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
1137+
ret.write_cvalue(fx, val);
1138+
}
1139+
sym::maximumf64 => {
1140+
intrinsic_args!(fx, args => (a, b); intrinsic);
1141+
let a = a.load_scalar(fx);
1142+
let b = b.load_scalar(fx);
1143+
1144+
let val = fx.bcx.ins().fmax(a, b);
1145+
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
1146+
ret.write_cvalue(fx, val);
1147+
}
1148+
11121149
sym::minnumf32 => {
11131150
intrinsic_args!(fx, args => (a, b); intrinsic);
11141151
let a = a.load_scalar(fx);

compiler/rustc_codegen_gcc/src/intrinsic/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,12 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
7474
sym::fabsf64 => "fabs",
7575
sym::minnumf32 => "fminf",
7676
sym::minnumf64 => "fmin",
77+
sym::minimumf32 => "fminimum",
78+
sym::minimumf64 => "fminimumf",
7779
sym::maxnumf32 => "fmaxf",
7880
sym::maxnumf64 => "fmax",
81+
sym::maximumf32 => "fmaximum",
82+
sym::maximumf64 => "fmaximumf",
7983
sym::copysignf32 => "copysignf",
8084
sym::copysignf64 => "copysign",
8185
sym::copysignf128 => "copysignl",

compiler/rustc_codegen_llvm/src/context.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1009,11 +1009,21 @@ impl<'ll> CodegenCx<'ll, '_> {
10091009
ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64);
10101010
ifn!("llvm.minnum.f128", fn(t_f128, t_f128) -> t_f128);
10111011

1012+
ifn!("llvm.minimum.f16", fn(t_f16, t_f16) -> t_f16);
1013+
ifn!("llvm.minimum.f32", fn(t_f32, t_f32) -> t_f32);
1014+
ifn!("llvm.minimum.f64", fn(t_f64, t_f64) -> t_f64);
1015+
ifn!("llvm.minimum.f128", fn(t_f128, t_f128) -> t_f128);
1016+
10121017
ifn!("llvm.maxnum.f16", fn(t_f16, t_f16) -> t_f16);
10131018
ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32);
10141019
ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64);
10151020
ifn!("llvm.maxnum.f128", fn(t_f128, t_f128) -> t_f128);
10161021

1022+
ifn!("llvm.maximum.f16", fn(t_f16, t_f16) -> t_f16);
1023+
ifn!("llvm.maximum.f32", fn(t_f32, t_f32) -> t_f32);
1024+
ifn!("llvm.maximum.f64", fn(t_f64, t_f64) -> t_f64);
1025+
ifn!("llvm.maximum.f128", fn(t_f128, t_f128) -> t_f128);
1026+
10171027
ifn!("llvm.floor.f16", fn(t_f16) -> t_f16);
10181028
ifn!("llvm.floor.f32", fn(t_f32) -> t_f32);
10191029
ifn!("llvm.floor.f64", fn(t_f64) -> t_f64);

compiler/rustc_codegen_llvm/src/intrinsic.rs

+10
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,21 @@ fn get_simple_intrinsic<'ll>(
103103
sym::minnumf64 => "llvm.minnum.f64",
104104
sym::minnumf128 => "llvm.minnum.f128",
105105

106+
sym::minimumf16 => "llvm.minimum.f16",
107+
sym::minimumf32 => "llvm.minimum.f32",
108+
sym::minimumf64 => "llvm.minimum.f64",
109+
sym::minimumf128 => "llvm.minimum.f128",
110+
106111
sym::maxnumf16 => "llvm.maxnum.f16",
107112
sym::maxnumf32 => "llvm.maxnum.f32",
108113
sym::maxnumf64 => "llvm.maxnum.f64",
109114
sym::maxnumf128 => "llvm.maxnum.f128",
110115

116+
sym::maximumf16 => "llvm.maximum.f16",
117+
sym::maximumf32 => "llvm.maximum.f32",
118+
sym::maximumf64 => "llvm.maximum.f64",
119+
sym::maximumf128 => "llvm.maximum.f128",
120+
111121
sym::copysignf16 => "llvm.copysign.f16",
112122
sym::copysignf32 => "llvm.copysign.f32",
113123
sym::copysignf64 => "llvm.copysign.f64",

compiler/rustc_const_eval/src/interpret/intrinsics.rs

+40
Original file line numberDiff line numberDiff line change
@@ -493,11 +493,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
493493
sym::minnumf64 => self.float_min_intrinsic::<Double>(args, dest)?,
494494
sym::minnumf128 => self.float_min_intrinsic::<Quad>(args, dest)?,
495495

496+
sym::minimumf16 => self.float_minimum_intrinsic::<Half>(args, dest)?,
497+
sym::minimumf32 => self.float_minimum_intrinsic::<Single>(args, dest)?,
498+
sym::minimumf64 => self.float_minimum_intrinsic::<Double>(args, dest)?,
499+
sym::minimumf128 => self.float_minimum_intrinsic::<Quad>(args, dest)?,
500+
496501
sym::maxnumf16 => self.float_max_intrinsic::<Half>(args, dest)?,
497502
sym::maxnumf32 => self.float_max_intrinsic::<Single>(args, dest)?,
498503
sym::maxnumf64 => self.float_max_intrinsic::<Double>(args, dest)?,
499504
sym::maxnumf128 => self.float_max_intrinsic::<Quad>(args, dest)?,
500505

506+
sym::maximumf16 => self.float_maximum_intrinsic::<Half>(args, dest)?,
507+
sym::maximumf32 => self.float_maximum_intrinsic::<Single>(args, dest)?,
508+
sym::maximumf64 => self.float_maximum_intrinsic::<Double>(args, dest)?,
509+
sym::maximumf128 => self.float_maximum_intrinsic::<Quad>(args, dest)?,
510+
501511
sym::copysignf16 => self.float_copysign_intrinsic::<Half>(args, dest)?,
502512
sym::copysignf32 => self.float_copysign_intrinsic::<Single>(args, dest)?,
503513
sym::copysignf64 => self.float_copysign_intrinsic::<Double>(args, dest)?,
@@ -830,6 +840,36 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
830840
interp_ok(())
831841
}
832842

843+
fn float_minimum_intrinsic<F>(
844+
&mut self,
845+
args: &[OpTy<'tcx, M::Provenance>],
846+
dest: &MPlaceTy<'tcx, M::Provenance>,
847+
) -> InterpResult<'tcx, ()>
848+
where
849+
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
850+
{
851+
let a: F = self.read_scalar(&args[0])?.to_float()?;
852+
let b: F = self.read_scalar(&args[1])?.to_float()?;
853+
let res = self.adjust_nan(a.minimum(b), &[a, b]);
854+
self.write_scalar(res, dest)?;
855+
interp_ok(())
856+
}
857+
858+
fn float_maximum_intrinsic<F>(
859+
&mut self,
860+
args: &[OpTy<'tcx, M::Provenance>],
861+
dest: &MPlaceTy<'tcx, M::Provenance>,
862+
) -> InterpResult<'tcx, ()>
863+
where
864+
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
865+
{
866+
let a: F = self.read_scalar(&args[0])?.to_float()?;
867+
let b: F = self.read_scalar(&args[1])?.to_float()?;
868+
let res = self.adjust_nan(a.maximum(b), &[a, b]);
869+
self.write_scalar(res, dest)?;
870+
interp_ok(())
871+
}
872+
833873
fn float_copysign_intrinsic<F>(
834874
&mut self,
835875
args: &[OpTy<'tcx, M::Provenance>],

compiler/rustc_hir_analysis/src/check/intrinsic.rs

+18
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,18 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
103103
| sym::minnumf32
104104
| sym::minnumf64
105105
| sym::minnumf128
106+
| sym::minimumf16
107+
| sym::minimumf32
108+
| sym::minimumf64
109+
| sym::minimumf128
106110
| sym::maxnumf16
107111
| sym::maxnumf32
108112
| sym::maxnumf64
109113
| sym::maxnumf128
114+
| sym::maximumf16
115+
| sym::maximumf32
116+
| sym::maximumf64
117+
| sym::maximumf128
110118
| sym::rustc_peek
111119
| sym::type_name
112120
| sym::forget
@@ -374,11 +382,21 @@ pub(crate) fn check_intrinsic_type(
374382
sym::minnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
375383
sym::minnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
376384

385+
sym::minimumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
386+
sym::minimumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
387+
sym::minimumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
388+
sym::minimumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
389+
377390
sym::maxnumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
378391
sym::maxnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
379392
sym::maxnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
380393
sym::maxnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
381394

395+
sym::maximumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
396+
sym::maximumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
397+
sym::maximumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
398+
sym::maximumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
399+
382400
sym::copysignf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
383401
sym::copysignf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
384402
sym::copysignf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),

compiler/rustc_span/src/symbol.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1301,6 +1301,10 @@ symbols! {
13011301
match_beginning_vert,
13021302
match_default_bindings,
13031303
matches_macro,
1304+
maximumf128,
1305+
maximumf16,
1306+
maximumf32,
1307+
maximumf64,
13041308
maxnumf128,
13051309
maxnumf16,
13061310
maxnumf32,
@@ -1335,6 +1339,10 @@ symbols! {
13351339
min_generic_const_args,
13361340
min_specialization,
13371341
min_type_alias_impl_trait,
1342+
minimumf128,
1343+
minimumf16,
1344+
minimumf32,
1345+
minimumf64,
13381346
minnumf128,
13391347
minnumf16,
13401348
minnumf32,

library/core/src/intrinsics/mod.rs

+92
Original file line numberDiff line numberDiff line change
@@ -3982,6 +3982,52 @@ pub const fn minnumf64(x: f64, y: f64) -> f64;
39823982
#[rustc_intrinsic]
39833983
pub const fn minnumf128(x: f128, y: f128) -> f128;
39843984

3985+
/// Returns the minimum (IEEE 754-2019 minimum) of two `f16` values.
3986+
///
3987+
/// Note that, unlike most intrinsics, this is safe to call;
3988+
/// it does not require an `unsafe` block.
3989+
/// Therefore, implementations must not require the user to uphold
3990+
/// any safety invariants.
3991+
#[rustc_nounwind]
3992+
#[rustc_intrinsic]
3993+
#[cfg(not(bootstrap))]
3994+
pub const fn minimumf16(x: f16, y: f16) -> f16;
3995+
3996+
/// Returns the minimum (IEEE 754-2019 minimum) of two `f32` values.
3997+
///
3998+
/// Note that, unlike most intrinsics, this is safe to call;
3999+
/// it does not require an `unsafe` block.
4000+
/// Therefore, implementations must not require the user to uphold
4001+
/// any safety invariants.
4002+
#[rustc_nounwind]
4003+
#[rustc_intrinsic_const_stable_indirect]
4004+
#[rustc_intrinsic]
4005+
#[cfg(not(bootstrap))]
4006+
pub const fn minimumf32(x: f32, y: f32) -> f32;
4007+
4008+
/// Returns the minimum (IEEE 754-2019 minimum) of two `f64` values.
4009+
///
4010+
/// Note that, unlike most intrinsics, this is safe to call;
4011+
/// it does not require an `unsafe` block.
4012+
/// Therefore, implementations must not require the user to uphold
4013+
/// any safety invariants.
4014+
#[rustc_nounwind]
4015+
#[rustc_intrinsic_const_stable_indirect]
4016+
#[rustc_intrinsic]
4017+
#[cfg(not(bootstrap))]
4018+
pub const fn minimumf64(x: f64, y: f64) -> f64;
4019+
4020+
/// Returns the minimum (IEEE 754-2019 minimum) of two `f128` values.
4021+
///
4022+
/// Note that, unlike most intrinsics, this is safe to call;
4023+
/// it does not require an `unsafe` block.
4024+
/// Therefore, implementations must not require the user to uphold
4025+
/// any safety invariants.
4026+
#[rustc_nounwind]
4027+
#[rustc_intrinsic]
4028+
#[cfg(not(bootstrap))]
4029+
pub const fn minimumf128(x: f128, y: f128) -> f128;
4030+
39854031
/// Returns the maximum of two `f16` values.
39864032
///
39874033
/// Note that, unlike most intrinsics, this is safe to call;
@@ -4036,6 +4082,52 @@ pub const fn maxnumf64(x: f64, y: f64) -> f64;
40364082
#[rustc_intrinsic]
40374083
pub const fn maxnumf128(x: f128, y: f128) -> f128;
40384084

4085+
/// Returns the maximum (IEEE 754-2019 maximum) of two `f16` values.
4086+
///
4087+
/// Note that, unlike most intrinsics, this is safe to call;
4088+
/// it does not require an `unsafe` block.
4089+
/// Therefore, implementations must not require the user to uphold
4090+
/// any safety invariants.
4091+
#[rustc_nounwind]
4092+
#[rustc_intrinsic]
4093+
#[cfg(not(bootstrap))]
4094+
pub const fn maximumf16(x: f16, y: f16) -> f16;
4095+
4096+
/// Returns the maximum (IEEE 754-2019 maximum) of two `f32` values.
4097+
///
4098+
/// Note that, unlike most intrinsics, this is safe to call;
4099+
/// it does not require an `unsafe` block.
4100+
/// Therefore, implementations must not require the user to uphold
4101+
/// any safety invariants.
4102+
#[rustc_nounwind]
4103+
#[rustc_intrinsic_const_stable_indirect]
4104+
#[rustc_intrinsic]
4105+
#[cfg(not(bootstrap))]
4106+
pub const fn maximumf32(x: f32, y: f32) -> f32;
4107+
4108+
/// Returns the maximum (IEEE 754-2019 maximum) of two `f64` values.
4109+
///
4110+
/// Note that, unlike most intrinsics, this is safe to call;
4111+
/// it does not require an `unsafe` block.
4112+
/// Therefore, implementations must not require the user to uphold
4113+
/// any safety invariants.
4114+
#[rustc_nounwind]
4115+
#[rustc_intrinsic_const_stable_indirect]
4116+
#[rustc_intrinsic]
4117+
#[cfg(not(bootstrap))]
4118+
pub const fn maximumf64(x: f64, y: f64) -> f64;
4119+
4120+
/// Returns the maximum (IEEE 754-2019 maximum) of two `f128` values.
4121+
///
4122+
/// Note that, unlike most intrinsics, this is safe to call;
4123+
/// it does not require an `unsafe` block.
4124+
/// Therefore, implementations must not require the user to uphold
4125+
/// any safety invariants.
4126+
#[rustc_nounwind]
4127+
#[rustc_intrinsic]
4128+
#[cfg(not(bootstrap))]
4129+
pub const fn maximumf128(x: f128, y: f128) -> f128;
4130+
40394131
/// Returns the absolute value of an `f16`.
40404132
///
40414133
/// The stabilized version of this intrinsic is

library/core/src/num/f128.rs

+33-17
Original file line numberDiff line numberDiff line change
@@ -755,16 +755,24 @@ impl f128 {
755755
#[inline]
756756
#[unstable(feature = "f128", issue = "116909")]
757757
// #[unstable(feature = "float_minimum_maximum", issue = "91079")]
758+
#[rustc_const_unstable(feature = "f128", issue = "116909")]
758759
#[must_use = "this returns the result of the comparison, without modifying either input"]
759760
pub const fn maximum(self, other: f128) -> f128 {
760-
if self > other {
761-
self
762-
} else if other > self {
763-
other
764-
} else if self == other {
765-
if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
766-
} else {
767-
self + other
761+
#[cfg(not(bootstrap))]
762+
{
763+
intrinsics::maximumf128(self, other)
764+
}
765+
#[cfg(bootstrap)]
766+
{
767+
if self > other {
768+
self
769+
} else if other > self {
770+
other
771+
} else if self == other {
772+
if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
773+
} else {
774+
self + other
775+
}
768776
}
769777
}
770778

@@ -796,17 +804,25 @@ impl f128 {
796804
#[inline]
797805
#[unstable(feature = "f128", issue = "116909")]
798806
// #[unstable(feature = "float_minimum_maximum", issue = "91079")]
807+
#[rustc_const_unstable(feature = "f128", issue = "116909")]
799808
#[must_use = "this returns the result of the comparison, without modifying either input"]
800809
pub const fn minimum(self, other: f128) -> f128 {
801-
if self < other {
802-
self
803-
} else if other < self {
804-
other
805-
} else if self == other {
806-
if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
807-
} else {
808-
// At least one input is NaN. Use `+` to perform NaN propagation and quieting.
809-
self + other
810+
#[cfg(not(bootstrap))]
811+
{
812+
intrinsics::minimumf128(self, other)
813+
}
814+
#[cfg(bootstrap)]
815+
{
816+
if self < other {
817+
self
818+
} else if other < self {
819+
other
820+
} else if self == other {
821+
if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
822+
} else {
823+
// At least one input is NaN. Use `+` to perform NaN propagation and quieting.
824+
self + other
825+
}
810826
}
811827
}
812828

0 commit comments

Comments
 (0)