This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Simplify floating point conversions II
> On Tue, Nov 05, 2002 at 06:14:00PM +0100, Jan Hubicka wrote:
> > Hi,
> > this patch makes us to simplify some of the floating point operations to
> > narrower mode when conversions are present. This include
> > +,-,/,*,abs,neg,sqrt/sin/cos/exp.
> > I believe it is IEEE safe, but some expert would be welcome.
>
> You should have commented this. It should not take someone 5
> minutes to even figure out what's going on here. To be sure, it's
>
> (float)sqrtl(x) -> sqrtf((float)x)
>
> correct? Well, clearly this fails for X = 2**(127 * 2), since
> X is not representable as a float, but its square root is. It
> would not be hard to identify similar problems with every other
> operation on your list except for ABS/NEG.
Hi,
here is updated version with the comments. Even when the cases it shoots for
looks incommon, they are not. In mesa (real one, not spec2000) I get 110
conversions removed with this patch. I get matches in most of code using
floats extensivly because of C conventions to implicitly cast to double in some
cases.
Interestingly enought I get matches in fortran code too in spec2000, so it may
be wortwhile to resolve the builtins problems.
Wed Nov 6 10:17:44 CET 2002 Jan Hubicka <jh@suse.cz>
* convert.c (convert_to_real): Simplify some special cases.
Index: convert.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/convert.c,v
retrieving revision 1.19
diff -c -3 -p -r1.19 convert.c
*** convert.c 4 Jul 2002 06:38:54 -0000 1.19
--- convert.c 6 Nov 2002 09:16:56 -0000
*************** tree
*** 80,85 ****
--- 80,223 ----
convert_to_real (type, expr)
tree type, expr;
{
+ enum built_in_function fcode = builtin_mathfn_code (expr);
+ tree itype = TREE_TYPE (expr);
+
+ /* Convert (float)sqrt((double)x) into sqrtf(x)
+ For fast math it would be safe probably to convert (float)sqrt(x)
+ into sqrt((float)x), but in strict mode the argument can overflow. */
+ if ((fcode == BUILT_IN_SQRT
+ || fcode == BUILT_IN_SQRTL
+ || fcode == BUILT_IN_SIN
+ || fcode == BUILT_IN_SINL
+ || fcode == BUILT_IN_COS
+ || fcode == BUILT_IN_COSL
+ || fcode == BUILT_IN_EXP
+ || fcode == BUILT_IN_EXPL)
+ && (TYPE_MODE (type) == TYPE_MODE (double_type_node)
+ || TYPE_MODE (type) == TYPE_MODE (float_type_node)))
+ {
+ tree arg0 = TREE_VALUE (TREE_OPERAND (expr, 1));
+ tree newtype = type;
+
+ /* Wind away possible cast. */
+ if (TREE_CODE (arg0) == NOP_EXPR)
+ arg0 = TREE_OPERAND (arg0, 0);
+
+ /* We have (outertype)sqrt((innertype)x). Choose the wider mode from
+ the both as the safe type for operation. */
+ if (TYPE_PRECISION (TREE_TYPE (arg0)) > TYPE_PRECISION (type))
+ newtype = TREE_TYPE (arg0);
+
+ /* Be curefull about integer to fp conversions.
+ These may overflow still. */
+ if (FLOAT_TYPE_P (TREE_TYPE (arg0))
+ && TYPE_PRECISION (newtype) <= TYPE_PRECISION (itype)
+ && (TYPE_MODE (newtype) == TYPE_MODE (double_type_node)
+ || TYPE_MODE (newtype) == TYPE_MODE (float_type_node)))
+ {
+ tree arglist, decl;
+ if (TYPE_MODE (type) == TYPE_MODE (float_type_node))
+ switch (fcode)
+ {
+ case BUILT_IN_SQRT:
+ case BUILT_IN_SQRTL:
+ fcode = BUILT_IN_SQRTF;
+ break;
+ case BUILT_IN_SIN:
+ case BUILT_IN_SINL:
+ fcode = BUILT_IN_SINF;
+ break;
+ case BUILT_IN_COS:
+ case BUILT_IN_COSL:
+ fcode = BUILT_IN_COSF;
+ break;
+ case BUILT_IN_EXP:
+ case BUILT_IN_EXPL:
+ fcode = BUILT_IN_EXPF;
+ break;
+ default:
+ abort ();
+ }
+ else
+ switch (fcode)
+ {
+ case BUILT_IN_SQRT:
+ case BUILT_IN_SQRTL:
+ fcode = BUILT_IN_SQRT;
+ break;
+ case BUILT_IN_SIN:
+ case BUILT_IN_SINL:
+ fcode = BUILT_IN_SIN;
+ break;
+ case BUILT_IN_COS:
+ case BUILT_IN_COSL:
+ fcode = BUILT_IN_COS;
+ break;
+ case BUILT_IN_EXP:
+ case BUILT_IN_EXPL:
+ fcode = BUILT_IN_EXP;
+ break;
+ default:
+ abort ();
+ }
+
+ /* ??? Fortran frontend does not initialize built_in_decls.
+ For some reason creating the decl using builtin_function does not
+ work as it should. */
+ if (built_in_decls [fcode])
+ {
+ decl = build_function_call_expr (built_in_decls [fcode], arglist);
+ return decl;
+ }
+ }
+ }
+
+ /* Propagate the cast into the operation. */
+ if (itype != type && FLOAT_TYPE_P (type))
+ switch (TREE_CODE (expr))
+ {
+ /* convert (float)-x into -(float)x. This is always safe. */
+ case ABS_EXPR:
+ case NEGATE_EXPR:
+ return build1 (TREE_CODE (expr), type,
+ fold (convert_to_real (type,
+ TREE_OPERAND (expr, 0))));
+ /* convert (outertype)((innertype0)a+(innertype1)b)
+ into ((newtype)a+(newtype)b) where newtype
+ is the widest mode from all of these. */
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case RDIV_EXPR:
+ {
+ tree arg0 = TREE_OPERAND (expr, 0);
+ tree arg1 = TREE_OPERAND (expr, 1);
+
+ /* Unwind possible casts. */
+ if (TREE_CODE (arg0) == NOP_EXPR)
+ arg0 = TREE_OPERAND (arg0, 0);
+ if (TREE_CODE (arg1) == NOP_EXPR)
+ arg1 = TREE_OPERAND (arg1, 0);
+ if (FLOAT_TYPE_P (TREE_TYPE (arg0))
+ && FLOAT_TYPE_P (TREE_TYPE (arg1)))
+ {
+ tree newtype = type;
+ if (TYPE_PRECISION (TREE_TYPE (arg0)) > TYPE_PRECISION (newtype))
+ newtype = TREE_TYPE (arg0);
+ if (TYPE_PRECISION (TREE_TYPE (arg1)) > TYPE_PRECISION (newtype))
+ newtype = TREE_TYPE (arg1);
+ if (TYPE_PRECISION (newtype) < TYPE_PRECISION (itype))
+ return build (TREE_CODE (expr), newtype,
+ fold (convert_to_real (newtype, arg0)),
+ fold (convert_to_real (newtype, arg1)));
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
switch (TREE_CODE (TREE_TYPE (expr)))
{
case REAL_TYPE: