Doh.

The original fix for PR97657 was incorrect.  It papered over a problem by reducing opportunities it could find. Given

  if (c_2 || c_3)

If the FALSE edge is taken, this is ! (c_2 || c_3) which is equivalent to !c_2 && !c_3.. so performing the intersection as combine_logical was originally doing was correct.

I found this by examining cases  we were missing because this was no longer being combined properly.  which sent be back to this PR to figure out what the real reason for the failure was.

The GORI design specification calculates outgoing ranges using dependency chains, but as soon as the chain goes outside the current block, we are suppose to revert to using the on-entry range since control flow could dictate further range changes.

I had noticed that on certain occasions we'd peek into other blocks, and each time I saw it, it was beneficial and seemed like a harmless recalucaltion, So I let it go.

In this particular case, during the on-entry cache propagation we were peeking into another block to pick up a value used in the logical OR operation. Unfortunately, the on-entry cache hadnt finished propagating and the incomplete range was picked up from that other block instead of the current one, and we ended up calculating a [0,0] range on an outgoing edge that should have been VARYING.  And bad things happened.

The fix is to patch the logical evaluation code to do the same thing as the non-logical code, follow the spec, and simply use the range-on-entry value for the block if the def chain  leads out of the current block.   Next release will integrate the full re-evaluation of def chains from outside the basic block.. properly planned :-)

I've added an additional test case to confirm that the logical or FALSE case is being optimized properly. The original fix fails this test, the current fix passes it,.

Bootstrapped on x86_64-pc-linux-gnu, no regressions. pushed.

Andrew




commit 7d26a337bfa1135d95caa3c213e82f2a97f18a01
Author: Andrew MacLeod <amacl...@redhat.com>
Date:   Mon Nov 9 19:38:22 2020 -0500

    Fix logical_combine OR operation. Again.
    
    The original fix was incorrect and results in loss of opportunities.
    Revert the original fix. When processing logical chains, do not
    follow chains outside of the current basic block.  Use the import
    value instead.
    
            gcc/
            PR tree-optimization/97567
            * gimple-range-gori.cc: (gori_compute::logical_combine): False
            OR operations should intersect the 2 results.
            (gori_compute::compute_logical_operands_in_chain): If def chains
            are outside the current basic block, don't follow them.
            gcc/testsuite/
            * gcc.dg/pr97567-2.c: New.

diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 54385baa629..af3609e414e 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -730,10 +730,10 @@ gori_compute::logical_combine (irange &r, enum tree_code code,
         if (lhs.zero_p ())
 	  {
 	    // An OR operation will only take the FALSE path if both
-	    // operands are false, so either [20, 255] or [0, 5] is the
-	    // union: [0,5][20,255].
+	    // operands are false simlulateously, which means they should
+	    // be intersected.  !(x || y) == !x && !y
 	    r = op1.false_range;
-	    r.union_ (op2.false_range);
+	    r.intersect (op2.false_range);
 	  }
 	else
 	  {
@@ -804,9 +804,12 @@ gori_compute::compute_logical_operands_in_chain (tf_range &range,
 						 tree name,
 						 tree op, bool op_in_chain)
 {
-  if (!op_in_chain)
+  gimple *src_stmt = gimple_range_ssa_p (op) ? SSA_NAME_DEF_STMT (op) : NULL;
+  basic_block bb = gimple_bb (stmt);
+  if (!op_in_chain || (src_stmt != NULL && bb != gimple_bb (src_stmt)))
     {
-      // If op is not in chain, use its known value.
+      // If op is not in the def chain, or defined in this block,
+      // use its known value on entry to the block.
       expr_range_in_bb (range.true_range, name, gimple_bb (stmt));
       range.false_range = range.true_range;
       return;
@@ -814,14 +817,12 @@ gori_compute::compute_logical_operands_in_chain (tf_range &range,
   if (optimize_logical_operands (range, stmt, lhs, name, op))
     return;
 
-  // Calulate ranges for true and false on both sides, since the false
+  // Calculate ranges for true and false on both sides, since the false
   // path is not always a simple inversion of the true side.
-  if (!compute_operand_range (range.true_range, SSA_NAME_DEF_STMT (op),
-			      m_bool_one, name))
-    expr_range_in_bb (range.true_range, name, gimple_bb (stmt));
-  if (!compute_operand_range (range.false_range, SSA_NAME_DEF_STMT (op),
-			      m_bool_zero, name))
-    expr_range_in_bb (range.false_range, name, gimple_bb (stmt));
+  if (!compute_operand_range (range.true_range, src_stmt, m_bool_one, name))
+    expr_range_in_bb (range.true_range, name, bb);
+  if (!compute_operand_range (range.false_range, src_stmt, m_bool_zero, name))
+    expr_range_in_bb (range.false_range, name, bb);
 }
 
 // Given a logical STMT, calculate true and false for each potential
diff --git a/gcc/testsuite/gcc.dg/pr97567-2.c b/gcc/testsuite/gcc.dg/pr97567-2.c
new file mode 100644
index 00000000000..dee31c6dc01
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr97567-2.c
@@ -0,0 +1,24 @@
+/* { dg-do compile} */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+char a[2];
+
+extern int x;
+
+void foo(void);
+
+signed char g (signed char min, signed char max)
+{
+   signed char i = x;
+   return i < min || max < i ? min : i;
+}
+
+void gg (void)
+{
+   signed char t = g (0, 9);
+   /* Ranger should be able to remove the call to foo ().  */
+   if (t > 9 || t < 0)
+     foo ();
+}
+
+/* { dg-final { scan-tree-dump-not "foo" "evrp" } }  */

Reply via email to