/* 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 Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* These routines are somewhat language-independent utility function
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
+#include "stor-layout.h"
#include "flags.h"
#include "convert.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
+#include "target.h"
#include "langhooks.h"
-#include "real.h"
-/* Convert EXPR to some pointer or reference type TYPE.
+#include "builtins.h"
+#include "ubsan.h"
+/* Convert EXPR to some pointer or reference type TYPE.
EXPR must be pointer, reference, integer, enumeral, or literal zero;
in other cases error is called. */
tree
convert_to_pointer (tree type, tree expr)
{
- if (integer_zerop (expr))
- return build_int_cst (type, 0);
+ location_t loc = EXPR_LOCATION (expr);
+ if (TREE_TYPE (expr) == type)
+ return expr;
switch (TREE_CODE (TREE_TYPE (expr)))
{
case POINTER_TYPE:
case REFERENCE_TYPE:
- return build1 (NOP_EXPR, type, expr);
+ {
+ /* If the pointers point to different address spaces, conversion needs
+ to be done via a ADDR_SPACE_CONVERT_EXPR instead of a NOP_EXPR. */
+ addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (type));
+ addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (expr)));
+
+ if (to_as == from_as)
+ return fold_build1_loc (loc, NOP_EXPR, type, expr);
+ else
+ return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, expr);
+ }
case INTEGER_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
- case CHAR_TYPE:
- if (TYPE_PRECISION (TREE_TYPE (expr)) != POINTER_SIZE)
- expr = fold_build1 (NOP_EXPR,
- lang_hooks.types.type_for_size (POINTER_SIZE, 0),
- expr);
- return fold_build1 (CONVERT_EXPR, type, expr);
+ {
+ /* If the input precision differs from the target pointer type
+ precision, first convert the input expression to an integer type of
+ the target precision. Some targets, e.g. VMS, need several pointer
+ sizes to coexist so the latter isn't necessarily POINTER_SIZE. */
+ unsigned int pprec = TYPE_PRECISION (type);
+ unsigned int eprec = TYPE_PRECISION (TREE_TYPE (expr));
+
+ if (eprec != pprec)
+ expr = fold_build1_loc (loc, NOP_EXPR,
+ lang_hooks.types.type_for_size (pprec, 0),
+ expr);
+ }
+ return fold_build1_loc (loc, CONVERT_EXPR, type, expr);
default:
error ("cannot convert to a pointer type");
}
}
-/* Avoid any floating point extensions from EXP. */
-tree
-strip_float_extensions (tree exp)
-{
- tree sub, expt, subt;
-
- /* For floating point constant look up the narrowest type that can hold
- it properly and handle it like (type)(narrowest_type)constant.
- This way we can optimize for instance a=a*2.0 where "a" is float
- but 2.0 is double constant. */
- if (TREE_CODE (exp) == REAL_CST)
- {
- REAL_VALUE_TYPE orig;
- tree type = NULL;
-
- orig = TREE_REAL_CST (exp);
- if (TYPE_PRECISION (TREE_TYPE (exp)) > TYPE_PRECISION (float_type_node)
- && exact_real_truncate (TYPE_MODE (float_type_node), &orig))
- type = float_type_node;
- else if (TYPE_PRECISION (TREE_TYPE (exp))
- > TYPE_PRECISION (double_type_node)
- && exact_real_truncate (TYPE_MODE (double_type_node), &orig))
- type = double_type_node;
- if (type)
- return build_real (type, real_value_truncate (TYPE_MODE (type), orig));
- }
-
- if (TREE_CODE (exp) != NOP_EXPR
- && TREE_CODE (exp) != CONVERT_EXPR)
- return exp;
-
- sub = TREE_OPERAND (exp, 0);
- subt = TREE_TYPE (sub);
- expt = TREE_TYPE (exp);
-
- if (!FLOAT_TYPE_P (subt))
- return exp;
-
- if (TYPE_PRECISION (subt) > TYPE_PRECISION (expt))
- return exp;
-
- return strip_float_extensions (sub);
-}
-
/* Convert EXPR to some floating-point type TYPE.
- EXPR must be float, integer, or enumeral;
+ EXPR must be float, fixed-point, integer, or enumeral;
in other cases error is called. */
tree
enum built_in_function fcode = builtin_mathfn_code (expr);
tree itype = TREE_TYPE (expr);
+ if (TREE_CODE (expr) == COMPOUND_EXPR)
+ {
+ tree t = convert_to_real (type, TREE_OPERAND (expr, 1));
+ if (t == TREE_OPERAND (expr, 1))
+ return expr;
+ return build2_loc (EXPR_LOCATION (expr), COMPOUND_EXPR, TREE_TYPE (t),
+ TREE_OPERAND (expr, 0), t);
+ }
+
/* Disable until we figure out how to decide whether the functions are
present in runtime. */
/* Convert (float)sqrt((double)x) where x is float into sqrtf(x) */
switch (fcode)
{
#define CASE_MATHFN(FN) case BUILT_IN_##FN: case BUILT_IN_##FN##L:
- CASE_MATHFN (ACOS)
- CASE_MATHFN (ACOSH)
- CASE_MATHFN (ASIN)
- CASE_MATHFN (ASINH)
- CASE_MATHFN (ATAN)
- CASE_MATHFN (ATANH)
- CASE_MATHFN (CBRT)
- CASE_MATHFN (COS)
CASE_MATHFN (COSH)
- CASE_MATHFN (ERF)
- CASE_MATHFN (ERFC)
CASE_MATHFN (EXP)
CASE_MATHFN (EXP10)
CASE_MATHFN (EXP2)
- CASE_MATHFN (EXPM1)
- CASE_MATHFN (FABS)
+ CASE_MATHFN (EXPM1)
CASE_MATHFN (GAMMA)
CASE_MATHFN (J0)
CASE_MATHFN (J1)
CASE_MATHFN (LGAMMA)
- CASE_MATHFN (LOG)
- CASE_MATHFN (LOG10)
- CASE_MATHFN (LOG1P)
- CASE_MATHFN (LOG2)
- CASE_MATHFN (LOGB)
CASE_MATHFN (POW10)
- CASE_MATHFN (SIN)
CASE_MATHFN (SINH)
- CASE_MATHFN (SQRT)
- CASE_MATHFN (TAN)
- CASE_MATHFN (TANH)
CASE_MATHFN (TGAMMA)
CASE_MATHFN (Y0)
CASE_MATHFN (Y1)
+ /* The above functions may set errno differently with float
+ input or output so this transformation is not safe with
+ -fmath-errno. */
+ if (flag_errno_math)
+ break;
+ CASE_MATHFN (ACOS)
+ CASE_MATHFN (ACOSH)
+ CASE_MATHFN (ASIN)
+ CASE_MATHFN (ASINH)
+ CASE_MATHFN (ATAN)
+ CASE_MATHFN (ATANH)
+ CASE_MATHFN (CBRT)
+ CASE_MATHFN (COS)
+ CASE_MATHFN (ERF)
+ CASE_MATHFN (ERFC)
+ CASE_MATHFN (LOG)
+ CASE_MATHFN (LOG10)
+ CASE_MATHFN (LOG2)
+ CASE_MATHFN (LOG1P)
+ CASE_MATHFN (SIN)
+ CASE_MATHFN (TAN)
+ CASE_MATHFN (TANH)
+ /* The above functions are not safe to do this conversion. */
+ if (!flag_unsafe_math_optimizations)
+ break;
+ CASE_MATHFN (SQRT)
+ CASE_MATHFN (FABS)
+ CASE_MATHFN (LOGB)
#undef CASE_MATHFN
{
- tree arg0 = strip_float_extensions (TREE_VALUE (TREE_OPERAND (expr, 1)));
+ tree arg0 = strip_float_extensions (CALL_EXPR_ARG (expr, 0));
tree newtype = type;
/* We have (outertype)sqrt((innertype)x). Choose the wider mode from
if (TYPE_PRECISION (TREE_TYPE (arg0)) > TYPE_PRECISION (type))
newtype = TREE_TYPE (arg0);
+ /* We consider to convert
+
+ (T1) sqrtT2 ((T2) exprT3)
+ to
+ (T1) sqrtT4 ((T4) exprT3)
+
+ , where T1 is TYPE, T2 is ITYPE, T3 is TREE_TYPE (ARG0),
+ and T4 is NEWTYPE. All those types are of floating point types.
+ T4 (NEWTYPE) should be narrower than T2 (ITYPE). This conversion
+ is safe only if P1 >= P2*2+2, where P1 and P2 are precisions of
+ T2 and T4. See the following URL for a reference:
+ http://stackoverflow.com/questions/9235456/determining-
+ floating-point-square-root
+ */
+ if ((fcode == BUILT_IN_SQRT || fcode == BUILT_IN_SQRTL)
+ && !flag_unsafe_math_optimizations)
+ {
+ /* The following conversion is unsafe even the precision condition
+ below is satisfied:
+
+ (float) sqrtl ((long double) double_val) -> (float) sqrt (double_val)
+ */
+ if (TYPE_MODE (type) != TYPE_MODE (newtype))
+ break;
+
+ int p1 = REAL_MODE_FORMAT (TYPE_MODE (itype))->p;
+ int p2 = REAL_MODE_FORMAT (TYPE_MODE (newtype))->p;
+ if (p1 < p2 * 2 + 2)
+ break;
+ }
+
/* Be careful 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;
+ {
tree fn = mathfn_built_in (newtype, fcode);
if (fn)
{
- arglist = build_tree_list (NULL_TREE, fold (convert_to_real (newtype, arg0)));
- expr = build_function_call_expr (fn, arglist);
+ tree arg = fold (convert_to_real (newtype, arg0));
+ expr = build_call_expr (fn, 1, arg);
if (newtype == type)
return expr;
}
if (fn)
{
- tree arg0 = strip_float_extensions (TREE_VALUE (TREE_OPERAND (expr,
- 1)));
- tree arglist = build_tree_list (NULL_TREE,
- fold (convert_to_real (type, arg0)));
-
- return build_function_call_expr (fn, arglist);
+ tree arg = strip_float_extensions (CALL_EXPR_ARG (expr, 0));
+
+ /* Make sure (type)arg0 is an extension, otherwise we could end up
+ changing (float)floor(double d) into floorf((float)d), which is
+ incorrect because (float)d uses round-to-nearest and can round
+ up to the next integer. */
+ if (TYPE_PRECISION (type) >= TYPE_PRECISION (TREE_TYPE (arg)))
+ return build_call_expr (fn, 1, fold (convert_to_real (type, arg)));
}
}
if (itype != type && FLOAT_TYPE_P (type))
switch (TREE_CODE (expr))
{
- /* Convert (float)-x into -(float)x. This is always safe. */
+ /* Convert (float)-x into -(float)x. This is safe for
+ round-to-nearest rounding mode when the inner type is float. */
case ABS_EXPR:
case NEGATE_EXPR:
- if (TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (expr)))
+ if (!flag_rounding_math
+ && FLOAT_TYPE_P (itype)
+ && TYPE_PRECISION (type) < TYPE_PRECISION (itype))
return build1 (TREE_CODE (expr), type,
fold (convert_to_real (type,
TREE_OPERAND (expr, 0))));
tree arg1 = strip_float_extensions (TREE_OPERAND (expr, 1));
if (FLOAT_TYPE_P (TREE_TYPE (arg0))
- && FLOAT_TYPE_P (TREE_TYPE (arg1)))
+ && FLOAT_TYPE_P (TREE_TYPE (arg1))
+ && DECIMAL_FLOAT_TYPE_P (itype) == DECIMAL_FLOAT_TYPE_P (type))
{
tree newtype = type;
+
+ if (TYPE_MODE (TREE_TYPE (arg0)) == SDmode
+ || TYPE_MODE (TREE_TYPE (arg1)) == SDmode
+ || TYPE_MODE (type) == SDmode)
+ newtype = dfloat32_type_node;
+ if (TYPE_MODE (TREE_TYPE (arg0)) == DDmode
+ || TYPE_MODE (TREE_TYPE (arg1)) == DDmode
+ || TYPE_MODE (type) == DDmode)
+ newtype = dfloat64_type_node;
+ if (TYPE_MODE (TREE_TYPE (arg0)) == TDmode
+ || TYPE_MODE (TREE_TYPE (arg1)) == TDmode
+ || TYPE_MODE (type) == TDmode)
+ newtype = dfloat128_type_node;
+ if (newtype == dfloat32_type_node
+ || newtype == dfloat64_type_node
+ || newtype == dfloat128_type_node)
+ {
+ expr = build2 (TREE_CODE (expr), newtype,
+ fold (convert_to_real (newtype, arg0)),
+ fold (convert_to_real (newtype, arg1)));
+ if (newtype == type)
+ return expr;
+ break;
+ }
+
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))
+ /* Sometimes this transformation is safe (cannot
+ change results through affecting double rounding
+ cases) and sometimes it is not. If NEWTYPE is
+ wider than TYPE, e.g. (float)((long double)double
+ + (long double)double) converted to
+ (float)(double + double), the transformation is
+ unsafe regardless of the details of the types
+ involved; double rounding can arise if the result
+ of NEWTYPE arithmetic is a NEWTYPE value half way
+ between two representable TYPE values but the
+ exact value is sufficiently different (in the
+ right direction) for this difference to be
+ visible in ITYPE arithmetic. If NEWTYPE is the
+ same as TYPE, however, the transformation may be
+ safe depending on the types involved: it is safe
+ if the ITYPE has strictly more than twice as many
+ mantissa bits as TYPE, can represent infinities
+ and NaNs if the TYPE can, and has sufficient
+ exponent range for the product or ratio of two
+ values representable in the TYPE to be within the
+ range of normal values of ITYPE. */
+ if (TYPE_PRECISION (newtype) < TYPE_PRECISION (itype)
+ && (flag_unsafe_math_optimizations
+ || (TYPE_PRECISION (newtype) == TYPE_PRECISION (type)
+ && real_can_shorten_arithmetic (TYPE_MODE (itype),
+ TYPE_MODE (type))
+ && !excess_precision_type (newtype))))
{
expr = build2 (TREE_CODE (expr), newtype,
fold (convert_to_real (newtype, arg0)),
switch (TREE_CODE (TREE_TYPE (expr)))
{
case REAL_TYPE:
- return build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR,
- type, expr);
+ /* Ignore the conversion if we don't need to store intermediate
+ results and neither type is a decimal float. */
+ return build1 ((flag_float_store
+ || DECIMAL_FLOAT_TYPE_P (type)
+ || DECIMAL_FLOAT_TYPE_P (itype))
+ ? CONVERT_EXPR : NOP_EXPR, type, expr);
case INTEGER_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
- case CHAR_TYPE:
return build1 (FLOAT_EXPR, type, expr);
+ case FIXED_POINT_TYPE:
+ return build1 (FIXED_CONVERT_EXPR, type, expr);
+
case COMPLEX_TYPE:
return convert (type,
fold_build1 (REALPART_EXPR,
/* Convert EXPR to some integer (or enum) type TYPE.
- EXPR must be pointer, integer, discrete (enum, char, or bool), float, or
- vector; in other cases error is called.
+ EXPR must be pointer, integer, discrete (enum, char, or bool), float,
+ fixed-point or vector; in other cases error is called.
The result of this is always supposed to be a newly created tree node
not in use in any existing structure. */
{
enum tree_code ex_form = TREE_CODE (expr);
tree intype = TREE_TYPE (expr);
- unsigned int inprec = TYPE_PRECISION (intype);
- unsigned int outprec = TYPE_PRECISION (type);
+ unsigned int inprec = element_precision (intype);
+ unsigned int outprec = element_precision (type);
+ location_t loc = EXPR_LOCATION (expr);
/* An INTEGER_TYPE cannot be incomplete, but an ENUMERAL_TYPE can
be. Consider `enum E = { a, b = (enum E) 3 };'. */
return error_mark_node;
}
+ if (ex_form == COMPOUND_EXPR)
+ {
+ tree t = convert_to_integer (type, TREE_OPERAND (expr, 1));
+ if (t == TREE_OPERAND (expr, 1))
+ return expr;
+ return build2_loc (EXPR_LOCATION (expr), COMPOUND_EXPR, TREE_TYPE (t),
+ TREE_OPERAND (expr, 0), t);
+ }
+
/* Convert e.g. (long)round(d) -> lround(d). */
/* If we're converting to char, we may encounter differing behavior
between converting from double->char vs double->long->char.
tree s_intype = TREE_TYPE (s_expr);
const enum built_in_function fcode = builtin_mathfn_code (s_expr);
tree fn = 0;
-
+
switch (fcode)
{
- case BUILT_IN_CEIL: case BUILT_IN_CEILF: case BUILT_IN_CEILL:
+ CASE_FLT_FN (BUILT_IN_CEIL):
/* Only convert in ISO C99 mode. */
- if (!TARGET_C99_FUNCTIONS)
+ if (!targetm.libc_has_function (function_c99_misc))
break;
- if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (long_long_integer_type_node))
- fn = mathfn_built_in (s_intype, BUILT_IN_LLCEIL);
- else
+ 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))
+ fn = mathfn_built_in (s_intype, BUILT_IN_LLCEIL);
break;
- case BUILT_IN_FLOOR: case BUILT_IN_FLOORF: case BUILT_IN_FLOORL:
+ CASE_FLT_FN (BUILT_IN_FLOOR):
/* Only convert in ISO C99 mode. */
- if (!TARGET_C99_FUNCTIONS)
+ if (!targetm.libc_has_function (function_c99_misc))
break;
- if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (long_long_integer_type_node))
- fn = mathfn_built_in (s_intype, BUILT_IN_LLFLOOR);
- else
+ 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))
+ fn = mathfn_built_in (s_intype, BUILT_IN_LLFLOOR);
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);
- else
+ CASE_FLT_FN (BUILT_IN_ROUND):
+ /* Only convert in ISO C99 mode and with -fno-math-errno. */
+ if (!targetm.libc_has_function (function_c99_misc) || flag_errno_math)
+ 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))
+ fn = mathfn_built_in (s_intype, BUILT_IN_LLROUND);
break;
- case BUILT_IN_RINT: case BUILT_IN_RINTF: case BUILT_IN_RINTL:
- /* Only convert rint* if we can ignore math exceptions. */
+ CASE_FLT_FN (BUILT_IN_NEARBYINT):
+ /* Only convert nearbyint* if we can ignore math exceptions. */
if (flag_trapping_math)
break;
/* ... Fall through ... */
- case BUILT_IN_NEARBYINT: case BUILT_IN_NEARBYINTF: case BUILT_IN_NEARBYINTL:
- if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (long_long_integer_type_node))
- fn = mathfn_built_in (s_intype, BUILT_IN_LLRINT);
- else
- fn = mathfn_built_in (s_intype, BUILT_IN_LRINT);
+ CASE_FLT_FN (BUILT_IN_RINT):
+ /* Only convert in ISO C99 mode and with -fno-math-errno. */
+ if (!targetm.libc_has_function (function_c99_misc) || flag_errno_math)
+ 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))
+ fn = mathfn_built_in (s_intype, BUILT_IN_LLRINT);
break;
- case BUILT_IN_TRUNC: case BUILT_IN_TRUNCF: case BUILT_IN_TRUNCL:
- {
- tree arglist = TREE_OPERAND (s_expr, 1);
- return convert_to_integer (type, TREE_VALUE (arglist));
- }
+ CASE_FLT_FN (BUILT_IN_TRUNC):
+ return convert_to_integer (type, CALL_EXPR_ARG (s_expr, 0));
default:
break;
}
-
+
if (fn)
{
- tree arglist = TREE_OPERAND (s_expr, 1);
- tree newexpr = build_function_call_expr (fn, arglist);
+ tree newexpr = build_call_expr (fn, 1, CALL_EXPR_ARG (s_expr, 0));
+ return convert_to_integer (type, newexpr);
+ }
+ }
+
+ /* Convert (int)logb(d) -> ilogb(d). */
+ if (optimize
+ && flag_unsafe_math_optimizations
+ && !flag_trapping_math && !flag_errno_math && flag_finite_math_only
+ && integer_type_node
+ && (outprec > TYPE_PRECISION (integer_type_node)
+ || (outprec == TYPE_PRECISION (integer_type_node)
+ && !TYPE_UNSIGNED (type))))
+ {
+ tree s_expr = strip_float_extensions (expr);
+ tree s_intype = TREE_TYPE (s_expr);
+ const enum built_in_function fcode = builtin_mathfn_code (s_expr);
+ tree fn = 0;
+
+ switch (fcode)
+ {
+ CASE_FLT_FN (BUILT_IN_LOGB):
+ fn = mathfn_built_in (s_intype, BUILT_IN_ILOGB);
+ break;
+
+ default:
+ break;
+ }
+
+ if (fn)
+ {
+ tree newexpr = build_call_expr (fn, 1, CALL_EXPR_ARG (s_expr, 0));
return convert_to_integer (type, newexpr);
}
}
if (integer_zerop (expr))
return build_int_cst (type, 0);
- /* Convert to an unsigned integer of the correct width first,
- and from there widen/truncate to the required type. */
+ /* Convert to an unsigned integer of the correct width first, and from
+ there widen/truncate to the required type. Some targets support the
+ coexistence of multiple valid pointer sizes, so fetch the one we need
+ from the type. */
expr = fold_build1 (CONVERT_EXPR,
- lang_hooks.types.type_for_size (POINTER_SIZE, 0),
+ lang_hooks.types.type_for_size
+ (TYPE_PRECISION (intype), 0),
expr);
- return fold_build1 (NOP_EXPR, type, expr);
+ return fold_convert (type, expr);
case INTEGER_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
- case CHAR_TYPE:
+ case OFFSET_TYPE:
/* If this is a logical operation, which just returns 0 or 1, we can
change the type of the expression. */
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;
- return build1 (code, type, expr);
+ return fold_build1 (code, type, expr);
}
/* If TYPE is an enumeral type or a type with a precision less
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)),
/* We can pass truncation down through right shifting
when the shift count is a nonpositive constant. */
if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST
- && tree_int_cst_lt (TREE_OPERAND (expr, 1),
- convert (TREE_TYPE (TREE_OPERAND (expr, 1)),
- integer_one_node)))
+ && tree_int_cst_sgn (TREE_OPERAND (expr, 1)) <= 0)
goto trunc1;
break;
but (int) a << 32 is undefined and would get a
warning. */
- tree t = convert_to_integer (type, integer_zero_node);
+ tree t = build_int_cst (type, 0);
/* If the original expression had side-effects, we must
preserve it. */
}
break;
+ case TRUNC_DIV_EXPR:
+ {
+ tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type);
+ tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type);
+
+ /* Don't distribute unless the output precision is at least as big
+ as the actual inputs and it has the same signedness. */
+ if (outprec >= TYPE_PRECISION (TREE_TYPE (arg0))
+ && outprec >= TYPE_PRECISION (TREE_TYPE (arg1))
+ /* If signedness of arg0 and arg1 don't match,
+ we can't necessarily find a type to compare them in. */
+ && (TYPE_UNSIGNED (TREE_TYPE (arg0))
+ == TYPE_UNSIGNED (TREE_TYPE (arg1)))
+ /* Do not change the sign of the division. */
+ && (TYPE_UNSIGNED (TREE_TYPE (expr))
+ == TYPE_UNSIGNED (TREE_TYPE (arg0)))
+ /* Either require unsigned division or a division by
+ a constant that is not -1. */
+ && (TYPE_UNSIGNED (TREE_TYPE (arg0))
+ || (TREE_CODE (arg1) == INTEGER_CST
+ && !integer_all_onesp (arg1))))
+ goto trunc1;
+ break;
+ }
+
case MAX_EXPR:
case MIN_EXPR:
case MULT_EXPR:
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))
/* Can't do arithmetic in enumeral types
so use an integer type that will hold the values. */
if (TREE_CODE (typex) == ENUMERAL_TYPE)
- typex = lang_hooks.types.type_for_size
- (TYPE_PRECISION (typex), TYPE_UNSIGNED (typex));
+ typex
+ = lang_hooks.types.type_for_size (TYPE_PRECISION (typex),
+ TYPE_UNSIGNED (typex));
/* But now perhaps TYPEX is as wide as INPREC.
In that case, do nothing special here.
|| ex_form == RSHIFT_EXPR
|| ex_form == LROTATE_EXPR
|| ex_form == RROTATE_EXPR))
- || ex_form == LSHIFT_EXPR)
- typex = lang_hooks.types.unsigned_type (typex);
+ || 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, 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 == MULT_EXPR)))
+ {
+ if (!TYPE_UNSIGNED (typex))
+ typex = unsigned_type_for (typex);
+ }
else
- typex = lang_hooks.types.signed_type (typex);
+ {
+ if (TYPE_UNSIGNED (typex))
+ typex = signed_type_for (typex);
+ }
return convert (type,
fold_build2 (ex_form, typex,
convert (typex, arg0),
/* This is not correct for ABS_EXPR,
since we must test the sign before truncation. */
{
+ /* Do the arithmetic in type TYPEX,
+ then convert result to TYPE. */
tree typex = type;
/* Can't do arithmetic in enumeral types
so use an integer type that will hold the values. */
if (TREE_CODE (typex) == ENUMERAL_TYPE)
- typex = lang_hooks.types.type_for_size
- (TYPE_PRECISION (typex), TYPE_UNSIGNED (typex));
-
- /* But now perhaps TYPEX is as wide as INPREC.
- In that case, do nothing special here.
- (Otherwise would recurse infinitely in convert. */
- if (TYPE_PRECISION (typex) != inprec)
- {
- /* Don't do unsigned arithmetic where signed was wanted,
- or vice versa. */
- if (TYPE_UNSIGNED (TREE_TYPE (expr)))
- typex = lang_hooks.types.unsigned_type (typex);
- else
- typex = lang_hooks.types.signed_type (typex);
- return convert (type,
- fold_build1 (ex_form, typex,
- convert (typex,
- TREE_OPERAND (expr, 0))));
- }
+ typex
+ = lang_hooks.types.type_for_size (TYPE_PRECISION (typex),
+ TYPE_UNSIGNED (typex));
+
+ if (!TYPE_UNSIGNED (typex))
+ typex = unsigned_type_for (typex);
+ return convert (type,
+ fold_build1 (ex_form, typex,
+ convert (typex,
+ TREE_OPERAND (expr, 0))));
}
- case NOP_EXPR:
+ CASE_CONVERT:
/* Don't introduce a
"can't convert between vector values of different size" error. */
if (TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == VECTOR_TYPE
case COND_EXPR:
/* It is sometimes worthwhile to push the narrowing down through
- the conditional and never loses. */
+ the conditional and never loses. A COND_EXPR may have a throw
+ as one operand, which then has void type. Just leave void
+ operands as they are. */
return fold_build3 (COND_EXPR, type, TREE_OPERAND (expr, 0),
- convert (type, TREE_OPERAND (expr, 1)),
- convert (type, TREE_OPERAND (expr, 2)));
+ VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1)))
+ ? TREE_OPERAND (expr, 1)
+ : convert (type, TREE_OPERAND (expr, 1)),
+ VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 2)))
+ ? TREE_OPERAND (expr, 2)
+ : convert (type, TREE_OPERAND (expr, 2)));
default:
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:
- return build1 (FIX_TRUNC_EXPR, type, expr);
+ if (flag_sanitize & SANITIZE_FLOAT_CAST
+ && do_ubsan_in_current_function ())
+ {
+ expr = save_expr (expr);
+ tree check = ubsan_instrument_float_cast (loc, type, expr, expr);
+ expr = build1 (FIX_TRUNC_EXPR, type, expr);
+ if (check == NULL)
+ return expr;
+ return fold_build2 (COMPOUND_EXPR, TREE_TYPE (expr), check, expr);
+ }
+ else
+ return build1 (FIX_TRUNC_EXPR, type, expr);
+
+ case FIXED_POINT_TYPE:
+ return build1 (FIXED_CONVERT_EXPR, type, expr);
case COMPLEX_TYPE:
return convert (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 a vector of type %qT"
+ " to type %qT which has different size",
+ TREE_TYPE (expr), type);
return error_mark_node;
}
- return build1 (NOP_EXPR, type, expr);
+ return build1 (VIEW_CONVERT_EXPR, type, expr);
default:
error ("aggregate value used where an integer was expected");
switch (TREE_CODE (TREE_TYPE (expr)))
{
case REAL_TYPE:
+ case FIXED_POINT_TYPE:
case INTEGER_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
- case CHAR_TYPE:
return build2 (COMPLEX_EXPR, type, convert (subtype, expr),
convert (subtype, integer_zero_node));
if (TYPE_MAIN_VARIANT (elt_type) == TYPE_MAIN_VARIANT (subtype))
return expr;
+ else if (TREE_CODE (expr) == COMPOUND_EXPR)
+ {
+ tree t = convert_to_complex (type, TREE_OPERAND (expr, 1));
+ if (t == TREE_OPERAND (expr, 1))
+ return expr;
+ return build2_loc (EXPR_LOCATION (expr), COMPOUND_EXPR,
+ TREE_TYPE (t), TREE_OPERAND (expr, 0), t);
+ }
else if (TREE_CODE (expr) == COMPLEX_EXPR)
return fold_build2 (COMPLEX_EXPR, type,
convert (subtype, TREE_OPERAND (expr, 0)),
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 a value of type %qT"
+ " to vector type %qT which has different size",
+ TREE_TYPE (expr), type);
return error_mark_node;
}
- return build1 (NOP_EXPR, type, expr);
+ return build1 (VIEW_CONVERT_EXPR, type, expr);
+
+ default:
+ error ("can%'t convert value to a vector");
+ return error_mark_node;
+ }
+}
+
+/* Convert EXPR to some fixed-point type TYPE.
+
+ EXPR must be fixed-point, float, integer, or enumeral;
+ in other cases error is called. */
+
+tree
+convert_to_fixed (tree type, tree expr)
+{
+ if (integer_zerop (expr))
+ {
+ tree fixed_zero_node = build_fixed (type, FCONST0 (TYPE_MODE (type)));
+ return fixed_zero_node;
+ }
+ else if (integer_onep (expr) && ALL_SCALAR_ACCUM_MODE_P (TYPE_MODE (type)))
+ {
+ tree fixed_one_node = build_fixed (type, FCONST1 (TYPE_MODE (type)));
+ return fixed_one_node;
+ }
+
+ switch (TREE_CODE (TREE_TYPE (expr)))
+ {
+ case FIXED_POINT_TYPE:
+ case INTEGER_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case REAL_TYPE:
+ return build1 (FIXED_CONVERT_EXPR, type, expr);
+
+ case COMPLEX_TYPE:
+ return convert (type,
+ fold_build1 (REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)), expr));
default:
- error ("can't convert value to a vector");
+ error ("aggregate value used where a fixed-point was expected");
return error_mark_node;
}
}