Add relation between op1 & op2 to lhs_opN_relation API.

We use the relation between op1 and op2 to help fold a statement, but
it was not provided to the lhs_op1_relation and lhs_op2_relation routines
to determine if is also creates a relation between the LHS and either operand.

	gcc/
	PR tree-optimization/104547
	* gimple-range-fold.cc (fold_using_range::range_of_range_op): Add
	the op1/op2 relation to the relation call.
	* range-op.cc (*::lhs_op1_relation): Add param.
	(*::lhs_op2_relation): Ditto.
	(operator_minus::lhs_op1_relation): New.
	(range_relational_tests): Add relation param.
	* range-op.h (lhs_op1_relation, lhs_op2_relation): Adjust prototype.

	gcc/testsuite/
	* g++.dg/pr104547.C: New.
This commit is contained in:
Andrew MacLeod 2022-02-15 10:17:26 -05:00
parent 0ee9a62ef4
commit cf2141a0c6
4 changed files with 68 additions and 18 deletions

View File

@ -640,13 +640,13 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
}
if (gimple_range_ssa_p (op1))
{
rel = handler->lhs_op1_relation (r, range1, range2);
rel = handler->lhs_op1_relation (r, range1, range2, rel);
if (rel != VREL_NONE)
src.register_relation (s, rel, lhs, op1);
}
if (gimple_range_ssa_p (op2))
{
rel= handler->lhs_op2_relation (r, range1, range2);
rel= handler->lhs_op2_relation (r, range1, range2, rel);
if (rel != VREL_NONE)
src.register_relation (s, rel, lhs, op2);
}

View File

@ -249,7 +249,8 @@ range_operator::op2_range (irange &r ATTRIBUTE_UNUSED,
enum tree_code
range_operator::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED,
const irange &op1 ATTRIBUTE_UNUSED,
const irange &op2 ATTRIBUTE_UNUSED) const
const irange &op2 ATTRIBUTE_UNUSED,
relation_kind rel ATTRIBUTE_UNUSED) const
{
return VREL_NONE;
}
@ -257,7 +258,8 @@ range_operator::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED,
enum tree_code
range_operator::lhs_op2_relation (const irange &lhs ATTRIBUTE_UNUSED,
const irange &op1 ATTRIBUTE_UNUSED,
const irange &op2 ATTRIBUTE_UNUSED) const
const irange &op2 ATTRIBUTE_UNUSED,
relation_kind rel ATTRIBUTE_UNUSED) const
{
return VREL_NONE;
}
@ -1182,9 +1184,11 @@ public:
const wide_int &rh_lb,
const wide_int &rh_ub) const;
virtual enum tree_code lhs_op1_relation (const irange &lhs, const irange &op1,
const irange &op2) const;
const irange &op2,
relation_kind rel) const;
virtual enum tree_code lhs_op2_relation (const irange &lhs, const irange &op1,
const irange &op2) const;
const irange &op2,
relation_kind rel) const;
} op_plus;
// Check to see if the range of OP2 indicates anything about the relation
@ -1193,7 +1197,8 @@ public:
enum tree_code
operator_plus::lhs_op1_relation (const irange &lhs,
const irange &op1,
const irange &op2) const
const irange &op2,
relation_kind) const
{
if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ())
return VREL_NONE;
@ -1258,9 +1263,9 @@ operator_plus::lhs_op1_relation (const irange &lhs,
enum tree_code
operator_plus::lhs_op2_relation (const irange &lhs, const irange &op1,
const irange &op2) const
const irange &op2, relation_kind rel) const
{
return lhs_op1_relation (lhs, op2, op1);
return lhs_op1_relation (lhs, op2, op1, rel);
}
void
@ -1310,6 +1315,10 @@ public:
const wide_int &lh_ub,
const wide_int &rh_lb,
const wide_int &rh_ub) const;
virtual enum tree_code lhs_op1_relation (const irange &lhs,
const irange &op1,
const irange &op2,
relation_kind rel) const;
virtual bool op1_op2_relation_effect (irange &lhs_range,
tree type,
const irange &op1_range,
@ -1329,6 +1338,27 @@ operator_minus::wi_fold (irange &r, tree type,
value_range_with_overflow (r, type, new_lb, new_ub, ov_lb, ov_ub);
}
// Return the relation between LHS and OP1 based on the relation between
// OP1 and OP2.
enum tree_code
operator_minus::lhs_op1_relation (const irange &lhs, const irange &,
const irange &, relation_kind rel) const
{
if (TYPE_SIGN (lhs.type ()) == UNSIGNED)
switch (rel)
{
case GT_EXPR:
return LT_EXPR;
case GE_EXPR:
return LE_EXPR;
default:
break;
}
return VREL_NONE;
}
// Check to see if the relation REL between OP1 and OP2 has any effect on the
// LHS of the expression. If so, apply it to LHS_RANGE. This is a helper
// function for both MINUS_EXPR and POINTER_DIFF_EXPR.
@ -1899,14 +1929,16 @@ public:
relation_kind rel = VREL_NONE) const;
virtual enum tree_code lhs_op1_relation (const irange &lhs,
const irange &op1,
const irange &op2) const;
const irange &op2,
relation_kind rel) const;
} op_rshift;
enum tree_code
operator_rshift::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED,
const irange &op1,
const irange &op2) const
const irange &op2,
relation_kind) const
{
// If both operands range are >= 0, then the LHS <= op1.
if (!op1.undefined_p () && !op2.undefined_p ()
@ -3532,7 +3564,8 @@ public:
relation_kind rel = VREL_NONE) const;
virtual enum tree_code lhs_op1_relation (const irange &lhs,
const irange &op1,
const irange &op2) const;
const irange &op2,
relation_kind rel) const;
} op_identity;
// Determine if there is a relationship between LHS and OP1.
@ -3540,7 +3573,8 @@ public:
enum tree_code
operator_identity::lhs_op1_relation (const irange &lhs,
const irange &op1 ATTRIBUTE_UNUSED,
const irange &op2 ATTRIBUTE_UNUSED) const
const irange &op2 ATTRIBUTE_UNUSED,
relation_kind) const
{
if (lhs.undefined_p ())
return VREL_NONE;
@ -4427,19 +4461,19 @@ range_relational_tests ()
int_range<2> op2 (UCHAR (20), UCHAR (20));
// Never wrapping additions mean LHS > OP1.
tree_code code = op_plus.lhs_op1_relation (lhs, op1, op2);
tree_code code = op_plus.lhs_op1_relation (lhs, op1, op2, VREL_NONE);
ASSERT_TRUE (code == GT_EXPR);
// Most wrapping additions mean nothing...
op1 = int_range<2> (UCHAR (8), UCHAR (10));
op2 = int_range<2> (UCHAR (0), UCHAR (255));
code = op_plus.lhs_op1_relation (lhs, op1, op2);
code = op_plus.lhs_op1_relation (lhs, op1, op2, VREL_NONE);
ASSERT_TRUE (code == VREL_NONE);
// However, always wrapping additions mean LHS < OP1.
op1 = int_range<2> (UCHAR (1), UCHAR (255));
op2 = int_range<2> (UCHAR (255), UCHAR (255));
code = op_plus.lhs_op1_relation (lhs, op1, op2);
code = op_plus.lhs_op1_relation (lhs, op1, op2, VREL_NONE);
ASSERT_TRUE (code == LT_EXPR);
}

View File

@ -78,12 +78,15 @@ public:
// 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.
// the optional relation passed in is the relation between op1 and op2.
virtual enum tree_code lhs_op1_relation (const irange &lhs,
const irange &op1,
const irange &op2) const;
const irange &op2,
relation_kind rel = VREL_NONE) const;
virtual enum tree_code lhs_op2_relation (const irange &lhs,
const irange &op1,
const irange &op2) const;
const irange &op2,
relation_kind rel = VREL_NONE) const;
virtual enum tree_code op1_op2_relation (const irange &lhs) const;
protected:
// Perform an integral operation between 2 sub-ranges and return it.

View File

@ -0,0 +1,13 @@
// { dg-do compile }
// { dg-options "-O3 -fdump-tree-vrp2" }
#include <vector>
void shrink(std::vector<int>& v, unsigned n) {
if (v.size() < n)
__builtin_unreachable();
v.resize(v.size() - n);
}
// Verify that std::vector<T>::_M_default_append() has been removed by vrp2.
// { dg-final { scan-tree-dump-not "_M_default_append" vrp2 } }