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:
parent
0ee9a62ef4
commit
cf2141a0c6
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
13
gcc/testsuite/g++.dg/pr104547.C
Normal file
13
gcc/testsuite/g++.dg/pr104547.C
Normal 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 } }
|
Loading…
Reference in New Issue
Block a user