aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael Avila de Espindola <espindola@google.com>2008-03-04 22:20:34 +0000
committerRafael Espindola <espindola@gcc.gnu.org>2008-03-04 22:20:34 +0000
commite918a58a835bf5e8c36ffff29d619fa778c2a347 (patch)
tree16846c4822ad2ee58f97b4349a12af73fde815d9
parent2925e1c8ad156081706df4a2447fb74af08c8a22 (diff)
downloadgcc-e918a58a835bf5e8c36ffff29d619fa778c2a347.zip
gcc-e918a58a835bf5e8c36ffff29d619fa778c2a347.tar.gz
gcc-e918a58a835bf5e8c36ffff29d619fa778c2a347.tar.bz2
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
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/fold-const.c332
2 files changed, 247 insertions, 94 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f0425f8..a536011 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 503da6a..e32a737 100644
--- a/gcc/fold-const.c
+++ b/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. */