This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Simplify floating point conversions III
> On Wed, Nov 06, 2002 at 06:54:41PM +0100, Jan Hubicka wrote:
> > + 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. */
>
> I don't believe this to be true.
>
> > + /* Wind away possible cast. */
> > + if (TREE_CODE (arg0) == NOP_EXPR)
> > + arg0 = TREE_OPERAND (arg0, 0);
>
> Why would you do this? This might be casting down to double from
> long double. You should only strip casts when they widen the type.
>
> > + /* convert (outertype)((innertype0)a+(innertype1)b)
> > + into ((newtype)a+(newtype)b) where newtype
> > + is the widest mode from all of these. */
>
> This changes overflow characteristics of +. Consider
>
> (double)((float)a + (float)b)
>
> where A = B = 2**127. The result should be +Inf, not 2**128.
>
> Finally, I think it is alarmingly incorrect that
>
> (float)((double)a + (double)b))
>
> does not result in a quantity of type float, as requested.
Hi,
this patch fixes the two problems and removes the comment.
Honza
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 21:45:01 -0000
*************** tree
*** 80,85 ****
--- 80,233 ----
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) where x is float into sqrtf(x) */
+ 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
+ && (TYPE_PRECISION (TREE_TYPE (arg0))
+ > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))))
+ 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;
+ 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])
+ {
+ arglist = build_tree_list (NULL_TREE, fold (convert_to_real (newtype, arg0)));
+ expr = build_function_call_expr (built_in_decls [fcode], arglist);
+ if (newtype == type)
+ return expr;
+ }
+ }
+ }
+
+ /* 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
+ && (TYPE_PRECISION (TREE_TYPE (arg0))
+ > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))))
+ arg0 = TREE_OPERAND (arg0, 0);
+ if (TREE_CODE (arg1) == NOP_EXPR
+ && (TYPE_PRECISION (TREE_TYPE (arg1))
+ > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 0)))))
+ 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))
+ {
+ expr = build (TREE_CODE (expr), newtype,
+ fold (convert_to_real (newtype, arg0)),
+ fold (convert_to_real (newtype, arg1)));
+ if (newtype == type)
+ return expr;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
switch (TREE_CODE (TREE_TYPE (expr)))
{
case REAL_TYPE: