From fa3d2d38107033fc7620171474fbb7e2894cc79e Mon Sep 17 00:00:00 2001 From: Janne Blomqvist Date: Tue, 21 Aug 2018 22:36:13 +0300 Subject: [PATCH] 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 * 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 * gfortran.dg/nan_1.f90: Remove tests that test MAX/MIN with NaNs. From-SVN: r263751 --- gcc/fortran/ChangeLog | 7 ++++ gcc/fortran/gfortran.texi | 16 +++++++++ gcc/fortran/trans-intrinsic.c | 55 ++++++----------------------- gcc/testsuite/ChangeLog | 4 +++ gcc/testsuite/gfortran.dg/nan_1.f90 | 35 ------------------ 5 files changed, 37 insertions(+), 80 deletions(-) diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 0d9aca49277..c91ffc93493 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,10 @@ +2018-08-21 Janne Blomqvist + + * 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 Thomas Koenig diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi index 39200027305..0f3f454ff83 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 db2bbab1412..387cf80b921 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 62cdaf2741f..f0a5ff50877 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2018-08-21 Janne Blomqvist + + * gfortran.dg/nan_1.f90: Remove tests that test MAX/MIN with NaNs. + 2018-08-21 Nicolas Koenig Thomas Koenig diff --git a/gcc/testsuite/gfortran.dg/nan_1.f90 b/gcc/testsuite/gfortran.dg/nan_1.f90 index e64b4ce65e1..1b39cc1f21c 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 -- 2.30.2