Hi!

The following testcases show two bugs in zero_one_operation (used during
undistribute optimization) and functions it calls.
The first one (wrong-code) is fixed by the
+  tree orig_def = *def;
and
-  if (stmts_to_fix.length () > 0)
+  if (stmts_to_fix.length () > 0 || *def == orig_def)
changes in zero_one_operation - e.g. in the testcase we have before reassoc
  _6 = _5 * a_11;
  _7 = _5 * _6;
and call zero_one_operation for _7 with op a_11.  The last stmt isn't pushed
into stmts_to_fix, the *def stmt is handled specially in
make_new_ssa_for_all_defs.  And the previous one, while it is pushed, it is
popped from there again, because the stmt is removed and instead _6 use
is replaced with _5.  That changes what value _7 holds, so we want to use
a new SSA_NAME for it (or deal with debug stmts and reset flow sensitive
info etc.).

The second one is wrong-debug, make_new_ssa_for_def replaces the uses of old
lhs with the new lhs (which is fine in the code uses, but for debug info
because we zeroed out a_11 we want to say that previous uses of _7 are now
the _7's replacement * a_11.  Which is what the rest of the patch does
and there is a guality testcase that verifies it (previously it would fail).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2016-12-08  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/78726
        * tree-ssa-reassoc.c (make_new_ssa_for_def): Add OPCODE and OP
        argument.  For lhs uses in debug stmts, don't replace lhs with
        new_lhs, but with a debug temp set to new_lhs opcode op.
        (make_new_ssa_for_all_defs): Add OPCODE argument, pass OPCODE and
        OP down to make_new_ssa_for_def.
        (zero_one_operation): Call make_new_ssa_for_all_defs even when
        stmts_to_fix is empty, if *def has not changed yet.  Pass
        OPCODE to make_new_ssa_for_all_defs.

        * gcc.c-torture/execute/pr78726.c: New test.
        * gcc.dg/guality/pr78726.c: New test.

--- gcc/tree-ssa-reassoc.c.jj   2016-11-09 16:34:58.000000000 +0100
+++ gcc/tree-ssa-reassoc.c      2016-12-08 15:53:13.768894146 +0100
@@ -1153,12 +1153,12 @@ decrement_power (gimple *stmt)
    SSA.  Also return the new SSA.  */
 
 static tree
-make_new_ssa_for_def (gimple *stmt)
+make_new_ssa_for_def (gimple *stmt, enum tree_code opcode, tree op)
 {
   gimple *use_stmt;
   use_operand_p use;
   imm_use_iterator iter;
-  tree new_lhs;
+  tree new_lhs, new_debug_lhs = NULL_TREE;
   tree lhs = gimple_get_lhs (stmt);
 
   new_lhs = make_ssa_name (TREE_TYPE (lhs));
@@ -1167,8 +1167,28 @@ make_new_ssa_for_def (gimple *stmt)
   /* Also need to update GIMPLE_DEBUGs.  */
   FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
     {
+      tree repl = new_lhs;
+      if (is_gimple_debug (use_stmt))
+       {
+         if (new_debug_lhs == NULL_TREE)
+           {
+             new_debug_lhs = make_node (DEBUG_EXPR_DECL);
+             gdebug *def_temp
+               = gimple_build_debug_bind (new_debug_lhs,
+                                          build2 (opcode, TREE_TYPE (lhs),
+                                                  new_lhs, op),
+                                          stmt);
+             DECL_ARTIFICIAL (new_debug_lhs) = 1;
+             TREE_TYPE (new_debug_lhs) = TREE_TYPE (lhs);
+             SET_DECL_MODE (new_debug_lhs, TYPE_MODE (TREE_TYPE (lhs)));
+             gimple_set_uid (def_temp, gimple_uid (stmt));
+             gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+             gsi_insert_after (&gsi, def_temp, GSI_SAME_STMT);
+           }
+         repl = new_debug_lhs;
+       }
       FOR_EACH_IMM_USE_ON_STMT (use, iter)
-       SET_USE (use, new_lhs);
+       SET_USE (use, repl);
       update_stmt (use_stmt);
     }
   return new_lhs;
@@ -1179,7 +1199,7 @@ make_new_ssa_for_def (gimple *stmt)
    if *DEF is not OP.  */
 
 static void
-make_new_ssa_for_all_defs (tree *def, tree op,
+make_new_ssa_for_all_defs (tree *def, enum tree_code opcode, tree op,
                           vec<gimple *> &stmts_to_fix)
 {
   unsigned i;
@@ -1189,10 +1209,10 @@ make_new_ssa_for_all_defs (tree *def, tr
       && TREE_CODE (*def) == SSA_NAME
       && (stmt = SSA_NAME_DEF_STMT (*def))
       && gimple_code (stmt) != GIMPLE_NOP)
-    *def = make_new_ssa_for_def (stmt);
+    *def = make_new_ssa_for_def (stmt, opcode, op);
 
   FOR_EACH_VEC_ELT (stmts_to_fix, i, stmt)
-    make_new_ssa_for_def (stmt);
+    make_new_ssa_for_def (stmt, opcode, op);
 }
 
 /* Find the single immediate use of STMT's LHS, and replace it
@@ -1232,6 +1252,7 @@ propagate_op_to_single_use (tree op, gim
 static void
 zero_one_operation (tree *def, enum tree_code opcode, tree op)
 {
+  tree orig_def = *def;
   gimple *stmt = SSA_NAME_DEF_STMT (*def);
   /* PR72835 - Record the stmt chain that has to be updated such that
      we dont use the same LHS when the values computed are different.  */
@@ -1335,8 +1356,8 @@ zero_one_operation (tree *def, enum tree
     }
   while (1);
 
-  if (stmts_to_fix.length () > 0)
-    make_new_ssa_for_all_defs (def, op, stmts_to_fix);
+  if (stmts_to_fix.length () > 0 || *def == orig_def)
+    make_new_ssa_for_all_defs (def, opcode, op, stmts_to_fix);
 }
 
 /* Returns true if statement S1 dominates statement S2.  Like
--- gcc/testsuite/gcc.c-torture/execute/pr78726.c.jj    2016-12-08 
15:55:08.847434702 +0100
+++ gcc/testsuite/gcc.c-torture/execute/pr78726.c       2016-12-08 
15:54:46.000000000 +0100
@@ -0,0 +1,23 @@
+/* PR tree-optimization/78726 */
+
+unsigned char b = 36, c = 173;
+unsigned int d;
+
+__attribute__((noinline, noclone)) void
+foo (void)
+{
+  unsigned a = ~b;
+  d = a * c * c + 1023094746U * a;
+}
+
+int
+main ()
+{
+  if (__SIZEOF_INT__ != 4 || __CHAR_BIT__ != 8)
+    return 0;
+  asm volatile ("" : : "g" (&b), "g" (&c) : "memory");
+  foo ();
+  if (d != 799092689U)
+    __builtin_abort ();
+  return 0;
+}
--- gcc/testsuite/gcc.dg/guality/pr78726.c.jj   2016-12-08 15:57:07.779926381 
+0100
+++ gcc/testsuite/gcc.dg/guality/pr78726.c      2016-12-08 16:02:57.216494771 
+0100
@@ -0,0 +1,30 @@
+/* PR tree-optimization/78726 */
+/* { dg-do run } */
+/* { dg-options "-g" } */
+
+#include "../nop.h"
+
+unsigned char b = 36, c = 173;
+unsigned int d;
+
+__attribute__((noinline, noclone)) void
+foo (void)
+{
+  unsigned a = ~b;
+  unsigned d1 = a * c;         /* { dg-final { gdb-test 21 "d1" "~36U * 173" } 
} */
+  unsigned d2 = d1 * c;                /* { dg-final { gdb-test 21 "d2" "~36U 
* 173 * 173" } } */
+  unsigned d3 = 1023094746 * a;        /* { dg-final { gdb-test 21 "d3" "~36U 
* 1023094746" } } */
+  d = d2 + d3;
+  unsigned d4 = d1 * 2;        /* { dg-final { gdb-test 21 "d4" "~36U * 173 * 
2" } } */
+  unsigned d5 = d2 * 2;                /* { dg-final { gdb-test 21 "d5" "~36U 
* 173 * 173 * 2" } } */
+  unsigned d6 = d3 * 2;                /* { dg-final { gdb-test 21 "d6" "~36U 
* 1023094746 * 2" } } */
+  asm (NOP : : : "memory");
+}
+
+int
+main ()
+{
+  asm volatile ("" : : "g" (&b), "g" (&c) : "memory");
+  foo ();
+  return 0;
+}

        Jakub

Reply via email to