https://gcc.gnu.org/g:999aad44aa86e64580d36e74bcc90b48f768cf55

commit r15-5852-g999aad44aa86e64580d36e74bcc90b48f768cf55
Author: Jovan Vukic <jovan.vu...@rt-rk.com>
Date:   Sun Dec 1 11:57:41 2024 -0700

    Thanks for the feedback on the first version of the patch. Accordingly:
    
    I have corrected the code formatting as requested. I added new tests to
    the existing file phi-opt-11.c, instead of creating a new one.
    
    I performed testing before and after applying the patch on the x86
    architecture, and I confirm that there are no new regressions.
    
    The logic and general code of the patch itself have not been changed.
    
    > So the A EQ/NE B expression, we can reverse A and B in the expression
    > and still get the same result. But don't we have to be more careful for
    > the TRUE/FALSE arms of the ternary? For BIT_AND we need ? a : b for
    > BIT_IOR we need ? b : a.
    >
    > I don't see that gets verified in the existing code or after your
    > change. I suspect I'm just missing something here. Can you clarify how
    > we verify that BIT_AND gets ? a : b for the true/false arms and that
    > BIT_IOR gets ? b : a for the true/false arms?
    
    I did not communicate this clearly last time, but the existing optimization
    simplifies the expression "(cond & (a == b)) ? a : b" to the simpler "b".
    Similarly, the expression "(cond & (a == b)) ? b : a" simplifies to "a".
    
    Thus, the existing and my optimization perform the following
    simplifications:
    
    (cond & (a == b)) ? a : b -> b
    (cond & (a == b)) ? b : a -> a
    (cond | (a != b)) ? a : b -> a
    (cond | (a != b)) ? b : a -> b
    
    For this reason, for BIT_AND_EXPR when we have A EQ B, it is sufficient to
    confirm that one operand matches the true/false arm and the other matches
    the false/true arm. In both cases, we simplify the expression to the third
    operand of the ternary operation (i.e., OP0 ? OP1 : OP2 simplifies to OP2).
    This is achieved in the value_replacement function after successfully
    setting the value of *code within the rhs_is_fed_for_value_replacement
    function to EQ_EXPR.
    
    For BIT_IOR_EXPR, the same check is performed for A NE B, except now
    *code remains NE_EXPR, and then value_replacement returns the second
    operand (i.e., OP0 ? OP1 : OP2 simplifies to OP1).
    
    2024-10-30  Jovan Vukic  <jovan.vu...@rt-rk.com>
    
    gcc/ChangeLog:
    
            * tree-ssa-phiopt.cc (rhs_is_fed_for_value_replacement): Add a new
            optimization opportunity for BIT_IOR_EXPR and a != b.
            (operand_equal_for_value_replacement): Ditto.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/phi-opt-11.c: Add more tests.

Diff:
---
 gcc/testsuite/gcc.dg/tree-ssa/phi-opt-11.c | 31 ++++++++++++++++++-
 gcc/tree-ssa-phiopt.cc                     | 48 +++++++++++++++++++-----------
 2 files changed, 60 insertions(+), 19 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-11.c 
b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-11.c
index 14c82cd52165..d1e284c53252 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-11.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-11.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O1 -fdump-tree-optimized --param 
logical-op-non-short-circuit=1" } */
+/* { dg-options "-O1 -fdump-tree-phiopt2 -fdump-tree-optimized --param 
logical-op-non-short-circuit=1" } */
 
 int f(int a, int b, int c)
 {
@@ -22,4 +22,33 @@ int h(int a, int b, int c, int d)
  return a;
 }
 
+int i(int a, int b, int c)
+{
+  if ((a > c) & (a == b))
+    return a;
+  return b;
+}
+
+int j(int a, int b, int c)
+{
+  if ((a > c) & (a == b))
+    return b;
+  return a;
+}
+
+int k(int a, int b, int c)
+{
+  if ((a > c) | (a != b))
+    return b;
+  return a;
+}
+
+int l(int a, int b, int c)
+{
+  if ((a > c) | (a != b))
+    return a;
+  return b;
+}
+
+/* { dg-final { scan-tree-dump-times "if" 0 "phiopt2" } } */
 /* { dg-final { scan-tree-dump-times "if" 0 "optimized" } } */
diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
index 0d9bc3eb4499..15651809d71b 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -1077,17 +1077,18 @@ jump_function_from_stmt (tree *arg, gimple *stmt)
   return false;
 }
 
-/* RHS is a source argument in a BIT_AND_EXPR which feeds a conditional
-   of the form SSA_NAME NE 0.
+/* RHS is a source argument in a BIT_AND_EXPR or BIT_IOR_EXPR which feeds
+   a conditional of the form SSA_NAME NE 0.
 
-   If RHS is fed by a simple EQ_EXPR comparison of two values, see if
-   the two input values of the EQ_EXPR match arg0 and arg1.
+   If RHS is fed by a simple EQ_EXPR or NE_EXPR comparison of two values,
+   see if the two input values of the comparison match arg0 and arg1.
 
    If so update *code and return TRUE.  Otherwise return FALSE.  */
 
 static bool
 rhs_is_fed_for_value_replacement (const_tree arg0, const_tree arg1,
-                                 enum tree_code *code, const_tree rhs)
+                                 enum tree_code *code, const_tree rhs,
+                                 enum tree_code bit_expression_code)
 {
   /* Obviously if RHS is not an SSA_NAME, we can't look at the defining
      statement.  */
@@ -1095,11 +1096,15 @@ rhs_is_fed_for_value_replacement (const_tree arg0, 
const_tree arg1,
     {
       gimple *def1 = SSA_NAME_DEF_STMT (rhs);
 
-      /* Verify the defining statement has an EQ_EXPR on the RHS.  */
-      if (is_gimple_assign (def1) && gimple_assign_rhs_code (def1) == EQ_EXPR)
+      /* Verify the defining statement has an EQ_EXPR or NE_EXPR on the RHS.  
*/
+      if (is_gimple_assign (def1)
+         && ((bit_expression_code == BIT_AND_EXPR
+              && gimple_assign_rhs_code (def1) == EQ_EXPR)
+             || (bit_expression_code == BIT_IOR_EXPR
+                 && gimple_assign_rhs_code (def1) == NE_EXPR)))
        {
-         /* Finally verify the source operands of the EQ_EXPR are equal
-            to arg0 and arg1.  */
+         /* Finally verify the source operands of the EQ_EXPR or NE_EXPR
+            are equal to arg0 and arg1.  */
          tree op0 = gimple_assign_rhs1 (def1);
          tree op1 = gimple_assign_rhs2 (def1);
          if ((operand_equal_for_phi_arg_p (arg0, op0)
@@ -1118,8 +1123,9 @@ rhs_is_fed_for_value_replacement (const_tree arg0, 
const_tree arg1,
 
 /* Return TRUE if arg0/arg1 are equal to the rhs/lhs or lhs/rhs of COND.
 
-   Also return TRUE if arg0/arg1 are equal to the source arguments of a
-   an EQ comparison feeding a BIT_AND_EXPR which feeds COND.
+   Also return TRUE if arg0/arg1 are equal to the source arguments of an
+   EQ comparison feeding a BIT_AND_EXPR, or NE comparison feeding a
+   BIT_IOR_EXPR which feeds COND.
 
    Return FALSE otherwise.  */
 
@@ -1138,27 +1144,33 @@ operand_equal_for_value_replacement (const_tree arg0, 
const_tree arg1,
     return true;
 
   /* Now handle more complex case where we have an EQ comparison
-     which feeds a BIT_AND_EXPR which feeds COND.
+     feeding a BIT_AND_EXPR, or a NE comparison feeding a BIT_IOR_EXPR,
+     which then feeds into COND.
 
      First verify that COND is of the form SSA_NAME NE 0.  */
   if (*code != NE_EXPR || !integer_zerop (rhs)
       || TREE_CODE (lhs) != SSA_NAME)
     return false;
 
-  /* Now ensure that SSA_NAME is set by a BIT_AND_EXPR.  */
+  /* Now ensure that SSA_NAME is set by a BIT_AND_EXPR or BIT_OR_EXPR.  */
   def = SSA_NAME_DEF_STMT (lhs);
-  if (!is_gimple_assign (def) || gimple_assign_rhs_code (def) != BIT_AND_EXPR)
+  if (!is_gimple_assign (def)
+      || (gimple_assign_rhs_code (def) != BIT_AND_EXPR
+         && gimple_assign_rhs_code (def) != BIT_IOR_EXPR))
     return false;
 
-  /* Now verify arg0/arg1 correspond to the source arguments of an
-     EQ comparison feeding the BIT_AND_EXPR.  */
+  /* Now verify arg0/arg1 correspond to the source arguments of an EQ
+     comparison feeding the BIT_AND_EXPR or a NE comparison feeding the
+     BIT_IOR_EXPR.  */
 
   tree tmp = gimple_assign_rhs1 (def);
-  if (rhs_is_fed_for_value_replacement (arg0, arg1, code, tmp))
+  if (rhs_is_fed_for_value_replacement (arg0, arg1, code, tmp,
+                                       gimple_assign_rhs_code (def)))
     return true;
 
   tmp = gimple_assign_rhs2 (def);
-  if (rhs_is_fed_for_value_replacement (arg0, arg1, code, tmp))
+  if (rhs_is_fed_for_value_replacement (arg0, arg1, code, tmp,
+                                       gimple_assign_rhs_code (def)))
     return true;
 
   return false;

Reply via email to