Commit fa3d2d38 by Janne Blomqvist

Unconditionally use MAX_EXPR/MIN_EXPR for MAX/MIN intrinsics

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
parent 2b4c9065
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>
......
......@@ -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
......
......@@ -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,
......
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>
......
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment