diff options
author | fxcoudert <fxcoudert@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-08-03 21:26:10 +0000 |
---|---|---|
committer | fxcoudert <fxcoudert@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-08-03 21:26:10 +0000 |
commit | ef080b63ed63be1dfb4d9d11b0f40d75daa09f9d (patch) | |
tree | b3c3360111641d52b502bddd36c0a4ce24d565cf /gcc/fortran | |
parent | 535fca1102af31bb0dd35fbc901af77915ee57e2 (diff) | |
download | gcc-ef080b63ed63be1dfb4d9d11b0f40d75daa09f9d.tar.gz |
PR fortran/31202
* f95-lang.c (gfc_init_builtin_functions): Defin builtins for
lround{f,,l} and llround{f,,l}.
* trans-intrinsic.c (build_fix_expr): Generate calls to the
{l,}round{f,,l} functions.
* intrinsics/c99_functions.c (roundl,lroundf,lround,lroundl,
llroundf,llround,llroundl): New functions.
* c99_protos.h (roundl,lroundf,lround,lroundl,llroundf,llround,
llroundl): New prototypes.
* configure.ac: Check for lroundf, lround, lroundl, llroundf,
llround and llroundl.
* configure: Regenerate.
* Makefile.in: Regenerate.
* config.h.in: Regenerate.
* gfortran.dg/nint_2.f90: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@127185 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/fortran')
-rw-r--r-- | gcc/fortran/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/fortran/f95-lang.c | 27 | ||||
-rw-r--r-- | gcc/fortran/trans-intrinsic.c | 70 |
3 files changed, 83 insertions, 22 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index c8e4a3c9931..5d1695bf2e4 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,11 @@ +2007-08-03 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org> + + PR fortran/31202 + * f95-lang.c (gfc_init_builtin_functions): Defin builtins for + lround{f,,l} and llround{f,,l}. + * trans-intrinsic.c (build_fix_expr): Generate calls to the + {l,}round{f,,l} functions. + 2007-08-01 Thomas Koenig <tkoenig@gcc.gnu.org> PR libfortran/32954 diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c index 0cecac0b0b4..425f4d3fecd 100644 --- a/gcc/fortran/f95-lang.c +++ b/gcc/fortran/f95-lang.c @@ -852,7 +852,7 @@ gfc_init_builtin_functions (void) tree func_double_doublep_doublep; tree func_longdouble_longdoublep_longdoublep; tree ftype, ptype; - tree tmp; + tree tmp, type; tree builtin_types[(int) BT_LAST + 1]; build_builtin_fntypes (mfunc_float, float_type_node); @@ -942,6 +942,31 @@ gfc_init_builtin_functions (void) gfc_define_builtin ("__builtin_fmodf", mfunc_float[1], BUILT_IN_FMODF, "fmodf", true); + /* lround{f,,l} and llround{f,,l} */ + type = tree_cons (NULL_TREE, float_type_node, void_list_node); + tmp = build_function_type (long_integer_type_node, type); + gfc_define_builtin ("__builtin_lroundf", tmp, BUILT_IN_LROUNDF, + "lroundf", true); + tmp = build_function_type (long_long_integer_type_node, type); + gfc_define_builtin ("__builtin_llroundf", tmp, BUILT_IN_LLROUNDF, + "llroundf", true); + + type = tree_cons (NULL_TREE, double_type_node, void_list_node); + tmp = build_function_type (long_integer_type_node, type); + gfc_define_builtin ("__builtin_lround", tmp, BUILT_IN_LROUND, + "lround", true); + tmp = build_function_type (long_long_integer_type_node, type); + gfc_define_builtin ("__builtin_llround", tmp, BUILT_IN_LLROUND, + "llround", true); + + type = tree_cons (NULL_TREE, long_double_type_node, void_list_node); + tmp = build_function_type (long_integer_type_node, type); + gfc_define_builtin ("__builtin_lroundl", tmp, BUILT_IN_LROUNDL, + "lroundl", true); + tmp = build_function_type (long_long_integer_type_node, type); + gfc_define_builtin ("__builtin_llroundl", tmp, BUILT_IN_LLROUNDL, + "llroundl", true); + /* These are used to implement the ** operator. */ gfc_define_builtin ("__builtin_powl", mfunc_longdouble[1], BUILT_IN_POWL, "powl", true); diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index 39deadb1a16..dc672401b42 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #include "system.h" #include "coretypes.h" +#include "tm.h" #include "tree.h" #include "ggc.h" #include "toplev.h" @@ -308,34 +309,57 @@ build_fixbound_expr (stmtblock_t * pblock, tree arg, tree type, int up) } -/* This is needed because the gcc backend only implements FIX_TRUNC_EXPR - NINT(x) = INT(x + ((x > 0) ? 0.5 : -0.5)). */ +/* Round to nearest integer, away from zero. */ static tree -build_round_expr (stmtblock_t * pblock, tree arg, tree type) +build_round_expr (tree arg, tree restype) { tree tmp; - tree cond; - tree neg; - tree pos; tree argtype; - REAL_VALUE_TYPE r; + tree fn; + bool longlong, convert; + int argprec, resprec; argtype = TREE_TYPE (arg); - arg = gfc_evaluate_now (arg, pblock); + argprec = TYPE_PRECISION (argtype); + resprec = TYPE_PRECISION (restype); - real_from_string (&r, "0.5"); - pos = build_real (argtype, r); - - real_from_string (&r, "-0.5"); - neg = build_real (argtype, r); + /* Depending on the type of the result, choose the long int intrinsic + (lround family) or long long intrinsic (llround). We might also + need to convert the result afterwards. */ + if (resprec <= LONG_TYPE_SIZE) + { + longlong = false; + if (resprec != LONG_TYPE_SIZE) + convert = true; + else + convert = false; + } + else if (resprec <= LONG_LONG_TYPE_SIZE) + { + longlong = true; + if (resprec != LONG_LONG_TYPE_SIZE) + convert = true; + else + convert = false; + } + else + gcc_unreachable (); - tmp = gfc_build_const (argtype, integer_zero_node); - cond = fold_build2 (GT_EXPR, boolean_type_node, arg, tmp); + /* Now, depending on the argument type, we choose between intrinsics. */ + if (argprec == TYPE_PRECISION (float_type_node)) + fn = built_in_decls[longlong ? BUILT_IN_LLROUNDF : BUILT_IN_LROUNDF]; + else if (argprec == TYPE_PRECISION (double_type_node)) + fn = built_in_decls[longlong ? BUILT_IN_LLROUND : BUILT_IN_LROUND]; + else if (argprec == TYPE_PRECISION (long_double_type_node)) + fn = built_in_decls[longlong ? BUILT_IN_LLROUNDL : BUILT_IN_LROUNDL]; + else + gcc_unreachable (); - tmp = fold_build3 (COND_EXPR, argtype, cond, pos, neg); - tmp = fold_build2 (PLUS_EXPR, argtype, arg, tmp); - return fold_build1 (FIX_TRUNC_EXPR, type, tmp); + tmp = build_call_expr (fn, 1, arg); + if (convert) + tmp = fold_convert (restype, tmp); + return tmp; } @@ -358,11 +382,15 @@ build_fix_expr (stmtblock_t * pblock, tree arg, tree type, break; case RND_ROUND: - return build_round_expr (pblock, arg, type); + return build_round_expr (arg, type); + break; - default: - gcc_assert (op == RND_TRUNC); + case RND_TRUNC: return build1 (FIX_TRUNC_EXPR, type, arg); + break; + + default: + gcc_unreachable (); } } |