2015-08-12 Richard Biener <rguenther@suse.de>
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 12 Aug 2015 14:27:40 +0000 (14:27 +0000)
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 12 Aug 2015 14:27:40 +0000 (14:27 +0000)
* tree-ssa-sccvn.c (vn_nary_op_compute_hash): Also canonicalize
comparison operand order and commutative ternary op operand order.
(sccvn_dom_walker::cond_stack): New state to track temporary
expressions.
(sccvn_dom_walker::after_dom_children): Remove tempoary expressions
no longer valid.
(sccvn_dom_walker::record_cond): Add a single temporary conditional
expression.
(sccvn_dom_walker::record_conds): Add a temporary conditional
expressions and all related expressions also true/false.
(sccvn_dom_walker::before_dom_children): Record temporary
expressions based on the controlling condition of a single
predecessor.  When trying to simplify a conditional statement
lookup expressions we might have inserted earlier.

* gcc.dg/tree-ssa/ssa-fre-47.c: New testcase.
* gcc.dg/tree-ssa/ssa-fre-48.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-49.c: Likewise.
* g++.dg/tree-ssa/pr61034.C: Adjust.
* gcc.dg/fold-compare-2.c: Likewise.
* gcc.dg/pr50763.c: Likewise.
* gcc.dg/predict-3.c: Likewise.
* gcc.dg/tree-ssa/20030709-2.c: Likewise.
* gcc.dg/tree-ssa/pr19831-3.c: Likewise.
* gcc.dg/tree-ssa/pr20657.c: Likewise.
* gcc.dg/tree-ssa/pr21001.c: Likewise.
* gcc.dg/tree-ssa/pr37508.c: Likewise.
* gcc.dg/tree-ssa/vrp04.c: Likewise.
* gcc.dg/tree-ssa/vrp07.c: Likewise.
* gcc.dg/tree-ssa/vrp09.c: Likewise.
* gcc.dg/tree-ssa/vrp16.c: Likewise.
* gcc.dg/tree-ssa/vrp20.c: Likewise.
* gcc.dg/tree-ssa/vrp25.c: Likewise.
* gcc.dg/tree-ssa/vrp87.c: Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@226814 138bc75d-0d04-0410-961f-82ee72b054a4

19 files changed:
gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/tree-ssa/pr61034.C
gcc/testsuite/gcc.dg/fold-compare-2.c
gcc/testsuite/gcc.dg/pr50763.c
gcc/testsuite/gcc.dg/predict-3.c
gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c
gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c
gcc/testsuite/gcc.dg/tree-ssa/pr20657.c
gcc/testsuite/gcc.dg/tree-ssa/pr21001.c
gcc/testsuite/gcc.dg/tree-ssa/pr37508.c
gcc/testsuite/gcc.dg/tree-ssa/vrp04.c
gcc/testsuite/gcc.dg/tree-ssa/vrp07.c
gcc/testsuite/gcc.dg/tree-ssa/vrp09.c
gcc/testsuite/gcc.dg/tree-ssa/vrp16.c
gcc/testsuite/gcc.dg/tree-ssa/vrp20.c
gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
gcc/testsuite/gcc.dg/tree-ssa/vrp87.c
gcc/tree-ssa-sccvn.c

index 0665009..6028d26 100644 (file)
@@ -1,3 +1,20 @@
+2015-08-12  Richard Biener  <rguenther@suse.de>
+
+       * tree-ssa-sccvn.c (vn_nary_op_compute_hash): Also canonicalize
+       comparison operand order and commutative ternary op operand order.
+       (sccvn_dom_walker::cond_stack): New state to track temporary
+       expressions.
+       (sccvn_dom_walker::after_dom_children): Remove tempoary expressions
+       no longer valid.
+       (sccvn_dom_walker::record_cond): Add a single temporary conditional
+       expression.
+       (sccvn_dom_walker::record_conds): Add a temporary conditional
+       expressions and all related expressions also true/false.
+       (sccvn_dom_walker::before_dom_children): Record temporary
+       expressions based on the controlling condition of a single
+       predecessor.  When trying to simplify a conditional statement
+       lookup expressions we might have inserted earlier.
+
 2015-08-12  Yvan Roux  <yvan.roux@linaro.org>
 
        PR target/67127
index b712e5f..15b0b41 100644 (file)
@@ -1,3 +1,25 @@
+2015-08-12  Richard Biener  <rguenther@suse.de>
+
+       * gcc.dg/tree-ssa/ssa-fre-47.c: New testcase.
+       * gcc.dg/tree-ssa/ssa-fre-48.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-fre-49.c: Likewise.
+       * g++.dg/tree-ssa/pr61034.C: Adjust.
+       * gcc.dg/fold-compare-2.c: Likewise.
+       * gcc.dg/pr50763.c: Likewise.
+       * gcc.dg/predict-3.c: Likewise.
+       * gcc.dg/tree-ssa/20030709-2.c: Likewise.
+       * gcc.dg/tree-ssa/pr19831-3.c: Likewise.
+       * gcc.dg/tree-ssa/pr20657.c: Likewise.
+       * gcc.dg/tree-ssa/pr21001.c: Likewise.
+       * gcc.dg/tree-ssa/pr37508.c: Likewise.
+       * gcc.dg/tree-ssa/vrp04.c: Likewise.
+       * gcc.dg/tree-ssa/vrp07.c: Likewise.
+       * gcc.dg/tree-ssa/vrp09.c: Likewise.
+       * gcc.dg/tree-ssa/vrp16.c: Likewise.
+       * gcc.dg/tree-ssa/vrp20.c: Likewise.
+       * gcc.dg/tree-ssa/vrp25.c: Likewise.
+       * gcc.dg/tree-ssa/vrp87.c: Likewise.
+
 2015-08-12  Nathan Sidwell  <nathan@acm.org>
 
        * gcc.dg/vrp-min-max-1.c: New.
index 14fd85a..628eb10 100644 (file)
@@ -43,5 +43,5 @@ bool f(I a, I b, I c, I d) {
 // This works only if everything is inlined into 'f'.
 
 // { dg-final { scan-tree-dump-times ";; Function" 1 "fre2" } }
-// { dg-final { scan-tree-dump-times "free" 18 "fre2" } }
+// { dg-final { scan-tree-dump-times "free" 10 "fre2" } }
 // { dg-final { scan-tree-dump-times "unreachable" 11 "fre2" } }
index f94fe04..16f0fd9 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-tail-merge -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-fre1" } */
 
 extern void abort (void);
 
@@ -15,5 +15,5 @@ main(void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "Removing basic block" 2 "vrp1" } } */
+/* { dg-final { scan-tree-dump-times "Removing basic block" 2 "fre1" } } */
 
index b233e93..102056f 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -ftree-tail-merge -fno-tree-dominator-opts -fdump-tree-pre" } */
+/* { dg-options "-O2 -ftree-tail-merge -fno-tree-dominator-opts" } */
 
 int bar (int i);
 
@@ -11,5 +11,3 @@ foo (int c, int d)
   d = 33;
   while (c == d);
 }
-
-/* { dg-final { scan-tree-dump-times "== 33" 2 "pre"} } */
index 2335201..e1be7cc 100644 (file)
@@ -12,6 +12,10 @@ void foo (int bound)
     {
       if (i < bound - 2)
        global += bar (i);
+      /* The following test is redundant with the loop bound check in the
+         for stmt and thus eliminated by FRE which makes the controlled
+        stmt always executed and thus equivalent to 100%.  Thus the
+        heuristic only applies three times.  */
       if (i <= bound)
        global += bar (i);
       if (i + 1 < bound)
@@ -21,4 +25,4 @@ void foo (int bound)
     }
 }
 
-/* { dg-final { scan-tree-dump-times "loop iv compare heuristics: 100.0%" 4 "profile_estimate"} } */
+/* { dg-final { scan-tree-dump-times "loop iv compare heuristics: 100.0%" 3 "profile_estimate"} } */
index aeff341..d4f42f9 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-cddce2" } */
+/* { dg-options "-O -fdump-tree-dce2" } */
   
 struct rtx_def;
 typedef struct rtx_def *rtx;
@@ -42,13 +42,13 @@ get_alias_set (t)
 
 /* There should be precisely one load of ->decl.rtl.  If there is
    more than, then the dominator optimizations failed.  */
-/* { dg-final { scan-tree-dump-times "->decl\\.rtl" 1 "cddce2"} } */
+/* { dg-final { scan-tree-dump-times "->decl\\.rtl" 1 "dce2"} } */
   
 /* There should be no loads of .rtmem since the complex return statement
    is just "return 0".  */
-/* { dg-final { scan-tree-dump-times ".rtmem" 0 "cddce2"} } */
+/* { dg-final { scan-tree-dump-times ".rtmem" 0 "dce2"} } */
   
 /* There should be one IF statement (the complex return statement should
    collapse down to a simple return 0 without any conditionals).  */
-/* { dg-final { scan-tree-dump-times "if " 1 "cddce2"} } */
+/* { dg-final { scan-tree-dump-times "if " 1 "dce2"} } */
 
index f78a17f..f5cb72d 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-options "-O2 -fno-ipa-icf -fdump-tree-optimized" } */
 
 void test2(void)
 {
index c1317a7..727ca4c 100644 (file)
@@ -3,7 +3,7 @@
    statement, which was needed to eliminate the second "if" statement.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-vrp1-details" } */
 
 int
 foo (int a)
index 05b495b..482d530 100644 (file)
@@ -5,7 +5,7 @@
    range information out of the conditional.  */
 
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-vrp1-details" } */
 
 int
 foo (int a)
index aa33626..0963cd9 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1" } */
 
 struct foo1 {
   int i:1;
@@ -10,9 +10,10 @@ struct foo2 {
 
 int test1 (struct foo1 *x)
 {
-  if (x->i == 0)
+  int i = x->i;
+  if (i == 0)
     return 1;
-  else if (x->i == -1)
+  else if (i == -1)
     return 1;
   return 0;
 }
@@ -37,9 +38,10 @@ int test3 (struct foo1 *x)
 
 int test4 (struct foo2 *x)
 {
-  if (x->i == 0)
+  unsigned int i = x->i;
+  if (i == 0)
     return 1;
-  else if (x->i == 1)
+  else if (i == 1)
     return 1;
   return 0;
 }
index 8af269f..61b7a47 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1" } */
 
 int
 foo (int a, int b)
index 3bc6869..a5bd670 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details -fdelete-null-pointer-checks" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details -fdelete-null-pointer-checks" } */
 
 int
 foo (int i, int *p)
index 98be0af..d42a566 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1 -std=gnu89" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1 -std=gnu89" } */
 
 foo (int *p)
 {
index 00a8e1a..8f5d5c8 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */
 
 
 extern void abort (void) __attribute__ ((__noreturn__));
@@ -12,9 +12,10 @@ struct rtx_def
 int
 nonlocal_mentioned_p (rtx x)
 {
-  if (x->code == 6 || x->code == 7)
-    if (x->code == 7)
-      if (x->code != 7)
+  int code = x->code;
+  if (code == 6 || code == 7)
+    if (code == 7)
+      if (code != 7)
        abort ();
 }
 
index 012d05a..60d1731 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-fwrapv -O1 -ftree-vrp -fdump-tree-vrp1" } */
+/* { dg-options "-fwrapv -O1 -fno-tree-fre -ftree-vrp -fdump-tree-vrp1" } */
 
 extern void abort ();
 extern void exit (int);
index 30da333..cbc4ec3 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */
 
 extern void abort ();
 extern void arf ();
index 7641c97..e81dd36 100644 (file)
@@ -1,8 +1,8 @@
 /* Setting LOGICAL_OP_NON_SHORT_CIRCUIT to 0 leads to two conditional jumps
-   when evaluating an && condition.  VRP is not able to optimize this.  */
+   when evaluating an && condition.  */
 /* { dg-do compile { target { ! { logical_op_short_circuit || { m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-* hppa*-*-* } } } } } */
 
-/* { dg-options "-O2 -fdump-tree-vrp2-details -fdump-tree-cddce2-details" } */
+/* { dg-options "-O2 -fdump-tree-fre1-details" } */
 
 struct bitmap_head_def;
 typedef struct bitmap_head_def *bitmap;
@@ -74,9 +74,6 @@ bitmap_ior_into (bitmap a, const_bitmap b)
   return changed;
 }
 
-/* Verify that VRP simplified an "if" statement.  */
-/* { dg-final { scan-tree-dump "Folded into: if.*" "vrp2"} } */
-/* Verify that DCE after VRP2 eliminates a dead conversion
-   to a (Bool).  */
-/* { dg-final { scan-tree-dump "Deleting.*_Bool.*;" "cddce2"} } */
-
+/* Verify that FRE simplified an if stmt.  */
+/* { dg-final { scan-tree-dump "Replaced a_elt_\[0-9\]+ != 0B with 1" "fre1" } } */
+/* { dg-final { scan-tree-dump "Replaced _\[0-9\]+ & _\[0-9\]+ with _\[0-9\]+" "fre1" } } */
index eca0d44..003433c 100644 (file)
@@ -2365,10 +2365,18 @@ vn_nary_op_compute_hash (const vn_nary_op_t vno1)
     if (TREE_CODE (vno1->op[i]) == SSA_NAME)
       vno1->op[i] = SSA_VAL (vno1->op[i]);
 
-  if (vno1->length == 2
-      && commutative_tree_code (vno1->opcode)
+  if (((vno1->length == 2
+       && commutative_tree_code (vno1->opcode))
+       || (vno1->length == 3
+          && commutative_ternary_tree_code (vno1->opcode)))
       && tree_swap_operands_p (vno1->op[0], vno1->op[1], false))
     std::swap (vno1->op[0], vno1->op[1]);
+  else if (TREE_CODE_CLASS (vno1->opcode) == tcc_comparison
+          && tree_swap_operands_p (vno1->op[0], vno1->op[1], false))
+    {
+      std::swap (vno1->op[0], vno1->op[1]);
+      vno1->opcode = swap_tree_comparison  (vno1->opcode);
+    }
 
   hstate.add_int (vno1->opcode);
   for (i = 0; i < vno1->length; ++i)
@@ -4281,13 +4289,105 @@ set_hashtable_value_ids (void)
 class sccvn_dom_walker : public dom_walker
 {
 public:
-  sccvn_dom_walker () : dom_walker (CDI_DOMINATORS), fail (false) {}
+  sccvn_dom_walker ()
+    : dom_walker (CDI_DOMINATORS), fail (false), cond_stack (vNULL) {}
 
   virtual void before_dom_children (basic_block);
+  virtual void after_dom_children (basic_block);
+
+  void record_cond (basic_block,
+                   enum tree_code code, tree lhs, tree rhs, bool value);
+  void record_conds (basic_block,
+                    enum tree_code code, tree lhs, tree rhs, bool value);
 
   bool fail;
+  vec<std::pair <basic_block, std::pair <vn_nary_op_t, vn_nary_op_t> > >
+    cond_stack;
 };
 
+/* Record a temporary condition for the BB and its dominated blocks.  */
+
+void
+sccvn_dom_walker::record_cond (basic_block bb,
+                              enum tree_code code, tree lhs, tree rhs,
+                              bool value)
+{
+  tree ops[2] = { lhs, rhs };
+  vn_nary_op_t old = NULL;
+  if (vn_nary_op_lookup_pieces (2, code, boolean_type_node, ops, &old))
+    current_info->nary->remove_elt_with_hash (old, old->hashcode);
+  vn_nary_op_t cond
+    = vn_nary_op_insert_pieces (2, code, boolean_type_node, ops,
+                               value
+                               ? boolean_true_node
+                               : boolean_false_node, 0);
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Recording temporarily ");
+      print_generic_expr (dump_file, ops[0], TDF_SLIM);
+      fprintf (dump_file, " %s ", get_tree_code_name (code));
+      print_generic_expr (dump_file, ops[1], TDF_SLIM);
+      fprintf (dump_file, " == %s%s\n",
+              value ? "true" : "false",
+              old ? " (old entry saved)" : "");
+    }
+  cond_stack.safe_push (std::make_pair (bb, std::make_pair (cond, old)));
+}
+
+/* Record temporary conditions for the BB and its dominated blocks
+   according to LHS CODE RHS == VALUE and its dominated conditions.  */
+
+void
+sccvn_dom_walker::record_conds (basic_block bb,
+                               enum tree_code code, tree lhs, tree rhs,
+                               bool value)
+{
+  /* Record the original condition.  */
+  record_cond (bb, code, lhs, rhs, value);
+
+  if (!value)
+    return;
+
+  /* Record dominated conditions if the condition is true.  Note that
+     the inversion is already recorded.  */
+  switch (code)
+    {
+    case LT_EXPR:
+    case GT_EXPR:
+      record_cond (bb, code == LT_EXPR ? LE_EXPR : GE_EXPR, lhs, rhs, true);
+      record_cond (bb, NE_EXPR, lhs, rhs, true);
+      record_cond (bb, EQ_EXPR, lhs, rhs, false);
+      break;
+
+    case EQ_EXPR:
+      record_cond (bb, LE_EXPR, lhs, rhs, true);
+      record_cond (bb, GE_EXPR, lhs, rhs, true);
+      record_cond (bb, LT_EXPR, lhs, rhs, false);
+      record_cond (bb, GT_EXPR, lhs, rhs, false);
+      break;
+
+    default:
+      break;
+    }
+}
+/* Restore expressions and values derived from conditionals.  */
+
+void
+sccvn_dom_walker::after_dom_children (basic_block bb)
+{
+  while (!cond_stack.is_empty ()
+        && cond_stack.last ().first == bb)
+    {
+      vn_nary_op_t cond = cond_stack.last ().second.first;
+      vn_nary_op_t old = cond_stack.last ().second.second;
+      current_info->nary->remove_elt_with_hash (cond, cond->hashcode);
+      if (old)
+       vn_nary_op_insert_into (old, current_info->nary, false);
+      cond_stack.pop ();
+    }
+}
+
 /* Value number all statements in BB.  */
 
 void
@@ -4320,6 +4420,39 @@ sccvn_dom_walker::before_dom_children (basic_block bb)
       return;
     }
 
+  /* If we have a single predecessor record the equivalence from a
+     possible condition on the predecessor edge.  */
+  if (single_pred_p (bb))
+    {
+      edge e = single_pred_edge (bb);
+      /* Check if there are multiple executable successor edges in
+        the source block.  Otherwise there is no additional info
+        to be recorded.  */
+      edge e2;
+      FOR_EACH_EDGE (e2, ei, e->src->succs)
+       if (e2 != e
+           && e2->flags & EDGE_EXECUTABLE)
+         break;
+      if (e2 && (e2->flags & EDGE_EXECUTABLE))
+       {
+
+         gimple stmt = last_stmt (e->src);
+         if (stmt
+             && gimple_code (stmt) == GIMPLE_COND)
+           {
+             enum tree_code code = gimple_cond_code (stmt);
+             tree lhs = gimple_cond_lhs (stmt);
+             tree rhs = gimple_cond_rhs (stmt);
+             record_conds (bb, code, lhs, rhs,
+                           (e->flags & EDGE_TRUE_VALUE) != 0);
+             code = invert_tree_comparison (code, HONOR_NANS (lhs));
+             if (code != ERROR_MARK)
+               record_conds (bb, code, lhs, rhs,
+                             (e->flags & EDGE_TRUE_VALUE) == 0);
+           }
+       }
+    }
+
   /* Value-number all defs in the basic-block.  */
   for (gphi_iterator gsi = gsi_start_phis (bb);
        !gsi_end_p (gsi); gsi_next (&gsi))
@@ -4389,6 +4522,16 @@ sccvn_dom_walker::before_dom_children (basic_block bb)
          rhs = vn_get_expr_for (rhs);
        val = fold_binary (gimple_cond_code (stmt),
                           boolean_type_node, lhs, rhs);
+       /* If that didn't simplify to a constant see if we have recorded
+          temporary expressions from taken edges.  */
+       if (!val || TREE_CODE (val) != INTEGER_CST)
+         {
+           tree ops[2];
+           ops[0] = gimple_cond_lhs (stmt);
+           ops[1] = gimple_cond_rhs (stmt);
+           val = vn_nary_op_lookup_pieces (2, gimple_cond_code (stmt),
+                                           boolean_type_node, ops, NULL);
+         }
        break;
       }
     case GIMPLE_SWITCH: