From 1d8aa13bc39eeef1afba0524dc5ea10d073522e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lo=C3=AFc=20BRANSTETT?= <loic.branstett@epitech.eu>
Date: Wed, 17 Nov 2021 23:41:03 +0100
Subject: [PATCH] Implement minimumf[32,64} and maximumf{32,64} intrinsics

---
 .../src/intrinsics/mod.rs                     | 21 ++++++++++++
 .../rustc_codegen_gcc/src/intrinsic/mod.rs    |  7 ++++
 compiler/rustc_codegen_llvm/src/context.rs    |  5 +++
 compiler/rustc_codegen_llvm/src/intrinsic.rs  |  4 +++
 compiler/rustc_span/src/symbol.rs             |  4 +++
 compiler/rustc_typeck/src/check/intrinsic.rs  | 10 +++++-
 library/core/src/intrinsics.rs                | 33 +++++++++++++++++++
 7 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 313b62c5770b6..c4e17533d46e8 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -1064,6 +1064,27 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             ret.write_cvalue(fx, val);
         };
 
+        minimumf32, (v a, v b) {
+            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);
+        };
+        minimumf64, (v a, v b) {
+            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);
+        };
+        maximumf32, (v a, v b) {
+            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);
+        };
+        maximumf64, (v a, v b) {
+            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);
+        };
+
         kw.Try, (v f, v data, v _catch_fn) {
             // FIXME once unwinding is supported, change this to actually catch panics
             let f_sig = fx.bcx.func.import_signature(Signature {
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 64bd586662d38..04450370dcbe9 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -53,6 +53,13 @@ fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) ->
         sym::minnumf64 => "fmin",
         sym::maxnumf32 => "fmaxf",
         sym::maxnumf64 => "fmax",
+        // FIXME: GCC currently doens't seems to have builtins that propagate NaN
+        // as required by the {min,max}imum instrinsics. For the mean time
+        // use the builtins that doens't propagate the NaN
+        sym::minimumf32 => "fminf",
+        sym::minimumf64 => "fmin",
+        sym::maximumf32 => "fmaxf",
+        sym::maximumf64 => "fmax",
         sym::copysignf32 => "copysignf",
         sym::copysignf64 => "copysign",
         sym::floorf32 => "floorf",
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 1dba264a9614a..ed4dc0a1292ae 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -640,6 +640,11 @@ impl CodegenCx<'b, 'tcx> {
         ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32);
         ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64);
 
+        ifn!("llvm.minimum.f32", fn(t_f32, t_f32) -> t_f32);
+        ifn!("llvm.minimum.f64", fn(t_f64, t_f64) -> t_f64);
+        ifn!("llvm.maximum.f32", fn(t_f32, t_f32) -> t_f32);
+        ifn!("llvm.maximum.f64", fn(t_f64, t_f64) -> t_f64);
+
         ifn!("llvm.floor.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.floor.f64", fn(t_f64) -> t_f64);
 
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 924bb803b368f..0baea3f61197d 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -55,6 +55,10 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<(&'ll T
         sym::minnumf64 => "llvm.minnum.f64",
         sym::maxnumf32 => "llvm.maxnum.f32",
         sym::maxnumf64 => "llvm.maxnum.f64",
+        sym::minimumf32 => "llvm.minimum.f32",
+        sym::minimumf64 => "llvm.minimum.f64",
+        sym::maximumf32 => "llvm.maximum.f32",
+        sym::maximumf64 => "llvm.maximum.f64",
         sym::copysignf32 => "llvm.copysign.f32",
         sym::copysignf64 => "llvm.copysign.f64",
         sym::floorf32 => "llvm.floor.f32",
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 99fa9f000944d..163e940d4b69d 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -810,6 +810,8 @@ symbols! {
         masked,
         match_beginning_vert,
         match_default_bindings,
+        maximumf32,
+        maximumf64,
         maxnumf32,
         maxnumf64,
         may_dangle,
@@ -837,6 +839,8 @@ symbols! {
         min_const_unsafe_fn,
         min_specialization,
         min_type_alias_impl_trait,
+        minimumf32,
+        minimumf64,
         minnumf32,
         minnumf64,
         mips_target_feature,
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index 6314f2aba4efe..aa64ee363d85c 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -98,8 +98,12 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
         | sym::minnumf32
         | sym::minnumf64
         | sym::maxnumf32
-        | sym::rustc_peek
         | sym::maxnumf64
+        | sym::minimumf32
+        | sym::minimumf64
+        | sym::maximumf32
+        | sym::maximumf64
+        | sym::rustc_peek
         | sym::type_name
         | sym::forget
         | sym::black_box
@@ -256,6 +260,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             sym::minnumf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
             sym::maxnumf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
             sym::maxnumf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::minimumf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::minimumf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::maximumf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::maximumf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
             sym::copysignf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
             sym::copysignf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
             sym::floorf32 => (0, vec![tcx.types.f32], tcx.types.f32),
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 0f57fb5b14180..d34e3dc9f4cb6 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1406,6 +1406,39 @@ extern "rust-intrinsic" {
     /// [`f64::max`]
     pub fn maxnumf64(x: f64, y: f64) -> f64;
 
+    /// Returns the minimum of two `f32` values.
+    ///
+    /// 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.
+    #[cfg(not(bootstrap))]
+    pub fn minimumf32(x: f32, y: f32) -> f32;
+    /// Returns the minimum of two `f64` values.
+    ///
+    /// 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.
+    #[cfg(not(bootstrap))]
+    pub fn minimumf64(x: f64, y: f64) -> f64;
+    /// Returns the maximum of two `f32` values.
+    ///
+    /// 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.
+    #[cfg(not(bootstrap))]
+    pub fn maximumf32(x: f32, y: f32) -> f32;
+    /// Returns the maximum of two `f64` values.
+    ///
+    /// 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.
+    #[cfg(not(bootstrap))]
+    pub fn maximumf64(x: f64, y: f64) -> f64;
+
     /// Copies the sign from `y` to `x` for `f32` values.
     ///
     /// The stabilized version of this intrinsic is