This implements what forward_propagate_comparison does (and fold for
a part).  This leaves the first loop backwards over stmts in a BB
in forwprop doing only address forward propagation (just in case
we want to separate that from the "folding" transforms).

It also makes the two conflicting transforms !compare -> inverted-compare
and X | !Y -> Y <= X (and friends) trigger in a more random fashion
which means we now generate better code for gcc.dg/tree-ssa/forwprop-28.c
(on x86) but the transform this testcase is testing for triggers less
often.  I have simply adjusted the testcase.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.

Richard.

2014-11-13  Richard Biener  <rguent...@suse.de>

        * match.pd: Add tcc_comparison, inverted_tcc_comparison
        and inverted_tcc_comparison_with_nans operator lists.
        Use tcc_comparison in the truth_valued_p predicate definition.
        Restrict logical_inverted_value with bit_xor to integral types.
        Build a boolean true for simplifying x |^ !x because of
        vector types.  Implement patterns from forward_propagate_comparison
        * tree-ssa-forwprop.c (forward_propagate_comparison): Remove.
        (get_prop_dest_stmt): Likewise.
        (pass_forwprop::execute): Do not call it.
        * fold-const.c (fold_unary_loc): Remove the pattern here.

        * gcc.dg/tree-ssa/forwprop-28.c: Adjust.

Index: trunk/gcc/match.pd
===================================================================
*** trunk.orig/gcc/match.pd     2014-11-13 12:38:20.337833493 +0100
--- trunk/gcc/match.pd  2014-11-13 12:44:40.370816862 +0100
*************** along with GCC; see the file COPYING3.
*** 31,36 ****
--- 31,44 ----
     CONSTANT_CLASS_P
     tree_expr_nonnegative_p)
  
+ /* Operator lists.  */
+ (define_operator_list tcc_comparison
+   lt   le   eq ne ge   gt   unordered ordered   unlt unle ungt unge uneq ltgt)
+ (define_operator_list inverted_tcc_comparison
+   ge   gt   ne eq lt   le   ordered   unordered ge   gt   le   lt   ltgt uneq)
+ (define_operator_list inverted_tcc_comparison_with_nans
+   unge ungt ne eq unlt unle ordered   unordered ge   gt   le   lt   ltgt uneq)
+ 
  
  /* Simplifications of operations with one constant operand and
     simplifications to constants or single values.  */
*************** along with GCC; see the file COPYING3.
*** 172,178 ****
  (match truth_valued_p
   @0
   (if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1)))
! (for op (lt le eq ne ge gt truth_and truth_andif truth_or truth_orif 
truth_xor)
   (match truth_valued_p
    (op @0 @1)))
  (match truth_valued_p
--- 180,186 ----
  (match truth_valued_p
   @0
   (if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1)))
! (for op (tcc_comparison truth_and truth_andif truth_or truth_orif truth_xor)
   (match truth_valued_p
    (op @0 @1)))
  (match truth_valued_p
*************** along with GCC; see the file COPYING3.
*** 187,193 ****
   (ne truth_valued_p@0 integer_onep)
   (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))))
  (match (logical_inverted_value @0)
!  (bit_xor truth_valued_p@0 integer_onep))
  
  /* X & !X -> 0.  */
  (simplify
--- 195,202 ----
   (ne truth_valued_p@0 integer_onep)
   (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))))
  (match (logical_inverted_value @0)
!  (bit_xor truth_valued_p@0 integer_onep)
!  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))))
  
  /* X & !X -> 0.  */
  (simplify
*************** along with GCC; see the file COPYING3.
*** 197,203 ****
  (for op (bit_ior bit_xor)
   (simplify
    (op:c truth_valued_p@0 (logical_inverted_value @0))
!   { build_one_cst (type); }))
  
  (for bitop (bit_and bit_ior)
       rbitop (bit_ior bit_and)
--- 206,212 ----
  (for op (bit_ior bit_xor)
   (simplify
    (op:c truth_valued_p@0 (logical_inverted_value @0))
!   { constant_boolean_node (true, type); }))
  
  (for bitop (bit_and bit_ior)
       rbitop (bit_ior bit_and)
*************** along with GCC; see the file COPYING3.
*** 638,640 ****
--- 647,688 ----
  (simplify
   (cond (logical_inverted_value truth_valued_p@0) @1 @2)
   (cond @0 @2 @1))
+ 
+ 
+ /* Simplifications of comparisons.  */
+ 
+ /* We can simplify a logical negation of a comparison to the
+    inverted comparison.  As we cannot compute an expression
+    operator using invert_tree_comparison we have to simulate
+    that with expression code iteration.  */
+ (for cmp (tcc_comparison)
+      icmp (inverted_tcc_comparison)
+      ncmp (inverted_tcc_comparison_with_nans)
+  /* Ideally we'd like to combine the following two patterns
+     and handle some more cases by using
+       (logical_inverted_value (cmp @0 @1))
+     here but for that genmatch would need to "inline" that.
+     For now implement what forward_propagate_comparison did.  */
+  (simplify
+   (bit_not (cmp @0 @1))
+   (if (VECTOR_TYPE_P (type)
+        || (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1))
+    /* Comparison inversion may be impossible for trapping math,
+       invert_tree_comparison will tell us.  But we can't use
+       a computed operator in the replacement tree thus we have
+       to play the trick below.  */
+    (with { enum tree_code ic = invert_tree_comparison
+              (cmp, HONOR_NANS (TYPE_MODE (TREE_TYPE (@0)))); }
+     (if (ic == icmp)
+      (icmp @0 @1))
+     (if (ic == ncmp)
+      (ncmp @0 @1)))))
+  (simplify
+   (bit_xor (cmp @0 @1) integer_onep)
+   (if (INTEGRAL_TYPE_P (type))
+    (with { enum tree_code ic = invert_tree_comparison
+              (cmp, HONOR_NANS (TYPE_MODE (TREE_TYPE (@0)))); }
+     (if (ic == icmp)
+      (icmp @0 @1))
+     (if (ic == ncmp)
+      (ncmp @0 @1))))))
Index: trunk/gcc/tree-ssa-forwprop.c
===================================================================
*** trunk.orig/gcc/tree-ssa-forwprop.c  2014-11-13 12:38:20.337833493 +0100
--- trunk/gcc/tree-ssa-forwprop.c       2014-11-13 12:44:40.371816862 +0100
*************** fwprop_invalidate_lattice (tree name)
*** 233,270 ****
  }
  
  
- /* Get the next statement we can propagate NAME's value into skipping
-    trivial copies.  Returns the statement that is suitable as a
-    propagation destination or NULL_TREE if there is no such one.
-    This only returns destinations in a single-use chain.  FINAL_NAME_P
-    if non-NULL is written to the ssa name that represents the use.  */
- 
- static gimple
- get_prop_dest_stmt (tree name, tree *final_name_p)
- {
-   use_operand_p use;
-   gimple use_stmt;
- 
-   do {
-     /* If name has multiple uses, bail out.  */
-     if (!single_imm_use (name, &use, &use_stmt))
-       return NULL;
- 
-     /* If this is not a trivial copy, we found it.  */
-     if (!gimple_assign_ssa_name_copy_p (use_stmt)
-       || gimple_assign_rhs1 (use_stmt) != name)
-       break;
- 
-     /* Continue searching uses of the copy destination.  */
-     name = gimple_assign_lhs (use_stmt);
-   } while (1);
- 
-   if (final_name_p)
-     *final_name_p = name;
- 
-   return use_stmt;
- }
- 
  /* Get the statement we can propagate from into NAME skipping
     trivial copies.  Returns the statement which defines the
     propagation source or NULL_TREE if there is no such one.
--- 233,238 ----
*************** forward_propagate_addr_expr (tree name,
*** 1060,1149 ****
  }
  
  
- /* Forward propagate the comparison defined in *DEFGSI like
-    cond_1 = x CMP y to uses of the form
-      a_1 = (T')cond_1
-      a_1 = !cond_1
-      a_1 = cond_1 != 0
-    Returns true if stmt is now unused.  Advance DEFGSI to the next
-    statement.  */
- 
- static bool
- forward_propagate_comparison (gimple_stmt_iterator *defgsi)
- {
-   gimple stmt = gsi_stmt (*defgsi);
-   tree name = gimple_assign_lhs (stmt);
-   gimple use_stmt;
-   tree tmp = NULL_TREE;
-   gimple_stmt_iterator gsi;
-   enum tree_code code;
-   tree lhs;
- 
-   /* Don't propagate ssa names that occur in abnormal phis.  */
-   if ((TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
-        && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs1 (stmt)))
-       || (TREE_CODE (gimple_assign_rhs2 (stmt)) == SSA_NAME
-         && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs2 (stmt))))
-     goto bailout;
- 
-   /* Do not un-cse comparisons.  But propagate through copies.  */
-   use_stmt = get_prop_dest_stmt (name, &name);
-   if (!use_stmt
-       || !is_gimple_assign (use_stmt))
-     goto bailout;
- 
-   code = gimple_assign_rhs_code (use_stmt);
-   lhs = gimple_assign_lhs (use_stmt);
-   if (!INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
-     goto bailout;
- 
-   /* We can propagate the condition into a statement that
-      computes the logical negation of the comparison result.  */
-   if ((code == BIT_NOT_EXPR
-        && TYPE_PRECISION (TREE_TYPE (lhs)) == 1)
-       || (code == BIT_XOR_EXPR
-         && integer_onep (gimple_assign_rhs2 (use_stmt))))
-     {
-       tree type = TREE_TYPE (gimple_assign_rhs1 (stmt));
-       bool nans = HONOR_NANS (TYPE_MODE (type));
-       enum tree_code inv_code;
-       inv_code = invert_tree_comparison (gimple_assign_rhs_code (stmt), nans);
-       if (inv_code == ERROR_MARK)
-       goto bailout;
- 
-       tmp = build2 (inv_code, TREE_TYPE (lhs), gimple_assign_rhs1 (stmt),
-                   gimple_assign_rhs2 (stmt));
-     }
-   else
-     goto bailout;
- 
-   gsi = gsi_for_stmt (use_stmt);
-   gimple_assign_set_rhs_from_tree (&gsi, unshare_expr (tmp));
-   use_stmt = gsi_stmt (gsi);
-   update_stmt (use_stmt);
- 
-   if (dump_file && (dump_flags & TDF_DETAILS))
-     {
-       fprintf (dump_file, "  Replaced '");
-       print_gimple_expr (dump_file, stmt, 0, dump_flags);
-       fprintf (dump_file, "' with '");
-       print_gimple_expr (dump_file, use_stmt, 0, dump_flags);
-       fprintf (dump_file, "'\n");
-     }
- 
-   /* When we remove stmt now the iterator defgsi goes off it's current
-      sequence, hence advance it now.  */
-   gsi_next (defgsi);
- 
-   /* Remove defining statements.  */
-   return remove_prop_source_from_use (name);
- 
- bailout:
-   gsi_next (defgsi);
-   return false;
- }
- 
- 
  /* Helper function for simplify_gimple_switch.  Remove case labels that
     have values outside the range of the new type.  */
  
--- 1028,1033 ----
*************** pass_forwprop::execute (function *fun)
*** 2316,2326 ****
              else
                gsi_next (&gsi);
            }
-         else if (TREE_CODE_CLASS (code) == tcc_comparison)
-           {
-             if (forward_propagate_comparison (&gsi))
-               cfg_changed = true;
-           }
          else
            gsi_next (&gsi);
        }
--- 2200,2205 ----
Index: trunk/gcc/fold-const.c
===================================================================
*** trunk.orig/gcc/fold-const.c 2014-11-13 12:38:20.337833493 +0100
--- trunk/gcc/fold-const.c      2014-11-13 12:44:40.376816862 +0100
*************** fold_unary_loc (location_t loc, enum tre
*** 7938,7955 ****
          if (i == count)
            return build_vector (type, elements);
        }
-       else if (COMPARISON_CLASS_P (arg0)
-              && (VECTOR_TYPE_P (type)
-                  || (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1)))
-       {
-         tree op_type = TREE_TYPE (TREE_OPERAND (arg0, 0));
-         enum tree_code subcode = invert_tree_comparison (TREE_CODE (arg0),
-                                    HONOR_NANS (TYPE_MODE (op_type)));
-         if (subcode != ERROR_MARK)
-           return build2_loc (loc, subcode, type, TREE_OPERAND (arg0, 0),
-                              TREE_OPERAND (arg0, 1));
-       }
- 
  
        return NULL_TREE;
  
--- 7938,7943 ----
Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/forwprop-28.c
===================================================================
*** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/forwprop-28.c      2014-11-13 
12:38:20.337833493 +0100
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/forwprop-28.c   2014-11-13 
12:51:11.918799728 +0100
*************** test_8 (int code)
*** 79,84 ****
      oof ();
  }
  
! /* { dg-final { scan-tree-dump-times "simplified to if \\\(\[^ ]* <" 8 
"forwprop1"} } */
  /* { dg-final { cleanup-tree-dump "forwprop1" } } */
  
--- 79,89 ----
      oof ();
  }
  
! /* ???  This used to check for 8 times transforming the combined conditional
!    to a ordered compare.  But the transform does not trigger if we transform
!    the negated code == 22 compare to code != 22 first.  It turns out if
!    we do that we even generate better code on x86 at least.  */
! 
! /* { dg-final { scan-tree-dump-times "simplified to if \\\(\[^ ]* <" 4 
"forwprop1"} } */
  /* { dg-final { cleanup-tree-dump "forwprop1" } } */
  

Reply via email to