From: Andrew MacLeod Date: Thu, 17 Jun 2021 15:49:21 +0000 (-0400) Subject: Add relational support to range-op. X-Git-Tag: basepoints/gcc-13~6593 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=80dd13f5c3bdc7899ee6e863e05b254815ec0cef;p=thirdparty%2Fgcc.git 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. --- diff --git a/gcc/range-op.cc b/gcc/range-op.cc index e805f26a333c..d807693900ae 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -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); } diff --git a/gcc/range-op.h b/gcc/range-op.h index d3d440830937..2b5db64bb98b 100644 --- a/gcc/range-op.h +++ b/gcc/range-op.h @@ -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);