From 80dd13f5c3bdc7899ee6e863e05b254815ec0cef Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Thu, 17 Jun 2021 11:49:21 -0400
Subject: [PATCH 2/7] Add relational support to range-op.
This patch integrates relations with range-op functionality so that any
known relations can be used to help reduce or resolve ranges.
Initially handle EQ_EXPR, NE_EXPR, LE_EXPR, LT_EXPR, GT_EXPR and GE_EXPR.
* range-op.cc (range_operator::wi_fold): Apply relation effect.
(range_operator::fold_range): Adjust and apply relation effect.
(*::fold_range): Add relation parameters.
(*::op1_range): Ditto.
(*::op2_range): Ditto.
(range_operator::lhs_op1_relation): New.
(range_operator::lhs_op2_relation): New.
(range_operator::op1_op2_relation): New.
(range_operator::op1_op2_relation_effect): New.
(relop_early_resolve): New.
(operator_equal::op1_op2_relation): New.
(operator_equal::fold_range): Call relop_early_resolve.
(operator_not_equal::op1_op2_relation): New.
(operator_not_equal::fold_range): Call relop_early_resolve.
(operator_lt::op1_op2_relation): New.
(operator_lt::fold_range): Call relop_early_resolve.
(operator_le::op1_op2_relation): New.
(operator_le::fold_range): Call relop_early_resolve.
(operator_gt::op1_op2_relation): New.
(operator_gt::fold_range): Call relop_early_resolve.
(operator_ge::op1_op2_relation): New.
(operator_ge::fold_range): Call relop_early_resolve.
* range-op.h (class range_operator): Adjust parameters and methods.
---
gcc/range-op.cc | 584 +++++++++++++++++++++++++++++++++++++-----------
gcc/range-op.h | 24 +-
2 files changed, 469 insertions(+), 139 deletions(-)
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-walk.h"
#include "tree-cfg.h"
#include "wide-int.h"
+#include "value-relation.h"
#include "range-op.h"
// Return the upper limit for a type.
@@ -138,7 +139,8 @@ range_operator::wi_fold (irange &r, tree type,
bool
range_operator::fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const
+ const irange &rh,
+ relation_kind rel) const
{
gcc_checking_assert (irange::supports_type_p (type));
if (empty_range_varying (r, type, lh, rh))
@@ -152,6 +154,7 @@ range_operator::fold_range (irange &r, tree type,
{
wi_fold (r, type, lh.lower_bound (0), lh.upper_bound (0),
rh.lower_bound (0), rh.upper_bound (0));
+ op1_op2_relation_effect (r, type, lh, rh, rel);
return true;
}
@@ -167,8 +170,12 @@ range_operator::fold_range (irange &r, tree type,
wi_fold (tmp, type, lh_lb, lh_ub, rh_lb, rh_ub);
r.union_ (tmp);
if (r.varying_p ())
- return true;
+ {
+ op1_op2_relation_effect (r, type, lh, rh, rel);
+ return true;
+ }
}
+ op1_op2_relation_effect (r, type, lh, rh, rel);
return true;
}
@@ -178,7 +185,8 @@ bool
range_operator::op1_range (irange &r ATTRIBUTE_UNUSED,
tree type ATTRIBUTE_UNUSED,
const irange &lhs ATTRIBUTE_UNUSED,
- const irange &op2 ATTRIBUTE_UNUSED) const
+ const irange &op2 ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return false;
}
@@ -189,11 +197,47 @@ bool
range_operator::op2_range (irange &r ATTRIBUTE_UNUSED,
tree type ATTRIBUTE_UNUSED,
const irange &lhs ATTRIBUTE_UNUSED,
- const irange &op1 ATTRIBUTE_UNUSED) const
+ const irange &op1 ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return false;
}
+// The default relation routines return VREL_NONE.
+
+enum tree_code
+range_operator::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED,
+ const irange &op1 ATTRIBUTE_UNUSED,
+ const irange &op2 ATTRIBUTE_UNUSED) const
+{
+ return VREL_NONE;
+}
+
+enum tree_code
+range_operator::lhs_op2_relation (const irange &lhs ATTRIBUTE_UNUSED,
+ const irange &op1 ATTRIBUTE_UNUSED,
+ const irange &op2 ATTRIBUTE_UNUSED) const
+{
+ return VREL_NONE;
+}
+
+enum tree_code
+range_operator::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED) const
+{
+ return VREL_NONE;
+}
+
+// Default is no relation affects the LHS.
+
+bool
+range_operator::op1_op2_relation_effect (irange &lhs_range ATTRIBUTE_UNUSED,
+ tree type ATTRIBUTE_UNUSED,
+ const irange &op1_range ATTRIBUTE_UNUSED,
+ const irange &op2_range ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
+{
+ return false;
+}
// Create and return a range from a pair of wide-ints that are known
// to have overflowed (or underflowed).
@@ -385,27 +429,82 @@ get_bool_state (irange &r, const irange &lhs, tree val_type)
return BRS_TRUE;
}
+// For relation opcodes, first try to see if the supplied relation
+// forces a true or false result, and return that.
+// Then check for undefined operands. If none of this applies,
+// return false.
+
+static inline bool
+relop_early_resolve (irange &r, tree type, const irange &op1,
+ const irange &op2, relation_kind rel,
+ relation_kind my_rel)
+{
+ // If known relation is a complete subset of this relation, always true.
+ if (relation_union (rel, my_rel) == my_rel)
+ {
+ r = range_true (type);
+ return true;
+ }
+
+ // If known relation has no subset of this relation, always false.
+ if (relation_intersect (rel, my_rel) == VREL_EMPTY)
+ {
+ r = range_false (type);
+ return true;
+ }
+
+ // If either operand is undefined, return VARYING.
+ if (empty_range_varying (r, type, op1, op2))
+ return true;
+
+ return false;
+}
+
class operator_equal : public range_operator
{
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &val) const;
+ const irange &val,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &val) const;
+ const irange &val,
+ relation_kind rel = VREL_NONE) const;
+ virtual enum tree_code op1_op2_relation (const irange &lhs) const;
} op_equal;
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+enum tree_code
+operator_equal::op1_op2_relation (const irange &lhs) const
+{
+ if (lhs.undefined_p ())
+ return VREL_EMPTY;
+
+ // FALSE = op1 == op2 indicates NE_EXPR.
+ if (lhs.zero_p ())
+ return NE_EXPR;
+
+ // TRUE = op1 == op2 indicates EQ_EXPR.
+ if (!lhs.contains_p (build_zero_cst (lhs.type ())))
+ return EQ_EXPR;
+ return VREL_NONE;
+}
+
+
bool
operator_equal::fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel) const
{
- if (empty_range_varying (r, type, op1, op2))
+ if (relop_early_resolve (r, type, op1, op2, rel, EQ_EXPR))
return true;
// We can be sure the values are always equal or not if both ranges
@@ -435,7 +534,8 @@ operator_equal::fold_range (irange &r, tree type,
bool
operator_equal::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -465,32 +565,55 @@ operator_equal::op1_range (irange &r, tree type,
bool
operator_equal::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel) const
{
- return operator_equal::op1_range (r, type, lhs, op1);
+ return operator_equal::op1_range (r, type, lhs, op1, rel);
}
-
class operator_not_equal : public range_operator
{
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
+ virtual enum tree_code op1_op2_relation (const irange &lhs) const;
} op_not_equal;
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+enum tree_code
+operator_not_equal::op1_op2_relation (const irange &lhs) const
+{
+ if (lhs.undefined_p ())
+ return VREL_EMPTY;
+
+ // FALSE = op1 != op2 indicates EQ_EXPR.
+ if (lhs.zero_p ())
+ return EQ_EXPR;
+
+ // TRUE = op1 != op2 indicates NE_EXPR.
+ if (!lhs.contains_p (build_zero_cst (lhs.type ())))
+ return NE_EXPR;
+ return VREL_NONE;
+}
+
bool
operator_not_equal::fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel) const
{
- if (empty_range_varying (r, type, op1, op2))
+ if (relop_early_resolve (r, type, op1, op2, rel, NE_EXPR))
return true;
// We can be sure the values are always equal or not if both ranges
@@ -520,7 +643,8 @@ operator_not_equal::fold_range (irange &r, tree type,
bool
operator_not_equal::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -551,9 +675,10 @@ operator_not_equal::op1_range (irange &r, tree type,
bool
operator_not_equal::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel) const
{
- return operator_not_equal::op1_range (r, type, lhs, op1);
+ return operator_not_equal::op1_range (r, type, lhs, op1, rel);
}
// (X < VAL) produces the range of [MIN, VAL - 1].
@@ -607,21 +732,44 @@ class operator_lt : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
+ virtual enum tree_code op1_op2_relation (const irange &lhs) const;
} op_lt;
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+enum tree_code
+operator_lt::op1_op2_relation (const irange &lhs) const
+{
+ if (lhs.undefined_p ())
+ return VREL_EMPTY;
+
+ // FALSE = op1 < op2 indicates GE_EXPR.
+ if (lhs.zero_p ())
+ return GE_EXPR;
+
+ // TRUE = op1 < op2 indicates LT_EXPR.
+ if (!lhs.contains_p (build_zero_cst (lhs.type ())))
+ return LT_EXPR;
+ return VREL_NONE;
+}
+
bool
operator_lt::fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel) const
{
- if (empty_range_varying (r, type, op1, op2))
+ if (relop_early_resolve (r, type, op1, op2, rel, LT_EXPR))
return true;
signop sign = TYPE_SIGN (op1.type ());
@@ -639,7 +787,8 @@ operator_lt::fold_range (irange &r, tree type,
bool
operator_lt::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -660,7 +809,8 @@ operator_lt::op1_range (irange &r, tree type,
bool
operator_lt::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -684,21 +834,44 @@ class operator_le : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
+ virtual enum tree_code op1_op2_relation (const irange &lhs) const;
} op_le;
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+enum tree_code
+operator_le::op1_op2_relation (const irange &lhs) const
+{
+ if (lhs.undefined_p ())
+ return VREL_EMPTY;
+
+ // FALSE = op1 <= op2 indicates GT_EXPR.
+ if (lhs.zero_p ())
+ return GT_EXPR;
+
+ // TRUE = op1 <= op2 indicates LE_EXPR.
+ if (!lhs.contains_p (build_zero_cst (lhs.type ())))
+ return LE_EXPR;
+ return VREL_NONE;
+}
+
bool
operator_le::fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel) const
{
- if (empty_range_varying (r, type, op1, op2))
+ if (relop_early_resolve (r, type, op1, op2, rel, LE_EXPR))
return true;
signop sign = TYPE_SIGN (op1.type ());
@@ -716,7 +889,8 @@ operator_le::fold_range (irange &r, tree type,
bool
operator_le::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -737,7 +911,8 @@ operator_le::op1_range (irange &r, tree type,
bool
operator_le::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -761,20 +936,44 @@ class operator_gt : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
+ virtual enum tree_code op1_op2_relation (const irange &lhs) const;
} op_gt;
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+enum tree_code
+operator_gt::op1_op2_relation (const irange &lhs) const
+{
+ if (lhs.undefined_p ())
+ return VREL_EMPTY;
+
+ // FALSE = op1 > op2 indicates LE_EXPR.
+ if (lhs.zero_p ())
+ return LE_EXPR;
+
+ // TRUE = op1 > op2 indicates GT_EXPR.
+ if (!lhs.contains_p (build_zero_cst (lhs.type ())))
+ return GT_EXPR;
+ return VREL_NONE;
+}
+
+
bool
operator_gt::fold_range (irange &r, tree type,
- const irange &op1, const irange &op2) const
+ const irange &op1, const irange &op2,
+ relation_kind rel) const
{
- if (empty_range_varying (r, type, op1, op2))
+ if (relop_early_resolve (r, type, op1, op2, rel, GT_EXPR))
return true;
signop sign = TYPE_SIGN (op1.type ());
@@ -791,7 +990,8 @@ operator_gt::fold_range (irange &r, tree type,
bool
operator_gt::op1_range (irange &r, tree type,
- const irange &lhs, const irange &op2) const
+ const irange &lhs, const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -812,7 +1012,8 @@ operator_gt::op1_range (irange &r, tree type,
bool
operator_gt::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -836,21 +1037,44 @@ class operator_ge : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
+ virtual enum tree_code op1_op2_relation (const irange &lhs) const;
} op_ge;
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+enum tree_code
+operator_ge::op1_op2_relation (const irange &lhs) const
+{
+ if (lhs.undefined_p ())
+ return VREL_EMPTY;
+
+ // FALSE = op1 >= op2 indicates LT_EXPR.
+ if (lhs.zero_p ())
+ return LT_EXPR;
+
+ // TRUE = op1 >= op2 indicates GE_EXPR.
+ if (!lhs.contains_p (build_zero_cst (lhs.type ())))
+ return GE_EXPR;
+ return VREL_NONE;
+}
+
bool
operator_ge::fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel) const
{
- if (empty_range_varying (r, type, op1, op2))
+ if (relop_early_resolve (r, type, op1, op2, rel, GE_EXPR))
return true;
signop sign = TYPE_SIGN (op1.type ());
@@ -868,7 +1092,8 @@ operator_ge::fold_range (irange &r, tree type,
bool
operator_ge::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -889,7 +1114,8 @@ operator_ge::op1_range (irange &r, tree type,
bool
operator_ge::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -913,10 +1139,12 @@ class operator_plus : public range_operator
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
const wide_int &lh_ub,
@@ -939,7 +1167,8 @@ operator_plus::wi_fold (irange &r, tree type,
bool
operator_plus::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2);
}
@@ -947,7 +1176,8 @@ operator_plus::op1_range (irange &r, tree type,
bool
operator_plus::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1);
}
@@ -958,10 +1188,12 @@ class operator_minus : public range_operator
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
const wide_int &lh_ub,
@@ -984,7 +1216,8 @@ operator_minus::wi_fold (irange &r, tree type,
bool
operator_minus::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2);
}
@@ -992,7 +1225,8 @@ operator_minus::op1_range (irange &r, tree type,
bool
operator_minus::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return fold_range (r, type, op1, lhs);
}
@@ -1127,15 +1361,18 @@ public:
const wide_int &w0, const wide_int &w1) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
} op_mult;
bool
operator_mult::op1_range (irange &r, tree type,
- const irange &lhs, const irange &op2) const
+ const irange &lhs, const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
tree offset;
@@ -1153,9 +1390,10 @@ operator_mult::op1_range (irange &r, tree type,
bool
operator_mult::op2_range (irange &r, tree type,
- const irange &lhs, const irange &op1) const
+ const irange &lhs, const irange &op1,
+ relation_kind rel) const
{
- return operator_mult::op1_range (r, type, lhs, op1);
+ return operator_mult::op1_range (r, type, lhs, op1, rel);
}
bool
@@ -1391,14 +1629,16 @@ public:
operator_exact_divide () : operator_div (TRUNC_DIV_EXPR) { }
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
} op_exact_div;
bool
operator_exact_divide::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
tree offset;
// [2, 4] = op1 / [3,3] since its exact divide, no need to worry about
@@ -1419,10 +1659,12 @@ class operator_lshift : public cross_product_operator
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb, const wide_int &lh_ub,
@@ -1438,7 +1680,8 @@ class operator_rshift : public cross_product_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
const wide_int &lh_ub,
@@ -1450,14 +1693,16 @@ public:
const wide_int &w1) const;
virtual bool op1_range (irange &, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_rshift;
bool
operator_lshift::fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
int_range_max shift_range;
if (!get_shift_range (shift_range, type, op2))
@@ -1572,7 +1817,8 @@ bool
operator_lshift::op1_range (irange &r,
tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
tree shift_amount;
if (op2.singleton_p (&shift_amount))
@@ -1632,7 +1878,8 @@ bool
operator_rshift::op1_range (irange &r,
tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
tree shift;
if (op2.singleton_p (&shift))
@@ -1708,7 +1955,8 @@ operator_rshift::wi_op_overflows (wide_int &res,
bool
operator_rshift::fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
int_range_max shift;
if (!get_shift_range (shift, type, op2))
@@ -1737,10 +1985,12 @@ class operator_cast: public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
private:
bool truncating_cast_p (const irange &inner, const irange &outer) const;
bool inside_domain_p (const wide_int &min, const wide_int &max,
@@ -1818,7 +2068,8 @@ operator_cast::fold_pair (irange &r, unsigned index,
bool
operator_cast::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
const irange &inner,
- const irange &outer) const
+ const irange &outer,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, inner, outer))
return true;
@@ -1844,7 +2095,8 @@ operator_cast::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
bool
operator_cast::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
tree lhs_type = lhs.type ();
gcc_checking_assert (types_compatible_p (op2.type(), type));
@@ -1954,20 +2206,24 @@ class operator_logical_and : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const;
+ const irange &rh,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
} op_logical_and;
bool
operator_logical_and::fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const
+ const irange &rh,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, lh, rh))
return true;
@@ -1989,7 +2245,8 @@ operator_logical_and::fold_range (irange &r, tree type,
bool
operator_logical_and::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2 ATTRIBUTE_UNUSED) const
+ const irange &op2 ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -2010,7 +2267,8 @@ operator_logical_and::op1_range (irange &r, tree type,
bool
operator_logical_and::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return operator_logical_and::op1_range (r, type, lhs, op1);
}
@@ -2021,13 +2279,16 @@ class operator_bitwise_and : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const;
+ const irange &rh,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
const wide_int &lh_ub,
@@ -2106,7 +2367,8 @@ operator_bitwise_and::remove_impossible_ranges (irange &r,
bool
operator_bitwise_and::fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const
+ const irange &rh,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (range_operator::fold_range (r, type, lh, rh))
{
@@ -2397,7 +2659,8 @@ operator_bitwise_and::simple_op1_range_solver (irange &r, tree type,
bool
operator_bitwise_and::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (types_compatible_p (type, boolean_type_node))
return op_logical_and.op1_range (r, type, lhs, op2);
@@ -2420,7 +2683,8 @@ operator_bitwise_and::op1_range (irange &r, tree type,
bool
operator_bitwise_and::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return operator_bitwise_and::op1_range (r, type, lhs, op1);
}
@@ -2431,19 +2695,23 @@ class operator_logical_or : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const;
+ const irange &rh,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
} op_logical_or;
bool
operator_logical_or::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
const irange &lh,
- const irange &rh) const
+ const irange &rh,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, lh, rh))
return true;
@@ -2456,7 +2724,8 @@ operator_logical_or::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
bool
operator_logical_or::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2 ATTRIBUTE_UNUSED) const
+ const irange &op2 ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -2477,7 +2746,8 @@ operator_logical_or::op1_range (irange &r, tree type,
bool
operator_logical_or::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return operator_logical_or::op1_range (r, type, lhs, op1);
}
@@ -2488,10 +2758,12 @@ class operator_bitwise_or : public range_operator
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel= VREL_NONE) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
const wide_int &lh_ub,
@@ -2553,7 +2825,8 @@ operator_bitwise_or::wi_fold (irange &r, tree type,
bool
operator_bitwise_or::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
// If this is really a logical wi_fold, call that.
if (types_compatible_p (type, boolean_type_node))
@@ -2572,7 +2845,8 @@ operator_bitwise_or::op1_range (irange &r, tree type,
bool
operator_bitwise_or::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return operator_bitwise_or::op1_range (r, type, lhs, op1);
}
@@ -2588,10 +2862,12 @@ public:
const wide_int &rh_ub) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
} op_bitwise_xor;
void
@@ -2628,7 +2904,8 @@ operator_bitwise_xor::wi_fold (irange &r, tree type,
bool
operator_bitwise_xor::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (lhs.undefined_p () || lhs.varying_p ())
{
@@ -2662,7 +2939,8 @@ operator_bitwise_xor::op1_range (irange &r, tree type,
bool
operator_bitwise_xor::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return operator_bitwise_xor::op1_range (r, type, lhs, op1);
}
@@ -2677,10 +2955,12 @@ public:
const wide_int &rh_ub) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
} op_trunc_mod;
void
@@ -2730,7 +3010,8 @@ operator_trunc_mod::wi_fold (irange &r, tree type,
bool
operator_trunc_mod::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &) const
+ const irange &,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
// PR 91029.
signop sign = TYPE_SIGN (type);
@@ -2753,7 +3034,8 @@ operator_trunc_mod::op1_range (irange &r, tree type,
bool
operator_trunc_mod::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &) const
+ const irange &,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
// PR 91029.
signop sign = TYPE_SIGN (type);
@@ -2792,10 +3074,12 @@ class operator_logical_not : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const;
+ const irange &rh,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_logical_not;
// Folding a logical NOT, oddly enough, involves doing nothing on the
@@ -2815,7 +3099,8 @@ public:
bool
operator_logical_not::fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh ATTRIBUTE_UNUSED) const
+ const irange &rh ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, lh, rh))
return true;
@@ -2831,7 +3116,8 @@ bool
operator_logical_not::op1_range (irange &r,
tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
// Logical NOT is involutary...do it again.
return fold_range (r, type, lhs, op2);
@@ -2843,16 +3129,19 @@ class operator_bitwise_not : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const;
+ const irange &rh,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_bitwise_not;
bool
operator_bitwise_not::fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const
+ const irange &rh,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, lh, rh))
return true;
@@ -2870,7 +3159,8 @@ operator_bitwise_not::fold_range (irange &r, tree type,
bool
operator_bitwise_not::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (types_compatible_p (type, boolean_type_node))
return op_logical_not.op1_range (r, type, lhs, op2);
@@ -2885,13 +3175,15 @@ class operator_cst : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_integer_cst;
bool
operator_cst::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
const irange &lh,
- const irange &rh ATTRIBUTE_UNUSED) const
+ const irange &rh ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
r = lh;
return true;
@@ -2903,16 +3195,19 @@ class operator_identity : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_identity;
bool
operator_identity::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
const irange &lh,
- const irange &rh ATTRIBUTE_UNUSED) const
+ const irange &rh ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
r = lh;
return true;
@@ -2921,7 +3216,8 @@ operator_identity::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
bool
operator_identity::op1_range (irange &r, tree type ATTRIBUTE_UNUSED,
const irange &lhs,
- const irange &op2 ATTRIBUTE_UNUSED) const
+ const irange &op2 ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
r = lhs;
return true;
@@ -2933,13 +3229,15 @@ class operator_unknown : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_unknown;
bool
operator_unknown::fold_range (irange &r, tree type,
const irange &lh ATTRIBUTE_UNUSED,
- const irange &rh ATTRIBUTE_UNUSED) const
+ const irange &rh ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
r.set_varying (type);
return true;
@@ -2956,7 +3254,8 @@ class operator_abs : public range_operator
const wide_int &rh_ub) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
} op_abs;
void
@@ -3036,7 +3335,8 @@ operator_abs::wi_fold (irange &r, tree type,
bool
operator_abs::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, lhs, op2))
return true;
@@ -3108,16 +3408,19 @@ class operator_negate : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_negate;
bool
operator_negate::fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const
+ const irange &rh,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, lh, rh))
return true;
@@ -3130,7 +3433,8 @@ operator_negate::fold_range (irange &r, tree type,
bool
operator_negate::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
// NEGATE is involutory.
return fold_range (r, type, lhs, op2);
@@ -3142,16 +3446,19 @@ class operator_addr_expr : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_addr;
bool
operator_addr_expr::fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const
+ const irange &rh,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, lh, rh))
return true;
@@ -3169,7 +3476,8 @@ operator_addr_expr::fold_range (irange &r, tree type,
bool
operator_addr_expr::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return operator_addr_expr::fold_range (r, type, lhs, op2);
}
@@ -3288,10 +3596,12 @@ class pointer_or_operator : public range_operator
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb, const wide_int &lh_ub,
const wide_int &rh_lb, const wide_int &rh_ub) const;
@@ -3300,7 +3610,8 @@ public:
bool
pointer_or_operator::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2 ATTRIBUTE_UNUSED) const
+ const irange &op2 ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (lhs.zero_p ())
{
@@ -3315,7 +3626,8 @@ pointer_or_operator::op1_range (irange &r, tree type,
bool
pointer_or_operator::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return pointer_or_operator::op1_range (r, type, lhs, op1);
}
@@ -52,7 +52,8 @@ public:
// Perform an operation between 2 ranges and return it.
virtual bool fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const;
+ const irange &rh,
+ relation_kind rel = VREL_NONE) const;
// Return the range for op[12] in the general case. LHS is the range for
// the LHS of the expression, OP[12]is the range for the other
@@ -67,11 +68,23 @@ public:
// is re-formed as R = [LHS] - OP2.
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
+ // The following routines are used to represent relations between the
+ // various operations. If the caller knows where the symbolics are,
+ // it can query for relationships between them given known ranges.
+ virtual enum tree_code lhs_op1_relation (const irange &lhs,
+ const irange &op1,
+ const irange &op2) const;
+ virtual enum tree_code lhs_op2_relation (const irange &lhs,
+ const irange &op1,
+ const irange &op2) const;
+ virtual enum tree_code op1_op2_relation (const irange &lhs) const;
protected:
// Perform an integral operation between 2 sub-ranges and return it.
virtual void wi_fold (irange &r, tree type,
@@ -79,6 +92,11 @@ protected:
const wide_int &lh_ub,
const wide_int &rh_lb,
const wide_int &rh_ub) const;
+ // Side effect of relation for generic fold_range clients.
+ virtual bool op1_op2_relation_effect (irange &lhs_range, tree type,
+ const irange &op1_range,
+ const irange &op2_range,
+ relation_kind rel) const;
};
extern range_operator *range_op_handler (enum tree_code code, tree type);
--
2.17.2