Skip to content

Commit cad0a57

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

File tree

12 files changed

+359
-76
lines changed

12 files changed

+359
-76
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

+6
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,14 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
7474
sym::fabsf64 => "fabs",
7575
sym::minnumf32 => "fminf",
7676
sym::minnumf64 => "fmin",
77+
sym::minimumf32 => "fminimumf",
78+
sym::minimumf64 => "fminimum",
79+
sym::minimumf128 => "fminimumf128",
7780
sym::maxnumf32 => "fmaxf",
7881
sym::maxnumf64 => "fmax",
82+
sym::maximumf32 => "fmaximumf",
83+
sym::maximumf64 => "fmaximum",
84+
sym::maximumf128 => "fmaximumf128",
7985
sym::copysignf32 => "copysignf",
8086
sym::copysignf64 => "copysign",
8187
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

+42
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,38 @@ 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 = a.minimum(b);
854+
let res = self.adjust_nan(res, &[a, b]);
855+
self.write_scalar(res, dest)?;
856+
interp_ok(())
857+
}
858+
859+
fn float_maximum_intrinsic<F>(
860+
&mut self,
861+
args: &[OpTy<'tcx, M::Provenance>],
862+
dest: &MPlaceTy<'tcx, M::Provenance>,
863+
) -> InterpResult<'tcx, ()>
864+
where
865+
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
866+
{
867+
let a: F = self.read_scalar(&args[0])?.to_float()?;
868+
let b: F = self.read_scalar(&args[1])?.to_float()?;
869+
let res = a.maximum(b);
870+
let res = self.adjust_nan(res, &[a, b]);
871+
self.write_scalar(res, dest)?;
872+
interp_ok(())
873+
}
874+
833875
fn float_copysign_intrinsic<F>(
834876
&mut self,
835877
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

+96-8
Original file line numberDiff line numberDiff line change
@@ -3928,7 +3928,7 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
39283928
}
39293929
}
39303930

3931-
/// Returns the minimum of two `f16` values.
3931+
/// Returns the minimum (IEEE 754-2008 minNum) of two `f16` values.
39323932
///
39333933
/// Note that, unlike most intrinsics, this is safe to call;
39343934
/// it does not require an `unsafe` block.
@@ -3941,7 +3941,7 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
39413941
#[rustc_intrinsic]
39423942
pub const fn minnumf16(x: f16, y: f16) -> f16;
39433943

3944-
/// Returns the minimum of two `f32` values.
3944+
/// Returns the minimum (IEEE 754-2008 minNum) of two `f32` values.
39453945
///
39463946
/// Note that, unlike most intrinsics, this is safe to call;
39473947
/// it does not require an `unsafe` block.
@@ -3955,7 +3955,7 @@ pub const fn minnumf16(x: f16, y: f16) -> f16;
39553955
#[rustc_intrinsic]
39563956
pub const fn minnumf32(x: f32, y: f32) -> f32;
39573957

3958-
/// Returns the minimum of two `f64` values.
3958+
/// Returns the minimum (IEEE 754-2008 minNum) of two `f64` values.
39593959
///
39603960
/// Note that, unlike most intrinsics, this is safe to call;
39613961
/// it does not require an `unsafe` block.
@@ -3969,7 +3969,7 @@ pub const fn minnumf32(x: f32, y: f32) -> f32;
39693969
#[rustc_intrinsic]
39703970
pub const fn minnumf64(x: f64, y: f64) -> f64;
39713971

3972-
/// Returns the minimum of two `f128` values.
3972+
/// Returns the minimum (IEEE 754-2008 minNum) of two `f128` values.
39733973
///
39743974
/// Note that, unlike most intrinsics, this is safe to call;
39753975
/// it does not require an `unsafe` block.
@@ -3982,7 +3982,51 @@ 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 maximum of two `f16` values.
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]
4004+
#[cfg(not(bootstrap))]
4005+
pub const fn minimumf32(x: f32, y: f32) -> f32;
4006+
4007+
/// Returns the minimum (IEEE 754-2019 minimum) of two `f64` values.
4008+
///
4009+
/// Note that, unlike most intrinsics, this is safe to call;
4010+
/// it does not require an `unsafe` block.
4011+
/// Therefore, implementations must not require the user to uphold
4012+
/// any safety invariants.
4013+
#[rustc_nounwind]
4014+
#[rustc_intrinsic]
4015+
#[cfg(not(bootstrap))]
4016+
pub const fn minimumf64(x: f64, y: f64) -> f64;
4017+
4018+
/// Returns the minimum (IEEE 754-2019 minimum) of two `f128` values.
4019+
///
4020+
/// Note that, unlike most intrinsics, this is safe to call;
4021+
/// it does not require an `unsafe` block.
4022+
/// Therefore, implementations must not require the user to uphold
4023+
/// any safety invariants.
4024+
#[rustc_nounwind]
4025+
#[rustc_intrinsic]
4026+
#[cfg(not(bootstrap))]
4027+
pub const fn minimumf128(x: f128, y: f128) -> f128;
4028+
4029+
/// Returns the maximum (IEEE 754-2008 maxNum) of two `f16` values.
39864030
///
39874031
/// Note that, unlike most intrinsics, this is safe to call;
39884032
/// it does not require an `unsafe` block.
@@ -3995,7 +4039,7 @@ pub const fn minnumf128(x: f128, y: f128) -> f128;
39954039
#[rustc_intrinsic]
39964040
pub const fn maxnumf16(x: f16, y: f16) -> f16;
39974041

3998-
/// Returns the maximum of two `f32` values.
4042+
/// Returns the maximum (IEEE 754-2008 maxNum) of two `f32` values.
39994043
///
40004044
/// Note that, unlike most intrinsics, this is safe to call;
40014045
/// it does not require an `unsafe` block.
@@ -4009,7 +4053,7 @@ pub const fn maxnumf16(x: f16, y: f16) -> f16;
40094053
#[rustc_intrinsic]
40104054
pub const fn maxnumf32(x: f32, y: f32) -> f32;
40114055

4012-
/// Returns the maximum of two `f64` values.
4056+
/// Returns the maximum (IEEE 754-2008 maxNum) of two `f64` values.
40134057
///
40144058
/// Note that, unlike most intrinsics, this is safe to call;
40154059
/// it does not require an `unsafe` block.
@@ -4023,7 +4067,7 @@ pub const fn maxnumf32(x: f32, y: f32) -> f32;
40234067
#[rustc_intrinsic]
40244068
pub const fn maxnumf64(x: f64, y: f64) -> f64;
40254069

4026-
/// Returns the maximum of two `f128` values.
4070+
/// Returns the maximum (IEEE 754-2008 maxNum) of two `f128` values.
40274071
///
40284072
/// Note that, unlike most intrinsics, this is safe to call;
40294073
/// it does not require an `unsafe` block.
@@ -4036,6 +4080,50 @@ pub const fn maxnumf64(x: f64, y: f64) -> f64;
40364080
#[rustc_intrinsic]
40374081
pub const fn maxnumf128(x: f128, y: f128) -> f128;
40384082

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

0 commit comments

Comments
 (0)