aboutsummaryrefslogtreecommitdiff
path: root/gcc/range-op.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/range-op.cc')
-rw-r--r--gcc/range-op.cc215
1 files changed, 191 insertions, 24 deletions
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index c88da8c..028b4b7 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -420,7 +420,7 @@ create_possibly_reversed_range (irange &r, tree type,
// return the equivalent range for TYPE in R; if FALSE/TRUE, do nothing.
bool_range_state
-get_bool_state (irange &r, const irange &lhs, tree val_type)
+get_bool_state (vrange &r, const vrange &lhs, tree val_type)
{
// If there is no result, then this is unexecutable.
if (lhs.undefined_p ())
@@ -446,6 +446,9 @@ get_bool_state (irange &r, const irange &lhs, tree val_type)
class operator_equal : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
@@ -562,6 +565,9 @@ operator_equal::op2_range (irange &r, tree type,
class operator_not_equal : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
@@ -738,6 +744,9 @@ build_ge (irange &r, tree type, const wide_int &val)
class operator_lt : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
@@ -846,6 +855,9 @@ operator_lt::op2_range (irange &r, tree type,
class operator_le : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
@@ -954,6 +966,9 @@ operator_le::op2_range (irange &r, tree type,
class operator_gt : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
@@ -1061,6 +1076,9 @@ operator_gt::op2_range (irange &r, tree type,
class operator_ge : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
@@ -1169,6 +1187,10 @@ operator_ge::op2_range (irange &r, tree type,
class operator_plus : public range_operator
{
+ using range_operator::op1_range;
+ using range_operator::op2_range;
+ using range_operator::lhs_op1_relation;
+ using range_operator::lhs_op2_relation;
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
@@ -1286,7 +1308,7 @@ operator_plus::op1_range (irange &r, tree type,
const irange &op2,
relation_kind rel ATTRIBUTE_UNUSED) const
{
- return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2);
+ return range_op_handler (MINUS_EXPR, type).fold_range (r, type, lhs, op2);
}
bool
@@ -1295,12 +1317,15 @@ operator_plus::op2_range (irange &r, tree type,
const irange &op1,
relation_kind rel ATTRIBUTE_UNUSED) const
{
- return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1);
+ return range_op_handler (MINUS_EXPR, type).fold_range (r, type, lhs, op1);
}
class operator_minus : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
@@ -1445,7 +1470,7 @@ operator_minus::op1_range (irange &r, tree type,
const irange &op2,
relation_kind rel ATTRIBUTE_UNUSED) const
{
- return range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2);
+ return range_op_handler (PLUS_EXPR, type).fold_range (r, type, lhs, op2);
}
bool
@@ -1597,6 +1622,8 @@ cross_product_operator::wi_cross_product (irange &r, tree type,
class operator_mult : public cross_product_operator
{
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
@@ -1629,8 +1656,8 @@ operator_mult::op1_range (irange &r, tree type,
return false;
if (op2.singleton_p (&offset) && !integer_zerop (offset))
- return range_op_handler (TRUNC_DIV_EXPR, type)->fold_range (r, type,
- lhs, op2);
+ return range_op_handler (TRUNC_DIV_EXPR, type).fold_range (r, type,
+ lhs, op2);
return false;
}
@@ -1857,6 +1884,7 @@ operator_div op_ceil_div (CEIL_DIV_EXPR);
class operator_exact_divide : public operator_div
{
+ using range_operator::op1_range;
public:
operator_exact_divide () : operator_div (TRUNC_DIV_EXPR) { }
virtual bool op1_range (irange &r, tree type,
@@ -1881,13 +1909,15 @@ operator_exact_divide::op1_range (irange &r, tree type,
// If op2 is a multiple of 2, we would be able to set some non-zero bits.
if (op2.singleton_p (&offset)
&& !integer_zerop (offset))
- return range_op_handler (MULT_EXPR, type)->fold_range (r, type, lhs, op2);
+ return range_op_handler (MULT_EXPR, type).fold_range (r, type, lhs, op2);
return false;
}
class operator_lshift : public cross_product_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
@@ -1909,6 +1939,9 @@ public:
class operator_rshift : public cross_product_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
+ using range_operator::lhs_op1_relation;
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
@@ -2248,6 +2281,8 @@ operator_rshift::wi_fold (irange &r, tree type,
class operator_cast: public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
@@ -2417,10 +2452,9 @@ operator_cast::op1_range (irange &r, tree type,
// Add this to the unsigned LHS range(s).
int_range_max lim_range (type, lim, lim);
int_range_max lhs_neg;
- range_op_handler (PLUS_EXPR, type)->fold_range (lhs_neg,
- type,
- converted_lhs,
- lim_range);
+ range_op_handler (PLUS_EXPR, type).fold_range (lhs_neg, type,
+ converted_lhs,
+ lim_range);
// lhs_neg now has all the negative versions of the LHS.
// Now union in all the values from SIGNED MIN (0x80000) to
// lim-1 in order to fill in all the ranges with the upper
@@ -2469,6 +2503,9 @@ operator_cast::op1_range (irange &r, tree type,
class operator_logical_and : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
@@ -2542,6 +2579,9 @@ operator_logical_and::op2_range (irange &r, tree type,
class operator_bitwise_and : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
@@ -2988,6 +3028,9 @@ operator_bitwise_and::op2_range (irange &r, tree type,
class operator_logical_or : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
@@ -3051,6 +3094,8 @@ operator_logical_or::op2_range (irange &r, tree type,
class operator_bitwise_or : public range_operator
{
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
@@ -3155,6 +3200,8 @@ operator_bitwise_or::op2_range (irange &r, tree type,
class operator_bitwise_xor : public range_operator
{
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
@@ -3296,6 +3343,8 @@ operator_bitwise_xor::op2_range (irange &r, tree type,
class operator_trunc_mod : public range_operator
{
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
@@ -3432,6 +3481,8 @@ operator_trunc_mod::op2_range (irange &r, tree type,
class operator_logical_not : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
@@ -3487,6 +3538,8 @@ operator_logical_not::op1_range (irange &r,
class operator_bitwise_not : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
@@ -3513,8 +3566,7 @@ operator_bitwise_not::fold_range (irange &r, tree type,
// ~X is simply -1 - X.
int_range<1> minusone (type, wi::minus_one (TYPE_PRECISION (type)),
wi::minus_one (TYPE_PRECISION (type)));
- return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, minusone,
- lh);
+ return range_op_handler (MINUS_EXPR, type).fold_range (r, type, minusone, lh);
}
bool
@@ -3533,6 +3585,7 @@ operator_bitwise_not::op1_range (irange &r, tree type,
class operator_cst : public range_operator
{
+ using range_operator::fold_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
@@ -3553,6 +3606,9 @@ operator_cst::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
class operator_identity : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
+ using range_operator::lhs_op1_relation;
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
@@ -3605,6 +3661,7 @@ operator_identity::op1_range (irange &r, tree type ATTRIBUTE_UNUSED,
class operator_unknown : public range_operator
{
+ using range_operator::fold_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
@@ -3625,6 +3682,7 @@ operator_unknown::fold_range (irange &r, tree type,
class operator_abs : public range_operator
{
+ using range_operator::op1_range;
public:
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
@@ -3790,6 +3848,8 @@ operator_absu::wi_fold (irange &r, tree type,
class operator_negate : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
@@ -3810,9 +3870,8 @@ operator_negate::fold_range (irange &r, tree type,
if (empty_range_varying (r, type, lh, rh))
return true;
// -X is simply 0 - X.
- return range_op_handler (MINUS_EXPR, type)->fold_range (r, type,
- range_zero (type),
- lh);
+ return range_op_handler (MINUS_EXPR, type).fold_range (r, type,
+ range_zero (type), lh);
}
bool
@@ -3828,6 +3887,8 @@ operator_negate::op1_range (irange &r, tree type,
class operator_addr_expr : public range_operator
{
+ using range_operator::fold_range;
+ using range_operator::op1_range;
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
@@ -3978,6 +4039,8 @@ pointer_and_operator::wi_fold (irange &r, tree type,
class pointer_or_operator : public range_operator
{
+ using range_operator::op1_range;
+ using range_operator::op2_range;
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
@@ -4139,8 +4202,8 @@ pointer_table::pointer_table ()
// The tables are hidden and accessed via a simple extern function.
-range_operator *
-range_op_handler (enum tree_code code, tree type)
+static inline range_operator *
+get_handler (enum tree_code code, tree type)
{
// First check if there is a pointer specialization.
if (POINTER_TYPE_P (type))
@@ -4150,16 +4213,120 @@ range_op_handler (enum tree_code code, tree type)
return NULL;
}
+range_op_handler::range_op_handler (tree_code code, tree type)
+{
+ m_op = get_handler (code, type);
+}
+
+range_op_handler::range_op_handler (const gimple *s)
+{
+ if (const gassign *ass = dyn_cast<const gassign *> (s))
+ {
+ enum tree_code code = gimple_assign_rhs_code (ass);
+ // The LHS of a comparison is always an int, so we must look at
+ // the operands.
+ if (TREE_CODE_CLASS (code) == tcc_comparison)
+ m_op = get_handler (code, TREE_TYPE (gimple_assign_rhs1 (ass)));
+ else
+ m_op = get_handler (code, TREE_TYPE (gimple_assign_lhs (ass)));
+ }
+ else if (const gcond *cond = dyn_cast<const gcond *> (s))
+ m_op = get_handler (gimple_cond_code (cond),
+ TREE_TYPE (gimple_cond_lhs (cond)));
+ else
+ m_op = NULL;
+}
+
+bool
+range_op_handler::fold_range (vrange &r, tree type,
+ const vrange &lh,
+ const vrange &rh,
+ relation_kind rel) const
+{
+ if (is_a <irange> (lh))
+ return m_op->fold_range (as_a <irange> (r), type,
+ as_a <irange> (lh),
+ as_a <irange> (rh), rel);
+ gcc_unreachable ();
+ return false;
+}
+
+bool
+range_op_handler::op1_range (vrange &r, tree type,
+ const vrange &lhs,
+ const vrange &op2,
+ relation_kind rel) const
+{
+ if (is_a <irange> (r))
+ return m_op->op1_range (as_a <irange> (r), type,
+ as_a <irange> (lhs),
+ as_a <irange> (op2), rel);
+ gcc_unreachable ();
+ return false;
+}
+
+bool
+range_op_handler::op2_range (vrange &r, tree type,
+ const vrange &lhs,
+ const vrange &op1,
+ relation_kind rel) const
+{
+ if (is_a <irange> (r))
+ return m_op->op2_range (as_a <irange> (r), type,
+ as_a <irange> (lhs),
+ as_a <irange> (op1), rel);
+ gcc_unreachable ();
+ return false;
+}
+
+relation_kind
+range_op_handler::lhs_op1_relation (const vrange &lhs,
+ const vrange &op1,
+ const vrange &op2,
+ relation_kind rel) const
+{
+ if (is_a <irange> (op1))
+ return m_op->lhs_op1_relation (as_a <irange> (lhs),
+ as_a <irange> (op1), as_a <irange> (op2), rel);
+ gcc_unreachable ();
+ return VREL_VARYING;
+}
+
+relation_kind
+range_op_handler::lhs_op2_relation (const vrange &lhs,
+ const vrange &op1,
+ const vrange &op2,
+ relation_kind rel) const
+{
+ if (is_a <irange> (op1))
+ return m_op->lhs_op2_relation (as_a <irange> (lhs),
+ as_a <irange> (op1), as_a <irange> (op2), rel);
+ gcc_unreachable ();
+ return VREL_VARYING;
+}
+
+relation_kind
+range_op_handler::op1_op2_relation (const vrange &lhs) const
+{
+ return m_op->op1_op2_relation (as_a <irange> (lhs));
+}
+
// Cast the range in R to TYPE.
-void
-range_cast (irange &r, tree type)
+bool
+range_cast (vrange &r, tree type)
{
- int_range_max tmp = r;
- range_operator *op = range_op_handler (CONVERT_EXPR, type);
+ Value_Range tmp (r);
+ Value_Range varying (type);
+ varying.set_varying (type);
+ range_op_handler op (CONVERT_EXPR, type);
// Call op_convert, if it fails, the result is varying.
- if (!op->fold_range (r, type, tmp, int_range<1> (type)))
- r.set_varying (type);
+ if (!op || !op.fold_range (r, type, tmp, varying))
+ {
+ r.set_varying (type);
+ return false;
+ }
+ return true;
}
#if CHECKING_P