This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Constant fold round, roundf and roundl


The following patch implements real_round in real.[ch] to implement
round to nearest integer (towards zero) as required by round(3m).
This is then used by (the new function) fold_builtin_round to provide
constant folding of round, roundf and roundl with constant arguments.

Whilst I was tweaking real.c, I also decided to make minor changes
to real_floor and real_ceil such that they function correctly when
the target of the operation overwrites the input operand.  These
functions are never called in this mode, but this tweak keeps them
consistent with many of the other functions in real.c/real.h.

Before Joseph asks, has there been any progress towards including
GMP as an upstream package within GCC?  Certainly tree-ssa's gfortran
would immediately benefit, and MPFR looks like the eventual replacement
for real.[ch].


The following patch has been tested on i686-pc-linux-gnu with a full
"make bootstrap", all languages except treelang, and regression tested
with a top-level "make -k check" with no new failures.

Ok for mainline?



2004-01-22  Roger Sayle  <roger@eyesopen.com>

	* real.c (real_floor, real_ceil): Tweak to allow input and output
	arguments to overlap.
	(real_round): New function to implement round(3m) semantics.
	* real.h (real_round): Prototype here.
	* builtins.c (fold_builtin_round): New function to constant fold
	round, roundf and roundl.
	(fold_builtin): Call fold_builtin_round for BUILT_IN_ROUND{,F,L}.

	* gcc.dg/builtins-29.c: New test case.


Index: real.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.c,v
retrieving revision 1.135
diff -c -3 -p -r1.135 real.c
*** real.c	12 Jan 2004 18:37:40 -0000	1.135
--- real.c	22 Jan 2004 18:26:07 -0000
*************** void
*** 4539,4549 ****
  real_floor (REAL_VALUE_TYPE *r, enum machine_mode mode,
  	    const REAL_VALUE_TYPE *x)
  {
!   do_fix_trunc (r, x);
!   if (! real_identical (r, x) && r->sign)
!     do_add (r, r, &dconstm1, 0);
    if (mode != VOIDmode)
!     real_convert (r, mode, r);
  }

  /* Round X to the smallest integer not less then argument, i.e. round
--- 4539,4551 ----
  real_floor (REAL_VALUE_TYPE *r, enum machine_mode mode,
  	    const REAL_VALUE_TYPE *x)
  {
!   REAL_VALUE_TYPE t;
!
!   do_fix_trunc (&t, x);
!   if (! real_identical (&t, x) && x->sign)
!     do_add (&t, &t, &dconstm1, 0);
    if (mode != VOIDmode)
!     real_convert (r, mode, &t);
  }

  /* Round X to the smallest integer not less then argument, i.e. round
*************** void
*** 4553,4561 ****
  real_ceil (REAL_VALUE_TYPE *r, enum machine_mode mode,
  	   const REAL_VALUE_TYPE *x)
  {
!   do_fix_trunc (r, x);
!   if (! real_identical (r, x) && ! r->sign)
!     do_add (r, r, &dconst1, 0);
    if (mode != VOIDmode)
      real_convert (r, mode, r);
  }
--- 4555,4579 ----
  real_ceil (REAL_VALUE_TYPE *r, enum machine_mode mode,
  	   const REAL_VALUE_TYPE *x)
  {
!   REAL_VALUE_TYPE t;
!
!   do_fix_trunc (&t, x);
!   if (! real_identical (&t, x) && ! x->sign)
!     do_add (&t, &t, &dconst1, 0);
!   if (mode != VOIDmode)
!     real_convert (r, mode, &t);
! }
!
! /* Round X to the nearest integer, away from zero, i.e. round to the
!    nearest integer, but round halfway cases away from zero.  */
!
! void
! real_round (REAL_VALUE_TYPE *r, enum machine_mode mode,
! 	    const REAL_VALUE_TYPE *x)
! {
!   do_add (r, x, &dconsthalf, x->sign);
!   do_fix_trunc (r, r);
    if (mode != VOIDmode)
      real_convert (r, mode, r);
  }
+
Index: real.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.h,v
retrieving revision 1.75
diff -c -3 -p -r1.75 real.h
*** real.h	10 Oct 2003 20:33:05 -0000	1.75
--- real.h	22 Jan 2004 18:26:07 -0000
***************
*** 1,6 ****
  /* Definitions of floating-point access for GNU compiler.
     Copyright (C) 1989, 1991, 1994, 1996, 1997, 1998, 1999,
!    2000, 2002, 2003 Free Software Foundation, Inc.

     This file is part of GCC.

--- 1,6 ----
  /* Definitions of floating-point access for GNU compiler.
     Copyright (C) 1989, 1991, 1994, 1996, 1997, 1998, 1999,
!    2000, 2002, 2003, 2004 Free Software Foundation, Inc.

     This file is part of GCC.

*************** extern void real_floor (REAL_VALUE_TYPE
*** 372,376 ****
--- 372,378 ----
  			const REAL_VALUE_TYPE *);
  extern void real_ceil (REAL_VALUE_TYPE *, enum machine_mode,
  		       const REAL_VALUE_TYPE *);
+ extern void real_round (REAL_VALUE_TYPE *, enum machine_mode,
+ 			const REAL_VALUE_TYPE *);

  #endif /* ! GCC_REAL_H */
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.277
diff -c -3 -p -r1.277 builtins.c
*** builtins.c	18 Jan 2004 20:04:59 -0000	1.277
--- builtins.c	22 Jan 2004 18:26:21 -0000
*************** static tree fold_builtin_cabs (tree, tre
*** 156,161 ****
--- 156,162 ----
  static tree fold_builtin_trunc (tree);
  static tree fold_builtin_floor (tree);
  static tree fold_builtin_ceil (tree);
+ static tree fold_builtin_round (tree);
  static tree fold_builtin_bitop (tree);
  static tree fold_builtin_memcpy (tree);
  static tree fold_builtin_mempcpy (tree);
*************** fold_builtin_ceil (tree exp)
*** 5923,5928 ****
--- 5924,5961 ----
    return fold_trunc_transparent_mathfn (exp);
  }

+ /* Fold function call to builtin round, roundf or roundl.  Return
+    NULL_TREE if no simplification can be made.  */
+
+ static tree
+ fold_builtin_round (tree exp)
+ {
+   tree arglist = TREE_OPERAND (exp, 1);
+   tree arg;
+
+   if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+     return 0;
+
+   /* Optimize ceil of constant value.  */
+   arg = TREE_VALUE (arglist);
+   if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
+     {
+       REAL_VALUE_TYPE x;
+
+       x = TREE_REAL_CST (arg);
+       if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
+ 	{
+ 	  tree type = TREE_TYPE (exp);
+ 	  REAL_VALUE_TYPE r;
+
+ 	  real_round (&r, TYPE_MODE (type), &x);
+ 	  return build_real (type, r);
+ 	}
+     }
+
+   return fold_trunc_transparent_mathfn (exp);
+ }
+
  /* Fold function call to builtin ffs, clz, ctz, popcount and parity
     and their long and long long variants (i.e. ffsl and ffsll).
     Return NULL_TREE if no simplification can be made.  */
*************** fold_builtin (tree exp)
*** 6868,6873 ****
--- 6901,6908 ----
      case BUILT_IN_ROUND:
      case BUILT_IN_ROUNDF:
      case BUILT_IN_ROUNDL:
+       return fold_builtin_round (exp);
+
      case BUILT_IN_NEARBYINT:
      case BUILT_IN_NEARBYINTF:
      case BUILT_IN_NEARBYINTL:


/* Copyright (C) 2004 Free Software Foundation.

   Check that constant folding of round, roundf and roundl math functions
   doesn't break anything and produces the expected results.

   Written by Roger Sayle, 22nd January 2004.  */

/* { dg-do link } */
/* { dg-options "-O2" } */

extern void link_error(void);

extern double round(double);
extern float roundf(float);
extern long double roundl(long double);

void test()
{
  if (round (0.0) != 0.0)
    link_error ();
  if (round (6.0) != 6.0)
    link_error ();
  if (round (-8.0) != -8.0)
    link_error ();

  if (round (3.2) != 3.0)
    link_error ();
  if (round (-2.8) != -3.0)
    link_error ();
  if (round (0.01) != 0.0)
    link_error ();
  if (round (-0.7) != -1.0)
    link_error ();

  if (round (2.5) != 3.0)
    link_error ();
  if (round (-1.5) != -2.0)
    link_error ();
}

void testf()
{
  if (roundf (0.0f) != 0.0f)
    link_error ();
  if (roundf (6.0f) != 6.0f)
    link_error ();
  if (roundf (-8.0f) != -8.0f)
    link_error ();

  if (roundf (3.2f) != 3.0f)
    link_error ();
  if (roundf (-2.8f) != -3.0f)
    link_error ();
  if (roundf (0.01f) != 0.0f)
    link_error ();
  if (roundf (-0.7f) != -1.0f)
    link_error ();

  if (roundf (2.5f) != 3.0f)
    link_error ();
  if (roundf (-1.5f) != -2.0f)
    link_error ();
}

void testl()
{
  if (roundl (0.0l) != 0.0l)
    link_error ();
  if (roundl (6.0l) != 6.0l)
    link_error ();
  if (roundl (-8.0l) != -8.0l)
    link_error ();

  if (roundl (3.2l) != 3.0l)
    link_error ();
  if (roundl (-2.8l) != -3.0l)
    link_error ();
  if (roundl (0.01l) != 0.0l)
    link_error ();
  if (roundl (-0.7l) != -1.0l)
    link_error ();

  if (roundl (2.5l) != 3.0l)
    link_error ();
  if (roundl (-1.5l) != -2.0l)
    link_error ();
}

int main()
{
  test ();
  testf ();
  testl ();
  return 0;
}


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]