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, midlevel]: Convert (int)floor -> lfloor


Hello!

Currently, i386 backend produces quite bad code for:

int test (double x) {
   return floor(x);
}

When this code is compiled with '-O2 -ffast-math', following asm code is produced:

      fnstcw  -2(%ebp)
      fldl    8(%ebp)
      movzwl  -2(%ebp), %eax
      andw    $-3073, %ax
      orw     $1024, %ax
      movw    %ax, -4(%ebp)
      movzwl  -2(%ebp), %eax
      fldcw   -4(%ebp)
(*)    frndint
      fldcw   -2(%ebp)
      orw     $3072, %ax
      movw    %ax, -4(%ebp)
      fldcw   -4(%ebp)
(*)    fistpl  -8(%ebp)
      fldcw   -2(%ebp)
      movl    -8(%ebp), %eax

There is no need for double conversion, as i387 can directly convert from floating point value to integer in any supported rounding mode. This way, it could short-circuit double conversion into single conversion with appropriate mode control word settings.

To enable this conversion, a little help from midlevel is needed. There is already a (int)round -> lround conversion implemented in convert.c to handle BUILT_IN_ROUND -> BUILT_IN_{L,LL}ROUND conversion. To implement similar "floor" conversions, we need similar new gcc internal builtin function, BUILT_IN_{L,LL}FLOOR.
However, there is no lfloor() or llfloor() function in libc. To overcome this problem, we look into machine instruction set and enable this transformation iff appropriate instruction is available (in addition to flag_unsafe_math_optimizations). This way, we won't fall back into (non-existing) library call.


Attached patch implements midlevel part of (int)floor -> floor /and similar/ conversions. Patch was bootstrapped on i686-pc-linux-gnu, regtested for c and c++. A testcase is also included to check generation of new itransformations.

(The 386 backend patch will follow shortly.)

BTW: This transformation triggers 39 times in povray-3.50c compilation (-O2 -ffast-math -mfmpath=387, -D__NO_MATH_INLINES). A similar ceil tranformation triggers 9 times.

OK for mainline?


2005-04-05 Uros Bizjak <uros@kss-loka.si> * builtins.def (BUILT_IN_LFLOOR, BUILT_IN_LFLOORF, BUILT_IN_LFLOORL) (BUILT_IN_LLFLOOR, BUILT_IN_LLFLOORF, BUILT_IN_LLFLOORL): New. * optabs.h (enum optab_index): Add new OTI_lfloor. (lfloor_optab): Define corresponding macro. * optabs.c (init_optabs): Initialize lfloor_optab. * genopinit.c (optabs): Implement lfloor_optab using lfloorsi2 and lfloordi2 patterns. * builtins.c (mathfn_built_in): Check whether the built-in insn is available for BUILT_IN_LFLOOR{,F,L} and BUILT_IN_LLFLOOR{,F,L}. (expand_builtin_mathfn): Handle BUILT_IN_LFLOOR{,F,L} and BUILT_IN_LLFLOOR{,F,L} using lfloor_optab. (expand_builtin): Expand BUILT_IN_LFLOOR{,F,L} and BUILT_IN_LLFLOOR{,F,L} using expand_builtin_mathfn if flag_unsafe_math_optimizations is set. * convert.c (convert_to_integer): Convert (long int)floor{,f,l}, into lfloor built-in function and (long long int)floor{,f,l} into llfloor built-in-function.

testsuite:

* gcc.dg/builtins-53.c: New test.

Uros.
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.450
diff -u -p -r1.450 builtins.c
--- builtins.c	30 Mar 2005 21:34:19 -0000	1.450
+++ builtins.c	5 Apr 2005 13:21:00 -0000
@@ -1509,6 +1509,8 @@ tree
 mathfn_built_in (tree type, enum built_in_function fn)
 {
   enum built_in_function fcode, fcodef, fcodel;
+  optab builtin_optab = NULL ;
+  enum machine_mode optab_mode;
 
   switch (fn)
     {
@@ -1587,10 +1589,35 @@ mathfn_built_in (tree type, enum built_i
       CASE_MATHFN (BUILT_IN_Y1)
       CASE_MATHFN (BUILT_IN_YN)
 
+      case BUILT_IN_LFLOOR:
+      case BUILT_IN_LFLOORF:
+      case BUILT_IN_LFLOORL:
+	fcode = BUILT_IN_LFLOOR;
+	fcodef = BUILT_IN_LFLOORF;
+	fcodel = BUILT_IN_LFLOORL;
+	builtin_optab = lfloor_optab;
+	optab_mode = SImode;
+        break;
+
+      case BUILT_IN_LLFLOOR:
+      case BUILT_IN_LLFLOORF:
+      case BUILT_IN_LLFLOORL:
+	fcode = BUILT_IN_LLFLOOR;
+	fcodef = BUILT_IN_LLFLOORF;
+	fcodel = BUILT_IN_LLFLOORL;
+	builtin_optab = lfloor_optab;
+	optab_mode = DImode;
+	break;
+
       default:
 	return 0;
       }
 
+  /* Check whether the instruction is available.  */
+  if (builtin_optab &&
+      (builtin_optab->handlers[(int) optab_mode].insn_code == CODE_FOR_nothing))
+      return 0;
+
   if (TYPE_MAIN_VARIANT (type) == double_type_node)
     return implicit_built_in_decls[fcode];
   else if (TYPE_MAIN_VARIANT (type) == float_type_node)
@@ -1733,6 +1760,13 @@ expand_builtin_mathfn (tree exp, rtx tar
     case BUILT_IN_FLOORF:
     case BUILT_IN_FLOORL:
       builtin_optab = floor_optab; break;
+    case BUILT_IN_LFLOOR:
+    case BUILT_IN_LFLOORF:
+    case BUILT_IN_LFLOORL:
+    case BUILT_IN_LLFLOOR:
+    case BUILT_IN_LLFLOORF:
+    case BUILT_IN_LLFLOORL:
+      builtin_optab = lfloor_optab; break;
     case BUILT_IN_CEIL:
     case BUILT_IN_CEILF:
     case BUILT_IN_CEILL:
@@ -5252,6 +5286,12 @@ expand_builtin (tree exp, rtx target, rt
     case BUILT_IN_FLOOR:
     case BUILT_IN_FLOORF:
     case BUILT_IN_FLOORL:
+    case BUILT_IN_LFLOOR:
+    case BUILT_IN_LFLOORF:
+    case BUILT_IN_LFLOORL:
+    case BUILT_IN_LLFLOOR:
+    case BUILT_IN_LLFLOORF:
+    case BUILT_IN_LLFLOORL:
     case BUILT_IN_CEIL:
     case BUILT_IN_CEILF:
     case BUILT_IN_CEILL:
Index: builtins.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.def,v
retrieving revision 1.99
diff -u -p -r1.99 builtins.def
--- builtins.def	3 Apr 2005 22:08:03 -0000	1.99
+++ builtins.def	5 Apr 2005 13:21:00 -0000
@@ -260,9 +260,15 @@ DEF_EXT_LIB_BUILTIN    (BUILT_IN_JNL, "j
 DEF_LIB_BUILTIN        (BUILT_IN_LDEXP, "ldexp", BT_FN_DOUBLE_DOUBLE_INT, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_LDEXPF, "ldexpf", BT_FN_FLOAT_FLOAT_INT, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_LDEXPL, "ldexpl", BT_FN_LONGDOUBLE_LONGDOUBLE_INT, ATTR_MATHFN_FPROUNDING_ERRNO)
+DEF_GCC_BUILTIN        (BUILT_IN_LFLOOR, "lfloor", BT_FN_LONG_DOUBLE, ATTR_MATHFN_ERRNO)
+DEF_GCC_BUILTIN        (BUILT_IN_LFLOORF, "lfloorf", BT_FN_LONG_FLOAT, ATTR_MATHFN_ERRNO)
+DEF_GCC_BUILTIN        (BUILT_IN_LFLOORL, "lfloorl", BT_FN_LONG_LONGDOUBLE, ATTR_MATHFN_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_LGAMMA, "lgamma", BT_FN_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_LGAMMAF, "lgammaf", BT_FN_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_LGAMMAL, "lgammal", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
+DEF_GCC_BUILTIN        (BUILT_IN_LLFLOOR, "llfloor", BT_FN_LONGLONG_DOUBLE, ATTR_MATHFN_ERRNO)
+DEF_GCC_BUILTIN        (BUILT_IN_LLFLOORF, "llfloorf", BT_FN_LONGLONG_FLOAT, ATTR_MATHFN_ERRNO)
+DEF_GCC_BUILTIN        (BUILT_IN_LLFLOORL, "llfloorl", BT_FN_LONGLONG_LONGDOUBLE, ATTR_MATHFN_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_LLRINT, "llrint", BT_FN_LONGLONG_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_LLRINTF, "llrintf", BT_FN_LONGLONG_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_LLRINTL, "llrintl", BT_FN_LONGLONG_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
Index: convert.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/convert.c,v
retrieving revision 1.57
diff -u -p -r1.57 convert.c
--- convert.c	17 Feb 2005 23:56:38 -0000	1.57
+++ convert.c	5 Apr 2005 13:21:00 -0000
@@ -349,6 +349,13 @@ convert_to_integer (tree type, tree expr
       
       switch (fcode)
         {
+	case BUILT_IN_FLOOR: case BUILT_IN_FLOORF: case BUILT_IN_FLOORL:
+	  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (long_long_integer_type_node))
+	    fn = mathfn_built_in (s_intype, BUILT_IN_LLFLOOR);
+	  else
+	    fn = mathfn_built_in (s_intype, BUILT_IN_LFLOOR);
+	  break;
+
 	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);
Index: genopinit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/genopinit.c,v
retrieving revision 1.89
diff -u -p -r1.89 genopinit.c
--- genopinit.c	24 Mar 2005 06:22:37 -0000	1.89
+++ genopinit.c	5 Apr 2005 13:21:00 -0000
@@ -119,6 +119,7 @@ static const char * const optabs[] =
   "copysign_optab->handlers[$A].insn_code = CODE_FOR_$(copysign$F$a3$)",
   "sqrt_optab->handlers[$A].insn_code = CODE_FOR_$(sqrt$a2$)",
   "floor_optab->handlers[$A].insn_code = CODE_FOR_$(floor$a2$)",
+  "lfloor_optab->handlers[$A].insn_code = CODE_FOR_$(lfloor$a2$)",
   "ceil_optab->handlers[$A].insn_code = CODE_FOR_$(ceil$a2$)",
   "round_optab->handlers[$A].insn_code = CODE_FOR_$(round$a2$)",
   "btrunc_optab->handlers[$A].insn_code = CODE_FOR_$(btrunc$a2$)",
Index: optabs.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/optabs.c,v
retrieving revision 1.268
diff -u -p -r1.268 optabs.c
--- optabs.c	24 Mar 2005 06:22:36 -0000	1.268
+++ optabs.c	5 Apr 2005 13:21:01 -0000
@@ -5033,6 +5033,7 @@ init_optabs (void)
   parity_optab = init_optab (PARITY);
   sqrt_optab = init_optab (SQRT);
   floor_optab = init_optab (UNKNOWN);
+  lfloor_optab = init_optab (UNKNOWN);
   ceil_optab = init_optab (UNKNOWN);
   round_optab = init_optab (UNKNOWN);
   btrunc_optab = init_optab (UNKNOWN);
Index: optabs.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/optabs.h,v
retrieving revision 1.52
diff -u -p -r1.52 optabs.h
--- optabs.h	24 Mar 2005 06:22:36 -0000	1.52
+++ optabs.h	5 Apr 2005 13:21:01 -0000
@@ -186,6 +186,7 @@ enum optab_index
   OTI_log1p,
   /* Rounding functions */
   OTI_floor,
+  OTI_lfloor,
   OTI_ceil,
   OTI_btrunc,
   OTI_round,
@@ -313,6 +314,7 @@ extern GTY(()) optab optab_table[OTI_MAX
 #define log2_optab (optab_table[OTI_log2])
 #define log1p_optab (optab_table[OTI_log1p])
 #define floor_optab (optab_table[OTI_floor])
+#define lfloor_optab (optab_table[OTI_lfloor])
 #define ceil_optab (optab_table[OTI_ceil])
 #define btrunc_optab (optab_table[OTI_btrunc])
 #define round_optab (optab_table[OTI_round])
/* Copyright (C) 2005 Free Software Foundation.

   Check that (long)floor, (long)floorf, (long)floorl,
   (long long)floor, (long long)floorf and (long long)floorl
   built-in functions compile.

   Written by Uros Bizjak, 5th April 2005.  */

/* { dg-do compile } */
/* { dg-options "-O2 -ffast-math" } */

extern double floor(double);
extern float floorf(float);
extern long double floorl(long double);


long int test1(double x)
{
  return floor(x);
}

long long int test2(double x)
{
  return floor(x);
}

long int test1f(float x)
{
  return floorf(x);
}

long long int test2f(float x)
{
  return floorf(x);
}

long int test1l(long double x)
{
  return floorl(x);
}

long long int test2l(long double x)
{
  return floorl(x);
}

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