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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@263751
138bc75d-0d04-0410-961f-
82ee72b054a4
+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>
* 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::
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
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;
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,
+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>
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
! 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