Add relation between op1 & op2 to lhs_opN_relation API.
authorAndrew MacLeod <amacleod@redhat.com>
Tue, 15 Feb 2022 15:17:26 +0000 (10:17 -0500)
committerAndrew MacLeod <amacleod@redhat.com>
Fri, 13 May 2022 14:20:15 +0000 (10:20 -0400)
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.

gcc/gimple-range-fold.cc
gcc/range-op.cc
gcc/range-op.h
gcc/testsuite/g++.dg/pr104547.C [new file with mode: 0644]

index 08d791a..bc8174e 100644 (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);
                }
index eaa0230..d015b9f 100644 (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);
 }
 
index c93eb84..a1f98cd 100644 (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.
diff --git a/gcc/testsuite/g++.dg/pr104547.C b/gcc/testsuite/g++.dg/pr104547.C
new file mode 100644 (file)
index 0000000..b6135ff
--- /dev/null
@@ -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 } }