public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [gfortran,patch] Fix code generated for NINT
@ 2007-07-31 21:39 FX Coudert
  2007-07-31 21:56 ` Paul Thomas
  0 siblings, 1 reply; 3+ messages in thread
From: FX Coudert @ 2007-07-31 21:39 UTC (permalink / raw)
  To: GFORTRAN list, GCC-patches list

[-- Attachment #1: Type: text/plain, Size: 589 bytes --]

Attached patch fixes PR31202 by correcting the code generated for  
calls to the intrinsic NINT (and ANINT). Instead of adding 0.5 and  
rounding by casting into an integer, we simply call the lround (or  
llround) functions. A fallback implementation of these functions is  
provided for libgfortran.

I've bootstrapped and regtested on x86_64-linux, but I'd be glad if  
someone with a platform without full C99 support, and especiall  
lround, could test it.  I once had access to a sparc-solaris2.9,  
which fulfilled these criteria, but not more.

OK for mainline?



:ADDPATCH 31202:

[-- Attachment #2: nint.ChangeLog --]
[-- Type: application/octet-stream, Size: 834 bytes --]

2007-07-31  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-07-31  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>

	PR fortran/31202
	* 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.


2007-07-31  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>

	PR fortran/31202
	* gfortran.dg/nint_2.f90: New test.

[-- Attachment #3: nint.diff --]
[-- Type: application/octet-stream, Size: 27705 bytes --]

Index: gcc/fortran/f95-lang.c
===================================================================
--- gcc/fortran/f95-lang.c	(revision 127059)
+++ gcc/fortran/f95-lang.c	(working copy)
@@ -853,7 +853,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);
@@ -943,6 +943,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);
Index: gcc/fortran/trans-intrinsic.c
===================================================================
--- gcc/fortran/trans-intrinsic.c	(revision 127059)
+++ gcc/fortran/trans-intrinsic.c	(working copy)
@@ -26,6 +26,7 @@ Software Foundation, 51 Franklin Street,
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "ggc.h"
 #include "toplev.h"
@@ -309,34 +310,57 @@ build_fixbound_expr (stmtblock_t * pbloc
 }
 
 
-/* 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;
 }
 
 
@@ -359,11 +383,15 @@ build_fix_expr (stmtblock_t * pblock, tr
       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 ();
     }
 }
 
Index: libgfortran/configure
===================================================================
--- libgfortran/configure	(revision 127059)
+++ libgfortran/configure	(working copy)
@@ -26314,6 +26314,468 @@ _ACEOF
 
 fi
 
+echo "$as_me:$LINENO: checking for lroundf in -lm" >&5
+echo $ECHO_N "checking for lroundf in -lm... $ECHO_C" >&6
+if test "${ac_cv_lib_m_lroundf+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+if test x$gcc_no_link = xyes; then
+  { { echo "$as_me:$LINENO: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&5
+echo "$as_me: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char lroundf ();
+int
+main ()
+{
+lroundf ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_m_lroundf=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_m_lroundf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_m_lroundf" >&5
+echo "${ECHO_T}$ac_cv_lib_m_lroundf" >&6
+if test $ac_cv_lib_m_lroundf = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LROUNDF 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for lround in -lm" >&5
+echo $ECHO_N "checking for lround in -lm... $ECHO_C" >&6
+if test "${ac_cv_lib_m_lround+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+if test x$gcc_no_link = xyes; then
+  { { echo "$as_me:$LINENO: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&5
+echo "$as_me: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char lround ();
+int
+main ()
+{
+lround ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_m_lround=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_m_lround=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_m_lround" >&5
+echo "${ECHO_T}$ac_cv_lib_m_lround" >&6
+if test $ac_cv_lib_m_lround = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LROUND 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for lroundl in -lm" >&5
+echo $ECHO_N "checking for lroundl in -lm... $ECHO_C" >&6
+if test "${ac_cv_lib_m_lroundl+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+if test x$gcc_no_link = xyes; then
+  { { echo "$as_me:$LINENO: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&5
+echo "$as_me: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char lroundl ();
+int
+main ()
+{
+lroundl ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_m_lroundl=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_m_lroundl=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_m_lroundl" >&5
+echo "${ECHO_T}$ac_cv_lib_m_lroundl" >&6
+if test $ac_cv_lib_m_lroundl = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LROUNDL 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for llroundf in -lm" >&5
+echo $ECHO_N "checking for llroundf in -lm... $ECHO_C" >&6
+if test "${ac_cv_lib_m_llroundf+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+if test x$gcc_no_link = xyes; then
+  { { echo "$as_me:$LINENO: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&5
+echo "$as_me: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char llroundf ();
+int
+main ()
+{
+llroundf ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_m_llroundf=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_m_llroundf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_m_llroundf" >&5
+echo "${ECHO_T}$ac_cv_lib_m_llroundf" >&6
+if test $ac_cv_lib_m_llroundf = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LLROUNDF 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for llround in -lm" >&5
+echo $ECHO_N "checking for llround in -lm... $ECHO_C" >&6
+if test "${ac_cv_lib_m_llround+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+if test x$gcc_no_link = xyes; then
+  { { echo "$as_me:$LINENO: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&5
+echo "$as_me: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char llround ();
+int
+main ()
+{
+llround ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_m_llround=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_m_llround=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_m_llround" >&5
+echo "${ECHO_T}$ac_cv_lib_m_llround" >&6
+if test $ac_cv_lib_m_llround = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LLROUND 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for llroundl in -lm" >&5
+echo $ECHO_N "checking for llroundl in -lm... $ECHO_C" >&6
+if test "${ac_cv_lib_m_llroundl+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+if test x$gcc_no_link = xyes; then
+  { { echo "$as_me:$LINENO: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&5
+echo "$as_me: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char llroundl ();
+int
+main ()
+{
+llroundl ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_m_llroundl=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_m_llroundl=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_m_llroundl" >&5
+echo "${ECHO_T}$ac_cv_lib_m_llroundl" >&6
+if test $ac_cv_lib_m_llroundl = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LLROUNDL 1
+_ACEOF
+
+fi
+
 echo "$as_me:$LINENO: checking for scalbnf in -lm" >&5
 echo $ECHO_N "checking for scalbnf in -lm... $ECHO_C" >&6
 if test "${ac_cv_lib_m_scalbnf+set}" = set; then
Index: libgfortran/Makefile.in
===================================================================
--- libgfortran/Makefile.in	(revision 127059)
+++ libgfortran/Makefile.in	(working copy)
@@ -50,8 +50,8 @@ am__aclocal_m4_deps = $(top_srcdir)/../c
 	$(top_srcdir)/../config/multi.m4 \
 	$(top_srcdir)/../config/stdint.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
-	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/acinclude.m4 \
-	$(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+	$(top_srcdir)/acinclude.m4 $(top_srcdir)/../config/acx.m4 \
 	$(top_srcdir)/../config/no-executables.m4 \
 	$(top_srcdir)/../libtool.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
@@ -343,9 +343,13 @@ SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
 VERSION = @VERSION@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_AS = @ac_ct_AS@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
 ac_ct_FC = @ac_ct_FC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
 am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
 am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
 am__include = @am__include@
@@ -362,9 +366,6 @@ build_os = @build_os@
 build_subdir = @build_subdir@
 build_vendor = @build_vendor@
 datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
@@ -375,23 +376,19 @@ host_cpu = @host_cpu@
 host_os = @host_os@
 host_subdir = @host_subdir@
 host_vendor = @host_vendor@
-htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
-localedir = @localedir@
 localstatedir = @localstatedir@
 lt_ECHO = @lt_ECHO@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 multi_basedir = @multi_basedir@
 oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
-psdir = @psdir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 sysconfdir = @sysconfdir@
Index: libgfortran/intrinsics/c99_functions.c
===================================================================
--- libgfortran/intrinsics/c99_functions.c	(revision 127059)
+++ libgfortran/intrinsics/c99_functions.c	(working copy)
@@ -500,6 +500,35 @@ powf(float x, float y)
 
 /* Algorithm by Steven G. Kargl.  */
 
+#if !defined(HAVE_ROUNDL) && defined(HAVE_CEILL)
+#define HAVE_ROUNDL 1
+/* Round to nearest integral value.  If the argument is halfway between two
+   integral values then round away from zero.  */
+
+long double
+roundl(long double x)
+{
+   long double t;
+   if (!isfinite (x))
+     return (x);
+
+   if (x >= 0.0)
+    {
+      t = ceill(x);
+      if (t - x > 0.5)
+	t -= 1.0;
+      return (t);
+    } 
+   else 
+    {
+      t = ceill(-x);
+      if (t + x > 0.5)
+	t -= 1.0;
+      return (-t);
+    }
+}
+#endif
+
 #ifndef HAVE_ROUND
 #define HAVE_ROUND 1
 /* Round to nearest integral value.  If the argument is halfway between two
@@ -558,6 +587,64 @@ roundf(float x)
 }
 #endif
 
+
+/* lround{f,,l} and llround{f,,l} functions.  */
+
+#if !defined(HAVE_LROUNDF) && defined(HAVE_ROUNDF)
+#define HAVE_LROUNDF 1
+long int
+lroundf (float x)
+{
+  return (long int) roundf (x);
+}
+#endif
+
+#if !defined(HAVE_LROUND) && defined(HAVE_ROUND)
+#define HAVE_LROUND 1
+long int
+lround (double x)
+{
+  return (long int) round (x);
+}
+#endif
+
+#if !defined(HAVE_LROUNDL) && defined(HAVE_ROUNDL)
+#define HAVE_LROUNDL 1
+long int
+lroundl (long double x)
+{
+  return (long long int) roundl (x);
+}
+#endif
+
+#if !defined(HAVE_LLROUNDF) && defined(HAVE_ROUNDF)
+#define HAVE_LLROUNDF 1
+long long int
+llroundf (float x)
+{
+  return (long long int) roundf (x);
+}
+#endif
+
+#if !defined(HAVE_LLROUND) && defined(HAVE_ROUND)
+#define HAVE_LLROUND 1
+long long int
+llround (double x)
+{
+  return (long long int) round (x);
+}
+#endif
+
+#if !defined(HAVE_LLROUNDL) && defined(HAVE_ROUNDL)
+#define HAVE_LLROUNDL 1
+long long int
+llroundl (long double x)
+{
+  return (long long int) roundl (x);
+}
+#endif
+
+
 #ifndef HAVE_LOG10L
 #define HAVE_LOG10L 1
 /* log10 function for long double variables. The version provided here
Index: libgfortran/config.h.in
===================================================================
--- libgfortran/config.h.in	(revision 127059)
+++ libgfortran/config.h.in	(working copy)
@@ -480,6 +480,15 @@
 /* Define to 1 if you have the `link' function. */
 #undef HAVE_LINK
 
+/* libm includes llround */
+#undef HAVE_LLROUND
+
+/* libm includes llroundf */
+#undef HAVE_LLROUNDF
+
+/* libm includes llroundl */
+#undef HAVE_LLROUNDL
+
 /* libm includes log */
 #undef HAVE_LOG
 
@@ -498,6 +507,15 @@
 /* libm includes logl */
 #undef HAVE_LOGL
 
+/* libm includes lround */
+#undef HAVE_LROUND
+
+/* libm includes lroundf */
+#undef HAVE_LROUNDF
+
+/* libm includes lroundl */
+#undef HAVE_LROUNDL
+
 /* Define to 1 if you have the `lstat' function. */
 #undef HAVE_LSTAT
 
Index: libgfortran/c99_protos.h
===================================================================
--- libgfortran/c99_protos.h	(revision 127059)
+++ libgfortran/c99_protos.h	(working copy)
@@ -200,6 +200,43 @@ extern double round(double);
 extern float roundf(float);
 #endif
 
+#if !defined(HAVE_ROUNDL) && defined(HAVE_CEILL)
+#define HAVE_ROUNDL 1
+extern long double roundl(long double);
+#endif
+
+
+
+#if !defined(HAVE_LROUNDF) && defined(HAVE_ROUNDF)
+#define HAVE_LROUNDF 1
+long int lroundf (float);
+#endif
+
+#if !defined(HAVE_LROUND) && defined(HAVE_ROUND)
+#define HAVE_LROUND 1
+long int lround (double);
+#endif
+
+#if !defined(HAVE_LROUNDL) && defined(HAVE_ROUNDL)
+#define HAVE_LROUNDL 1
+long int lroundl (long double);
+#endif
+
+#if !defined(HAVE_LLROUNDF) && defined(HAVE_ROUNDF)
+#define HAVE_LLROUNDF 1
+long long int llroundf (float);
+#endif
+
+#if !defined(HAVE_LLROUND) && defined(HAVE_ROUND)
+#define HAVE_LLROUND 1
+long long int llround (double);
+#endif
+
+#if !defined(HAVE_LLROUNDL) && defined(HAVE_ROUNDL)
+#define HAVE_LLROUNDL 1
+long long int llroundl (long double);
+#endif
+
 /* Wrappers for systems without the various C99 single precision Bessel
    functions.  */
 
Index: libgfortran/configure.ac
===================================================================
--- libgfortran/configure.ac	(revision 127059)
+++ libgfortran/configure.ac	(working copy)
@@ -301,6 +301,12 @@ AC_CHECK_LIB([m],[cpowl],[AC_DEFINE([HAV
 AC_CHECK_LIB([m],[roundf],[AC_DEFINE([HAVE_ROUNDF],[1],[libm includes roundf])])
 AC_CHECK_LIB([m],[round],[AC_DEFINE([HAVE_ROUND],[1],[libm includes round])])
 AC_CHECK_LIB([m],[roundl],[AC_DEFINE([HAVE_ROUNDL],[1],[libm includes roundl])])
+AC_CHECK_LIB([m],[lroundf],[AC_DEFINE([HAVE_LROUNDF],[1],[libm includes lroundf])])
+AC_CHECK_LIB([m],[lround],[AC_DEFINE([HAVE_LROUND],[1],[libm includes lround])])
+AC_CHECK_LIB([m],[lroundl],[AC_DEFINE([HAVE_LROUNDL],[1],[libm includes lroundl])])
+AC_CHECK_LIB([m],[llroundf],[AC_DEFINE([HAVE_LLROUNDF],[1],[libm includes llroundf])])
+AC_CHECK_LIB([m],[llround],[AC_DEFINE([HAVE_LLROUND],[1],[libm includes llround])])
+AC_CHECK_LIB([m],[llroundl],[AC_DEFINE([HAVE_LLROUNDL],[1],[libm includes llroundl])])
 AC_CHECK_LIB([m],[scalbnf],[AC_DEFINE([HAVE_SCALBNF],[1],[libm includes scalbnf])])
 AC_CHECK_LIB([m],[scalbn],[AC_DEFINE([HAVE_SCALBN],[1],[libm includes scalbn])])
 AC_CHECK_LIB([m],[scalbnl],[AC_DEFINE([HAVE_SCALBNL],[1],[libm includes scalbnl])])
Index: gcc/testsuite/gfortran.dg/nint_2.f90
===================================================================
--- gcc/testsuite/gfortran.dg/nint_2.f90	(revision 0)
+++ gcc/testsuite/gfortran.dg/nint_2.f90	(revision 0)
@@ -0,0 +1,51 @@
+! Test that NINT gives right results even in corner cases
+!
+! PR 31202
+! http://gcc.gnu.org/ml/fortran/2005-04/msg00139.html
+!
+! { dg-do run }
+  real(kind=8) :: a
+  integer(kind=8) :: i1, i2
+  real :: b
+  integer :: j1, j2
+
+  a = nearest(0.5_8,-1.0_8)
+  i2 = nint(nearest(0.5_8,-1.0_8))
+  i1 = nint(a)
+  if (i1 /= 0 .or. i2 /= 0) call abort
+
+  a = 0.5_8
+  i2 = nint(0.5_8)
+  i1 = nint(a)
+  if (i1 /= 1 .or. i2 /= 1) call abort
+
+  a = nearest(0.5_8,1.0_8)
+  i2 = nint(nearest(0.5_8,1.0_8))
+  i1 = nint(a)
+  if (i1 /= 1 .or. i2 /= 1) call abort
+
+  b = nearest(0.5,-1.0)
+  j2 = nint(nearest(0.5,-1.0))
+  j1 = nint(b)
+  if (j1 /= 0 .or. j2 /= 0) call abort
+
+  b = 0.5
+  j2 = nint(0.5)
+  j1 = nint(b)
+  if (j1 /= 1 .or. j2 /= 1) call abort
+
+  b = nearest(0.5,1.0)
+  j2 = nint(nearest(0.5,1.0))
+  j1 = nint(b)
+  if (j1 /= 1 .or. j2 /= 1) call abort
+
+  a = 4503599627370497.0_8
+  i1 = nint(a,kind=8)
+  i2 = nint(4503599627370497.0_8,kind=8)
+  if (i1 /= i2 .or. i1 /= 4503599627370497_8) call abort
+
+  a = -4503599627370497.0_8
+  i1 = nint(a,kind=8)
+  i2 = nint(-4503599627370497.0_8,kind=8)
+  if (i1 /= i2 .or. i1 /= -4503599627370497_8) call abort
+  end

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2007-07-31 21:44 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-07-31 21:39 [gfortran,patch] Fix code generated for NINT FX Coudert
2007-07-31 21:56 ` Paul Thomas
2007-07-31 23:24   ` FX Coudert

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).