public inbox for fortran@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
@ 2023-06-06 13:19 FX
  2023-06-06 15:43 ` Steve Kargl
                   ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: FX @ 2023-06-06 13:19 UTC (permalink / raw)
  To: fortran; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 240 bytes --]

Hi,

This patch adds four IEEE functions from the Fortran 2018 standard: IEEE_MIN_NUM, IEEE_MAX_NUM, IEEE_MIN_NUM_MAG, and IEEE_MAX_NUM_MAG.

Bootstrapped and regtested on x86_64-pc-linux-gnu, both 32 and 64-bit. OK to commit?

FX


[-- Attachment #2: 0001-Fortran-add-Fortran-2018-IEEE_-MIN-MAX-functions.patch --]
[-- Type: application/octet-stream, Size: 50930 bytes --]

From 915fd0427b77a308281ce42990501620bbd933a7 Mon Sep 17 00:00:00 2001
From: Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
Date: Fri, 9 Sep 2022 19:12:31 +0200
Subject: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions

libgfortran/

	* ieee/ieee_arithmetic.F90: Add IEEE_MIN_NUM, IEEE_MAX_NUM,
	IEEE_MIN_NUM_MAG, and IEEE_MAX_NUM_MAG functions.

gcc/fortran/

	* f95-lang.cc (gfc_init_builtin_functions): Add fmax() and
	fmin() built-ins, and their variants.
	* mathbuiltins.def: Add FMAX and FMIN built-ins.
	* trans-intrinsic.cc (conv_intrinsic_ieee_minmax): New function.
	(gfc_conv_ieee_arithmetic_function): Handle IEEE_MIN_NUM and
	IEEE_MAX_NUM functions.

gcc/testsuite/
	* gfortran.dg/ieee/minmax_1.f90: New test.
---
 gcc/fortran/f95-lang.cc                     |  14 ++
 gcc/fortran/mathbuiltins.def                |   2 +
 gcc/fortran/trans-intrinsic.cc              | 117 ++++++++++
 gcc/testsuite/gfortran.dg/ieee/minmax_1.f90 | 235 ++++++++++++++++++++
 gcc/testsuite/gfortran.dg/ieee/minmax_2.f90 | 235 ++++++++++++++++++++
 gcc/testsuite/gfortran.dg/ieee/minmax_3.f90 | 235 ++++++++++++++++++++
 gcc/testsuite/gfortran.dg/ieee/minmax_4.f90 | 235 ++++++++++++++++++++
 libgfortran/ieee/ieee_arithmetic.F90        | 126 +++++++++++
 8 files changed, 1199 insertions(+)
 create mode 100644 gcc/testsuite/gfortran.dg/ieee/minmax_1.f90
 create mode 100644 gcc/testsuite/gfortran.dg/ieee/minmax_2.f90
 create mode 100644 gcc/testsuite/gfortran.dg/ieee/minmax_3.f90
 create mode 100644 gcc/testsuite/gfortran.dg/ieee/minmax_4.f90

diff --git a/gcc/fortran/f95-lang.cc b/gcc/fortran/f95-lang.cc
index 9684f1d4921..89944f4e383 100644
--- a/gcc/fortran/f95-lang.cc
+++ b/gcc/fortran/f95-lang.cc
@@ -836,6 +836,20 @@ gfc_init_builtin_functions (void)
   gfc_define_builtin ("__builtin_scalbnf", mfunc_float[2],
 		      BUILT_IN_SCALBNF, "scalbnf", ATTR_CONST_NOTHROW_LEAF_LIST);
  
+  gfc_define_builtin ("__builtin_fmaxl", mfunc_longdouble[1],
+		      BUILT_IN_FMAXL, "fmaxl", ATTR_CONST_NOTHROW_LEAF_LIST);
+  gfc_define_builtin ("__builtin_fmax", mfunc_double[1],
+		      BUILT_IN_FMAX, "fmax", ATTR_CONST_NOTHROW_LEAF_LIST);
+  gfc_define_builtin ("__builtin_fmaxf", mfunc_float[1],
+		      BUILT_IN_FMAXF, "fmaxf", ATTR_CONST_NOTHROW_LEAF_LIST);
+
+  gfc_define_builtin ("__builtin_fminl", mfunc_longdouble[1],
+		      BUILT_IN_FMINL, "fminl", ATTR_CONST_NOTHROW_LEAF_LIST);
+  gfc_define_builtin ("__builtin_fmin", mfunc_double[1],
+		      BUILT_IN_FMIN, "fmin", ATTR_CONST_NOTHROW_LEAF_LIST);
+  gfc_define_builtin ("__builtin_fminf", mfunc_float[1],
+		      BUILT_IN_FMINF, "fminf", ATTR_CONST_NOTHROW_LEAF_LIST);
+
   gfc_define_builtin ("__builtin_fmodl", mfunc_longdouble[1], 
 		      BUILT_IN_FMODL, "fmodl", ATTR_CONST_NOTHROW_LEAF_LIST);
   gfc_define_builtin ("__builtin_fmod", mfunc_double[1], 
diff --git a/gcc/fortran/mathbuiltins.def b/gcc/fortran/mathbuiltins.def
index c6bb3e88eeb..51cb9a4aa91 100644
--- a/gcc/fortran/mathbuiltins.def
+++ b/gcc/fortran/mathbuiltins.def
@@ -61,6 +61,8 @@ OTHER_BUILTIN (COPYSIGN,  "copysign",  2,       true)
 OTHER_BUILTIN (CPOW,      "cpow",      cpow,    true)
 OTHER_BUILTIN (FABS,      "fabs",      1,       true)
 OTHER_BUILTIN (FMA,       "fma",       3,       true)
+OTHER_BUILTIN (FMAX,      "fmax",      2,       true)
+OTHER_BUILTIN (FMIN,      "fmin",      2,       true)
 OTHER_BUILTIN (FMOD,      "fmod",      2,       true)
 OTHER_BUILTIN (FREXP,     "frexp",     frexp,   false)
 OTHER_BUILTIN (LOGB,      "logb",      1,       true)
diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc
index a0e1110c5e0..b6ea26e413d 100644
--- a/gcc/fortran/trans-intrinsic.cc
+++ b/gcc/fortran/trans-intrinsic.cc
@@ -10263,6 +10263,119 @@ conv_intrinsic_ieee_fma (gfc_se * se, gfc_expr * expr)
 }
 
 
+/* Generate code for IEEE_{MIN,MAX}_NUM{,_MAG}.  */
+
+static void
+conv_intrinsic_ieee_minmax (gfc_se * se, gfc_expr * expr, int max,
+			    const char *name)
+{
+  tree args[2], func;
+  built_in_function fn;
+
+  conv_ieee_function_args (se, expr, args, 2);
+  gcc_assert (TYPE_PRECISION (TREE_TYPE (args[0])) == TYPE_PRECISION (TREE_TYPE (args[1])));
+  args[0] = gfc_evaluate_now (args[0], &se->pre);
+  args[1] = gfc_evaluate_now (args[1], &se->pre);
+
+  if (startswith (name, "mag"))
+    {
+      /* IEEE_MIN_NUM_MAG and IEEE_MAX_NUM_MAG translate to C functions
+	 fminmag() and fmaxmag(), which do not exist as built-ins.
+
+	 Following glibc, we emit this:
+
+	   fminmag (x, y) {
+	     ax = ABS (x);
+	     ay = ABS (y);
+	     if (isless (ax, ay))
+	       return x;
+	     else if (isgreater (ax, ay))
+	       return y;
+	     else if (ax == ay)
+	       return x < y ? x : y;
+	     else if (issignaling (x) || issignaling (y))
+	       return x + y;
+	     else
+	       return isnan (y) ? x : y;
+	   }
+
+	   fmaxmag (x, y) {
+	     ax = ABS (x);
+	     ay = ABS (y);
+	     if (isgreater (ax, ay))
+	       return x;
+	     else if (isless (ax, ay))
+	       return y;
+	     else if (ax == ay)
+	       return x > y ? x : y;
+	     else if (issignaling (x) || issignaling (y))
+	       return x + y;
+	     else
+	       return isnan (y) ? x : y;
+	   }
+
+	 */
+
+      tree abs0, abs1, sig0, sig1;
+      tree cond1, cond2, cond3, cond4, cond5;
+      tree res;
+      tree type = TREE_TYPE (args[0]);
+
+      func = gfc_builtin_decl_for_float_kind (BUILT_IN_FABS, expr->ts.kind);
+      abs0 = build_call_expr_loc (input_location, func, 1, args[0]);
+      abs1 = build_call_expr_loc (input_location, func, 1, args[1]);
+      abs0 = gfc_evaluate_now (abs0, &se->pre);
+      abs1 = gfc_evaluate_now (abs1, &se->pre);
+
+      cond5 = build_call_expr_loc (input_location,
+				   builtin_decl_explicit (BUILT_IN_ISNAN),
+				   1, args[1]);
+      res = fold_build3_loc (input_location, COND_EXPR, type, cond5,
+			     args[0], args[1]);
+
+      sig0 = build_call_expr_loc (input_location,
+				  builtin_decl_explicit (BUILT_IN_ISSIGNALING),
+				  1, args[0]);
+      sig1 = build_call_expr_loc (input_location,
+				  builtin_decl_explicit (BUILT_IN_ISSIGNALING),
+				  1, args[1]);
+      cond4 = fold_build2_loc (input_location, TRUTH_ORIF_EXPR,
+			       logical_type_node, sig0, sig1);
+      res = fold_build3_loc (input_location, COND_EXPR, type, cond4,
+			     fold_build2_loc (input_location, PLUS_EXPR,
+					      type, args[0], args[1]),
+			     res);
+
+      cond3 = fold_build2_loc (input_location, EQ_EXPR, logical_type_node,
+			       abs0, abs1);
+      res = fold_build3_loc (input_location, COND_EXPR, type, cond3,
+			     fold_build2_loc (input_location,
+					      max ? MAX_EXPR : MIN_EXPR,
+					      type, args[0], args[1]),
+			     res);
+
+      func = builtin_decl_explicit (max ? BUILT_IN_ISLESS : BUILT_IN_ISGREATER);
+      cond2 = build_call_expr_loc (input_location, func, 2, abs0, abs1);
+      res = fold_build3_loc (input_location, COND_EXPR, type, cond2,
+			     args[1], res);
+
+      func = builtin_decl_explicit (max ? BUILT_IN_ISGREATER : BUILT_IN_ISLESS);
+      cond1 = build_call_expr_loc (input_location, func, 2, abs0, abs1);
+      res = fold_build3_loc (input_location, COND_EXPR, type, cond1,
+			     args[0], res);
+
+      se->expr = res;
+    }
+  else
+    {
+      /* IEEE_MIN_NUM and IEEE_MAX_NUM translate to fmin() and fmax().  */
+      fn = max ? BUILT_IN_FMAX : BUILT_IN_FMIN;
+      func = gfc_builtin_decl_for_float_kind (fn, expr->ts.kind);
+      se->expr = build_call_expr_loc_array (input_location, func, 2, args);
+    }
+}
+
+
 /* Generate code for an intrinsic function from the IEEE_ARITHMETIC
    module.  */
 
@@ -10301,6 +10414,10 @@ gfc_conv_ieee_arithmetic_function (gfc_se * se, gfc_expr * expr)
     conv_intrinsic_ieee_value (se, expr);
   else if (startswith (name, "_gfortran_ieee_fma"))
     conv_intrinsic_ieee_fma (se, expr);
+  else if (startswith (name, "_gfortran_ieee_min_num_"))
+    conv_intrinsic_ieee_minmax (se, expr, 0, name + 23);
+  else if (startswith (name, "_gfortran_ieee_max_num_"))
+    conv_intrinsic_ieee_minmax (se, expr, 1, name + 23);
   else
     /* It is not among the functions we translate directly.  We return
        false, so a library function call is emitted.  */
diff --git a/gcc/testsuite/gfortran.dg/ieee/minmax_1.f90 b/gcc/testsuite/gfortran.dg/ieee/minmax_1.f90
new file mode 100644
index 00000000000..c820b134956
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/ieee/minmax_1.f90
@@ -0,0 +1,235 @@
+! { dg-do run }
+!
+program test
+  call real()
+  call double()
+  call large1()
+  call large2()
+end program test
+
+
+subroutine real
+  use ieee_arithmetic
+  implicit none
+
+  real :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_max_num_mag (0., 0.) /= 0.) stop 1
+  if (ieee_max_num_mag (-0., -0.) /= -0.) stop 2
+  if (.not. ieee_signbit (ieee_max_num_mag (-0., -0.))) stop 3
+  if (ieee_max_num_mag (0., -0.) /= 0.) stop 4
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num_mag (0., -0.))) stop 5
+  if (ieee_max_num_mag (-0., 0.) /= 0.) stop 6
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num_mag (-0., 0.))) stop 7
+
+  if (ieee_max_num_mag (9., 0.) /= 9.) stop 8
+  if (ieee_max_num_mag (0., 9.) /= 9.) stop 9
+  if (ieee_max_num_mag (-9., 0.) /= -9.) stop 10
+  if (ieee_max_num_mag (0., -9.) /= -9.) stop 11
+
+  if (ieee_max_num_mag (inf, 9.) /= inf) stop 12
+  if (ieee_max_num_mag (0., inf) /= inf) stop 13
+  if (ieee_max_num_mag (-9., inf) /= inf) stop 14
+  if (ieee_max_num_mag (inf, -9.) /= inf) stop 15
+  if (ieee_max_num_mag (-inf, 9.) /= -inf) stop 16
+  if (ieee_max_num_mag (0., -inf) /= -inf) stop 17
+  if (ieee_max_num_mag (-9., -inf) /= -inf) stop 18
+  if (ieee_max_num_mag (-inf, -9.) /= -inf) stop 19
+
+  if (ieee_max_num_mag (0., nan) /= 0.) stop 20
+  if (ieee_max_num_mag (nan, 0.) /= 0.) stop 21
+  if (ieee_max_num_mag (-0., nan) /= -0.) stop 22
+  if (.not. ieee_signbit (ieee_max_num_mag (-0., nan))) stop 23
+  if (ieee_max_num_mag (nan, -0.) /= -0.) stop 24
+  if (.not. ieee_signbit (ieee_max_num_mag (nan, -0.))) stop 25
+  if (ieee_max_num_mag (9., nan) /= 9.) stop 26
+  if (ieee_max_num_mag (nan, 9.) /= 9.) stop 27
+  if (ieee_max_num_mag (-9., nan) /= -9.) stop 28
+  if (ieee_max_num_mag (nan, -9.) /= -9.) stop 29
+
+  if (ieee_max_num_mag (nan, inf) /= inf) stop 30
+  if (ieee_max_num_mag (inf, nan) /= inf) stop 31
+  if (ieee_max_num_mag (nan, -inf) /= -inf) stop 32
+  if (ieee_max_num_mag (-inf, nan) /= -inf) stop 33
+
+  if (.not. ieee_is_nan (ieee_max_num_mag (nan, nan))) stop 34
+end subroutine real
+
+
+subroutine double
+  use ieee_arithmetic
+  implicit none
+
+  double precision :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_max_num_mag (0.d0, 0.d0) /= 0.d0) stop 35
+  if (ieee_max_num_mag (-0.d0, -0.d0) /= -0.d0) stop 36
+  if (.not. ieee_signbit (ieee_max_num_mag (-0.d0, -0.d0))) stop 37
+  if (ieee_max_num_mag (0.d0, -0.d0) /= 0.d0) stop 38
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num_mag (0.d0, -0.d0))) stop 39
+  if (ieee_max_num_mag (-0.d0, 0.d0) /= 0.d0) stop 40
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num_mag (-0.d0, 0.d0))) stop 41
+
+  if (ieee_max_num_mag (9.d0, 0.d0) /= 9.d0) stop 42
+  if (ieee_max_num_mag (0.d0, 9.d0) /= 9.d0) stop 43
+  if (ieee_max_num_mag (-9.d0, 0.d0) /= -9.d0) stop 44
+  if (ieee_max_num_mag (0.d0, -9.d0) /= -9.d0) stop 45
+
+  if (ieee_max_num_mag (inf, 9.d0) /= inf) stop 46
+  if (ieee_max_num_mag (0.d0, inf) /= inf) stop 47
+  if (ieee_max_num_mag (-9.d0, inf) /= inf) stop 48
+  if (ieee_max_num_mag (inf, -9.d0) /= inf) stop 49
+  if (ieee_max_num_mag (-inf, 9.d0) /= -inf) stop 50
+  if (ieee_max_num_mag (0.d0, -inf) /= -inf) stop 51
+  if (ieee_max_num_mag (-9.d0, -inf) /= -inf) stop 52
+  if (ieee_max_num_mag (-inf, -9.d0) /= -inf) stop 53
+
+  if (ieee_max_num_mag (0.d0, nan) /= 0.d0) stop 54
+  if (ieee_max_num_mag (nan, 0.d0) /= 0.d0) stop 55
+  if (ieee_max_num_mag (-0.d0, nan) /= -0.d0) stop 56
+  if (.not. ieee_signbit (ieee_max_num_mag (-0.d0, nan))) stop 57
+  if (ieee_max_num_mag (nan, -0.d0) /= -0.d0) stop 58
+  if (.not. ieee_signbit (ieee_max_num_mag (nan, -0.d0))) stop 59
+  if (ieee_max_num_mag (9.d0, nan) /= 9.d0) stop 60
+  if (ieee_max_num_mag (nan, 9.d0) /= 9.d0) stop 61
+  if (ieee_max_num_mag (-9.d0, nan) /= -9.d0) stop 62
+  if (ieee_max_num_mag (nan, -9.d0) /= -9.d0) stop 63
+
+  if (ieee_max_num_mag (nan, inf) /= inf) stop 64
+  if (ieee_max_num_mag (inf, nan) /= inf) stop 65
+  if (ieee_max_num_mag (nan, -inf) /= -inf) stop 66
+  if (ieee_max_num_mag (-inf, nan) /= -inf) stop 67
+
+  if (.not. ieee_is_nan (ieee_max_num_mag (nan, nan))) stop 68
+end subroutine double
+
+
+subroutine large1
+  use ieee_arithmetic
+  implicit none
+
+  ! k1 and k2 will be large real kinds, if supported, and single/double
+  ! otherwise
+  integer, parameter :: k1 = &
+    max(ieee_selected_real_kind(precision(0.d0) + 1), kind(0.))
+  integer, parameter :: k2 = &
+    max(ieee_selected_real_kind(precision(0._k1) + 1), kind(0.d0))
+
+  real(kind=k1) :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_max_num_mag (0._k1, 0._k1) /= 0._k1) stop 35
+  if (ieee_max_num_mag (-0._k1, -0._k1) /= -0._k1) stop 36
+  if (.not. ieee_signbit (ieee_max_num_mag (-0._k1, -0._k1))) stop 37
+  if (ieee_max_num_mag (0._k1, -0._k1) /= 0._k1) stop 38
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num_mag (0._k1, -0._k1))) stop 39
+  if (ieee_max_num_mag (-0._k1, 0._k1) /= 0._k1) stop 40
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num_mag (-0._k1, 0._k1))) stop 41
+
+  if (ieee_max_num_mag (9._k1, 0._k1) /= 9._k1) stop 42
+  if (ieee_max_num_mag (0._k1, 9._k1) /= 9._k1) stop 43
+  if (ieee_max_num_mag (-9._k1, 0._k1) /= -9._k1) stop 44
+  if (ieee_max_num_mag (0._k1, -9._k1) /= -9._k1) stop 45
+
+  if (ieee_max_num_mag (inf, 9._k1) /= inf) stop 46
+  if (ieee_max_num_mag (0._k1, inf) /= inf) stop 47
+  if (ieee_max_num_mag (-9._k1, inf) /= inf) stop 48
+  if (ieee_max_num_mag (inf, -9._k1) /= inf) stop 49
+  if (ieee_max_num_mag (-inf, 9._k1) /= -inf) stop 50
+  if (ieee_max_num_mag (0._k1, -inf) /= -inf) stop 51
+  if (ieee_max_num_mag (-9._k1, -inf) /= -inf) stop 52
+  if (ieee_max_num_mag (-inf, -9._k1) /= -inf) stop 53
+
+  if (ieee_max_num_mag (0._k1, nan) /= 0._k1) stop 54
+  if (ieee_max_num_mag (nan, 0._k1) /= 0._k1) stop 55
+  if (ieee_max_num_mag (-0._k1, nan) /= -0._k1) stop 56
+  if (.not. ieee_signbit (ieee_max_num_mag (-0._k1, nan))) stop 57
+  if (ieee_max_num_mag (nan, -0._k1) /= -0._k1) stop 58
+  if (.not. ieee_signbit (ieee_max_num_mag (nan, -0._k1))) stop 59
+  if (ieee_max_num_mag (9._k1, nan) /= 9._k1) stop 60
+  if (ieee_max_num_mag (nan, 9._k1) /= 9._k1) stop 61
+  if (ieee_max_num_mag (-9._k1, nan) /= -9._k1) stop 62
+  if (ieee_max_num_mag (nan, -9._k1) /= -9._k1) stop 63
+
+  if (ieee_max_num_mag (nan, inf) /= inf) stop 64
+  if (ieee_max_num_mag (inf, nan) /= inf) stop 65
+  if (ieee_max_num_mag (nan, -inf) /= -inf) stop 66
+  if (ieee_max_num_mag (-inf, nan) /= -inf) stop 67
+
+  if (.not. ieee_is_nan (ieee_max_num_mag (nan, nan))) stop 68
+end subroutine large1
+
+
+subroutine large2
+  use ieee_arithmetic
+  implicit none
+
+  ! k1 and k2 will be large real kinds, if supported, and single/double
+  ! otherwise
+  integer, parameter :: k1 = &
+    max(ieee_selected_real_kind(precision(0.d0) + 1), kind(0.))
+  integer, parameter :: k2 = &
+    max(ieee_selected_real_kind(precision(0._k1) + 1), kind(0.d0))
+
+  real(kind=k2) :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_max_num_mag (0._k2, 0._k2) /= 0._k2) stop 35
+  if (ieee_max_num_mag (-0._k2, -0._k2) /= -0._k2) stop 36
+  if (.not. ieee_signbit (ieee_max_num_mag (-0._k2, -0._k2))) stop 37
+  if (ieee_max_num_mag (0._k2, -0._k2) /= 0._k2) stop 38
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num_mag (0._k2, -0._k2))) stop 39
+  if (ieee_max_num_mag (-0._k2, 0._k2) /= 0._k2) stop 40
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num_mag (-0._k2, 0._k2))) stop 41
+
+  if (ieee_max_num_mag (9._k2, 0._k2) /= 9._k2) stop 42
+  if (ieee_max_num_mag (0._k2, 9._k2) /= 9._k2) stop 43
+  if (ieee_max_num_mag (-9._k2, 0._k2) /= -9._k2) stop 44
+  if (ieee_max_num_mag (0._k2, -9._k2) /= -9._k2) stop 45
+
+  if (ieee_max_num_mag (inf, 9._k2) /= inf) stop 46
+  if (ieee_max_num_mag (0._k2, inf) /= inf) stop 47
+  if (ieee_max_num_mag (-9._k2, inf) /= inf) stop 48
+  if (ieee_max_num_mag (inf, -9._k2) /= inf) stop 49
+  if (ieee_max_num_mag (-inf, 9._k2) /= -inf) stop 50
+  if (ieee_max_num_mag (0._k2, -inf) /= -inf) stop 51
+  if (ieee_max_num_mag (-9._k2, -inf) /= -inf) stop 52
+  if (ieee_max_num_mag (-inf, -9._k2) /= -inf) stop 53
+
+  if (ieee_max_num_mag (0._k2, nan) /= 0._k2) stop 54
+  if (ieee_max_num_mag (nan, 0._k2) /= 0._k2) stop 55
+  if (ieee_max_num_mag (-0._k2, nan) /= -0._k2) stop 56
+  if (.not. ieee_signbit (ieee_max_num_mag (-0._k2, nan))) stop 57
+  if (ieee_max_num_mag (nan, -0._k2) /= -0._k2) stop 58
+  if (.not. ieee_signbit (ieee_max_num_mag (nan, -0._k2))) stop 59
+  if (ieee_max_num_mag (9._k2, nan) /= 9._k2) stop 60
+  if (ieee_max_num_mag (nan, 9._k2) /= 9._k2) stop 61
+  if (ieee_max_num_mag (-9._k2, nan) /= -9._k2) stop 62
+  if (ieee_max_num_mag (nan, -9._k2) /= -9._k2) stop 63
+
+  if (ieee_max_num_mag (nan, inf) /= inf) stop 64
+  if (ieee_max_num_mag (inf, nan) /= inf) stop 65
+  if (ieee_max_num_mag (nan, -inf) /= -inf) stop 66
+  if (ieee_max_num_mag (-inf, nan) /= -inf) stop 67
+
+  if (.not. ieee_is_nan (ieee_max_num_mag (nan, nan))) stop 68
+end subroutine large2
+
diff --git a/gcc/testsuite/gfortran.dg/ieee/minmax_2.f90 b/gcc/testsuite/gfortran.dg/ieee/minmax_2.f90
new file mode 100644
index 00000000000..52c3fa01547
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/ieee/minmax_2.f90
@@ -0,0 +1,235 @@
+! { dg-do run }
+!
+program test
+  call real()
+  call double()
+  call large1()
+  call large2()
+end program test
+
+
+subroutine real
+  use ieee_arithmetic
+  implicit none
+
+  real :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_min_num_mag (0., 0.) /= 0.) stop 1
+  if (ieee_min_num_mag (-0., -0.) /= -0.) stop 2
+  if (.not. ieee_signbit (ieee_min_num_mag (-0., -0.))) stop 3
+  if (ieee_min_num_mag (0., -0.) /= -0.) stop 4
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num_mag (0., -0.))) stop 5
+  if (ieee_min_num_mag (-0., 0.) /= 0.) stop 6
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num_mag (-0., 0.))) stop 7
+
+  if (ieee_min_num_mag (9., 0.) /= 0.) stop 8
+  if (ieee_min_num_mag (0., 9.) /= 0.) stop 9
+  if (ieee_min_num_mag (-9., 0.) /= 0.) stop 10
+  if (ieee_min_num_mag (0., -9.) /= 0.) stop 11
+
+  if (ieee_min_num_mag (inf, 9.) /= 9.) stop 12
+  if (ieee_min_num_mag (0., inf) /= 0.) stop 13
+  if (ieee_min_num_mag (-9., inf) /= -9.) stop 14
+  if (ieee_min_num_mag (inf, -9.) /= -9.) stop 15
+  if (ieee_min_num_mag (-inf, 9.) /= 9.) stop 16
+  if (ieee_min_num_mag (0., -inf) /= 0.) stop 17
+  if (ieee_min_num_mag (-9., -inf) /= -9.) stop 18
+  if (ieee_min_num_mag (-inf, -9.) /= -9.) stop 19
+
+  if (ieee_min_num_mag (0., nan) /= 0.) stop 20
+  if (ieee_min_num_mag (nan, 0.) /= 0.) stop 21
+  if (ieee_min_num_mag (-0., nan) /= -0.) stop 22
+  if (.not. ieee_signbit (ieee_min_num_mag (-0., nan))) stop 23
+  if (ieee_min_num_mag (nan, -0.) /= -0.) stop 24
+  if (.not. ieee_signbit (ieee_min_num_mag (nan, -0.))) stop 25
+  if (ieee_min_num_mag (9., nan) /= 9.) stop 26
+  if (ieee_min_num_mag (nan, 9.) /= 9.) stop 27
+  if (ieee_min_num_mag (-9., nan) /= -9.) stop 28
+  if (ieee_min_num_mag (nan, -9.) /= -9.) stop 29
+
+  if (ieee_min_num_mag (nan, inf) /= inf) stop 30
+  if (ieee_min_num_mag (inf, nan) /= inf) stop 31
+  if (ieee_min_num_mag (nan, -inf) /= -inf) stop 32
+  if (ieee_min_num_mag (-inf, nan) /= -inf) stop 33
+
+  if (.not. ieee_is_nan (ieee_min_num_mag (nan, nan))) stop 34
+end subroutine real
+
+
+subroutine double
+  use ieee_arithmetic
+  implicit none
+
+  double precision :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_min_num_mag (0.d0, 0.d0) /= 0.d0) stop 35
+  if (ieee_min_num_mag (-0.d0, -0.d0) /= -0.d0) stop 36
+  if (.not. ieee_signbit (ieee_min_num_mag (-0.d0, -0.d0))) stop 37
+  if (ieee_min_num_mag (0.d0, -0.d0) /= 0.d0) stop 38
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num_mag (0.d0, -0.d0))) stop 39
+  if (ieee_min_num_mag (-0.d0, 0.d0) /= 0.d0) stop 40
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num_mag (-0.d0, 0.d0))) stop 41
+
+  if (ieee_min_num_mag (9.d0, 0.d0) /= 0.d0) stop 42
+  if (ieee_min_num_mag (0.d0, 9.d0) /= 0.d0) stop 43
+  if (ieee_min_num_mag (-9.d0, 0.d0) /= 0.d0) stop 44
+  if (ieee_min_num_mag (0.d0, -9.d0) /= 0.d0) stop 45
+
+  if (ieee_min_num_mag (inf, 9.d0) /= 9.d0) stop 46
+  if (ieee_min_num_mag (0.d0, inf) /= 0.d0) stop 47
+  if (ieee_min_num_mag (-9.d0, inf) /= -9.d0) stop 48
+  if (ieee_min_num_mag (inf, -9.d0) /= -9.d0) stop 49
+  if (ieee_min_num_mag (-inf, 9.d0) /= 9.d0) stop 50
+  if (ieee_min_num_mag (0.d0, -inf) /= 0.d0) stop 51
+  if (ieee_min_num_mag (-9.d0, -inf) /= -9.d0) stop 52
+  if (ieee_min_num_mag (-inf, -9.d0) /= -9.d0) stop 53
+
+  if (ieee_min_num_mag (0.d0, nan) /= 0.d0) stop 54
+  if (ieee_min_num_mag (nan, 0.d0) /= 0.d0) stop 55
+  if (ieee_min_num_mag (-0.d0, nan) /= -0.d0) stop 56
+  if (.not. ieee_signbit (ieee_min_num_mag (-0.d0, nan))) stop 57
+  if (ieee_min_num_mag (nan, -0.d0) /= -0.d0) stop 58
+  if (.not. ieee_signbit (ieee_min_num_mag (nan, -0.d0))) stop 59
+  if (ieee_min_num_mag (9.d0, nan) /= 9.d0) stop 60
+  if (ieee_min_num_mag (nan, 9.d0) /= 9.d0) stop 61
+  if (ieee_min_num_mag (-9.d0, nan) /= -9.d0) stop 62
+  if (ieee_min_num_mag (nan, -9.d0) /= -9.d0) stop 63
+
+  if (ieee_min_num_mag (nan, inf) /= inf) stop 64
+  if (ieee_min_num_mag (inf, nan) /= inf) stop 65
+  if (ieee_min_num_mag (nan, -inf) /= -inf) stop 66
+  if (ieee_min_num_mag (-inf, nan) /= -inf) stop 67
+
+  if (.not. ieee_is_nan (ieee_min_num_mag (nan, nan))) stop 68
+end subroutine double
+
+
+subroutine large1
+  use ieee_arithmetic
+  implicit none
+
+  ! k1 and k2 will be large real kinds, if supported, and single/double
+  ! otherwise
+  integer, parameter :: k1 = &
+    max(ieee_selected_real_kind(precision(0.d0) + 1), kind(0.))
+  integer, parameter :: k2 = &
+    max(ieee_selected_real_kind(precision(0._k1) + 1), kind(0.d0))
+
+  real(kind=k1) :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_min_num_mag (0._k1, 0._k1) /= 0._k1) stop 35
+  if (ieee_min_num_mag (-0._k1, -0._k1) /= -0._k1) stop 36
+  if (.not. ieee_signbit (ieee_min_num_mag (-0._k1, -0._k1))) stop 37
+  if (ieee_min_num_mag (0._k1, -0._k1) /= 0._k1) stop 38
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num_mag (0._k1, -0._k1))) stop 39
+  if (ieee_min_num_mag (-0._k1, 0._k1) /= 0._k1) stop 40
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num_mag (-0._k1, 0._k1))) stop 41
+
+  if (ieee_min_num_mag (9._k1, 0._k1) /= 0._k1) stop 42
+  if (ieee_min_num_mag (0._k1, 9._k1) /= 0._k1) stop 43
+  if (ieee_min_num_mag (-9._k1, 0._k1) /= 0._k1) stop 44
+  if (ieee_min_num_mag (0._k1, -9._k1) /= 0._k1) stop 45
+
+  if (ieee_min_num_mag (inf, 9._k1) /= 9._k1) stop 46
+  if (ieee_min_num_mag (0._k1, inf) /= 0._k1) stop 47
+  if (ieee_min_num_mag (-9._k1, inf) /= -9._k1) stop 48
+  if (ieee_min_num_mag (inf, -9._k1) /= -9._k1) stop 49
+  if (ieee_min_num_mag (-inf, 9._k1) /= 9._k1) stop 50
+  if (ieee_min_num_mag (0._k1, -inf) /= 0._k1) stop 51
+  if (ieee_min_num_mag (-9._k1, -inf) /= -9._k1) stop 52
+  if (ieee_min_num_mag (-inf, -9._k1) /= -9._k1) stop 53
+
+  if (ieee_min_num_mag (0._k1, nan) /= 0._k1) stop 54
+  if (ieee_min_num_mag (nan, 0._k1) /= 0._k1) stop 55
+  if (ieee_min_num_mag (-0._k1, nan) /= -0._k1) stop 56
+  if (.not. ieee_signbit (ieee_min_num_mag (-0._k1, nan))) stop 57
+  if (ieee_min_num_mag (nan, -0._k1) /= -0._k1) stop 58
+  if (.not. ieee_signbit (ieee_min_num_mag (nan, -0._k1))) stop 59
+  if (ieee_min_num_mag (9._k1, nan) /= 9._k1) stop 60
+  if (ieee_min_num_mag (nan, 9._k1) /= 9._k1) stop 61
+  if (ieee_min_num_mag (-9._k1, nan) /= -9._k1) stop 62
+  if (ieee_min_num_mag (nan, -9._k1) /= -9._k1) stop 63
+
+  if (ieee_min_num_mag (nan, inf) /= inf) stop 64
+  if (ieee_min_num_mag (inf, nan) /= inf) stop 65
+  if (ieee_min_num_mag (nan, -inf) /= -inf) stop 66
+  if (ieee_min_num_mag (-inf, nan) /= -inf) stop 67
+
+  if (.not. ieee_is_nan (ieee_min_num_mag (nan, nan))) stop 68
+end subroutine large1
+
+
+subroutine large2
+  use ieee_arithmetic
+  implicit none
+
+  ! k1 and k2 will be large real kinds, if supported, and single/double
+  ! otherwise
+  integer, parameter :: k1 = &
+    max(ieee_selected_real_kind(precision(0.d0) + 1), kind(0.))
+  integer, parameter :: k2 = &
+    max(ieee_selected_real_kind(precision(0._k1) + 1), kind(0.d0))
+
+  real(kind=k2) :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_min_num_mag (0._k2, 0._k2) /= 0._k2) stop 35
+  if (ieee_min_num_mag (-0._k2, -0._k2) /= -0._k2) stop 36
+  if (.not. ieee_signbit (ieee_min_num_mag (-0._k2, -0._k2))) stop 37
+  if (ieee_min_num_mag (0._k2, -0._k2) /= 0._k2) stop 38
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num_mag (0._k2, -0._k2))) stop 39
+  if (ieee_min_num_mag (-0._k2, 0._k2) /= 0._k2) stop 40
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num_mag (-0._k2, 0._k2))) stop 41
+
+  if (ieee_min_num_mag (9._k2, 0._k2) /= 0._k2) stop 42
+  if (ieee_min_num_mag (0._k2, 9._k2) /= 0._k2) stop 43
+  if (ieee_min_num_mag (-9._k2, 0._k2) /= 0._k2) stop 44
+  if (ieee_min_num_mag (0._k2, -9._k2) /= 0._k2) stop 45
+
+  if (ieee_min_num_mag (inf, 9._k2) /= 9._k2) stop 46
+  if (ieee_min_num_mag (0._k2, inf) /= 0._k2) stop 47
+  if (ieee_min_num_mag (-9._k2, inf) /= -9._k2) stop 48
+  if (ieee_min_num_mag (inf, -9._k2) /= -9._k2) stop 49
+  if (ieee_min_num_mag (-inf, 9._k2) /= 9._k2) stop 50
+  if (ieee_min_num_mag (0._k2, -inf) /= 0._k2) stop 51
+  if (ieee_min_num_mag (-9._k2, -inf) /= -9._k2) stop 52
+  if (ieee_min_num_mag (-inf, -9._k2) /= -9._k2) stop 53
+
+  if (ieee_min_num_mag (0._k2, nan) /= 0._k2) stop 54
+  if (ieee_min_num_mag (nan, 0._k2) /= 0._k2) stop 55
+  if (ieee_min_num_mag (-0._k2, nan) /= -0._k2) stop 56
+  if (.not. ieee_signbit (ieee_min_num_mag (-0._k2, nan))) stop 57
+  if (ieee_min_num_mag (nan, -0._k2) /= -0._k2) stop 58
+  if (.not. ieee_signbit (ieee_min_num_mag (nan, -0._k2))) stop 59
+  if (ieee_min_num_mag (9._k2, nan) /= 9._k2) stop 60
+  if (ieee_min_num_mag (nan, 9._k2) /= 9._k2) stop 61
+  if (ieee_min_num_mag (-9._k2, nan) /= -9._k2) stop 62
+  if (ieee_min_num_mag (nan, -9._k2) /= -9._k2) stop 63
+
+  if (ieee_min_num_mag (nan, inf) /= inf) stop 64
+  if (ieee_min_num_mag (inf, nan) /= inf) stop 65
+  if (ieee_min_num_mag (nan, -inf) /= -inf) stop 66
+  if (ieee_min_num_mag (-inf, nan) /= -inf) stop 67
+
+  if (.not. ieee_is_nan (ieee_min_num_mag (nan, nan))) stop 68
+end subroutine large2
+
diff --git a/gcc/testsuite/gfortran.dg/ieee/minmax_3.f90 b/gcc/testsuite/gfortran.dg/ieee/minmax_3.f90
new file mode 100644
index 00000000000..337bb368d0b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/ieee/minmax_3.f90
@@ -0,0 +1,235 @@
+! { dg-do run }
+!
+program test
+  call real()
+  call double()
+  call large1()
+  call large2()
+end program test
+
+
+subroutine real
+  use ieee_arithmetic
+  implicit none
+
+  real :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_max_num (0., 0.) /= 0.) stop 1
+  if (ieee_max_num (-0., -0.) /= -0.) stop 2
+  if (.not. ieee_signbit (ieee_max_num (-0., -0.))) stop 3
+  if (ieee_max_num (0., -0.) /= 0.) stop 4
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num (0., -0.))) stop 5
+  if (ieee_max_num (-0., 0.) /= 0.) stop 6
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num (-0., 0.))) stop 7
+
+  if (ieee_max_num (9., 0.) /= 9.) stop 8
+  if (ieee_max_num (0., 9.) /= 9.) stop 9
+  if (ieee_max_num (-9., 0.) /= 0.) stop 10
+  if (ieee_max_num (0., -9.) /= 0.) stop 11
+
+  if (ieee_max_num (inf, 9.) /= inf) stop 12
+  if (ieee_max_num (0., inf) /= inf) stop 13
+  if (ieee_max_num (-9., inf) /= inf) stop 14
+  if (ieee_max_num (inf, -9.) /= inf) stop 15
+  if (ieee_max_num (-inf, 9.) /= 9.) stop 16
+  if (ieee_max_num (0., -inf) /= 0.) stop 17
+  if (ieee_max_num (-9., -inf) /= -9.) stop 18
+  if (ieee_max_num (-inf, -9.) /= -9.) stop 19
+
+  if (ieee_max_num (0., nan) /= 0.) stop 20
+  if (ieee_max_num (nan, 0.) /= 0.) stop 21
+  if (ieee_max_num (-0., nan) /= -0.) stop 22
+  if (.not. ieee_signbit (ieee_max_num (-0., nan))) stop 23
+  if (ieee_max_num (nan, -0.) /= -0.) stop 24
+  if (.not. ieee_signbit (ieee_max_num (nan, -0.))) stop 25
+  if (ieee_max_num (9., nan) /= 9.) stop 26
+  if (ieee_max_num (nan, 9.) /= 9.) stop 27
+  if (ieee_max_num (-9., nan) /= -9.) stop 28
+  if (ieee_max_num (nan, -9.) /= -9.) stop 29
+
+  if (ieee_max_num (nan, inf) /= inf) stop 30
+  if (ieee_max_num (inf, nan) /= inf) stop 31
+  if (ieee_max_num (nan, -inf) /= -inf) stop 32
+  if (ieee_max_num (-inf, nan) /= -inf) stop 33
+
+  if (.not. ieee_is_nan (ieee_max_num (nan, nan))) stop 34
+end subroutine real
+
+
+subroutine double
+  use ieee_arithmetic
+  implicit none
+
+  double precision :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_max_num (0.d0, 0.d0) /= 0.d0) stop 35
+  if (ieee_max_num (-0.d0, -0.d0) /= -0.d0) stop 36
+  if (.not. ieee_signbit (ieee_max_num (-0.d0, -0.d0))) stop 37
+  if (ieee_max_num (0.d0, -0.d0) /= 0.d0) stop 38
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num (0.d0, -0.d0))) stop 39
+  if (ieee_max_num (-0.d0, 0.d0) /= 0.d0) stop 40
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num (-0.d0, 0.d0))) stop 41
+
+  if (ieee_max_num (9.d0, 0.d0) /= 9.d0) stop 42
+  if (ieee_max_num (0.d0, 9.d0) /= 9.d0) stop 43
+  if (ieee_max_num (-9.d0, 0.d0) /= 0.d0) stop 44
+  if (ieee_max_num (0.d0, -9.d0) /= 0.d0) stop 45
+
+  if (ieee_max_num (inf, 9.d0) /= inf) stop 46
+  if (ieee_max_num (0.d0, inf) /= inf) stop 47
+  if (ieee_max_num (-9.d0, inf) /= inf) stop 48
+  if (ieee_max_num (inf, -9.d0) /= inf) stop 49
+  if (ieee_max_num (-inf, 9.d0) /= 9.d0) stop 50
+  if (ieee_max_num (0.d0, -inf) /= 0.d0) stop 51
+  if (ieee_max_num (-9.d0, -inf) /= -9.d0) stop 52
+  if (ieee_max_num (-inf, -9.d0) /= -9.d0) stop 53
+
+  if (ieee_max_num (0.d0, nan) /= 0.d0) stop 54
+  if (ieee_max_num (nan, 0.d0) /= 0.d0) stop 55
+  if (ieee_max_num (-0.d0, nan) /= -0.d0) stop 56
+  if (.not. ieee_signbit (ieee_max_num (-0.d0, nan))) stop 57
+  if (ieee_max_num (nan, -0.d0) /= -0.d0) stop 58
+  if (.not. ieee_signbit (ieee_max_num (nan, -0.d0))) stop 59
+  if (ieee_max_num (9.d0, nan) /= 9.d0) stop 60
+  if (ieee_max_num (nan, 9.d0) /= 9.d0) stop 61
+  if (ieee_max_num (-9.d0, nan) /= -9.d0) stop 62
+  if (ieee_max_num (nan, -9.d0) /= -9.d0) stop 63
+
+  if (ieee_max_num (nan, inf) /= inf) stop 64
+  if (ieee_max_num (inf, nan) /= inf) stop 65
+  if (ieee_max_num (nan, -inf) /= -inf) stop 66
+  if (ieee_max_num (-inf, nan) /= -inf) stop 67
+
+  if (.not. ieee_is_nan (ieee_max_num (nan, nan))) stop 68
+end subroutine double
+
+
+subroutine large1
+  use ieee_arithmetic
+  implicit none
+
+  ! k1 and k2 will be large real kinds, if supported, and single/double
+  ! otherwise
+  integer, parameter :: k1 = &
+    max(ieee_selected_real_kind(precision(0.d0) + 1), kind(0.))
+  integer, parameter :: k2 = &
+    max(ieee_selected_real_kind(precision(0._k1) + 1), kind(0.d0))
+
+  real(kind=k1) :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_max_num (0._k1, 0._k1) /= 0._k1) stop 35
+  if (ieee_max_num (-0._k1, -0._k1) /= -0._k1) stop 36
+  if (.not. ieee_signbit (ieee_max_num (-0._k1, -0._k1))) stop 37
+  if (ieee_max_num (0._k1, -0._k1) /= 0._k1) stop 38
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num (0._k1, -0._k1))) stop 39
+  if (ieee_max_num (-0._k1, 0._k1) /= 0._k1) stop 40
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num (-0._k1, 0._k1))) stop 41
+
+  if (ieee_max_num (9._k1, 0._k1) /= 9._k1) stop 42
+  if (ieee_max_num (0._k1, 9._k1) /= 9._k1) stop 43
+  if (ieee_max_num (-9._k1, 0._k1) /= 0._k1) stop 44
+  if (ieee_max_num (0._k1, -9._k1) /= 0._k1) stop 45
+
+  if (ieee_max_num (inf, 9._k1) /= inf) stop 46
+  if (ieee_max_num (0._k1, inf) /= inf) stop 47
+  if (ieee_max_num (-9._k1, inf) /= inf) stop 48
+  if (ieee_max_num (inf, -9._k1) /= inf) stop 49
+  if (ieee_max_num (-inf, 9._k1) /= 9._k1) stop 50
+  if (ieee_max_num (0._k1, -inf) /= 0._k1) stop 51
+  if (ieee_max_num (-9._k1, -inf) /= -9._k1) stop 52
+  if (ieee_max_num (-inf, -9._k1) /= -9._k1) stop 53
+
+  if (ieee_max_num (0._k1, nan) /= 0._k1) stop 54
+  if (ieee_max_num (nan, 0._k1) /= 0._k1) stop 55
+  if (ieee_max_num (-0._k1, nan) /= -0._k1) stop 56
+  if (.not. ieee_signbit (ieee_max_num (-0._k1, nan))) stop 57
+  if (ieee_max_num (nan, -0._k1) /= -0._k1) stop 58
+  if (.not. ieee_signbit (ieee_max_num (nan, -0._k1))) stop 59
+  if (ieee_max_num (9._k1, nan) /= 9._k1) stop 60
+  if (ieee_max_num (nan, 9._k1) /= 9._k1) stop 61
+  if (ieee_max_num (-9._k1, nan) /= -9._k1) stop 62
+  if (ieee_max_num (nan, -9._k1) /= -9._k1) stop 63
+
+  if (ieee_max_num (nan, inf) /= inf) stop 64
+  if (ieee_max_num (inf, nan) /= inf) stop 65
+  if (ieee_max_num (nan, -inf) /= -inf) stop 66
+  if (ieee_max_num (-inf, nan) /= -inf) stop 67
+
+  if (.not. ieee_is_nan (ieee_max_num (nan, nan))) stop 68
+end subroutine large1
+
+
+subroutine large2
+  use ieee_arithmetic
+  implicit none
+
+  ! k1 and k2 will be large real kinds, if supported, and single/double
+  ! otherwise
+  integer, parameter :: k1 = &
+    max(ieee_selected_real_kind(precision(0.d0) + 1), kind(0.))
+  integer, parameter :: k2 = &
+    max(ieee_selected_real_kind(precision(0._k1) + 1), kind(0.d0))
+
+  real(kind=k2) :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_max_num (0._k2, 0._k2) /= 0._k2) stop 35
+  if (ieee_max_num (-0._k2, -0._k2) /= -0._k2) stop 36
+  if (.not. ieee_signbit (ieee_max_num (-0._k2, -0._k2))) stop 37
+  if (ieee_max_num (0._k2, -0._k2) /= 0._k2) stop 38
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num (0._k2, -0._k2))) stop 39
+  if (ieee_max_num (-0._k2, 0._k2) /= 0._k2) stop 40
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_max_num (-0._k2, 0._k2))) stop 41
+
+  if (ieee_max_num (9._k2, 0._k2) /= 9._k2) stop 42
+  if (ieee_max_num (0._k2, 9._k2) /= 9._k2) stop 43
+  if (ieee_max_num (-9._k2, 0._k2) /= 0._k2) stop 44
+  if (ieee_max_num (0._k2, -9._k2) /= 0._k2) stop 45
+
+  if (ieee_max_num (inf, 9._k2) /= inf) stop 46
+  if (ieee_max_num (0._k2, inf) /= inf) stop 47
+  if (ieee_max_num (-9._k2, inf) /= inf) stop 48
+  if (ieee_max_num (inf, -9._k2) /= inf) stop 49
+  if (ieee_max_num (-inf, 9._k2) /= 9._k2) stop 50
+  if (ieee_max_num (0._k2, -inf) /= 0._k2) stop 51
+  if (ieee_max_num (-9._k2, -inf) /= -9._k2) stop 52
+  if (ieee_max_num (-inf, -9._k2) /= -9._k2) stop 53
+
+  if (ieee_max_num (0._k2, nan) /= 0._k2) stop 54
+  if (ieee_max_num (nan, 0._k2) /= 0._k2) stop 55
+  if (ieee_max_num (-0._k2, nan) /= -0._k2) stop 56
+  if (.not. ieee_signbit (ieee_max_num (-0._k2, nan))) stop 57
+  if (ieee_max_num (nan, -0._k2) /= -0._k2) stop 58
+  if (.not. ieee_signbit (ieee_max_num (nan, -0._k2))) stop 59
+  if (ieee_max_num (9._k2, nan) /= 9._k2) stop 60
+  if (ieee_max_num (nan, 9._k2) /= 9._k2) stop 61
+  if (ieee_max_num (-9._k2, nan) /= -9._k2) stop 62
+  if (ieee_max_num (nan, -9._k2) /= -9._k2) stop 63
+
+  if (ieee_max_num (nan, inf) /= inf) stop 64
+  if (ieee_max_num (inf, nan) /= inf) stop 65
+  if (ieee_max_num (nan, -inf) /= -inf) stop 66
+  if (ieee_max_num (-inf, nan) /= -inf) stop 67
+
+  if (.not. ieee_is_nan (ieee_max_num (nan, nan))) stop 68
+end subroutine large2
+
diff --git a/gcc/testsuite/gfortran.dg/ieee/minmax_4.f90 b/gcc/testsuite/gfortran.dg/ieee/minmax_4.f90
new file mode 100644
index 00000000000..f55a96ba652
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/ieee/minmax_4.f90
@@ -0,0 +1,235 @@
+! { dg-do run }
+!
+program test
+  call real()
+  call double()
+  call large1()
+  call large2()
+end program test
+
+
+subroutine real
+  use ieee_arithmetic
+  implicit none
+
+  real :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_min_num (0., 0.) /= 0.) stop 1
+  if (ieee_min_num (-0., -0.) /= -0.) stop 2
+  if (.not. ieee_signbit (ieee_min_num (-0., -0.))) stop 3
+  if (ieee_min_num (0., -0.) /= -0.) stop 4
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num (0., -0.))) stop 5
+  if (ieee_min_num (-0., 0.) /= 0.) stop 6
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num (-0., 0.))) stop 7
+
+  if (ieee_min_num (9., 0.) /= 0.) stop 8
+  if (ieee_min_num (0., 9.) /= 0.) stop 9
+  if (ieee_min_num (-9., 0.) /= -9.) stop 10
+  if (ieee_min_num (0., -9.) /= -9.) stop 11
+
+  if (ieee_min_num (inf, 9.) /= 9.) stop 12
+  if (ieee_min_num (0., inf) /= 0.) stop 13
+  if (ieee_min_num (-9., inf) /= -9.) stop 14
+  if (ieee_min_num (inf, -9.) /= -9.) stop 15
+  if (ieee_min_num (-inf, 9.) /= -inf) stop 16
+  if (ieee_min_num (0., -inf) /= -inf) stop 17
+  if (ieee_min_num (-9., -inf) /= -inf) stop 18
+  if (ieee_min_num (-inf, -9.) /= -inf) stop 19
+
+  if (ieee_min_num (0., nan) /= 0.) stop 20
+  if (ieee_min_num (nan, 0.) /= 0.) stop 21
+  if (ieee_min_num (-0., nan) /= -0.) stop 22
+  if (.not. ieee_signbit (ieee_min_num (-0., nan))) stop 23
+  if (ieee_min_num (nan, -0.) /= -0.) stop 24
+  if (.not. ieee_signbit (ieee_min_num (nan, -0.))) stop 25
+  if (ieee_min_num (9., nan) /= 9.) stop 26
+  if (ieee_min_num (nan, 9.) /= 9.) stop 27
+  if (ieee_min_num (-9., nan) /= -9.) stop 28
+  if (ieee_min_num (nan, -9.) /= -9.) stop 29
+
+  if (ieee_min_num (nan, inf) /= inf) stop 30
+  if (ieee_min_num (inf, nan) /= inf) stop 31
+  if (ieee_min_num (nan, -inf) /= -inf) stop 32
+  if (ieee_min_num (-inf, nan) /= -inf) stop 33
+
+  if (.not. ieee_is_nan (ieee_min_num (nan, nan))) stop 34
+end subroutine real
+
+
+subroutine double
+  use ieee_arithmetic
+  implicit none
+
+  double precision :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_min_num (0.d0, 0.d0) /= 0.d0) stop 35
+  if (ieee_min_num (-0.d0, -0.d0) /= -0.d0) stop 36
+  if (.not. ieee_signbit (ieee_min_num (-0.d0, -0.d0))) stop 37
+  if (ieee_min_num (0.d0, -0.d0) /= 0.d0) stop 38
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num (0.d0, -0.d0))) stop 39
+  if (ieee_min_num (-0.d0, 0.d0) /= 0.d0) stop 40
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num (-0.d0, 0.d0))) stop 41
+
+  if (ieee_min_num (9.d0, 0.d0) /= 0.d0) stop 42
+  if (ieee_min_num (0.d0, 9.d0) /= 0.d0) stop 43
+  if (ieee_min_num (-9.d0, 0.d0) /= -9.d0) stop 44
+  if (ieee_min_num (0.d0, -9.d0) /= -9.d0) stop 45
+
+  if (ieee_min_num (inf, 9.d0) /= 9.d0) stop 46
+  if (ieee_min_num (0.d0, inf) /= 0.d0) stop 47
+  if (ieee_min_num (-9.d0, inf) /= -9.d0) stop 48
+  if (ieee_min_num (inf, -9.d0) /= -9.d0) stop 49
+  if (ieee_min_num (-inf, 9.d0) /= -inf) stop 50
+  if (ieee_min_num (0.d0, -inf) /= -inf) stop 51
+  if (ieee_min_num (-9.d0, -inf) /= -inf) stop 52
+  if (ieee_min_num (-inf, -9.d0) /= -inf) stop 53
+
+  if (ieee_min_num (0.d0, nan) /= 0.d0) stop 54
+  if (ieee_min_num (nan, 0.d0) /= 0.d0) stop 55
+  if (ieee_min_num (-0.d0, nan) /= -0.d0) stop 56
+  if (.not. ieee_signbit (ieee_min_num (-0.d0, nan))) stop 57
+  if (ieee_min_num (nan, -0.d0) /= -0.d0) stop 58
+  if (.not. ieee_signbit (ieee_min_num (nan, -0.d0))) stop 59
+  if (ieee_min_num (9.d0, nan) /= 9.d0) stop 60
+  if (ieee_min_num (nan, 9.d0) /= 9.d0) stop 61
+  if (ieee_min_num (-9.d0, nan) /= -9.d0) stop 62
+  if (ieee_min_num (nan, -9.d0) /= -9.d0) stop 63
+
+  if (ieee_min_num (nan, inf) /= inf) stop 64
+  if (ieee_min_num (inf, nan) /= inf) stop 65
+  if (ieee_min_num (nan, -inf) /= -inf) stop 66
+  if (ieee_min_num (-inf, nan) /= -inf) stop 67
+
+  if (.not. ieee_is_nan (ieee_min_num (nan, nan))) stop 68
+end subroutine double
+
+
+subroutine large1
+  use ieee_arithmetic
+  implicit none
+
+  ! k1 and k2 will be large real kinds, if supported, and single/double
+  ! otherwise
+  integer, parameter :: k1 = &
+    max(ieee_selected_real_kind(precision(0.d0) + 1), kind(0.))
+  integer, parameter :: k2 = &
+    max(ieee_selected_real_kind(precision(0._k1) + 1), kind(0.d0))
+
+  real(kind=k1) :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_min_num (0._k1, 0._k1) /= 0._k1) stop 35
+  if (ieee_min_num (-0._k1, -0._k1) /= -0._k1) stop 36
+  if (.not. ieee_signbit (ieee_min_num (-0._k1, -0._k1))) stop 37
+  if (ieee_min_num (0._k1, -0._k1) /= 0._k1) stop 38
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num (0._k1, -0._k1))) stop 39
+  if (ieee_min_num (-0._k1, 0._k1) /= 0._k1) stop 40
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num (-0._k1, 0._k1))) stop 41
+
+  if (ieee_min_num (9._k1, 0._k1) /= 0._k1) stop 42
+  if (ieee_min_num (0._k1, 9._k1) /= 0._k1) stop 43
+  if (ieee_min_num (-9._k1, 0._k1) /= -9._k1) stop 44
+  if (ieee_min_num (0._k1, -9._k1) /= -9._k1) stop 45
+
+  if (ieee_min_num (inf, 9._k1) /= 9._k1) stop 46
+  if (ieee_min_num (0._k1, inf) /= 0._k1) stop 47
+  if (ieee_min_num (-9._k1, inf) /= -9._k1) stop 48
+  if (ieee_min_num (inf, -9._k1) /= -9._k1) stop 49
+  if (ieee_min_num (-inf, 9._k1) /= -inf) stop 50
+  if (ieee_min_num (0._k1, -inf) /= -inf) stop 51
+  if (ieee_min_num (-9._k1, -inf) /= -inf) stop 52
+  if (ieee_min_num (-inf, -9._k1) /= -inf) stop 53
+
+  if (ieee_min_num (0._k1, nan) /= 0._k1) stop 54
+  if (ieee_min_num (nan, 0._k1) /= 0._k1) stop 55
+  if (ieee_min_num (-0._k1, nan) /= -0._k1) stop 56
+  if (.not. ieee_signbit (ieee_min_num (-0._k1, nan))) stop 57
+  if (ieee_min_num (nan, -0._k1) /= -0._k1) stop 58
+  if (.not. ieee_signbit (ieee_min_num (nan, -0._k1))) stop 59
+  if (ieee_min_num (9._k1, nan) /= 9._k1) stop 60
+  if (ieee_min_num (nan, 9._k1) /= 9._k1) stop 61
+  if (ieee_min_num (-9._k1, nan) /= -9._k1) stop 62
+  if (ieee_min_num (nan, -9._k1) /= -9._k1) stop 63
+
+  if (ieee_min_num (nan, inf) /= inf) stop 64
+  if (ieee_min_num (inf, nan) /= inf) stop 65
+  if (ieee_min_num (nan, -inf) /= -inf) stop 66
+  if (ieee_min_num (-inf, nan) /= -inf) stop 67
+
+  if (.not. ieee_is_nan (ieee_min_num (nan, nan))) stop 68
+end subroutine large1
+
+
+subroutine large2
+  use ieee_arithmetic
+  implicit none
+
+  ! k1 and k2 will be large real kinds, if supported, and single/double
+  ! otherwise
+  integer, parameter :: k1 = &
+    max(ieee_selected_real_kind(precision(0.d0) + 1), kind(0.))
+  integer, parameter :: k2 = &
+    max(ieee_selected_real_kind(precision(0._k1) + 1), kind(0.d0))
+
+  real(kind=k2) :: inf, nan
+
+  inf = ieee_value(inf, ieee_positive_inf)
+  nan = ieee_value(nan, ieee_quiet_nan)
+
+  if (ieee_min_num (0._k2, 0._k2) /= 0._k2) stop 35
+  if (ieee_min_num (-0._k2, -0._k2) /= -0._k2) stop 36
+  if (.not. ieee_signbit (ieee_min_num (-0._k2, -0._k2))) stop 37
+  if (ieee_min_num (0._k2, -0._k2) /= 0._k2) stop 38
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num (0._k2, -0._k2))) stop 39
+  if (ieee_min_num (-0._k2, 0._k2) /= 0._k2) stop 40
+  ! Processor-dependent
+  !if (ieee_signbit (ieee_min_num (-0._k2, 0._k2))) stop 41
+
+  if (ieee_min_num (9._k2, 0._k2) /= 0._k2) stop 42
+  if (ieee_min_num (0._k2, 9._k2) /= 0._k2) stop 43
+  if (ieee_min_num (-9._k2, 0._k2) /= -9._k2) stop 44
+  if (ieee_min_num (0._k2, -9._k2) /= -9._k2) stop 45
+
+  if (ieee_min_num (inf, 9._k2) /= 9._k2) stop 46
+  if (ieee_min_num (0._k2, inf) /= 0._k2) stop 47
+  if (ieee_min_num (-9._k2, inf) /= -9._k2) stop 48
+  if (ieee_min_num (inf, -9._k2) /= -9._k2) stop 49
+  if (ieee_min_num (-inf, 9._k2) /= -inf) stop 50
+  if (ieee_min_num (0._k2, -inf) /= -inf) stop 51
+  if (ieee_min_num (-9._k2, -inf) /= -inf) stop 52
+  if (ieee_min_num (-inf, -9._k2) /= -inf) stop 53
+
+  if (ieee_min_num (0._k2, nan) /= 0._k2) stop 54
+  if (ieee_min_num (nan, 0._k2) /= 0._k2) stop 55
+  if (ieee_min_num (-0._k2, nan) /= -0._k2) stop 56
+  if (.not. ieee_signbit (ieee_min_num (-0._k2, nan))) stop 57
+  if (ieee_min_num (nan, -0._k2) /= -0._k2) stop 58
+  if (.not. ieee_signbit (ieee_min_num (nan, -0._k2))) stop 59
+  if (ieee_min_num (9._k2, nan) /= 9._k2) stop 60
+  if (ieee_min_num (nan, 9._k2) /= 9._k2) stop 61
+  if (ieee_min_num (-9._k2, nan) /= -9._k2) stop 62
+  if (ieee_min_num (nan, -9._k2) /= -9._k2) stop 63
+
+  if (ieee_min_num (nan, inf) /= inf) stop 64
+  if (ieee_min_num (inf, nan) /= inf) stop 65
+  if (ieee_min_num (nan, -inf) /= -inf) stop 66
+  if (ieee_min_num (-inf, nan) /= -inf) stop 67
+
+  if (.not. ieee_is_nan (ieee_min_num (nan, nan))) stop 68
+end subroutine large2
+
diff --git a/libgfortran/ieee/ieee_arithmetic.F90 b/libgfortran/ieee/ieee_arithmetic.F90
index 9c0b9f31730..d34ece6c8d2 100644
--- a/libgfortran/ieee/ieee_arithmetic.F90
+++ b/libgfortran/ieee/ieee_arithmetic.F90
@@ -223,6 +223,132 @@ module IEEE_ARITHMETIC
   end interface
   public :: IEEE_IS_NORMAL
 
+  ! IEEE_MIN_NUM, IEEE_MAX_NUM, IEEE_MIN_NUM_MAG, IEEE_MAX_NUM_MAG
+
+  interface
+    elemental real(kind=4) function _gfortran_ieee_max_num_4(X, Y)
+      real(kind=4), intent(in) :: X, Y
+    end function
+    elemental real(kind=8) function _gfortran_ieee_max_num_8(X, Y)
+      real(kind=8), intent(in) :: X, Y
+    end function
+#ifdef HAVE_GFC_REAL_10
+    elemental real(kind=10) function _gfortran_ieee_max_num_10(X, Y)
+      real(kind=10), intent(in) :: X, Y
+    end function
+#endif
+#ifdef HAVE_GFC_REAL_16
+    elemental real(kind=16) function _gfortran_ieee_max_num_16(X, Y)
+      real(kind=16), intent(in) :: X, Y
+    end function
+#endif
+  end interface
+
+  interface IEEE_MAX_NUM
+    procedure &
+#ifdef HAVE_GFC_REAL_16
+      _gfortran_ieee_max_num_16, &
+#endif
+#ifdef HAVE_GFC_REAL_10
+      _gfortran_ieee_max_num_10, &
+#endif
+      _gfortran_ieee_max_num_8, _gfortran_ieee_max_num_4
+  end interface
+  public :: IEEE_MAX_NUM
+
+  interface
+    elemental real(kind=4) function _gfortran_ieee_max_num_mag_4(X, Y)
+      real(kind=4), intent(in) :: X, Y
+    end function
+    elemental real(kind=8) function _gfortran_ieee_max_num_mag_8(X, Y)
+      real(kind=8), intent(in) :: X, Y
+    end function
+#ifdef HAVE_GFC_REAL_10
+    elemental real(kind=10) function _gfortran_ieee_max_num_mag_10(X, Y)
+      real(kind=10), intent(in) :: X, Y
+    end function
+#endif
+#ifdef HAVE_GFC_REAL_16
+    elemental real(kind=16) function _gfortran_ieee_max_num_mag_16(X, Y)
+      real(kind=16), intent(in) :: X, Y
+    end function
+#endif
+  end interface
+
+  interface IEEE_MAX_NUM_MAG
+    procedure &
+#ifdef HAVE_GFC_REAL_16
+      _gfortran_ieee_max_num_mag_16, &
+#endif
+#ifdef HAVE_GFC_REAL_10
+      _gfortran_ieee_max_num_mag_10, &
+#endif
+      _gfortran_ieee_max_num_mag_8, _gfortran_ieee_max_num_mag_4
+  end interface
+  public :: IEEE_MAX_NUM_MAG
+
+  interface
+    elemental real(kind=4) function _gfortran_ieee_min_num_4(X, Y)
+      real(kind=4), intent(in) :: X, Y
+    end function
+    elemental real(kind=8) function _gfortran_ieee_min_num_8(X, Y)
+      real(kind=8), intent(in) :: X, Y
+    end function
+#ifdef HAVE_GFC_REAL_10
+    elemental real(kind=10) function _gfortran_ieee_min_num_10(X, Y)
+      real(kind=10), intent(in) :: X, Y
+    end function
+#endif
+#ifdef HAVE_GFC_REAL_16
+    elemental real(kind=16) function _gfortran_ieee_min_num_16(X, Y)
+      real(kind=16), intent(in) :: X, Y
+    end function
+#endif
+  end interface
+
+  interface IEEE_MIN_NUM
+    procedure &
+#ifdef HAVE_GFC_REAL_16
+      _gfortran_ieee_min_num_16, &
+#endif
+#ifdef HAVE_GFC_REAL_10
+      _gfortran_ieee_min_num_10, &
+#endif
+      _gfortran_ieee_min_num_8, _gfortran_ieee_min_num_4
+  end interface
+  public :: IEEE_MIN_NUM
+
+  interface
+    elemental real(kind=4) function _gfortran_ieee_min_num_mag_4(X, Y)
+      real(kind=4), intent(in) :: X, Y
+    end function
+    elemental real(kind=8) function _gfortran_ieee_min_num_mag_8(X, Y)
+      real(kind=8), intent(in) :: X, Y
+    end function
+#ifdef HAVE_GFC_REAL_10
+    elemental real(kind=10) function _gfortran_ieee_min_num_mag_10(X, Y)
+      real(kind=10), intent(in) :: X, Y
+    end function
+#endif
+#ifdef HAVE_GFC_REAL_16
+    elemental real(kind=16) function _gfortran_ieee_min_num_mag_16(X, Y)
+      real(kind=16), intent(in) :: X, Y
+    end function
+#endif
+  end interface
+
+  interface IEEE_MIN_NUM_MAG
+    procedure &
+#ifdef HAVE_GFC_REAL_16
+      _gfortran_ieee_min_num_mag_16, &
+#endif
+#ifdef HAVE_GFC_REAL_10
+      _gfortran_ieee_min_num_mag_10, &
+#endif
+      _gfortran_ieee_min_num_mag_8, _gfortran_ieee_min_num_mag_4
+  end interface
+  public :: IEEE_MIN_NUM_MAG
+
   ! IEEE_COPY_SIGN
 
 #define COPYSIGN_MACRO(A,B) \
-- 
2.34.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-06 13:19 [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions FX
@ 2023-06-06 15:43 ` Steve Kargl
  2023-06-06 15:51   ` Steve Kargl
  2023-06-06 19:00 ` Harald Anlauf
  2023-06-06 19:35 ` FX Coudert
  2 siblings, 1 reply; 19+ messages in thread
From: Steve Kargl @ 2023-06-06 15:43 UTC (permalink / raw)
  To: FX via Fortran; +Cc: gcc-patches

On Tue, Jun 06, 2023 at 03:19:18PM +0200, FX via Fortran wrote:
> Hi,
> 
> This patch adds four IEEE functions from the Fortran 2018
> standard: IEEE_MIN_NUM, IEEE_MAX_NUM, IEEE_MIN_NUM_MAG,
> and IEEE_MAX_NUM_MAG.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, both 32
> and 64-bit. OK to commit?
> 

FX,

If no one else looks over the patch before the weekend,
I'll give it a deeper look.  Two questions after a 
quick scan:

1. You added fmin, fmax, and friends.  Are these used 
   internally by gfortran in support of the IEEE_*
   functions or are these exposed to the user?

2. I did not see error handling or conversion, but on a
   quick scan I may have missed it.  What happens with
   IEEE_MAX_NUM(2.0_4, 3.0_8) or IEEE_MAX_NUM(2.0_4, INT(3))?
   17.11.17 has

   X shall be of type real.
   Y shall be of the same type and kind type parameter as X.

-- 
Steve

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-06 15:43 ` Steve Kargl
@ 2023-06-06 15:51   ` Steve Kargl
  2023-06-06 18:21     ` Steve Kargl
  0 siblings, 1 reply; 19+ messages in thread
From: Steve Kargl @ 2023-06-06 15:51 UTC (permalink / raw)
  To: Steve Kargl via Fortran; +Cc: gcc-patches

On Tue, Jun 06, 2023 at 08:43:36AM -0700, Steve Kargl via Fortran wrote:
> On Tue, Jun 06, 2023 at 03:19:18PM +0200, FX via Fortran wrote:
> > Hi,
> > 
> > This patch adds four IEEE functions from the Fortran 2018
> > standard: IEEE_MIN_NUM, IEEE_MAX_NUM, IEEE_MIN_NUM_MAG,
> > and IEEE_MAX_NUM_MAG.
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, both 32
> > and 64-bit. OK to commit?
> > 
> 
> FX,
> 
> If no one else looks over the patch before the weekend,
> I'll give it a deeper look.  Two questions after a 
> quick scan:
> 
> 1. You added fmin, fmax, and friends.  Are these used 
>    internally by gfortran in support of the IEEE_*
>    functions or are these exposed to the user?
> 
> 2. I did not see error handling or conversion, but on a
>    quick scan I may have missed it.  What happens with
>    IEEE_MAX_NUM(2.0_4, 3.0_8) or IEEE_MAX_NUM(2.0_4, INT(3))?
>    17.11.17 has
> 
>    X shall be of type real.
>    Y shall be of the same type and kind type parameter as X.
> 

Scratch 2.  Another scan shows that you moduled the Fortran
module where interface are built.  This will automatically
catch and report the items in 2.

-- 
Steve

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-06 15:51   ` Steve Kargl
@ 2023-06-06 18:21     ` Steve Kargl
  0 siblings, 0 replies; 19+ messages in thread
From: Steve Kargl @ 2023-06-06 18:21 UTC (permalink / raw)
  To: Steve Kargl via Fortran; +Cc: gcc-patches

On Tue, Jun 06, 2023 at 08:51:54AM -0700, Steve Kargl via Fortran wrote:
> 
> Scratch 2.  Another scan shows that you moduled the Fortran

s/you moduled/you added to 

> module where interface are built.  This will automatically

s/interface/interfaces

> catch and report the items in 2.

Complete lack of coffee.

-- 
Steve

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-06 13:19 [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions FX
  2023-06-06 15:43 ` Steve Kargl
@ 2023-06-06 19:00 ` Harald Anlauf
  2023-06-06 19:11   ` FX Coudert
  2023-06-06 19:35 ` FX Coudert
  2 siblings, 1 reply; 19+ messages in thread
From: Harald Anlauf @ 2023-06-06 19:00 UTC (permalink / raw)
  To: FX, fortran; +Cc: gcc-patches

Hi FX,

On 6/6/23 15:19, FX via Gcc-patches wrote:
> Hi,
>
> This patch adds four IEEE functions from the Fortran 2018 standard: IEEE_MIN_NUM, IEEE_MAX_NUM, IEEE_MIN_NUM_MAG, and IEEE_MAX_NUM_MAG.
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, both 32 and 64-bit. OK to commit?
>
> FX
>

it would be great if someone with access to a Power platform and
knowledge of IEEE128 thereon could have a look.

I cannot see if there is proper support for kind=17 in your patch;
at least the libgfortran/ieee/ieee_arithmetic.F90 part does not
seem to have any related code.

Thanks,
Harald


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-06 19:00 ` Harald Anlauf
@ 2023-06-06 19:11   ` FX Coudert
  2023-06-07 18:31     ` Harald Anlauf
  0 siblings, 1 reply; 19+ messages in thread
From: FX Coudert @ 2023-06-06 19:11 UTC (permalink / raw)
  To: Harald Anlauf; +Cc: fortran, gcc-patches

Hi,

> I cannot see if there is proper support for kind=17 in your patch;
> at least the libgfortran/ieee/ieee_arithmetic.F90 part does not
> seem to have any related code.

Can real(kind=17) ever be an IEEE mode? If so, something seriously wrong happened, because the IEEE modules have no kind=17 mention in them anywhere.

Actually, where is the kind=17 documented?

FX

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-06 13:19 [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions FX
  2023-06-06 15:43 ` Steve Kargl
  2023-06-06 19:00 ` Harald Anlauf
@ 2023-06-06 19:35 ` FX Coudert
  2023-06-07  3:15   ` Steve Kargl
  2 siblings, 1 reply; 19+ messages in thread
From: FX Coudert @ 2023-06-06 19:35 UTC (permalink / raw)
  To: fortran; +Cc: gcc-patches, sgk

Hi Steve,

I am not subscribed to the list (too little time, sadly), please keep me in CC of your responses.

> 1. You added fmin, fmax, and friends.  Are these used 
>    internally by gfortran in support of the IEEE_*
>    functions or are these exposed to the user?

The math builtins are added to the front-end, and use for code generation. In conv_intrinsic_ieee_minmax(), you can see we find the right function using things like: builtin_decl_explicit (BUILT_IN_ISSIGNALING)

Those built-ins are not exposed to the user: we don’t need any more GNU-specific intrinsics, methinks.


> 2. I did not see error handling or conversion, but on a
>    quick scan I may have missed it.  What happens with
>    IEEE_MAX_NUM(2.0_4, 3.0_8) or IEEE_MAX_NUM(2.0_4, INT(3))?
>    17.11.17 has
> 
>    X shall be of type real.
>    Y shall be of the same type and kind type parameter as X.


As you saw, the module built as part of libgfortran deals with that. In the longer term, we would need a revamp of those modules to handle everything as intrinsic modules, which would give us more flexibility, but I never found the time to do this migration :(

Best,
FX

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-06 19:35 ` FX Coudert
@ 2023-06-07  3:15   ` Steve Kargl
  2023-06-10 15:42     ` FX Coudert
  0 siblings, 1 reply; 19+ messages in thread
From: Steve Kargl @ 2023-06-07  3:15 UTC (permalink / raw)
  To: FX Coudert; +Cc: fortran, gcc-patches

On Tue, Jun 06, 2023 at 09:35:26PM +0200, FX Coudert wrote:
> Hi Steve,
> 
> I am not subscribed to the list (too little time, sadly), please keep me in CC of your responses.
> 

Unfortunately, fx is using a gmail account.  Emails from my
system to @gmail.com users are routinely and silently rejected.


> > 1. You added fmin, fmax, and friends.  Are these used 
> >    internally by gfortran in support of the IEEE_*
> >    functions or are these exposed to the user?
> 
> The math builtins are added to the front-end, and use for
> code generation.  In conv_intrinsic_ieee_minmax(), you can
> see we find the right function using things like:
> builtin_decl_explicit (BUILT_IN_ISSIGNALING)


This answers my question 1.  I think the patch can be committed
after you've given time for Harald to answer your question about
REAL(17).  I think isn't important as all of the other ieee
testcase would be broken on powerpc.

-- 
Steve

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-06 19:11   ` FX Coudert
@ 2023-06-07 18:31     ` Harald Anlauf
  2023-06-07 18:50       ` Steve Kargl
  0 siblings, 1 reply; 19+ messages in thread
From: Harald Anlauf @ 2023-06-07 18:31 UTC (permalink / raw)
  To: FX Coudert; +Cc: fortran, gcc-patches

Hi FX,

On 6/6/23 21:11, FX Coudert via Gcc-patches wrote:
> Hi,
>
>> I cannot see if there is proper support for kind=17 in your patch;
>> at least the libgfortran/ieee/ieee_arithmetic.F90 part does not
>> seem to have any related code.
>
> Can real(kind=17) ever be an IEEE mode? If so, something seriously wrong happened, because the IEEE modules have no kind=17 mention in them anywhere.
>
> Actually, where is the kind=17 documented?
>
> FX

I was hoping for Thomas to come forward with some comment, as
he was quite involved in related work.

There are several threads on IEEE128 for Power on the fortran ML
e.g. around November/December 2021, January 2022.

I wasn't meaning to block your work, just wondering if the Power
platform needs more attention here.

Harald


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-07 18:31     ` Harald Anlauf
@ 2023-06-07 18:50       ` Steve Kargl
  2023-06-08 10:17         ` Thomas Koenig
  0 siblings, 1 reply; 19+ messages in thread
From: Steve Kargl @ 2023-06-07 18:50 UTC (permalink / raw)
  To: Harald Anlauf via Fortran; +Cc: FX Coudert, gcc-patches

On Wed, Jun 07, 2023 at 08:31:35PM +0200, Harald Anlauf via Fortran wrote:
> Hi FX,
> 
> On 6/6/23 21:11, FX Coudert via Gcc-patches wrote:
> > Hi,
> > 
> > > I cannot see if there is proper support for kind=17 in your patch;
> > > at least the libgfortran/ieee/ieee_arithmetic.F90 part does not
> > > seem to have any related code.
> > 
> > Can real(kind=17) ever be an IEEE mode? If so, something seriously wrong happened, because the IEEE modules have no kind=17 mention in them anywhere.
> > 
> > Actually, where is the kind=17 documented?
> > 
> > FX
> 
> I was hoping for Thomas to come forward with some comment, as
> he was quite involved in related work.
> 
> There are several threads on IEEE128 for Power on the fortran ML
> e.g. around November/December 2021, January 2022.
> 
> I wasn't meaning to block your work, just wondering if the Power
> platform needs more attention here.
> 

% cd gcc/gccx/libgfortran
% grep HAVE_GFC_REAL_17 ieee/*
% troutmask:sgk[219] ls ieee
% ieee_arithmetic.F90     ieee_features.F90
% ieee_exceptions.F90     ieee_helper.c

There are zero hits for REAL(17) in the IEEE code.  If REAL(17)
is intended to be an IEEE-754 type, then it seems gfortran's
support was never added for it.  If anyone has access to a
power system, it's easy to test

program foo
   use ieee_arithmetic
   print *, ieee_support_datatype(1.e_17)
end program foo
-- 
Steve

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-07 18:50       ` Steve Kargl
@ 2023-06-08 10:17         ` Thomas Koenig
  2023-06-08 10:21           ` FX Coudert
                             ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Thomas Koenig @ 2023-06-08 10:17 UTC (permalink / raw)
  To: sgk, Harald Anlauf via Fortran; +Cc: FX Coudert, gcc-patches, Michael Meissner

Hi together,

>> On 6/6/23 21:11, FX Coudert via Gcc-patches wrote:
>>> Hi,
>>>
>>>> I cannot see if there is proper support for kind=17 in your patch;
>>>> at least the libgfortran/ieee/ieee_arithmetic.F90 part does not
>>>> seem to have any related code.
>>>
>>> Can real(kind=17) ever be an IEEE mode? If so, something seriously wrong happened, because the IEEE modules have no kind=17 mention in them anywhere.
>>>
>>> Actually, where is the kind=17 documented?
>>>
>>> FX
>>
>> I was hoping for Thomas to come forward with some comment, as
>> he was quite involved in related work.
>>
>> There are several threads on IEEE128 for Power on the fortran ML
>> e.g. around November/December 2021, January 2022.
>>
>> I wasn't meaning to block your work, just wondering if the Power
>> platform needs more attention here.
>>
> 
> % cd gcc/gccx/libgfortran
> % grep HAVE_GFC_REAL_17 ieee/*
> % troutmask:sgk[219] ls ieee
> % ieee_arithmetic.F90     ieee_features.F90
> % ieee_exceptions.F90     ieee_helper.c
> 
> There are zero hits for REAL(17) in the IEEE code.  If REAL(17)
> is intended to be an IEEE-754 type, then it seems gfortran's
> support was never added for it.  If anyone has access to a
> power system, it's easy to test
> 
> program foo
>     use ieee_arithmetic
>     print *, ieee_support_datatype(1.e_17)
> end program foo

The KIND=17 is a bit of a kludge.  It is not visible for
user programs, they use KIND=16, but this is then translated
to library calls as if it was KIND=17 if the IEEE 128-bit floats
are selected:

$ cat ml.f90
subroutine mm(a)
   real(kind=16), dimension(:,:) :: a
   print *,maxloc(a)
end subroutine mm
$ gfortran -S -mabi=ieeelongdouble ml.f90 && grep maxloc ml.s
         bl _gfortran_maxloc0_4_r17
$ gfortran -S  ml.f90 && grep maxloc ml.s
         bl _gfortran_maxloc0_4_r16

On POWER, if IBM long double exists, it is GFC_REAL_16, with GFC_REAL_17
being IEEE long double. Everywhere else, GFC_REAL_16 is IEEE long
double.

If POWER gets the flag -mabi=ieeelongdouble, it uses IEEE long doubles.

If it gets the additionalflag -mcpu=power9 or -mcpu=power10, it uses
the hardware instructions for the arithmetic instead of library calls.

Having a POWER system isn't enough, it also needs the IBM "advance
toolchain", and (at least with current distros, which default to
ibm long double), you need to dance counterclockwise three
times... I mean you need to invoke configure with some special magic
like

configure \
         --prefix=$HOME \
         --enable-languages=c,c++,fortran \
         --disable-plugin \
         --enable-checking \
         --enable-stage1-checking \
         --enable-gnu-indirect-function \
         --disable-maintainer-mode \
         --disable-libgomp \
         --enable-decimal-float \
         --enable-secureplt \
         --enable-threads=posix \
         --enable-__cxa_atexit \
         --with-cpu=power9 \
         --with-long-double-128 \
         --with-as=/opt/at15.0/bin/as \
         --with-ld=/opt/at15.0/bin/ld \
         --with-gnu-as=/opt/at15.0/bin/as \
         --with-gnu-ld=/opt/at15.0/bin/ld \
         --with-advance-toolchain=at15.0 \
         --with-native-system-header-dir=/opt/at15.0/include \
         --without-ppl \
         --without-cloog \
         --without-isl

which Michael Meissner helped me with, I would never have figured it out
on my own.

There is a virutal POWER machine at OSUL dedicated to the IEEE QP
gfortran effort. It hasn't been used for some time, but it's still
active. I just bootstrapped trunk there and ran all the IEEE from the
testsuite manually, with

$ for a in *.f90; do echo "Testing $a"; gfortran -o $a.exe 
-fno-range-check -mcpu=power9 -mabi=ieeelongdouble -static-libgfortran 
$a signaling_1_c.c signaling_2_c.c ; ./$a.exe ; done 2>&1 | grep -v 
command-line
Testing fma_1.f90
    2.00000000
    1.50000000
    2.0000000000000000
    1.5000000000000000
    2.00000000000000000000000000000000000
    1.50000000000000000000000000000000000
    2.0000000000000000
    1.5000000000000000
Testing ieee_10.f90
Testing ieee_12.f90
Testing ieee_2.f90
Testing ieee_3.f90
Testing ieee_4.f90
Testing ieee_5.f90
Testing ieee_6.f90
Testing ieee_7.f90
Testing ieee_8.f90
Testing ieee_9.f90
Testing intrinsics_1.f90
Testing large_1.f90
Testing large_2.f90
Testing large_4.f90
Testing modes_1.f90
Testing pr77372.f90
Testing pr77507.f90
         -Infinity
  F
Testing rounding_1.f90
Testing rounding_2.f90
Testing rounding_3.f90
Testing signaling_1.f90
Testing signaling_2.f90
Testing signaling_3.f90
Testing signbit_1.f90
Testing underflow_1.f90

so that seems to be OK.  However, the fact that there is no
mention of GFC_REAL_17 in there makes me a bit suspicious,

Michael, maybe you can comment if all is indeed well there,
and if the right things are being tested?

Regarding FX's patch: I am not quite sure that I am
actually testing the right thing if running the testsuite
there, so POWER should not hold up this patch.  If it turns
out that POWER needs additonal work on IEEE, we can always
add that later.

Best regards

	Thomas

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-08 10:17         ` Thomas Koenig
@ 2023-06-08 10:21           ` FX Coudert
  2023-06-08 11:24             ` Thomas Koenig
  2023-06-08 16:31           ` Steve Kargl
  2023-06-10 15:24           ` FX Coudert
  2 siblings, 1 reply; 19+ messages in thread
From: FX Coudert @ 2023-06-08 10:21 UTC (permalink / raw)
  To: Thomas Koenig
  Cc: sgk, Harald Anlauf via Fortran, gcc-patches, Michael Meissner

> Having a POWER system isn't enough, it also needs the IBM "advance
> toolchain", and (at least with current distros, which default to
> ibm long double), you need to dance counterclockwise three
> times... I mean you need to invoke configure with some special magic

Thanks for the frank description, Thomas. To be honest, it reinforces my feeling from when this was originally proposed and added: why are we doing so much extra work for a feature that is used by such a tiny fraction of our user base.

FX

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-08 10:21           ` FX Coudert
@ 2023-06-08 11:24             ` Thomas Koenig
  0 siblings, 0 replies; 19+ messages in thread
From: Thomas Koenig @ 2023-06-08 11:24 UTC (permalink / raw)
  To: FX Coudert; +Cc: sgk, Harald Anlauf via Fortran, gcc-patches, Michael Meissner

Hi FX,

>> Having a POWER system isn't enough, it also needs the IBM "advance
>> toolchain", and (at least with current distros, which default to
>> ibm long double), you need to dance counterclockwise three
>> times... I mean you need to invoke configure with some special magic
> 
> Thanks for the frank description, Thomas. To be honest, it reinforces > my feeling from when this was originally proposed and added: why> are 
we doing so much extra work for a feature that is used by> such a tiny 
fraction of our user base.

Well, I can tell you why I helped in this:  I like non-standard
architectures, I like 128-bit floats, and I like fast execution
speed of programs.  And if POWER having this goes any way towards
pushing Intel, AMD, or ARM towards having 128-bit floating point...
well, I would like that a lot.

And the need for all this magic will go away once distributions switch
to IEEE QP float as default.

By the way, if anybody wants to play with it, there should be no
problem in getting an account on the the OSL (virtual) machine
I ran this on.

As for the speed difference: A simple matrix multiplication has around
50 MFlops on my home box and around 250 MFlops on the POWER9 box I am
testing this on.  POWER10 should double that.

Best regards

	Thomas

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-08 10:17         ` Thomas Koenig
  2023-06-08 10:21           ` FX Coudert
@ 2023-06-08 16:31           ` Steve Kargl
  2023-06-08 18:17             ` Thomas Koenig
  2023-06-10 15:24           ` FX Coudert
  2 siblings, 1 reply; 19+ messages in thread
From: Steve Kargl @ 2023-06-08 16:31 UTC (permalink / raw)
  To: Thomas Koenig
  Cc: Harald Anlauf via Fortran, FX Coudert, gcc-patches, Michael Meissner

On Thu, Jun 08, 2023 at 12:17:02PM +0200, Thomas Koenig wrote:
> Hi together,
> 
> > > On 6/6/23 21:11, FX Coudert via Gcc-patches wrote:
> > > > Hi,
> > > > 
> > > > > I cannot see if there is proper support for kind=17 in your patch;
> > > > > at least the libgfortran/ieee/ieee_arithmetic.F90 part does not
> > > > > seem to have any related code.
> > > > 
> > > > Can real(kind=17) ever be an IEEE mode? If so, something seriously wrong happened, because the IEEE modules have no kind=17 mention in them anywhere.
> > > > 
> > > > Actually, where is the kind=17 documented?
> > > > 
> > > > FX
> > > 
> > > I was hoping for Thomas to come forward with some comment, as
> > > he was quite involved in related work.
> > > 
> > > There are several threads on IEEE128 for Power on the fortran ML
> > > e.g. around November/December 2021, January 2022.
> > > 
> > > I wasn't meaning to block your work, just wondering if the Power
> > > platform needs more attention here.
> > > 
> > 
> > % cd gcc/gccx/libgfortran
> > % grep HAVE_GFC_REAL_17 ieee/*
> > % troutmask:sgk[219] ls ieee
> > % ieee_arithmetic.F90     ieee_features.F90
> > % ieee_exceptions.F90     ieee_helper.c
> > 
> > There are zero hits for REAL(17) in the IEEE code.  If REAL(17)
> > is intended to be an IEEE-754 type, then it seems gfortran's
> > support was never added for it.  If anyone has access to a
> > power system, it's easy to test
> > 
> > program foo
> >     use ieee_arithmetic
> >     print *, ieee_support_datatype(1.e_17)
> > end program foo
> 
> The KIND=17 is a bit of a kludge.  It is not visible for
> user programs, they use KIND=16, but this is then translated
> to library calls as if it was KIND=17 if the IEEE 128-bit floats
> are selected:
> 
> $ cat ml.f90
> subroutine mm(a)
>   real(kind=16), dimension(:,:) :: a
>   print *,maxloc(a)
> end subroutine mm
> $ gfortran -S -mabi=ieeelongdouble ml.f90 && grep maxloc ml.s
>         bl _gfortran_maxloc0_4_r17
> $ gfortran -S  ml.f90 && grep maxloc ml.s
>         bl _gfortran_maxloc0_4_r16
> 
> On POWER, if IBM long double exists, it is GFC_REAL_16, with GFC_REAL_17
> being IEEE long double. Everywhere else, GFC_REAL_16 is IEEE long
> double.
> 
> If POWER gets the flag -mabi=ieeelongdouble, it uses IEEE long doubles.
> 
> If it gets the additionalflag -mcpu=power9 or -mcpu=power10, it uses
> the hardware instructions for the arithmetic instead of library calls.
> 

(trimming for length)

Thanks for the explanation.  As I likely will not use a POWER-based
system, I only loosely followed the discussion.  I don't remember
if ibm double-double is REAL(16) or REAL(17).  If ieee 128-bit is
REAL(16), then everything should (I believe) be okay.

> There is a virutal POWER machine at OSUL dedicated to the IEEE QP
> gfortran effort. It hasn't been used for some time, but it's still
> active. I just bootstrapped trunk there and ran all the IEEE from the
> testsuite manually, with
> 
> $ for a in *.f90; do echo "Testing $a"; gfortran -o $a.exe -fno-range-check
> -mcpu=power9 -mabi=ieeelongdouble -static-libgfortran $a signaling_1_c.c
> signaling_2_c.c ; ./$a.exe ; done 2>&1 | grep -v command-line
> Testing fma_1.f90

These could be misleading.  gfortran has pre-processor tokens
for REAL(10) and REAL(16).   If __GFC_REAL_16__ isn't defined
the ieee testing is skipped.

% cd gcc/gccx/gcc/fortran/
% grep __GFC_REAL_ *
cpp.cc: cpp_define (cpp_in, "__GFC_REAL_10__=1");
cpp.cc: cpp_define (cpp_in, "__GFC_REAL_16__=1");
invoke.texi:@code{__GFC_REAL_10__}, and @code{__GFC_REAL_16__}.
% more cpp.cc
...
  /* Pre-defined macros for non-required REAL kind types.  */
  for (gfc_real_info *rtype = gfc_real_kinds; rtype->kind != 0; rtype++)
    {
      if (rtype->kind == 10)
        cpp_define (cpp_in, "__GFC_REAL_10__=1");
      if (rtype->kind == 16)
        cpp_define (cpp_in, "__GFC_REAL_16__=1");
    }
...

Should we have a __GFC_REAL_17__?

% cd ../testsuite/gfortran.dg/
% grep __GFC_REAL ieee/*
ieee/dec_math_1.f90:  ! Note however that if both __GFC_REAL_10__ and __GFC_REAL_16__ are defined,
ieee/dec_math_1.f90:#if defined(__GFC_REAL_10__)
ieee/dec_math_1.f90:#elif defined(__GFC_REAL_16__)
ieee/dec_math_1.f90:#ifdef __GFC_REAL_10__
ieee/dec_math_1.f90:#elif defined(__GFC_REAL_16__)
ieee/dec_math_1.f90:#ifdef __GFC_REAL_16__
ieee/dec_math_1.f90:#elif defined(__GFC_REAL_10__)
ieee/ieee_11.F90:#ifdef __GFC_REAL_10__
ieee/ieee_11.F90:#ifdef __GFC_REAL_16__

-- 
Steve

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-08 16:31           ` Steve Kargl
@ 2023-06-08 18:17             ` Thomas Koenig
  0 siblings, 0 replies; 19+ messages in thread
From: Thomas Koenig @ 2023-06-08 18:17 UTC (permalink / raw)
  To: sgk; +Cc: Harald Anlauf via Fortran, FX Coudert, gcc-patches, Michael Meissner

Hi Steve,

> On Thu, Jun 08, 2023 at 12:17:02PM +0200, Thomas Koenig wrote:
[...]

> Thanks for the explanation.  As I likely will not use a POWER-based
> system, I only loosely followed the discussion.  I don't remember
> if ibm double-double is REAL(16) or REAL(17).  If ieee 128-bit is
> REAL(16), then everything should (I believe) be okay.

 From a user standpoint, REAL(16) is always used. We only use the 17
as a marker in the library, and to be able to have library versions
of IBM long double co-reside with IEEE long double.

>> There is a virutal POWER machine at OSUL dedicated to the IEEE QP
>> gfortran effort. It hasn't been used for some time, but it's still
>> active. I just bootstrapped trunk there and ran all the IEEE from the
>> testsuite manually, with
>>
>> $ for a in *.f90; do echo "Testing $a"; gfortran -o $a.exe -fno-range-check
>> -mcpu=power9 -mabi=ieeelongdouble -static-libgfortran $a signaling_1_c.c
>> signaling_2_c.c ; ./$a.exe ; done 2>&1 | grep -v command-line
>> Testing fma_1.f90
> 
> These could be misleading.  gfortran has pre-processor tokens
> for REAL(10) and REAL(16).   If __GFC_REAL_16__ isn't defined
> the ieee testing is skipped.

Hmm... need to check.  With the recently-built compiler:

$ cat tst.F90
program memain
#if __GFC_REAL_16__
   print *,"__GFC_REAL_16 found"
#endif
#if __GFC_REAL_17__
   print *,"__GFC_REAL_17 found"
#endif
   print *,"digits is ",digits(1._16)
end program memain
$ gfortran -static-libgfortran tst.F90 && ./a.out
  __GFC_REAL_16 found
  digits is          106
$ gfortran -static-libgfortran -mabi=ieeelongdouble -mcpu=power9 tst.F90 
&& ./a.out
  __GFC_REAL_16 found
  digits is          113

Looks clean.

[...]

> Should we have a __GFC_REAL_17__?

I don't think we need it - REAL(KIND=17) is not supported in
the compiler (we discussed and rejected that), and people
who mix IBM long double and IEEE long double will have no
joy with their programs; they need to recompile everything.

But we may have to do something about the files in the
thelibgfortran/ieee subdirectory.

Best regards

	Thomas

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-08 10:17         ` Thomas Koenig
  2023-06-08 10:21           ` FX Coudert
  2023-06-08 16:31           ` Steve Kargl
@ 2023-06-10 15:24           ` FX Coudert
  2023-06-11  9:50             ` Thomas Koenig
  2 siblings, 1 reply; 19+ messages in thread
From: FX Coudert @ 2023-06-10 15:24 UTC (permalink / raw)
  To: Thomas Koenig
  Cc: sgk, Harald Anlauf via Fortran, gcc-patches, Michael Meissner

Hi Thomas,

> The KIND=17 is a bit of a kludge.  It is not visible for
> user programs, they use KIND=16, but this is then translated
> to library calls as if it was KIND=17 if the IEEE 128-bit floats
> are selected

Can you check what the IEEE test results are when -mabi=ieeelongdouble is enabled?
It’s not even clear to me what the IEEE kinds selected should be, in this case, depending on -mabi=ieeelongdouble


> Regarding FX's patch: I am not quite sure that I am
> actually testing the right thing if running the testsuite
> there, so POWER should not hold up this patch.  If it turns
> out that POWER needs additonal work on IEEE, we can always
> add that later.

Actually, it sounds like the situation is: the same target can have two ABIs based on a compile-time flag. That sounds like a job for multilib, i.e., we should compile libgfortran twice, one for each ABI. I am sure this was considered and rejected, do you remember what was the rationale?

Thanks,
FX

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-07  3:15   ` Steve Kargl
@ 2023-06-10 15:42     ` FX Coudert
  0 siblings, 0 replies; 19+ messages in thread
From: FX Coudert @ 2023-06-10 15:42 UTC (permalink / raw)
  To: sgk; +Cc: Harald Anlauf via Fortran, gcc-patches

Given the agreement that the patch is not making things for powerpc worse, and the review by Steve, I have committed as https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=17bccd1d2c0fa1f08e0483c8ed841994a95febb0

Best,
FX

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-10 15:24           ` FX Coudert
@ 2023-06-11  9:50             ` Thomas Koenig
  2023-06-11 13:43               ` FX Coudert
  0 siblings, 1 reply; 19+ messages in thread
From: Thomas Koenig @ 2023-06-11  9:50 UTC (permalink / raw)
  To: FX Coudert; +Cc: sgk, Harald Anlauf via Fortran, gcc-patches, Michael Meissner

Hi FX,

 >> The KIND=17 is a bit of a kludge.  It is not visible for
 >> user programs, they use KIND=16, but this is then translated
 >> to library calls as if it was KIND=17 if the IEEE 128-bit floats
 >> are selected
 >
 > Can you check what the IEEE test results are when 
-mabi=ieeelongdouble is enabled?
Running

nohup make -j7 check-fortran 
RUNTESTFLAGS="--target_board=unix/-mabi=ieeelongdouble/-mcpu=power9"&

from the gcc subdirectory yielded only a single failure:

grep ^FAIL nohup.out
FAIL: gfortran.dg/gomp/target-update-1.f90   -O   scan-tree-dump gimple 
"#pragma omp target update to\\(c \\[len: [0-9]+\\]\\) to\\(present:a 
\\[len: [0-9]+\\]\\) to\\(e \\[len: [0-9]+\\]\\) from\\(present:b 
\\[len: [0-9]+\\]\\) from\\(d \\[len: [0-9]+\\]\\)

and also ran the correct tests, as seen from gfortran.log; for example:

Executing on host: gfortran 
/home/tkoenig/gcc/gcc/testsuite/gfortran.dg/ieee/large_2.f90 
-mabi=ieeelongdouble -mcpu=power9   -fdiagnostics-plain-output 
-fdiagnostics-plain-output    -O0   -pedantic-errors 
-fintrinsic-modules-path 
/home/tkoenig/gcc-bin/powerpc64le-unknown-linux-gnu/./libgfortran/ 
-fno-unsafe-math-optimizations -frounding-math -fsignaling-nans    -lm 
-o ./large_2.exe    (timeout = 300)
spawn -ignore SIGHUP gfortran 
/home/tkoenig/gcc/gcc/testsuite/gfortran.dg/ieee/large_2.f90 
-mabi=ieeelongdouble -mcpu=power9 -fdiagnostics-plain-output 
-fdiagnostics-plain-output -O0 -pedantic-errors -fintrinsic-modules-path 
/home/tkoenig/gcc-bin/powerpc64le-unknown-linux-gnu/./libgfortran/ 
-fno-unsafe-math-optimizations -frounding-math -fsignaling-nans -lm -o 
./large_2.exe^M
PASS: gfortran.dg/ieee/large_2.f90   -O0  (test for excess errors)
Setting LD_LIBRARY_PATH to 
.:/home/tkoenig/lib/../lib64:.:/home/tkoenig/lib/../lib64
Execution timeout is: 300
spawn [open ...]^M
PASS: gfortran.dg/ieee/large_2.f90   -O0  execution test

This is a test that fails on POWER with the IBM long double format,
so things look ok.  It also works when compiled individually.

So, this is looking good.

By the way, if you or any other gfortran maintainer would like an
account on the POWER virtual machine in question, that would be
no problem. I would ask the cluster administrators for permission
and then create the account (I have admin privileges on that
virtual machine).

 > It’s not even clear to me what the IEEE kinds selected should be, in 
this case, depending on -mabi=ieeelongdouble

The "KIND=17" stuff should only be visible inside the library.

 >
 >> Regarding FX's patch: I am not quite sure that I am
 >> actually testing the right thing if running the testsuite
 >> there, so POWER should not hold up this patch.  If it turns
 >> out that POWER needs additonal work on IEEE, we can always
 >> add that later.
 >
 > Actually, it sounds like the situation is: the same target can
 > have two ABIs based on a compile-time flag. That sounds like a job
 > for multilib, i.e., we should compile libgfortran twice, one for
 > each ABI. I am sure> this was considered and rejected, do you
 > remember what was the rationale?

I don't remember discussing multilib in this context, sorry.

Best regards

	Thomas

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
  2023-06-11  9:50             ` Thomas Koenig
@ 2023-06-11 13:43               ` FX Coudert
  0 siblings, 0 replies; 19+ messages in thread
From: FX Coudert @ 2023-06-11 13:43 UTC (permalink / raw)
  To: Thomas Koenig
  Cc: Steve Kargl, Harald Anlauf via Fortran, gcc-patches, Michael Meissner

Hi,

> Running
> nohup make -j7 check-fortran RUNTESTFLAGS="--target_board=unix/-mabi=ieeelongdouble/-mcpu=power9"&
> from the gcc subdirectory yielded only a single failure:

I dug more into the code and I understand why all tests are running: since db630423a97ec6690a8eb0e5c3cb186c91e3740d and 0c2d6aa1be2ea85e751852834986ae52d58134d3 all IEEE functions manipulating real or complex arguments are actually expanded fully inline (we retain functions in libgfortran for backward compatibility).

The only IEEE functions that depend on libgfortran runtime are the “IEEE_SUPPORT_*” functions.

FX

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2023-06-11 13:43 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-06 13:19 [PATCH] Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions FX
2023-06-06 15:43 ` Steve Kargl
2023-06-06 15:51   ` Steve Kargl
2023-06-06 18:21     ` Steve Kargl
2023-06-06 19:00 ` Harald Anlauf
2023-06-06 19:11   ` FX Coudert
2023-06-07 18:31     ` Harald Anlauf
2023-06-07 18:50       ` Steve Kargl
2023-06-08 10:17         ` Thomas Koenig
2023-06-08 10:21           ` FX Coudert
2023-06-08 11:24             ` Thomas Koenig
2023-06-08 16:31           ` Steve Kargl
2023-06-08 18:17             ` Thomas Koenig
2023-06-10 15:24           ` FX Coudert
2023-06-11  9:50             ` Thomas Koenig
2023-06-11 13:43               ` FX Coudert
2023-06-06 19:35 ` FX Coudert
2023-06-07  3:15   ` Steve Kargl
2023-06-10 15:42     ` FX Coudert

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).