/* Utility routines for data type conversion for GCC.
Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1997, 1998,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of GCC.
#include "tree.h"
#include "flags.h"
#include "convert.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
#include "langhooks.h"
-#include "real.h"
-#include "fixed-value.h"
/* Convert EXPR to some pointer or reference type TYPE.
EXPR must be pointer, reference, integer, enumeral, or literal zero;
if (TREE_TYPE (expr) == type)
return expr;
- /* Propagate overflow to the NULL pointer. */
- if (integer_zerop (expr))
- return force_fit_type_double (type, 0, 0, 0, TREE_OVERFLOW (expr));
-
switch (TREE_CODE (TREE_TYPE (expr)))
{
case POINTER_TYPE:
/* Only convert in ISO C99 mode. */
if (!TARGET_C99_FUNCTIONS)
break;
- if (outprec < TYPE_PRECISION (long_integer_type_node)
- || (outprec == TYPE_PRECISION (long_integer_type_node)
+ if (outprec < TYPE_PRECISION (integer_type_node)
+ || (outprec == TYPE_PRECISION (integer_type_node)
&& !TYPE_UNSIGNED (type)))
+ fn = mathfn_built_in (s_intype, BUILT_IN_ICEIL);
+ else if (outprec == TYPE_PRECISION (long_integer_type_node)
+ && !TYPE_UNSIGNED (type))
fn = mathfn_built_in (s_intype, BUILT_IN_LCEIL);
else if (outprec == TYPE_PRECISION (long_long_integer_type_node)
&& !TYPE_UNSIGNED (type))
/* Only convert in ISO C99 mode. */
if (!TARGET_C99_FUNCTIONS)
break;
- if (outprec < TYPE_PRECISION (long_integer_type_node)
- || (outprec == TYPE_PRECISION (long_integer_type_node)
+ if (outprec < TYPE_PRECISION (integer_type_node)
+ || (outprec == TYPE_PRECISION (integer_type_node)
&& !TYPE_UNSIGNED (type)))
+ fn = mathfn_built_in (s_intype, BUILT_IN_IFLOOR);
+ else if (outprec == TYPE_PRECISION (long_integer_type_node)
+ && !TYPE_UNSIGNED (type))
fn = mathfn_built_in (s_intype, BUILT_IN_LFLOOR);
else if (outprec == TYPE_PRECISION (long_long_integer_type_node)
&& !TYPE_UNSIGNED (type))
break;
CASE_FLT_FN (BUILT_IN_ROUND):
- if (outprec < TYPE_PRECISION (long_integer_type_node)
- || (outprec == TYPE_PRECISION (long_integer_type_node)
+ /* Only convert in ISO C99 mode. */
+ if (!TARGET_C99_FUNCTIONS)
+ break;
+ if (outprec < TYPE_PRECISION (integer_type_node)
+ || (outprec == TYPE_PRECISION (integer_type_node)
&& !TYPE_UNSIGNED (type)))
+ fn = mathfn_built_in (s_intype, BUILT_IN_IROUND);
+ else if (outprec == TYPE_PRECISION (long_integer_type_node)
+ && !TYPE_UNSIGNED (type))
fn = mathfn_built_in (s_intype, BUILT_IN_LROUND);
else if (outprec == TYPE_PRECISION (long_long_integer_type_node)
&& !TYPE_UNSIGNED (type))
break;
/* ... Fall through ... */
CASE_FLT_FN (BUILT_IN_RINT):
- if (outprec < TYPE_PRECISION (long_integer_type_node)
- || (outprec == TYPE_PRECISION (long_integer_type_node)
+ /* Only convert in ISO C99 mode. */
+ if (!TARGET_C99_FUNCTIONS)
+ break;
+ if (outprec < TYPE_PRECISION (integer_type_node)
+ || (outprec == TYPE_PRECISION (integer_type_node)
&& !TYPE_UNSIGNED (type)))
+ fn = mathfn_built_in (s_intype, BUILT_IN_IRINT);
+ else if (outprec == TYPE_PRECISION (long_integer_type_node)
+ && !TYPE_UNSIGNED (type))
fn = mathfn_built_in (s_intype, BUILT_IN_LRINT);
else if (outprec == TYPE_PRECISION (long_long_integer_type_node)
&& !TYPE_UNSIGNED (type))
be cleared. */
if (TYPE_UNSIGNED (type) != TYPE_UNSIGNED (TREE_TYPE (expr))
&& (TYPE_PRECISION (TREE_TYPE (expr))
- != GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (expr)))))
+ != GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (expr)))))
code = CONVERT_EXPR;
else
code = NOP_EXPR;
type corresponding to its mode, then do a nop conversion
to TYPE. */
else if (TREE_CODE (type) == ENUMERAL_TYPE
- || outprec != GET_MODE_BITSIZE (TYPE_MODE (type)))
+ || outprec != GET_MODE_PRECISION (TYPE_MODE (type)))
return build1 (NOP_EXPR, type,
convert (lang_hooks.types.type_for_mode
(TYPE_MODE (type), TYPE_UNSIGNED (type)),
tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type);
tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type);
+ /* Do not try to narrow operands of pointer subtraction;
+ that will interfere with other folding. */
+ if (ex_form == MINUS_EXPR
+ && CONVERT_EXPR_P (arg0)
+ && CONVERT_EXPR_P (arg1)
+ && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 0)))
+ && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (arg1, 0))))
+ break;
+
if (outprec >= BITS_PER_WORD
|| TRULY_NOOP_TRUNCATION (outprec, inprec)
|| inprec > TYPE_PRECISION (TREE_TYPE (arg0))
(Otherwise would recurse infinitely in convert. */
if (TYPE_PRECISION (typex) != inprec)
{
+ tree otypex = typex;
/* Don't do unsigned arithmetic where signed was wanted,
or vice versa.
Exception: if both of the original operands were
|| ex_form == LSHIFT_EXPR
/* If we have !flag_wrapv, and either ARG0 or
ARG1 is of a signed type, we have to do
- PLUS_EXPR or MINUS_EXPR in an unsigned
- type. Otherwise, we would introduce
+ PLUS_EXPR, MINUS_EXPR or MULT_EXPR in an unsigned
+ type in case the operation in outprec precision
+ could overflow. Otherwise, we would introduce
signed-overflow undefinedness. */
|| ((!TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0))
|| !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1)))
+ && ((TYPE_PRECISION (TREE_TYPE (arg0)) * 2u
+ > outprec)
+ || (TYPE_PRECISION (TREE_TYPE (arg1)) * 2u
+ > outprec))
&& (ex_form == PLUS_EXPR
- || ex_form == MINUS_EXPR)))
+ || ex_form == MINUS_EXPR
+ || ex_form == MULT_EXPR)))
typex = unsigned_type_for (typex);
else
typex = signed_type_for (typex);
- return convert (type,
- fold_build2 (ex_form, typex,
- convert (typex, arg0),
- convert (typex, arg1)));
+
+ if (TYPE_PRECISION (otypex) == TYPE_PRECISION (typex))
+ return convert (type,
+ fold_build2 (ex_form, typex,
+ convert (typex, arg0),
+ convert (typex, arg1)));
}
}
}
/* This is not correct for ABS_EXPR,
since we must test the sign before truncation. */
{
- tree typex;
-
- /* Don't do unsigned arithmetic where signed was wanted,
- or vice versa. */
- if (TYPE_UNSIGNED (TREE_TYPE (expr)))
- typex = unsigned_type_for (type);
- else
- typex = signed_type_for (type);
+ tree typex = unsigned_type_for (type);
return convert (type,
fold_build1 (ex_form, typex,
convert (typex,
break;
}
+ /* When parsing long initializers, we might end up with a lot of casts.
+ Shortcut this. */
+ if (TREE_CODE (expr) == INTEGER_CST)
+ return fold_convert (type, expr);
return build1 (CONVERT_EXPR, type, expr);
case REAL_TYPE:
case VECTOR_TYPE:
if (!tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (TREE_TYPE (expr))))
{
- error ("can't convert between vector values of different size");
+ error ("can%'t convert between vector values of different size");
return error_mark_node;
}
return build1 (VIEW_CONVERT_EXPR, type, expr);
case VECTOR_TYPE:
if (!tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (TREE_TYPE (expr))))
{
- error ("can't convert between vector values of different size");
+ error ("can%'t convert between vector values of different size");
return error_mark_node;
}
return build1 (VIEW_CONVERT_EXPR, type, expr);
default:
- error ("can't convert value to a vector");
+ error ("can%'t convert value to a vector");
return error_mark_node;
}
}