aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJanne Blomqvist <jb@gcc.gnu.org>2018-08-21 22:36:13 +0300
committerJanne Blomqvist <jb@gcc.gnu.org>2018-08-21 22:36:13 +0300
commitfa3d2d38107033fc7620171474fbb7e2894cc79e (patch)
treeb106cd8075ae04792a2c458ffd2dbbe9d9711385
parent2b4c90656132abb8b8ad155d345c7d4fbf1687c9 (diff)
downloadgcc-fa3d2d38107033fc7620171474fbb7e2894cc79e.zip
gcc-fa3d2d38107033fc7620171474fbb7e2894cc79e.tar.gz
gcc-fa3d2d38107033fc7620171474fbb7e2894cc79e.tar.bz2
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
-rw-r--r--gcc/fortran/ChangeLog7
-rw-r--r--gcc/fortran/gfortran.texi16
-rw-r--r--gcc/fortran/trans-intrinsic.c55
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gfortran.dg/nan_1.f9035
5 files changed, 37 insertions, 80 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 0d9aca4..c91ffc9 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -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>
diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi
index 3920002..0f3f454 100644
--- a/gcc/fortran/gfortran.texi
+++ b/gcc/fortran/gfortran.texi
@@ -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
diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c
index db2bbab..387cf80 100644
--- a/gcc/fortran/trans-intrinsic.c
+++ b/gcc/fortran/trans-intrinsic.c
@@ -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,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 62cdaf2..f0a5ff5 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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>
diff --git a/gcc/testsuite/gfortran.dg/nan_1.f90 b/gcc/testsuite/gfortran.dg/nan_1.f90
index e64b4ce..1b39cc1 100644
--- a/gcc/testsuite/gfortran.dg/nan_1.f90
+++ b/gcc/testsuite/gfortran.dg/nan_1.f90
@@ -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