fold-const.c (tree_simple_nonnegative_warnv_p): New.
2008-03-04 Rafael Espindola <espindola@google.com> * fold-const.c (tree_simple_nonnegative_warnv_p): New. (tree_unary_nonnegative_warnv_p): New. (tree_binary_nonnegative_warnv_p): New. (tree_single_nonnegative_warnv_p): New. (tree_invalid_nonnegative_warnv_p): New. (tree_expr_nonnegative_warnv_p): Redefine in term of the new functions. From-SVN: r132875
This commit is contained in:
parent
2925e1c8ad
commit
e918a58a83
@ -1,3 +1,12 @@
|
||||
2008-03-04 Rafael Espindola <espindola@google.com>
|
||||
|
||||
* fold-const.c (tree_simple_nonnegative_warnv_p): New.
|
||||
(tree_unary_nonnegative_warnv_p): New.
|
||||
(tree_binary_nonnegative_warnv_p): New.
|
||||
(tree_single_nonnegative_warnv_p): New.
|
||||
(tree_invalid_nonnegative_warnv_p): New.
|
||||
(tree_expr_nonnegative_warnv_p): Redefine in term of the new functions.
|
||||
|
||||
2008-03-04 Manuel Lopez-Ibanez <manu@gcc.gnu.org>
|
||||
|
||||
PR 28322
|
||||
|
332
gcc/fold-const.c
332
gcc/fold-const.c
@ -14043,106 +14043,161 @@ multiple_of_p (tree type, const_tree top, const_tree bottom)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return true if `t' is known to be non-negative. If the return
|
||||
/* Return true if CODE or TYPE is known to be non-negative. */
|
||||
|
||||
static bool
|
||||
tree_simple_nonnegative_warnv_p (enum tree_code code, tree type)
|
||||
{
|
||||
if ((TYPE_PRECISION (type) != 1 || TYPE_UNSIGNED (type))
|
||||
&& truth_value_p (code))
|
||||
/* Truth values evaluate to 0 or 1, which is nonnegative unless we
|
||||
have a signed:1 type (where the value is -1 and 0). */
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if (CODE OP0) 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_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
|
||||
static bool
|
||||
tree_unary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0,
|
||||
bool *strict_overflow_p)
|
||||
{
|
||||
if (t == error_mark_node)
|
||||
return false;
|
||||
|
||||
if (TYPE_UNSIGNED (TREE_TYPE (t)))
|
||||
if (TYPE_UNSIGNED (type))
|
||||
return true;
|
||||
|
||||
switch (TREE_CODE (t))
|
||||
switch (code)
|
||||
{
|
||||
case SSA_NAME:
|
||||
/* Query VRP to see if it has recorded any information about
|
||||
the range of this object. */
|
||||
return ssa_name_nonnegative_p (t);
|
||||
|
||||
case ABS_EXPR:
|
||||
/* We can't return 1 if flag_wrapv is set because
|
||||
ABS_EXPR<INT_MIN> = INT_MIN. */
|
||||
if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
|
||||
if (!INTEGRAL_TYPE_P (type))
|
||||
return true;
|
||||
if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t)))
|
||||
if (TYPE_OVERFLOW_UNDEFINED (type))
|
||||
{
|
||||
*strict_overflow_p = true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case INTEGER_CST:
|
||||
return tree_int_cst_sgn (t) >= 0;
|
||||
case NON_LVALUE_EXPR:
|
||||
case FLOAT_EXPR:
|
||||
case FIX_TRUNC_EXPR:
|
||||
return tree_expr_nonnegative_warnv_p (op0,
|
||||
strict_overflow_p);
|
||||
|
||||
case REAL_CST:
|
||||
return ! REAL_VALUE_NEGATIVE (TREE_REAL_CST (t));
|
||||
case NOP_EXPR:
|
||||
{
|
||||
tree inner_type = TREE_TYPE (op0);
|
||||
tree outer_type = type;
|
||||
|
||||
case FIXED_CST:
|
||||
return ! FIXED_VALUE_NEGATIVE (TREE_FIXED_CST (t));
|
||||
if (TREE_CODE (outer_type) == REAL_TYPE)
|
||||
{
|
||||
if (TREE_CODE (inner_type) == REAL_TYPE)
|
||||
return tree_expr_nonnegative_warnv_p (op0,
|
||||
strict_overflow_p);
|
||||
if (TREE_CODE (inner_type) == INTEGER_TYPE)
|
||||
{
|
||||
if (TYPE_UNSIGNED (inner_type))
|
||||
return true;
|
||||
return tree_expr_nonnegative_warnv_p (op0,
|
||||
strict_overflow_p);
|
||||
}
|
||||
}
|
||||
else if (TREE_CODE (outer_type) == INTEGER_TYPE)
|
||||
{
|
||||
if (TREE_CODE (inner_type) == REAL_TYPE)
|
||||
return tree_expr_nonnegative_warnv_p (op0,
|
||||
strict_overflow_p);
|
||||
if (TREE_CODE (inner_type) == INTEGER_TYPE)
|
||||
return TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type)
|
||||
&& TYPE_UNSIGNED (inner_type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return tree_simple_nonnegative_warnv_p (code, type);
|
||||
}
|
||||
|
||||
/* We don't know sign of `t', so be conservative and return false. */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if (CODE OP0 OP1) 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. */
|
||||
|
||||
static bool
|
||||
tree_binary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0,
|
||||
tree op1, bool *strict_overflow_p)
|
||||
{
|
||||
if (TYPE_UNSIGNED (type))
|
||||
return true;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case POINTER_PLUS_EXPR:
|
||||
case PLUS_EXPR:
|
||||
if (FLOAT_TYPE_P (TREE_TYPE (t)))
|
||||
return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
|
||||
if (FLOAT_TYPE_P (type))
|
||||
return (tree_expr_nonnegative_warnv_p (op0,
|
||||
strict_overflow_p)
|
||||
&& tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
|
||||
&& tree_expr_nonnegative_warnv_p (op1,
|
||||
strict_overflow_p));
|
||||
|
||||
/* zero_extend(x) + zero_extend(y) is non-negative if x and y are
|
||||
both unsigned and at least 2 bits shorter than the result. */
|
||||
if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE
|
||||
&& TREE_CODE (TREE_OPERAND (t, 0)) == NOP_EXPR
|
||||
&& TREE_CODE (TREE_OPERAND (t, 1)) == NOP_EXPR)
|
||||
if (TREE_CODE (type) == INTEGER_TYPE
|
||||
&& TREE_CODE (op0) == NOP_EXPR
|
||||
&& TREE_CODE (op1) == NOP_EXPR)
|
||||
{
|
||||
tree inner1 = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 0), 0));
|
||||
tree inner2 = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 1), 0));
|
||||
tree inner1 = TREE_TYPE (TREE_OPERAND (op0, 0));
|
||||
tree inner2 = TREE_TYPE (TREE_OPERAND (op1, 0));
|
||||
if (TREE_CODE (inner1) == INTEGER_TYPE && TYPE_UNSIGNED (inner1)
|
||||
&& TREE_CODE (inner2) == INTEGER_TYPE && TYPE_UNSIGNED (inner2))
|
||||
{
|
||||
unsigned int prec = MAX (TYPE_PRECISION (inner1),
|
||||
TYPE_PRECISION (inner2)) + 1;
|
||||
return prec < TYPE_PRECISION (TREE_TYPE (t));
|
||||
return prec < TYPE_PRECISION (type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MULT_EXPR:
|
||||
if (FLOAT_TYPE_P (TREE_TYPE (t)))
|
||||
if (FLOAT_TYPE_P (type))
|
||||
{
|
||||
/* x * x for floating point x is always non-negative. */
|
||||
if (operand_equal_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1), 0))
|
||||
if (operand_equal_p (op0, op1, 0))
|
||||
return true;
|
||||
return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
|
||||
return (tree_expr_nonnegative_warnv_p (op0,
|
||||
strict_overflow_p)
|
||||
&& tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
|
||||
&& tree_expr_nonnegative_warnv_p (op1,
|
||||
strict_overflow_p));
|
||||
}
|
||||
|
||||
/* zero_extend(x) * zero_extend(y) is non-negative if x and y are
|
||||
both unsigned and their total bits is shorter than the result. */
|
||||
if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE
|
||||
&& TREE_CODE (TREE_OPERAND (t, 0)) == NOP_EXPR
|
||||
&& TREE_CODE (TREE_OPERAND (t, 1)) == NOP_EXPR)
|
||||
if (TREE_CODE (type) == INTEGER_TYPE
|
||||
&& TREE_CODE (op0) == NOP_EXPR
|
||||
&& TREE_CODE (op1) == NOP_EXPR)
|
||||
{
|
||||
tree inner1 = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 0), 0));
|
||||
tree inner2 = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 1), 0));
|
||||
tree inner1 = TREE_TYPE (TREE_OPERAND (op0, 0));
|
||||
tree inner2 = TREE_TYPE (TREE_OPERAND (op1, 0));
|
||||
if (TREE_CODE (inner1) == INTEGER_TYPE && TYPE_UNSIGNED (inner1)
|
||||
&& TREE_CODE (inner2) == INTEGER_TYPE && TYPE_UNSIGNED (inner2))
|
||||
return TYPE_PRECISION (inner1) + TYPE_PRECISION (inner2)
|
||||
< TYPE_PRECISION (TREE_TYPE (t));
|
||||
< TYPE_PRECISION (type);
|
||||
}
|
||||
return false;
|
||||
|
||||
case BIT_AND_EXPR:
|
||||
case MAX_EXPR:
|
||||
return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
|
||||
return (tree_expr_nonnegative_warnv_p (op0,
|
||||
strict_overflow_p)
|
||||
|| tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
|
||||
|| tree_expr_nonnegative_warnv_p (op1,
|
||||
strict_overflow_p));
|
||||
|
||||
case BIT_IOR_EXPR:
|
||||
@ -14153,68 +14208,80 @@ tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
|
||||
case CEIL_DIV_EXPR:
|
||||
case FLOOR_DIV_EXPR:
|
||||
case ROUND_DIV_EXPR:
|
||||
return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
|
||||
return (tree_expr_nonnegative_warnv_p (op0,
|
||||
strict_overflow_p)
|
||||
&& tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
|
||||
&& tree_expr_nonnegative_warnv_p (op1,
|
||||
strict_overflow_p));
|
||||
|
||||
case TRUNC_MOD_EXPR:
|
||||
case CEIL_MOD_EXPR:
|
||||
case FLOOR_MOD_EXPR:
|
||||
case ROUND_MOD_EXPR:
|
||||
case SAVE_EXPR:
|
||||
case NON_LVALUE_EXPR:
|
||||
case FLOAT_EXPR:
|
||||
case FIX_TRUNC_EXPR:
|
||||
return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
|
||||
return tree_expr_nonnegative_warnv_p (op0,
|
||||
strict_overflow_p);
|
||||
default:
|
||||
return tree_simple_nonnegative_warnv_p (code, type);
|
||||
}
|
||||
|
||||
case COMPOUND_EXPR:
|
||||
case MODIFY_EXPR:
|
||||
case GIMPLE_MODIFY_STMT:
|
||||
return tree_expr_nonnegative_warnv_p (GENERIC_TREE_OPERAND (t, 1),
|
||||
strict_overflow_p);
|
||||
/* We don't know sign of `t', so be conservative and return false. */
|
||||
return false;
|
||||
}
|
||||
|
||||
case BIND_EXPR:
|
||||
return tree_expr_nonnegative_warnv_p (expr_last (TREE_OPERAND (t, 1)),
|
||||
strict_overflow_p);
|
||||
/* 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. */
|
||||
|
||||
static bool
|
||||
tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
|
||||
{
|
||||
if (TYPE_UNSIGNED (TREE_TYPE (t)))
|
||||
return true;
|
||||
|
||||
enum tree_code code = TREE_CODE (t);
|
||||
switch (code)
|
||||
{
|
||||
case SSA_NAME:
|
||||
/* Query VRP to see if it has recorded any information about
|
||||
the range of this object. */
|
||||
return ssa_name_nonnegative_p (t);
|
||||
|
||||
case INTEGER_CST:
|
||||
return tree_int_cst_sgn (t) >= 0;
|
||||
|
||||
case REAL_CST:
|
||||
return ! REAL_VALUE_NEGATIVE (TREE_REAL_CST (t));
|
||||
|
||||
case FIXED_CST:
|
||||
return ! FIXED_VALUE_NEGATIVE (TREE_FIXED_CST (t));
|
||||
|
||||
case COND_EXPR:
|
||||
return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
|
||||
strict_overflow_p)
|
||||
&& tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 2),
|
||||
strict_overflow_p));
|
||||
default:
|
||||
return tree_simple_nonnegative_warnv_p (TREE_CODE (t),
|
||||
TREE_TYPE (t));
|
||||
}
|
||||
/* We don't know sign of `t', so be conservative and return false. */
|
||||
return false;
|
||||
}
|
||||
|
||||
case NOP_EXPR:
|
||||
{
|
||||
tree inner_type = TREE_TYPE (TREE_OPERAND (t, 0));
|
||||
tree outer_type = TREE_TYPE (t);
|
||||
/* 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. */
|
||||
|
||||
if (TREE_CODE (outer_type) == REAL_TYPE)
|
||||
{
|
||||
if (TREE_CODE (inner_type) == REAL_TYPE)
|
||||
return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
|
||||
strict_overflow_p);
|
||||
if (TREE_CODE (inner_type) == INTEGER_TYPE)
|
||||
{
|
||||
if (TYPE_UNSIGNED (inner_type))
|
||||
return true;
|
||||
return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
|
||||
strict_overflow_p);
|
||||
}
|
||||
}
|
||||
else if (TREE_CODE (outer_type) == INTEGER_TYPE)
|
||||
{
|
||||
if (TREE_CODE (inner_type) == REAL_TYPE)
|
||||
return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t,0),
|
||||
strict_overflow_p);
|
||||
if (TREE_CODE (inner_type) == INTEGER_TYPE)
|
||||
return TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type)
|
||||
&& TYPE_UNSIGNED (inner_type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
static bool
|
||||
tree_invalid_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
|
||||
{
|
||||
if (TYPE_UNSIGNED (TREE_TYPE (t)))
|
||||
return true;
|
||||
|
||||
enum tree_code code = TREE_CODE (t);
|
||||
switch (code)
|
||||
{
|
||||
case TARGET_EXPR:
|
||||
{
|
||||
tree temp = TARGET_EXPR_SLOT (t);
|
||||
@ -14372,25 +14439,102 @@ tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return tree_simple_nonnegative_warnv_p (TREE_CODE (t),
|
||||
TREE_TYPE (t));
|
||||
}
|
||||
break;
|
||||
|
||||
/* ... fall through ... */
|
||||
case COMPOUND_EXPR:
|
||||
case MODIFY_EXPR:
|
||||
case GIMPLE_MODIFY_STMT:
|
||||
return tree_expr_nonnegative_warnv_p (GENERIC_TREE_OPERAND (t, 1),
|
||||
strict_overflow_p);
|
||||
case BIND_EXPR:
|
||||
return tree_expr_nonnegative_warnv_p (expr_last (TREE_OPERAND (t, 1)),
|
||||
strict_overflow_p);
|
||||
case SAVE_EXPR:
|
||||
return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
|
||||
strict_overflow_p);
|
||||
|
||||
default:
|
||||
{
|
||||
tree type = TREE_TYPE (t);
|
||||
if ((TYPE_PRECISION (type) != 1 || TYPE_UNSIGNED (type))
|
||||
&& truth_value_p (TREE_CODE (t)))
|
||||
/* Truth values evaluate to 0 or 1, which is nonnegative unless we
|
||||
have a signed:1 type (where the value is -1 and 0). */
|
||||
return true;
|
||||
}
|
||||
return tree_simple_nonnegative_warnv_p (TREE_CODE (t),
|
||||
TREE_TYPE (t));
|
||||
}
|
||||
|
||||
/* We don't know sign of `t', so be conservative and return false. */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 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_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
|
||||
{
|
||||
enum tree_code code;
|
||||
if (t == error_mark_node)
|
||||
return false;
|
||||
|
||||
code = TREE_CODE (t);
|
||||
switch (TREE_CODE_CLASS (code))
|
||||
{
|
||||
case tcc_binary:
|
||||
case tcc_comparison:
|
||||
return tree_binary_nonnegative_warnv_p (TREE_CODE (t),
|
||||
TREE_TYPE (t),
|
||||
TREE_OPERAND (t, 0),
|
||||
TREE_OPERAND (t, 1),
|
||||
strict_overflow_p);
|
||||
|
||||
case tcc_unary:
|
||||
return tree_unary_nonnegative_warnv_p (TREE_CODE (t),
|
||||
TREE_TYPE (t),
|
||||
TREE_OPERAND (t, 0),
|
||||
strict_overflow_p);
|
||||
|
||||
case tcc_constant:
|
||||
case tcc_declaration:
|
||||
case tcc_reference:
|
||||
return tree_single_nonnegative_warnv_p (t, strict_overflow_p);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case TRUTH_AND_EXPR:
|
||||
case TRUTH_OR_EXPR:
|
||||
case TRUTH_XOR_EXPR:
|
||||
return tree_binary_nonnegative_warnv_p (TREE_CODE (t),
|
||||
TREE_TYPE (t),
|
||||
TREE_OPERAND (t, 0),
|
||||
TREE_OPERAND (t, 1),
|
||||
strict_overflow_p);
|
||||
case TRUTH_NOT_EXPR:
|
||||
return tree_unary_nonnegative_warnv_p (TREE_CODE (t),
|
||||
TREE_TYPE (t),
|
||||
TREE_OPERAND (t, 0),
|
||||
strict_overflow_p);
|
||||
|
||||
case COND_EXPR:
|
||||
case CONSTRUCTOR:
|
||||
case OBJ_TYPE_REF:
|
||||
case ASSERT_EXPR:
|
||||
case ADDR_EXPR:
|
||||
case WITH_SIZE_EXPR:
|
||||
case EXC_PTR_EXPR:
|
||||
case SSA_NAME:
|
||||
case FILTER_EXPR:
|
||||
return tree_single_nonnegative_warnv_p (t, strict_overflow_p);
|
||||
|
||||
default:
|
||||
return tree_invalid_nonnegative_warnv_p (t, strict_overflow_p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return true if `t' is known to be non-negative. Handle warnings
|
||||
about undefined signed overflow. */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user