diff options
author | Francois-Xavier Coudert <fxcoudert@gcc.gnu.org> | 2022-09-09 19:12:31 +0200 |
---|---|---|
committer | Francois-Xavier Coudert <fxcoudert@gcc.gnu.org> | 2023-06-10 17:39:29 +0200 |
commit | 17bccd1d2c0fa1f08e0483c8ed841994a95febb0 (patch) | |
tree | a7215e7dc2894fd80f228c607b2959ec6ea3907f /gcc/fortran | |
parent | db80262475d28ae074a2cda7a1a6c2ea525791b9 (diff) | |
download | gcc-17bccd1d2c0fa1f08e0483c8ed841994a95febb0.zip gcc-17bccd1d2c0fa1f08e0483c8ed841994a95febb0.tar.gz gcc-17bccd1d2c0fa1f08e0483c8ed841994a95febb0.tar.bz2 |
Fortran: add Fortran 2018 IEEE_{MIN,MAX} functions
libgfortran/
* ieee/ieee_arithmetic.F90: Add IEEE_MIN_NUM, IEEE_MAX_NUM,
IEEE_MIN_NUM_MAG, and IEEE_MAX_NUM_MAG functions.
gcc/fortran/
* f95-lang.cc (gfc_init_builtin_functions): Add fmax() and
fmin() built-ins, and their variants.
* mathbuiltins.def: Add FMAX and FMIN built-ins.
* trans-intrinsic.cc (conv_intrinsic_ieee_minmax): New function.
(gfc_conv_ieee_arithmetic_function): Handle IEEE_MIN_NUM and
IEEE_MAX_NUM functions.
gcc/testsuite/
* gfortran.dg/ieee/minmax_1.f90: New test.
Diffstat (limited to 'gcc/fortran')
-rw-r--r-- | gcc/fortran/f95-lang.cc | 14 | ||||
-rw-r--r-- | gcc/fortran/mathbuiltins.def | 2 | ||||
-rw-r--r-- | gcc/fortran/trans-intrinsic.cc | 117 |
3 files changed, 133 insertions, 0 deletions
diff --git a/gcc/fortran/f95-lang.cc b/gcc/fortran/f95-lang.cc index 9684f1d..89944f4 100644 --- a/gcc/fortran/f95-lang.cc +++ b/gcc/fortran/f95-lang.cc @@ -836,6 +836,20 @@ gfc_init_builtin_functions (void) gfc_define_builtin ("__builtin_scalbnf", mfunc_float[2], BUILT_IN_SCALBNF, "scalbnf", ATTR_CONST_NOTHROW_LEAF_LIST); + gfc_define_builtin ("__builtin_fmaxl", mfunc_longdouble[1], + BUILT_IN_FMAXL, "fmaxl", ATTR_CONST_NOTHROW_LEAF_LIST); + gfc_define_builtin ("__builtin_fmax", mfunc_double[1], + BUILT_IN_FMAX, "fmax", ATTR_CONST_NOTHROW_LEAF_LIST); + gfc_define_builtin ("__builtin_fmaxf", mfunc_float[1], + BUILT_IN_FMAXF, "fmaxf", ATTR_CONST_NOTHROW_LEAF_LIST); + + gfc_define_builtin ("__builtin_fminl", mfunc_longdouble[1], + BUILT_IN_FMINL, "fminl", ATTR_CONST_NOTHROW_LEAF_LIST); + gfc_define_builtin ("__builtin_fmin", mfunc_double[1], + BUILT_IN_FMIN, "fmin", ATTR_CONST_NOTHROW_LEAF_LIST); + gfc_define_builtin ("__builtin_fminf", mfunc_float[1], + BUILT_IN_FMINF, "fminf", ATTR_CONST_NOTHROW_LEAF_LIST); + gfc_define_builtin ("__builtin_fmodl", mfunc_longdouble[1], BUILT_IN_FMODL, "fmodl", ATTR_CONST_NOTHROW_LEAF_LIST); gfc_define_builtin ("__builtin_fmod", mfunc_double[1], diff --git a/gcc/fortran/mathbuiltins.def b/gcc/fortran/mathbuiltins.def index c6bb3e8..51cb9a4 100644 --- a/gcc/fortran/mathbuiltins.def +++ b/gcc/fortran/mathbuiltins.def @@ -61,6 +61,8 @@ OTHER_BUILTIN (COPYSIGN, "copysign", 2, true) OTHER_BUILTIN (CPOW, "cpow", cpow, true) OTHER_BUILTIN (FABS, "fabs", 1, true) OTHER_BUILTIN (FMA, "fma", 3, true) +OTHER_BUILTIN (FMAX, "fmax", 2, true) +OTHER_BUILTIN (FMIN, "fmin", 2, true) OTHER_BUILTIN (FMOD, "fmod", 2, true) OTHER_BUILTIN (FREXP, "frexp", frexp, false) OTHER_BUILTIN (LOGB, "logb", 1, true) diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc index a0e1110..b6ea26e 100644 --- a/gcc/fortran/trans-intrinsic.cc +++ b/gcc/fortran/trans-intrinsic.cc @@ -10263,6 +10263,119 @@ conv_intrinsic_ieee_fma (gfc_se * se, gfc_expr * expr) } +/* Generate code for IEEE_{MIN,MAX}_NUM{,_MAG}. */ + +static void +conv_intrinsic_ieee_minmax (gfc_se * se, gfc_expr * expr, int max, + const char *name) +{ + tree args[2], func; + built_in_function fn; + + conv_ieee_function_args (se, expr, args, 2); + gcc_assert (TYPE_PRECISION (TREE_TYPE (args[0])) == TYPE_PRECISION (TREE_TYPE (args[1]))); + args[0] = gfc_evaluate_now (args[0], &se->pre); + args[1] = gfc_evaluate_now (args[1], &se->pre); + + if (startswith (name, "mag")) + { + /* IEEE_MIN_NUM_MAG and IEEE_MAX_NUM_MAG translate to C functions + fminmag() and fmaxmag(), which do not exist as built-ins. + + Following glibc, we emit this: + + fminmag (x, y) { + ax = ABS (x); + ay = ABS (y); + if (isless (ax, ay)) + return x; + else if (isgreater (ax, ay)) + return y; + else if (ax == ay) + return x < y ? x : y; + else if (issignaling (x) || issignaling (y)) + return x + y; + else + return isnan (y) ? x : y; + } + + fmaxmag (x, y) { + ax = ABS (x); + ay = ABS (y); + if (isgreater (ax, ay)) + return x; + else if (isless (ax, ay)) + return y; + else if (ax == ay) + return x > y ? x : y; + else if (issignaling (x) || issignaling (y)) + return x + y; + else + return isnan (y) ? x : y; + } + + */ + + tree abs0, abs1, sig0, sig1; + tree cond1, cond2, cond3, cond4, cond5; + tree res; + tree type = TREE_TYPE (args[0]); + + func = gfc_builtin_decl_for_float_kind (BUILT_IN_FABS, expr->ts.kind); + abs0 = build_call_expr_loc (input_location, func, 1, args[0]); + abs1 = build_call_expr_loc (input_location, func, 1, args[1]); + abs0 = gfc_evaluate_now (abs0, &se->pre); + abs1 = gfc_evaluate_now (abs1, &se->pre); + + cond5 = build_call_expr_loc (input_location, + builtin_decl_explicit (BUILT_IN_ISNAN), + 1, args[1]); + res = fold_build3_loc (input_location, COND_EXPR, type, cond5, + args[0], args[1]); + + sig0 = build_call_expr_loc (input_location, + builtin_decl_explicit (BUILT_IN_ISSIGNALING), + 1, args[0]); + sig1 = build_call_expr_loc (input_location, + builtin_decl_explicit (BUILT_IN_ISSIGNALING), + 1, args[1]); + cond4 = fold_build2_loc (input_location, TRUTH_ORIF_EXPR, + logical_type_node, sig0, sig1); + res = fold_build3_loc (input_location, COND_EXPR, type, cond4, + fold_build2_loc (input_location, PLUS_EXPR, + type, args[0], args[1]), + res); + + cond3 = fold_build2_loc (input_location, EQ_EXPR, logical_type_node, + abs0, abs1); + res = fold_build3_loc (input_location, COND_EXPR, type, cond3, + fold_build2_loc (input_location, + max ? MAX_EXPR : MIN_EXPR, + type, args[0], args[1]), + res); + + func = builtin_decl_explicit (max ? BUILT_IN_ISLESS : BUILT_IN_ISGREATER); + cond2 = build_call_expr_loc (input_location, func, 2, abs0, abs1); + res = fold_build3_loc (input_location, COND_EXPR, type, cond2, + args[1], res); + + func = builtin_decl_explicit (max ? BUILT_IN_ISGREATER : BUILT_IN_ISLESS); + cond1 = build_call_expr_loc (input_location, func, 2, abs0, abs1); + res = fold_build3_loc (input_location, COND_EXPR, type, cond1, + args[0], res); + + se->expr = res; + } + else + { + /* IEEE_MIN_NUM and IEEE_MAX_NUM translate to fmin() and fmax(). */ + fn = max ? BUILT_IN_FMAX : BUILT_IN_FMIN; + func = gfc_builtin_decl_for_float_kind (fn, expr->ts.kind); + se->expr = build_call_expr_loc_array (input_location, func, 2, args); + } +} + + /* Generate code for an intrinsic function from the IEEE_ARITHMETIC module. */ @@ -10301,6 +10414,10 @@ gfc_conv_ieee_arithmetic_function (gfc_se * se, gfc_expr * expr) conv_intrinsic_ieee_value (se, expr); else if (startswith (name, "_gfortran_ieee_fma")) conv_intrinsic_ieee_fma (se, expr); + else if (startswith (name, "_gfortran_ieee_min_num_")) + conv_intrinsic_ieee_minmax (se, expr, 0, name + 23); + else if (startswith (name, "_gfortran_ieee_max_num_")) + conv_intrinsic_ieee_minmax (se, expr, 1, name + 23); else /* It is not among the functions we translate directly. We return false, so a library function call is emitted. */ |