/* Fold a constant sub-tree into a single node for C-compiler
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GCC.
static void
fold_overflow_warning (const char* gmsgid, enum warn_strict_overflow_code wc)
{
- gcc_assert (!flag_wrapv && !flag_trapv);
if (fold_deferring_overflow_warnings > 0)
{
if (fold_deferred_overflow_warning == NULL
if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK)
return 0;
+ /* Check equality of integer constants before bailing out due to
+ precision differences. */
+ if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
+ return tree_int_cst_equal (arg0, arg1);
+
/* If both types don't have the same signedness, then we can't consider
them equal. We must check this before the STRIP_NOPS calls
- because they may change the signedness of the arguments. */
- if (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE (arg1)))
+ because they may change the signedness of the arguments. As pointers
+ strictly don't have a signedness, require either two pointers or
+ two non-pointers as well. */
+ if (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE (arg1))
+ || POINTER_TYPE_P (TREE_TYPE (arg0)) != POINTER_TYPE_P (TREE_TYPE (arg1)))
return 0;
/* If both types don't have the same precision, then it is not safe
/* Two conversions are equal only if signedness and modes match. */
switch (TREE_CODE (arg0))
{
- case NOP_EXPR:
- case CONVERT_EXPR:
+ CASE_CONVERT:
case FIX_TRUNC_EXPR:
if (TYPE_UNSIGNED (TREE_TYPE (arg0))
!= TYPE_UNSIGNED (TREE_TYPE (arg1)))
/* We are interested in the bare arrangement of bits, so strip everything
that doesn't affect the machine mode. However, record the type of the
outermost expression if it may matter below. */
- if (TREE_CODE (exp) == NOP_EXPR
- || TREE_CODE (exp) == CONVERT_EXPR
+ if (CONVERT_EXPR_P (exp)
|| TREE_CODE (exp) == NON_LVALUE_EXPR)
outer_type = TREE_TYPE (exp);
STRIP_NOPS (exp);
exp = arg0;
continue;
- case NOP_EXPR: case NON_LVALUE_EXPR: case CONVERT_EXPR:
+ CASE_CONVERT: case NON_LVALUE_EXPR:
if (TYPE_PRECISION (arg0_type) > TYPE_PRECISION (exp_type))
break;
fold_convert (ctype, c), 0);
break;
- case CONVERT_EXPR: case NON_LVALUE_EXPR: case NOP_EXPR:
+ CASE_CONVERT: case NON_LVALUE_EXPR:
/* If op0 is an expression ... */
if ((COMPARISON_CLASS_P (op0)
|| UNARY_CLASS_P (op0)
/* If these are the same operation types, we can associate them
assuming no overflow. */
if (tcode == code
- && 0 != (t1 = const_binop (MULT_EXPR, fold_convert (ctype, op1),
- fold_convert (ctype, c), 0))
+ && 0 != (t1 = int_const_binop (MULT_EXPR, fold_convert (ctype, op1),
+ fold_convert (ctype, c), 1))
+ && 0 != (t1 = force_fit_type_double (ctype, TREE_INT_CST_LOW (t1),
+ TREE_INT_CST_HIGH (t1),
+ (TYPE_UNSIGNED (ctype)
+ && tcode != MULT_EXPR) ? -1 : 1,
+ TREE_OVERFLOW (t1)))
&& !TREE_OVERFLOW (t1))
return fold_build2 (tcode, ctype, fold_convert (ctype, op0), t1);
|| TYPE_UNSIGNED (TREE_TYPE (arg0)) == TYPE_UNSIGNED (shorter_type))
&& (TREE_TYPE (arg1_unw) == shorter_type
|| (TYPE_PRECISION (shorter_type)
- >= TYPE_PRECISION (TREE_TYPE (arg1_unw)))
+ > TYPE_PRECISION (TREE_TYPE (arg1_unw)))
+ || ((TYPE_PRECISION (shorter_type)
+ == TYPE_PRECISION (TREE_TYPE (arg1_unw)))
+ && (TYPE_UNSIGNED (shorter_type)
+ == TYPE_UNSIGNED (TREE_TYPE (arg1_unw))))
|| (TREE_CODE (arg1_unw) == INTEGER_CST
&& (TREE_CODE (shorter_type) == INTEGER_TYPE
|| TREE_CODE (shorter_type) == BOOLEAN_TYPE)
tree arg0_inner;
tree inner_type, outer_type;
- if (TREE_CODE (arg0) != NOP_EXPR
- && TREE_CODE (arg0) != CONVERT_EXPR)
+ if (!CONVERT_EXPR_P (arg0))
return NULL_TREE;
outer_type = TREE_TYPE (arg0);
return NULL_TREE;
if (TREE_CODE (arg1) != INTEGER_CST
- && !((TREE_CODE (arg1) == NOP_EXPR
- || TREE_CODE (arg1) == CONVERT_EXPR)
+ && !(CONVERT_EXPR_P (arg1)
&& TREE_TYPE (TREE_OPERAND (arg1, 0)) == inner_type))
return NULL_TREE;
- if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type)
+ if ((TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type)
+ || POINTER_TYPE_P (inner_type) != POINTER_TYPE_P (outer_type))
&& code != NE_EXPR
&& code != EQ_EXPR)
return NULL_TREE;
else
{
/* Try if delta is a multiple of step. */
- tree tmp = div_if_zero_remainder (EXACT_DIV_EXPR, delta, step);
+ tree tmp = div_if_zero_remainder (EXACT_DIV_EXPR, op1, step);
if (! tmp)
continue;
delta = tmp;
return fold_convert (type, op0);
return NULL_TREE;
- case NOP_EXPR:
+ CASE_CONVERT:
case FLOAT_EXPR:
- case CONVERT_EXPR:
case FIX_TRUNC_EXPR:
if (TREE_TYPE (op0) == type)
return op0;
TREE_OPERAND (op0, 1));
/* Handle cases of two conversions in a row. */
- if (TREE_CODE (op0) == NOP_EXPR
- || TREE_CODE (op0) == CONVERT_EXPR)
+ if (CONVERT_EXPR_P (op0))
{
tree inside_type = TREE_TYPE (TREE_OPERAND (op0, 0));
tree inter_type = TREE_TYPE (op0);
/* Convert (T)(x & c) into (T)x & (T)c, if c is an integer
constants (if x has signed type, the sign bit cannot be set
in c). This folds extension into the BIT_AND_EXPR. */
- if (INTEGRAL_TYPE_P (type)
- && TREE_CODE (type) != BOOLEAN_TYPE
+ if (TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (op0) == BIT_AND_EXPR
&& TREE_CODE (TREE_OPERAND (op0, 1)) == INTEGER_CST)
{
if (INTEGRAL_TYPE_P (type)
&& TREE_CODE (op0) == BIT_NOT_EXPR
&& INTEGRAL_TYPE_P (TREE_TYPE (op0))
- && (TREE_CODE (TREE_OPERAND (op0, 0)) == NOP_EXPR
- || TREE_CODE (TREE_OPERAND (op0, 0)) == CONVERT_EXPR)
+ && CONVERT_EXPR_P (TREE_OPERAND (op0, 0))
&& TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (op0)))
{
tem = TREE_OPERAND (TREE_OPERAND (op0, 0), 0);
return fold_convert (type, op0);
/* Strip inner integral conversions that do not change the precision. */
- if ((TREE_CODE (op0) == NOP_EXPR
- || TREE_CODE (op0) == CONVERT_EXPR)
+ if (CONVERT_EXPR_P (op0)
&& (INTEGRAL_TYPE_P (TREE_TYPE (op0))
|| POINTER_TYPE_P (TREE_TYPE (op0)))
&& (INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (op0, 0)))
return t;
}
+/* Return whether BASE + OFFSET + BITPOS may wrap around the address
+ space. This is used to avoid issuing overflow warnings for
+ expressions like &p->x which can not wrap. */
+
+static bool
+pointer_may_wrap_p (tree base, tree offset, HOST_WIDE_INT bitpos)
+{
+ unsigned HOST_WIDE_INT offset_low, total_low;
+ HOST_WIDE_INT size, offset_high, total_high;
+
+ if (!POINTER_TYPE_P (TREE_TYPE (base)))
+ return true;
+
+ if (bitpos < 0)
+ return true;
+
+ if (offset == NULL_TREE)
+ {
+ offset_low = 0;
+ offset_high = 0;
+ }
+ else if (TREE_CODE (offset) != INTEGER_CST || TREE_OVERFLOW (offset))
+ return true;
+ else
+ {
+ offset_low = TREE_INT_CST_LOW (offset);
+ offset_high = TREE_INT_CST_HIGH (offset);
+ }
+
+ if (add_double_with_sign (offset_low, offset_high,
+ bitpos / BITS_PER_UNIT, 0,
+ &total_low, &total_high,
+ true))
+ return true;
+
+ if (total_high != 0)
+ return true;
+
+ size = int_size_in_bytes (TREE_TYPE (TREE_TYPE (base)));
+ if (size <= 0)
+ return true;
+
+ /* We can do slightly better for SIZE if we have an ADDR_EXPR of an
+ array. */
+ if (TREE_CODE (base) == ADDR_EXPR)
+ {
+ HOST_WIDE_INT base_size;
+
+ base_size = int_size_in_bytes (TREE_TYPE (TREE_OPERAND (base, 0)));
+ if (base_size > 0 && size < base_size)
+ size = base_size;
+ }
+
+ return total_low > (unsigned HOST_WIDE_INT) size;
+}
+
/* Subroutine of fold_binary. This routine performs all of the
transformations that are common to the equality/inequality
operators (EQ_EXPR and NE_EXPR) and the ordering operators
{
/* We can fold this expression to a constant if the non-constant
offset parts are equal. */
- if (offset0 == offset1
- || (offset0 && offset1
- && operand_equal_p (offset0, offset1, 0)))
+ if ((offset0 == offset1
+ || (offset0 && offset1
+ && operand_equal_p (offset0, offset1, 0)))
+ && (code == EQ_EXPR
+ || code == NE_EXPR
+ || POINTER_TYPE_OVERFLOW_UNDEFINED))
+
{
+ if (code != EQ_EXPR
+ && code != NE_EXPR
+ && bitpos0 != bitpos1
+ && (pointer_may_wrap_p (base0, offset0, bitpos0)
+ || pointer_may_wrap_p (base1, offset1, bitpos1)))
+ fold_overflow_warning (("assuming pointer wraparound does not "
+ "occur when comparing P +- C1 with "
+ "P +- C2"),
+ WARN_STRICT_OVERFLOW_CONDITIONAL);
+
switch (code)
{
case EQ_EXPR:
because pointer arithmetic is restricted to retain within an
object and overflow on pointer differences is undefined as of
6.5.6/8 and /9 with respect to the signed ptrdiff_t. */
- else if (bitpos0 == bitpos1)
+ else if (bitpos0 == bitpos1
+ && ((code == EQ_EXPR || code == NE_EXPR)
+ || POINTER_TYPE_OVERFLOW_UNDEFINED))
{
tree signed_size_type_node;
signed_size_type_node = signed_type_for (size_type_node);
else
offset1 = fold_convert (signed_size_type_node, offset1);
+ if (code != EQ_EXPR
+ && code != NE_EXPR
+ && (pointer_may_wrap_p (base0, offset0, bitpos0)
+ || pointer_may_wrap_p (base1, offset1, bitpos1)))
+ fold_overflow_warning (("assuming pointer wraparound does not "
+ "occur when comparing P +- C1 with "
+ "P +- C2"),
+ WARN_STRICT_OVERFLOW_COMPARISON);
+
return fold_build2 (code, type, offset0, offset1);
}
}
}
if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE
- && (TREE_CODE (arg0) == NOP_EXPR
- || TREE_CODE (arg0) == CONVERT_EXPR))
+ && CONVERT_EXPR_P (arg0))
{
/* If we are widening one operand of an integer comparison,
see if the other operand is similarly being widened. Perhaps we
safe for every expression, except for a comparison expression
because its signedness is derived from its operands. So, in
the latter case, only strip conversions that don't change the
- signedness.
+ signedness. MIN_EXPR/MAX_EXPR also need signedness of arguments
+ preserved.
Note that this is done as an internal manipulation within the
constant folder, in order to find the simplest representation
cases, the appropriate type conversions should be put back in
the tree that will get out of the constant folder. */
- if (kind == tcc_comparison)
+ if (kind == tcc_comparison || code == MIN_EXPR || code == MAX_EXPR)
{
STRIP_SIGN_NOPS (arg0);
STRIP_SIGN_NOPS (arg1);
/* With undefined overflow we can only associate constants
with one variable. */
- if ((POINTER_TYPE_P (type)
+ if (((POINTER_TYPE_P (type) && POINTER_TYPE_OVERFLOW_UNDEFINED)
|| (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_WRAPS (type)))
&& var0 && var1)
{
return fold_build2 (LSHIFT_EXPR, type, op1,
TREE_OPERAND (arg0, 1));
+ /* (A + A) * C -> A * 2 * C */
+ if (TREE_CODE (arg0) == PLUS_EXPR
+ && TREE_CODE (arg1) == INTEGER_CST
+ && operand_equal_p (TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg0, 1), 0))
+ return fold_build2 (MULT_EXPR, type,
+ omit_one_operand (type, TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg0, 1)),
+ fold_build2 (MULT_EXPR, type,
+ build_int_cst (type, 2) , arg1));
+
strict_overflow_p = false;
if (TREE_CODE (arg1) == INTEGER_CST
&& 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE,
if ((code == LT_EXPR || code == GE_EXPR)
&& TYPE_UNSIGNED (TREE_TYPE (arg0))
- && (TREE_CODE (arg1) == NOP_EXPR
- || TREE_CODE (arg1) == CONVERT_EXPR)
+ && CONVERT_EXPR_P (arg1)
&& TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR
&& integer_onep (TREE_OPERAND (TREE_OPERAND (arg1, 0), 0)))
return
*STRICT_OVERFLOW_P. */
bool
+tree_call_nonnegative_warnv_p (enum tree_code code, tree type, tree fndecl,
+ tree arg0, tree arg1, bool *strict_overflow_p)
+{
+ if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+ switch (DECL_FUNCTION_CODE (fndecl))
+ {
+ CASE_FLT_FN (BUILT_IN_ACOS):
+ CASE_FLT_FN (BUILT_IN_ACOSH):
+ CASE_FLT_FN (BUILT_IN_CABS):
+ CASE_FLT_FN (BUILT_IN_COSH):
+ CASE_FLT_FN (BUILT_IN_ERFC):
+ CASE_FLT_FN (BUILT_IN_EXP):
+ CASE_FLT_FN (BUILT_IN_EXP10):
+ CASE_FLT_FN (BUILT_IN_EXP2):
+ CASE_FLT_FN (BUILT_IN_FABS):
+ CASE_FLT_FN (BUILT_IN_FDIM):
+ CASE_FLT_FN (BUILT_IN_HYPOT):
+ CASE_FLT_FN (BUILT_IN_POW10):
+ CASE_INT_FN (BUILT_IN_FFS):
+ CASE_INT_FN (BUILT_IN_PARITY):
+ CASE_INT_FN (BUILT_IN_POPCOUNT):
+ case BUILT_IN_BSWAP32:
+ case BUILT_IN_BSWAP64:
+ /* Always true. */
+ return true;
+
+ CASE_FLT_FN (BUILT_IN_SQRT):
+ /* sqrt(-0.0) is -0.0. */
+ if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type)))
+ return true;
+ return tree_expr_nonnegative_warnv_p (arg0,
+ strict_overflow_p);
+
+ CASE_FLT_FN (BUILT_IN_ASINH):
+ CASE_FLT_FN (BUILT_IN_ATAN):
+ CASE_FLT_FN (BUILT_IN_ATANH):
+ CASE_FLT_FN (BUILT_IN_CBRT):
+ CASE_FLT_FN (BUILT_IN_CEIL):
+ CASE_FLT_FN (BUILT_IN_ERF):
+ CASE_FLT_FN (BUILT_IN_EXPM1):
+ CASE_FLT_FN (BUILT_IN_FLOOR):
+ CASE_FLT_FN (BUILT_IN_FMOD):
+ CASE_FLT_FN (BUILT_IN_FREXP):
+ CASE_FLT_FN (BUILT_IN_LCEIL):
+ CASE_FLT_FN (BUILT_IN_LDEXP):
+ CASE_FLT_FN (BUILT_IN_LFLOOR):
+ CASE_FLT_FN (BUILT_IN_LLCEIL):
+ CASE_FLT_FN (BUILT_IN_LLFLOOR):
+ CASE_FLT_FN (BUILT_IN_LLRINT):
+ CASE_FLT_FN (BUILT_IN_LLROUND):
+ CASE_FLT_FN (BUILT_IN_LRINT):
+ CASE_FLT_FN (BUILT_IN_LROUND):
+ CASE_FLT_FN (BUILT_IN_MODF):
+ CASE_FLT_FN (BUILT_IN_NEARBYINT):
+ CASE_FLT_FN (BUILT_IN_RINT):
+ CASE_FLT_FN (BUILT_IN_ROUND):
+ CASE_FLT_FN (BUILT_IN_SCALB):
+ CASE_FLT_FN (BUILT_IN_SCALBLN):
+ CASE_FLT_FN (BUILT_IN_SCALBN):
+ CASE_FLT_FN (BUILT_IN_SIGNBIT):
+ CASE_FLT_FN (BUILT_IN_SIGNIFICAND):
+ CASE_FLT_FN (BUILT_IN_SINH):
+ CASE_FLT_FN (BUILT_IN_TANH):
+ CASE_FLT_FN (BUILT_IN_TRUNC):
+ /* True if the 1st argument is nonnegative. */
+ return tree_expr_nonnegative_warnv_p (arg0,
+ strict_overflow_p);
+
+ CASE_FLT_FN (BUILT_IN_FMAX):
+ /* True if the 1st OR 2nd arguments are nonnegative. */
+ return (tree_expr_nonnegative_warnv_p (arg0,
+ strict_overflow_p)
+ || (tree_expr_nonnegative_warnv_p (arg1,
+ strict_overflow_p)));
+
+ CASE_FLT_FN (BUILT_IN_FMIN):
+ /* True if the 1st AND 2nd arguments are nonnegative. */
+ return (tree_expr_nonnegative_warnv_p (arg0,
+ strict_overflow_p)
+ && (tree_expr_nonnegative_warnv_p (arg1,
+ strict_overflow_p)));
+
+ CASE_FLT_FN (BUILT_IN_COPYSIGN):
+ /* True if the 2nd argument is nonnegative. */
+ return tree_expr_nonnegative_warnv_p (arg1,
+ strict_overflow_p);
+
+ CASE_FLT_FN (BUILT_IN_POWI):
+ /* True if the 1st argument is nonnegative or the second
+ argument is an even integer. */
+ if (TREE_CODE (arg1) == INTEGER_CST
+ && (TREE_INT_CST_LOW (arg1) & 1) == 0)
+ return true;
+ return tree_expr_nonnegative_warnv_p (arg0,
+ strict_overflow_p);
+
+ CASE_FLT_FN (BUILT_IN_POW):
+ /* True if the 1st argument is nonnegative or the second
+ argument is an even integer valued real. */
+ if (TREE_CODE (arg1) == REAL_CST)
+ {
+ REAL_VALUE_TYPE c;
+ HOST_WIDE_INT n;
+
+ c = TREE_REAL_CST (arg1);
+ n = real_to_integer (&c);
+ if ((n & 1) == 0)
+ {
+ REAL_VALUE_TYPE cint;
+ real_from_integer (&cint, VOIDmode, n,
+ n < 0 ? -1 : 0, 0);
+ if (real_identical (&c, &cint))
+ return true;
+ }
+ }
+ return tree_expr_nonnegative_warnv_p (arg0,
+ strict_overflow_p);
+
+ default:
+ break;
+ }
+ return tree_simple_nonnegative_warnv_p (code,
+ type);
+}
+
+/* Return true if T is known to be non-negative. If the return
+ value is based on the assumption that signed overflow is undefined,
+ set *STRICT_OVERFLOW_P to true; otherwise, don't change
+ *STRICT_OVERFLOW_P. */
+
+bool
tree_invalid_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
{
enum tree_code code = TREE_CODE (t);
case CALL_EXPR:
{
- tree fndecl = get_callee_fndecl (t);
- if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
- switch (DECL_FUNCTION_CODE (fndecl))
- {
- CASE_FLT_FN (BUILT_IN_ACOS):
- CASE_FLT_FN (BUILT_IN_ACOSH):
- CASE_FLT_FN (BUILT_IN_CABS):
- CASE_FLT_FN (BUILT_IN_COSH):
- CASE_FLT_FN (BUILT_IN_ERFC):
- CASE_FLT_FN (BUILT_IN_EXP):
- CASE_FLT_FN (BUILT_IN_EXP10):
- CASE_FLT_FN (BUILT_IN_EXP2):
- CASE_FLT_FN (BUILT_IN_FABS):
- CASE_FLT_FN (BUILT_IN_FDIM):
- CASE_FLT_FN (BUILT_IN_HYPOT):
- CASE_FLT_FN (BUILT_IN_POW10):
- CASE_INT_FN (BUILT_IN_FFS):
- CASE_INT_FN (BUILT_IN_PARITY):
- CASE_INT_FN (BUILT_IN_POPCOUNT):
- case BUILT_IN_BSWAP32:
- case BUILT_IN_BSWAP64:
- /* Always true. */
- return true;
-
- CASE_FLT_FN (BUILT_IN_SQRT):
- /* sqrt(-0.0) is -0.0. */
- if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (t))))
- return true;
- return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
- strict_overflow_p);
-
- CASE_FLT_FN (BUILT_IN_ASINH):
- CASE_FLT_FN (BUILT_IN_ATAN):
- CASE_FLT_FN (BUILT_IN_ATANH):
- CASE_FLT_FN (BUILT_IN_CBRT):
- CASE_FLT_FN (BUILT_IN_CEIL):
- CASE_FLT_FN (BUILT_IN_ERF):
- CASE_FLT_FN (BUILT_IN_EXPM1):
- CASE_FLT_FN (BUILT_IN_FLOOR):
- CASE_FLT_FN (BUILT_IN_FMOD):
- CASE_FLT_FN (BUILT_IN_FREXP):
- CASE_FLT_FN (BUILT_IN_LCEIL):
- CASE_FLT_FN (BUILT_IN_LDEXP):
- CASE_FLT_FN (BUILT_IN_LFLOOR):
- CASE_FLT_FN (BUILT_IN_LLCEIL):
- CASE_FLT_FN (BUILT_IN_LLFLOOR):
- CASE_FLT_FN (BUILT_IN_LLRINT):
- CASE_FLT_FN (BUILT_IN_LLROUND):
- CASE_FLT_FN (BUILT_IN_LRINT):
- CASE_FLT_FN (BUILT_IN_LROUND):
- CASE_FLT_FN (BUILT_IN_MODF):
- CASE_FLT_FN (BUILT_IN_NEARBYINT):
- CASE_FLT_FN (BUILT_IN_RINT):
- CASE_FLT_FN (BUILT_IN_ROUND):
- CASE_FLT_FN (BUILT_IN_SCALB):
- CASE_FLT_FN (BUILT_IN_SCALBLN):
- CASE_FLT_FN (BUILT_IN_SCALBN):
- CASE_FLT_FN (BUILT_IN_SIGNBIT):
- CASE_FLT_FN (BUILT_IN_SIGNIFICAND):
- CASE_FLT_FN (BUILT_IN_SINH):
- CASE_FLT_FN (BUILT_IN_TANH):
- CASE_FLT_FN (BUILT_IN_TRUNC):
- /* True if the 1st argument is nonnegative. */
- return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
- strict_overflow_p);
-
- CASE_FLT_FN (BUILT_IN_FMAX):
- /* True if the 1st OR 2nd arguments are nonnegative. */
- return (tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
- strict_overflow_p)
- || (tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 1),
- strict_overflow_p)));
-
- CASE_FLT_FN (BUILT_IN_FMIN):
- /* True if the 1st AND 2nd arguments are nonnegative. */
- return (tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
- strict_overflow_p)
- && (tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 1),
- strict_overflow_p)));
-
- CASE_FLT_FN (BUILT_IN_COPYSIGN):
- /* True if the 2nd argument is nonnegative. */
- return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 1),
- strict_overflow_p);
-
- CASE_FLT_FN (BUILT_IN_POWI):
- /* True if the 1st argument is nonnegative or the second
- argument is an even integer. */
- if (TREE_CODE (CALL_EXPR_ARG (t, 1)) == INTEGER_CST)
- {
- tree arg1 = CALL_EXPR_ARG (t, 1);
- if ((TREE_INT_CST_LOW (arg1) & 1) == 0)
- return true;
- }
- return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
- strict_overflow_p);
-
- CASE_FLT_FN (BUILT_IN_POW):
- /* True if the 1st argument is nonnegative or the second
- argument is an even integer valued real. */
- if (TREE_CODE (CALL_EXPR_ARG (t, 1)) == REAL_CST)
- {
- REAL_VALUE_TYPE c;
- HOST_WIDE_INT n;
+ tree arg0 = call_expr_nargs (t) > 0 ? CALL_EXPR_ARG (t, 0) : NULL_TREE;
+ tree arg1 = call_expr_nargs (t) > 1 ? CALL_EXPR_ARG (t, 1) : NULL_TREE;
- c = TREE_REAL_CST (CALL_EXPR_ARG (t, 1));
- n = real_to_integer (&c);
- if ((n & 1) == 0)
- {
- REAL_VALUE_TYPE cint;
- real_from_integer (&cint, VOIDmode, n,
- n < 0 ? -1 : 0, 0);
- if (real_identical (&c, &cint))
- return true;
- }
- }
- return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
- strict_overflow_p);
-
- default:
- break;
- }
- return tree_simple_nonnegative_warnv_p (TREE_CODE (t),
- TREE_TYPE (t));
+ return tree_call_nonnegative_warnv_p (TREE_CODE (t),
+ TREE_TYPE (t),
+ get_callee_fndecl (t),
+ arg0,
+ arg1,
+ strict_overflow_p);
}
- break;
-
case COMPOUND_EXPR:
case MODIFY_EXPR:
case GIMPLE_MODIFY_STMT: