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]: convert (long)round(d) -> lround(d), etc


This patch implements some builtin conversions from rounding functions
with floating point results into functions with integer results when
the floating point routines are converted or cast to fixed point
values.  Namely:

(long)round(d) -> lround(d)
(long)nearbyint(d) -> lrint(d)
(long)rint(d) -> lrint(d) /* only if we're ignoring trapping math. */

and I do the respective long long conversions.

BTW, this conversion was first hinted at by Jan back in late 2002:
http://gcc.gnu.org/ml/gcc-patches/2002-11/msg00268.html


I also convert to narrower FP types, e.g when f is a float we already do:

round(f) -> (double)roundf(f)

So I added stripping float extensions, like so:

(long)(double)roundf(f) -> lroundf(f)

which means with my patch we can now do:

(long)round(f) -> lroundf(f)


This patch was bootstrapped/tested on mips-sgi-irix6.5, but since all
the resulting functions are C99 and irix isn't, that wasn't much of a
test other than ensuring the patch doesn't break anything.

So I also targetted i686-pc-linux-gnu and compiled the testcase at
various opt levels and made sure that all the testcase code was folded
away.


Ok for mainline?

		Thanks,
		--Kaveh


2004-04-27  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>

	* convert.c (convert_to_integer): Convert (long)round -> lround,
	etc.

testsuite:
	* gcc.dg/torture/builtin-convert-2.c: New test.

diff -rup orig/egcc-CVS20040423/gcc/convert.c egcc-CVS20040423/gcc/convert.c
--- orig/egcc-CVS20040423/gcc/convert.c	2004-04-01 20:03:26.000000000 -0500
+++ egcc-CVS20040423/gcc/convert.c	2004-04-26 21:50:31.651576000 -0400
@@ -332,6 +332,46 @@ convert_to_integer (tree type, tree expr
       return error_mark_node;
     }
 
+  /* Convert e.g. (long)round(d) -> lround(d).  */
+  if (optimize)
+    {
+      tree s_expr = strip_float_extensions (expr);
+      tree s_intype = TREE_TYPE (s_expr);
+      const enum built_in_function fcode = builtin_mathfn_code (s_expr);
+      tree fn = 0;
+      
+      switch (fcode)
+        {
+	case BUILT_IN_ROUND: case BUILT_IN_ROUNDF: case BUILT_IN_ROUNDL:
+	  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (long_long_integer_type_node))
+	    fn = mathfn_built_in (s_intype, BUILT_IN_LLROUND);
+	  else
+	    fn = mathfn_built_in (s_intype, BUILT_IN_LROUND);
+	  break;
+
+	case BUILT_IN_RINT: case BUILT_IN_RINTF: case BUILT_IN_RINTL:
+	  /* Only convert rint* if we can ignore math exceptions.  */
+	  if (flag_trapping_math)
+	    break;
+	  /* ... Fall through ...  */
+	case BUILT_IN_NEARBYINT: case BUILT_IN_NEARBYINTF: case BUILT_IN_NEARBYINTL:
+	  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (long_long_integer_type_node))
+            fn = mathfn_built_in (s_intype, BUILT_IN_LLRINT);
+	  else
+            fn = mathfn_built_in (s_intype, BUILT_IN_LRINT);
+	  break;
+	default:
+	  break;
+	}
+      
+      if (fn)
+        {
+	  tree arglist = TREE_OPERAND (s_expr, 1);
+	  tree newexpr = build_function_call_expr (fn, arglist);
+	  return convert_to_integer (type, newexpr);
+	}
+    }
+
   switch (TREE_CODE (intype))
     {
     case POINTER_TYPE:


/* Copyright (C) 2004  Free Software Foundation.

   Verify that built-in math function conversion into integer rounding
   functions is correctly performed by the compiler.

   Written by Kaveh ghazi, 2004-04-26.  */

/* { dg-do link } */
/* { dg-options "-ffast-math" } */

#include "./builtins-config.h"

#define PROTOTYPE(FN) extern double FN(double); \
  extern float FN##f(float); \
  extern long double FN##l(long double);
#define PROTOTYPE_RET(FN, RET) extern RET FN(double); \
  extern RET FN##f(float); \
  extern RET FN##l(long double);

/* Macro to do all FP type combinations.  The second half tests
   narrowing the FP type.  */
#define TEST_FP2FIXED(FN1, FN2) \
  PROTOTYPE(FN1) \
  PROTOTYPE_RET(FN2, long) \
  PROTOTYPE_RET(l##FN2, long long) \
  extern void link_error_##FN1##_##FN2(void); \
  extern void link_error_##FN1##f_##FN2##f(void); \
  extern void link_error_##FN1##l_##FN2##l(void); \
  extern void link_error_##FN1##_l##FN2(void); \
  extern void link_error_##FN1##f_l##FN2##f(void); \
  extern void link_error_##FN1##l_l##FN2##l(void); \
  if ((long)FN1(d) != FN2(d)) \
    link_error_##FN1##_##FN2(); \
  if ((long)FN1##f(f) != FN2##f(f)) \
    link_error_##FN1##f_##FN2##f(); \
  if ((long)FN1##l(ld) != FN2##l(ld)) \
    link_error_##FN1##l_##FN2##l(); \
  if ((long long)FN1(d) != l##FN2(d)) \
    link_error_##FN1##_l##FN2(); \
  if ((long long)FN1##f(f) != l##FN2##f(f)) \
    link_error_##FN1##f_l##FN2##f(); \
  if ((long long)FN1##l(ld) != l##FN2##l(ld)) \
    link_error_##FN1##l_l##FN2##l(); \
  extern void link_error_##FN1##_##FN2##f(void); \
  extern void link_error_##FN1##l_##FN2(void); \
  extern void link_error_##FN1##l_##FN2##f(void); \
  extern void link_error_##FN1##_l##FN2##f(void); \
  extern void link_error_##FN1##l_l##FN2(void); \
  extern void link_error_##FN1##l_l##FN2##f(void); \
  if (sizeof(double) > sizeof(float) && (long)FN1(f) != FN2##f(f)) \
    link_error_##FN1##_##FN2##f(); \
  if (sizeof(long double) > sizeof(double) && (long)FN1##l(d) != FN2(d)) \
    link_error_##FN1##l_##FN2(); \
  if (sizeof(long double) > sizeof(float) && (long)FN1##l(f) != FN2##f(f)) \
    link_error_##FN1##l_##FN2##f(); \
  if (sizeof(double) > sizeof(float) && (long long)FN1(f) != l##FN2##f(f)) \
    link_error_##FN1##_l##FN2##f(); \
  if (sizeof(long double) > sizeof(double) && (long long)FN1##l(d) != l##FN2(d)) \
    link_error_##FN1##l_l##FN2(); \
  if (sizeof(long double) > sizeof(float) && (long long)FN1##l(f) != l##FN2##f(f)) \
    link_error_##FN1##l_l##FN2##f()

void __attribute__ ((__noinline__)) foo (double d, float f, long double ld)
{
#ifdef __OPTIMIZE__
# ifdef HAVE_C99_RUNTIME
  /* The resulting transformation functions are all C99.  */
  TEST_FP2FIXED (round, lround);
  TEST_FP2FIXED (nearbyint, lrint);
  TEST_FP2FIXED (rint, lrint);
# endif
#endif
}

int main()
{
  foo (1.0, 2.0, 3.0);
  return 0;
}


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