This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH, midlevel]: Convert (int)floor -> lfloor
- From: Uros Bizjak <uros at kss-loka dot si>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 05 Apr 2005 16:09:39 +0200
- Subject: [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);
}