[COMMITTED] PR tree-optimization/104547 - Add relation between op1 & op2 to lhs_opN_relation API.

Message ID fc4a71c4-fa9d-cba1-cec5-b63926964488@redhat.com
State Committed
Headers
Series [COMMITTED] PR tree-optimization/104547 - Add relation between op1 & op2 to lhs_opN_relation API. |

Commit Message

Andrew MacLeod May 13, 2022, 2:21 p.m. UTC
  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.

This patch adds the relation to the API.  It also implelements the basic 
operation that for unsigned values,
    lhs = op1 - op2
that   if op1 > op2, then LHS < op1  and  if op1 >= op2, then LHS <= op1

If someone wants to make this work with signed values and handle all the 
cases, or extend it to deal with the relations between LHS and op2, feel 
free.. it gives me a headache when I try.

The relevant routine is operator_minus::lhs_op1_relation().  and would 
simply have to add the operator_minus::lhs_op2_relation to deal with the 
op2 case.

This resolves the PR, bootstraps on x86_64-pc-linux-gnu with no 
regressions.  pushed.

Andrew
  

Patch

commit cf2141a0c640fc9b1c497db3f4d5b270f4b8252a
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Tue Feb 15 10:17:26 2022 -0500

    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.

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 08d791a0418..bc8174e15e6 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -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);
 		}
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index eaa02309d70..d015b9f1363 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -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);
 }
 
diff --git a/gcc/range-op.h b/gcc/range-op.h
index c93eb844547..a1f98cd5226 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -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
index 00000000000..b6135ffe3a0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr104547.C
@@ -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 } }