Skip to content

Commit b8a7222

Browse files
committed
Auto merge of #140792 - Urgau:minimum-maximum-intrinsics, r=<try>
Use intrinsics for `{f16,f32,f64,f128}::{minimum,maximum}` operations This PR creates intrinsics for `{f16,f32,f64,f64}::{minimum,maximum}` operations. This wasn't done when those operations were added as the LLVM support was too weak but now that LLVM has libcalls for unsupported platforms we can finally use them. Cranelift and GCC[^1] support are partial, Cranelift doesn't support `f16` and `f128`, while GCC doesn't support `f16`. r? `@tgross35` try-job: aarch64-gnu try-job: dist-various-1 try-job: dist-various-2 [^1]: https://www.gnu.org/software///gnulib/manual/html_node/Functions-in-_003cmath_002eh_003e.html
2 parents 7e432c4 + 7f0ae5e commit b8a7222

File tree

12 files changed

+349
-84
lines changed

12 files changed

+349
-84
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

+36
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,44 @@ 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 => {
80+
// GCC doesn't have the intrinsic we want so we use the compiler-builtins one
81+
// https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fminimumf128.html
82+
let f128_type = cx.type_f128();
83+
return Some(cx.context.new_function(
84+
None,
85+
FunctionType::Extern,
86+
f128_type,
87+
&[
88+
cx.context.new_parameter(None, f128_type, "a"),
89+
cx.context.new_parameter(None, f128_type, "b"),
90+
],
91+
"fminimumf128",
92+
false,
93+
));
94+
}
7795
sym::maxnumf32 => "fmaxf",
7896
sym::maxnumf64 => "fmax",
97+
sym::maximumf32 => "fmaximumf",
98+
sym::maximumf64 => "fmaximum",
99+
sym::maximumf128 => {
100+
// GCC doesn't have the intrinsic we want so we use the compiler-builtins one
101+
// https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fmaximumf128.html
102+
let f128_type = cx.type_f128();
103+
return Some(cx.context.new_function(
104+
None,
105+
FunctionType::Extern,
106+
f128_type,
107+
&[
108+
cx.context.new_parameter(None, f128_type, "a"),
109+
cx.context.new_parameter(None, f128_type, "b"),
110+
],
111+
"fmaximumf128",
112+
false,
113+
));
114+
}
79115
sym::copysignf32 => "copysignf",
80116
sym::copysignf64 => "copysign",
81117
sym::copysignf128 => "copysignl",

compiler/rustc_codegen_llvm/src/context.rs

+16
Original file line numberDiff line numberDiff line change
@@ -1009,11 +1009,27 @@ 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+
// There are issues on x86_64 and aarch64 with the f128 variant.
1016+
// - https://github.com/llvm/llvm-project/issues/139380
1017+
// - https://github.com/llvm/llvm-project/issues/139381
1018+
// ifn!("llvm.minimum.f128", fn(t_f128, t_f128) -> t_f128);
1019+
10121020
ifn!("llvm.maxnum.f16", fn(t_f16, t_f16) -> t_f16);
10131021
ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32);
10141022
ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64);
10151023
ifn!("llvm.maxnum.f128", fn(t_f128, t_f128) -> t_f128);
10161024

1025+
ifn!("llvm.maximum.f16", fn(t_f16, t_f16) -> t_f16);
1026+
ifn!("llvm.maximum.f32", fn(t_f32, t_f32) -> t_f32);
1027+
ifn!("llvm.maximum.f64", fn(t_f64, t_f64) -> t_f64);
1028+
// There are issues on x86_64 and aarch64 with the f128 variant.
1029+
// - https://github.com/llvm/llvm-project/issues/139380
1030+
// - https://github.com/llvm/llvm-project/issues/139381
1031+
// ifn!("llvm.maximum.f128", fn(t_f128, t_f128) -> t_f128);
1032+
10171033
ifn!("llvm.floor.f16", fn(t_f16) -> t_f16);
10181034
ifn!("llvm.floor.f32", fn(t_f32) -> t_f32);
10191035
ifn!("llvm.floor.f64", fn(t_f64) -> t_f64);

compiler/rustc_codegen_llvm/src/intrinsic.rs

+12
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,23 @@ 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+
// There are issues on x86_64 and aarch64 with the f128 variant,
110+
// let's instead use the instrinsic fallback body.
111+
// sym::minimumf128 => "llvm.minimum.f128",
106112
sym::maxnumf16 => "llvm.maxnum.f16",
107113
sym::maxnumf32 => "llvm.maxnum.f32",
108114
sym::maxnumf64 => "llvm.maxnum.f64",
109115
sym::maxnumf128 => "llvm.maxnum.f128",
110116

117+
sym::maximumf16 => "llvm.maximum.f16",
118+
sym::maximumf32 => "llvm.maximum.f32",
119+
sym::maximumf64 => "llvm.maximum.f64",
120+
// There are issues on x86_64 and aarch64 with the f128 variant,
121+
// let's instead use the instrinsic fallback body.
122+
// sym::maximumf128 => "llvm.maximum.f128",
111123
sym::copysignf16 => "llvm.copysign.f16",
112124
sym::copysignf32 => "llvm.copysign.f32",
113125
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,

0 commit comments

Comments
 (0)