Unconditionally use MAX_EXPR/MIN_EXPR for MAX/MIN intrinsics
authorJanne Blomqvist <jb@gcc.gnu.org>
Tue, 21 Aug 2018 19:36:13 +0000 (22:36 +0300)
committerJanne Blomqvist <jb@gcc.gnu.org>
Tue, 21 Aug 2018 19:36:13 +0000 (22:36 +0300)
For floating point types, the question is what MAX(a, NaN) or MIN(a,
NaN) should return (where "a" is a normal number).  There are valid
usecases for returning either one, but the Fortran standard doesn't
specify which one should be chosen.  Also, there is no consensus among
other tested compilers.  In short, it's a mess.  So lets just do
whatever is fastest, which is using MAX_EXPR/MIN_EXPR which are not
defined to do anything in particular if one of the operands is a NaN.

gcc/fortran/ChangeLog:

2018-08-21  Janne Blomqvist  <jb@gcc.gnu.org>

* trans-intrinsic.c (gfc_conv_intrinsic_minmax): Use
MAX_EXPR/MIN_EXPR unconditionally for real arguments.
* gfortran.texi (Compiler Characteristics): Document MAX/MIN
behavior wrt NaN.

gcc/testsuite/ChangeLog:

2018-08-21  Janne Blomqvist  <jb@gcc.gnu.org>

* gfortran.dg/nan_1.f90: Remove tests that test MAX/MIN with NaNs.

From-SVN: r263751

gcc/fortran/ChangeLog
gcc/fortran/gfortran.texi
gcc/fortran/trans-intrinsic.c
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/nan_1.f90

index 0d9aca49277ae5405e23e0c087fcbe220b495281..c91ffc93493ef7f8fcd74224cd9c5a1858134e5d 100644 (file)
@@ -1,3 +1,10 @@
+2018-08-21  Janne Blomqvist  <jb@gcc.gnu.org>
+
+       * trans-intrinsic.c (gfc_conv_intrinsic_minmax): Use
+       MAX_EXPR/MIN_EXPR unconditionally for real arguments.
+       * gfortran.texi (Compiler Characteristics): Document MAX/MIN
+       behavior wrt NaN.
+
 2018-08-21  Nicolas Koenig  <koenigni@gcc.gnu.org>
        Thomas Koenig <tkoenig@gcc.gnu.org>
 
index 392000273055c2d241877f1b79c3499d8e485d1e..0f3f454ff83692a9c0008817d697cf55fbed33f2 100644 (file)
@@ -1177,6 +1177,7 @@ might in some way or another become visible to the programmer.
 * KIND Type Parameters::
 * Internal representation of LOGICAL variables::
 * Evaluation of logical expressions::
+* MAX and MIN intrinsics with REAL NaN arguments::
 * Thread-safety of the runtime library::
 * Data consistency and durability::
 * Files opened without an explicit ACTION= specifier::
@@ -1265,6 +1266,21 @@ program flow and subsequent results, GNU Fortran throws warnings for such
 situations with the @option{-Wfunction-elimination} flag.
 
 
+@node MAX and MIN intrinsics with REAL NaN arguments
+@section MAX and MIN intrinsics with REAL NaN arguments
+@cindex MAX, MIN, NaN
+
+The Fortran standard does not specify what the result of the
+@code{MAX} and @code{MIN} intrinsics are if one of the arguments is a
+@code{NaN}.  Accordingly, the GNU Fortran compiler does not specify
+that either, as this allows for faster and more compact code to be
+generated.  If the programmer wishes to take some specific action in
+case one of the arguments is a @code{NaN}, it is necessary to
+explicitly test the arguments before calling @code{MAX} or @code{MIN},
+e.g. with the @code{IEEE_IS_NAN} function from the intrinsic module
+@code{IEEE_ARITHMETIC}.
+
+
 @node Thread-safety of the runtime library
 @section Thread-safety of the runtime library
 @cindex thread-safety, threads
index db2bbab14123966ca99bcdc34d1f7afa286d7b84..387cf80b921fad90c3c6f93d7a95e4ff07d66712 100644 (file)
@@ -3914,8 +3914,6 @@ gfc_conv_intrinsic_minmax (gfc_se * se, gfc_expr * expr, enum tree_code op)
   mvar = gfc_create_var (type, "M");
   gfc_add_modify (&se->pre, mvar, args[0]);
 
-  internal_fn ifn = op == GT_EXPR ? IFN_FMAX : IFN_FMIN;
-
   for (i = 1, argexpr = argexpr->next; i < nargs; i++, argexpr = argexpr->next)
     {
       tree cond = NULL_TREE;
@@ -3936,49 +3934,16 @@ gfc_conv_intrinsic_minmax (gfc_se * se, gfc_expr * expr, enum tree_code op)
        val = gfc_evaluate_now (val, &se->pre);
 
       tree calc;
-      /* If we dealing with integral types or we don't care about NaNs
-        just do a MIN/MAX_EXPR.  */
-      if (!HONOR_NANS (type) && !HONOR_SIGNED_ZEROS (type))
-       {
-
-         tree_code code = op == GT_EXPR ? MAX_EXPR : MIN_EXPR;
-         calc = fold_build2_loc (input_location, code, type,
-                                 convert (type, val), mvar);
-         tmp = build2_v (MODIFY_EXPR, mvar, calc);
-
-       }
-      /* If we care about NaNs and we have internal functions available for
-        fmin/fmax to perform the comparison, use those.  */
-      else if (SCALAR_FLOAT_TYPE_P (type)
-             && direct_internal_fn_supported_p (ifn, type, OPTIMIZE_FOR_SPEED))
-       {
-         calc = build_call_expr_internal_loc (input_location, ifn, type,
-                                               2, mvar, convert (type, val));
-         tmp = build2_v (MODIFY_EXPR, mvar, calc);
-
-       }
-      /* Otherwise expand to:
-       mvar = a1;
-       if (a2 .op. mvar || isnan (mvar))
-         mvar = a2;
-       if (a3 .op. mvar || isnan (mvar))
-         mvar = a3;
-       ...  */
-      else
-       {
-         tree isnan = build_call_expr_loc (input_location,
-                                       builtin_decl_explicit (BUILT_IN_ISNAN),
-                                       1, mvar);
-         tmp = fold_build2_loc (input_location, op, logical_type_node,
-                                convert (type, val), mvar);
-
-         tmp = fold_build2_loc (input_location, TRUTH_OR_EXPR,
-                                 logical_type_node, tmp,
-                                 fold_convert (logical_type_node, isnan));
-         tmp = build3_v (COND_EXPR, tmp,
-                         build2_v (MODIFY_EXPR, mvar, convert (type, val)),
-                         build_empty_stmt (input_location));
-       }
+      /* For floating point types, the question is what MAX(a, NaN) or
+        MIN(a, NaN) should return (where "a" is a normal number).
+        There are valid usecase for returning either one, but the
+        Fortran standard doesn't specify which one should be chosen.
+        Also, there is no consensus among other tested compilers.  In
+        short, it's a mess.  So lets just do whatever is fastest.  */
+      tree_code code = op == GT_EXPR ? MAX_EXPR : MIN_EXPR;
+      calc = fold_build2_loc (input_location, code, type,
+                             convert (type, val), mvar);
+      tmp = build2_v (MODIFY_EXPR, mvar, calc);
 
       if (cond != NULL_TREE)
        tmp = build3_v (COND_EXPR, cond, tmp,
index 62cdaf2741fd9cd82d42faffeff830f239ad8a9e..f0a5ff50877dec2e93bcab66dc93328641a0f59b 100644 (file)
@@ -1,3 +1,7 @@
+2018-08-21  Janne Blomqvist  <jb@gcc.gnu.org>
+
+       * gfortran.dg/nan_1.f90: Remove tests that test MAX/MIN with NaNs.
+
 2018-08-21  Nicolas Koenig  <koenigni@gcc.gnu.org>
        Thomas Koenig <tkoenig@gcc.gnu.org>
 
index e64b4ce65e1c29523cbdc7e5605ef929bc4a79b3..1b39cc1f21caaa11e8e9ce6974ba1e65e1e580dd 100644 (file)
@@ -66,35 +66,12 @@ program test
   if (isinf(-nan) .or. isinf(-large) .or. .not. isinf(-inf)) STOP 4
 
   ! Check that MIN and MAX behave correctly
-  if (max(2.0, nan) /= 2.0) STOP 5
-  if (min(2.0, nan) /= 2.0) STOP 6
-  if (max(nan, 2.0) /= 2.0) STOP 7
-  if (min(nan, 2.0) /= 2.0) STOP 8
-
-  if (max(2.d0, nan) /= 2.d0) STOP 9! { dg-warning "Extension: Different type kinds" }
-  if (min(2.d0, nan) /= 2.d0) STOP 10! { dg-warning "Extension: Different type kinds" }
-  if (max(nan, 2.d0) /= 2.d0) STOP 11! { dg-warning "Extension: Different type kinds" }
-  if (min(nan, 2.d0) /= 2.d0) STOP 12! { dg-warning "Extension: Different type kinds" }
 
   if (.not. isnan(min(nan,nan))) STOP 13
   if (.not. isnan(max(nan,nan))) STOP 14
 
   ! Same thing, with more arguments
 
-  if (max(3.0, 2.0, nan) /= 3.0) STOP 15
-  if (min(3.0, 2.0, nan) /= 2.0) STOP 16
-  if (max(3.0, nan, 2.0) /= 3.0) STOP 17
-  if (min(3.0, nan, 2.0) /= 2.0) STOP 18
-  if (max(nan, 3.0, 2.0) /= 3.0) STOP 19
-  if (min(nan, 3.0, 2.0) /= 2.0) STOP 20
-
-  if (max(3.d0, 2.d0, nan) /= 3.d0) STOP 21! { dg-warning "Extension: Different type kinds" }
-  if (min(3.d0, 2.d0, nan) /= 2.d0) STOP 22! { dg-warning "Extension: Different type kinds" }
-  if (max(3.d0, nan, 2.d0) /= 3.d0) STOP 23! { dg-warning "Extension: Different type kinds" }
-  if (min(3.d0, nan, 2.d0) /= 2.d0) STOP 24! { dg-warning "Extension: Different type kinds" }
-  if (max(nan, 3.d0, 2.d0) /= 3.d0) STOP 25! { dg-warning "Extension: Different type kinds" }
-  if (min(nan, 3.d0, 2.d0) /= 2.d0) STOP 26! { dg-warning "Extension: Different type kinds" }
-
   if (.not. isnan(min(nan,nan,nan))) STOP 27
   if (.not. isnan(max(nan,nan,nan))) STOP 28
   if (.not. isnan(min(nan,nan,nan,nan))) STOP 29
@@ -105,20 +82,8 @@ program test
   ! Large values, INF and NaNs
   if (.not. isinf(max(large, inf))) STOP 33
   if (isinf(min(large, inf))) STOP 34
-  if (.not. isinf(max(nan, large, inf))) STOP 35
-  if (isinf(min(nan, large, inf))) STOP 36
-  if (.not. isinf(max(large, nan, inf))) STOP 37
-  if (isinf(min(large, nan, inf))) STOP 38
-  if (.not. isinf(max(large, inf, nan))) STOP 39
-  if (isinf(min(large, inf, nan))) STOP 40
 
   if (.not. isinf(min(-large, -inf))) STOP 41
   if (isinf(max(-large, -inf))) STOP 42
-  if (.not. isinf(min(nan, -large, -inf))) STOP 43
-  if (isinf(max(nan, -large, -inf))) STOP 44
-  if (.not. isinf(min(-large, nan, -inf))) STOP 45
-  if (isinf(max(-large, nan, -inf))) STOP 46
-  if (.not. isinf(min(-large, -inf, nan))) STOP 47
-  if (isinf(max(-large, -inf, nan))) STOP 48
 
 end program test