re PR tree-optimization/81741 (Misoptimisation : replacing a constant field read...
authorJeff Law <law@redhat.com>
Tue, 22 Aug 2017 15:13:09 +0000 (09:13 -0600)
committerJeff Law <law@gcc.gnu.org>
Tue, 22 Aug 2017 15:13:09 +0000 (09:13 -0600)
PR tree-optimization/81741
PR tree-optimization/71947
* tree-ssa-dom.c: Include tree-inline.h.
(record_temporary_equivalences): Only record SSA_NAME = SSA_NAME
equivalences if one is more expensive to compute than the other.
* tree-ssa-scopedtables.h (class const_or_copies): Make
record_const_or_copy_raw method private.
(class avail_exprs_stack): New method simplify_binary_operation.
* tree-ssa-scopedtables.c (avail_exprs_stack::lookup_avail_expr): Call
avail_exprs_stack::simplify_binary_operation as needed.
(avail_exprs_stack::simplify_binary_operation): New function.

PR tree-optimization/81741
PR tree-optimization/71947
* gcc.dg/tree-ssa/pr81741.c: New test.
* gcc.dg/tree-ssa/pr71947-7.c: New test.
* gcc.dg/tree-ssa/pr71947-8.c: New test.
* gcc.dg/tree-ssa/pr71947-9.c: New test.
* gcc.dg/tree-ssa/pr71941-1.c: Tweak expected output.
* gcc.dg/tree-ssa/pr71941-2.c: Tweak expected output.
* gcc.dg/tree-ssa/pr71941-3.c: Tweak expected output.
* gcc.dg/tree-ssa/20030922-2.c: xfail.

From-SVN: r251279

13 files changed:
gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/20030922-2.c
gcc/testsuite/gcc.dg/tree-ssa/pr71947-1.c
gcc/testsuite/gcc.dg/tree-ssa/pr71947-2.c
gcc/testsuite/gcc.dg/tree-ssa/pr71947-3.c
gcc/testsuite/gcc.dg/tree-ssa/pr71947-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr71947-8.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr71947-9.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr81741.c [new file with mode: 0644]
gcc/tree-ssa-dom.c
gcc/tree-ssa-scopedtables.c
gcc/tree-ssa-scopedtables.h

index ab85c074f24241bc0bc359c013bc40d346a91b47..9b941af74c69efbb362b1fa3defc6cef3f5f6c61 100644 (file)
@@ -1,3 +1,17 @@
+2017-08-22  Jeff Law  <law@redhat.com>
+
+       PR tree-optimization/81741
+       PR tree-optimization/71947
+       * tree-ssa-dom.c: Include tree-inline.h.
+       (record_temporary_equivalences): Only record SSA_NAME = SSA_NAME
+       equivalences if one is more expensive to compute than the other.
+       * tree-ssa-scopedtables.h (class const_or_copies): Make
+       record_const_or_copy_raw method private.
+       (class avail_exprs_stack): New method simplify_binary_operation.
+       * tree-ssa-scopedtables.c (avail_exprs_stack::lookup_avail_expr): Call
+       avail_exprs_stack::simplify_binary_operation as needed.
+       (avail_exprs_stack::simplify_binary_operation): New function.
+
 2017-08-22  Sebastian Huber  <sebastian.huber@embedded-brains.de>
 
        * config.gcc (powerpc-*-rtems*): Add rs6000/linux64.opt.
index 17733519e0b611608448efe80598b3d0bfc369ec..531d0f95ae78a757472e8d852c0ee7ce1f036a4a 100644 (file)
@@ -1,3 +1,16 @@
+2017-08-22  Jeff Law  <law@redhat.com>
+
+       PR tree-optimization/81741
+       PR tree-optimization/71947
+       * gcc.dg/tree-ssa/pr81741.c: New test.
+       * gcc.dg/tree-ssa/pr71947-7.c: New test.
+       * gcc.dg/tree-ssa/pr71947-8.c: New test.
+       * gcc.dg/tree-ssa/pr71947-9.c: New test.
+       * gcc.dg/tree-ssa/pr71941-1.c: Tweak expected output.
+       * gcc.dg/tree-ssa/pr71941-2.c: Tweak expected output.
+       * gcc.dg/tree-ssa/pr71941-3.c: Tweak expected output.
+       * gcc.dg/tree-ssa/20030922-2.c: xfail.
+
 2017-08-22  Yvan Roux  <yvan.roux@linaro.org>
 
         PR c++/80287
index 16c79da9521cec88426d1e48958c53a219307ce1..172f203cf8e4da0959b990e4d94c95a302ad53d7 100644 (file)
@@ -20,4 +20,6 @@ rgn_rank (rtx insn1, rtx insn2)
 }
 
 /* There should be two IF conditionals.  */
-/* { dg-final { scan-tree-dump-times "if " 2 "dom2" } } */
+/* We no longer record the conditional equivalence by design, thus we
+   are unable to simplify the 3rd conditional at compile time.  */
+/* { dg-final { scan-tree-dump-times "if " 2 "dom2" { xfail *-*-* } } } */
index b03349546fd89134a0665bdf3c31bfd15d5ea625..ac8271cc574c28001bdb77ad56ac6ea22d64e36d 100644 (file)
@@ -14,6 +14,6 @@ int f(int x, int y)
    return ret;
 }
 
-/* { dg-final { scan-tree-dump "Folded to: ret_\[0-9\]+ = 0;"  "dom2" } } */
+/* { dg-final { scan-tree-dump "Replaced redundant expr \[^\r\n\]* with .0."  "dom2" } } */
 
 
index de8f88b88d7d694c00fc0add378df09717925ba7..b2c09cbb02119efb4d1dc49ee747cae9c8944fd4 100644 (file)
@@ -13,4 +13,4 @@ int f(int x, int y)
   return ret;
 }
 
-/* { dg-final { scan-tree-dump "Folded to: ret_\[0-9\]+ = 0;"  "dom2" } } */
+/* { dg-final { scan-tree-dump "Replaced redundant expr \[^\r\n\]* with .0."  "dom2" } } */
index e79847f83c85e87bea884bbb475d17f7878bcfdc..2316f7e1c0494df4b8907a8b706df912f3336d2e 100644 (file)
@@ -9,4 +9,5 @@ int f(int x, int y)
   return ret;
 }
 
-/* { dg-final { scan-tree-dump "Folded to: ret_\[0-9\]+ = 0;"  "dom2" } } */
+/* { dg-final { scan-tree-dump "Replaced redundant expr \[^\r\n\]* with .0."  "dom2" } } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr71947-7.c b/gcc/testsuite/gcc.dg/tree-ssa/pr71947-7.c
new file mode 100644 (file)
index 0000000..b44c064
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-tree-vrp -fdump-tree-dom-details" } */
+
+
+int f(int x, int y)
+{
+  int ret;
+  if (x == y)
+    ret = x % y;
+  else
+    ret = 1;
+
+  return ret;
+}
+/* { dg-final { scan-tree-dump "Replaced redundant expr \[^\r\n\]* with .0."  "dom2" } } */
+
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr71947-8.c b/gcc/testsuite/gcc.dg/tree-ssa/pr71947-8.c
new file mode 100644 (file)
index 0000000..26e5abb
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-tree-vrp -fdump-tree-dom-details" } */
+
+
+int f(int x, int y)
+{
+  int ret;
+  if (x == y)
+    ret = x / y;
+  else
+    ret = 0;
+
+  return ret;
+}
+/* { dg-final { scan-tree-dump "Replaced redundant expr \[^\r\n\]* with .1."  "dom2" } } */
+
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr71947-9.c b/gcc/testsuite/gcc.dg/tree-ssa/pr71947-9.c
new file mode 100644 (file)
index 0000000..22b68d5
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-tree-vrp -fdump-tree-dom-details" } */
+
+
+int f(int x, int y)
+{
+  int ret;
+  if (x == y)
+    ret = x & y;
+  else
+    ret = 0;
+
+  return ret;
+}
+/* { dg-final { scan-tree-dump "Replaced redundant expr \[^\r\n\]* with .\(x|y\)."  "dom2" } } */
+
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr81741.c b/gcc/testsuite/gcc.dg/tree-ssa/pr81741.c
new file mode 100644 (file)
index 0000000..a162c3c
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -w -fdump-tree-dom2-details" } */
+
+#include <string.h>
+
+typedef struct string_s {
+  unsigned long size, alloc;
+  char *ptr;
+} string_t[1];
+
+# define M_ASSUME(x)                                    \
+  (! __builtin_constant_p (!!(x) || !(x)) || (x) ?      \
+   (void) 0 : __builtin_unreachable())
+
+int f(string_t s)
+{
+  M_ASSUME(strlen(s->ptr) == s->size);
+  return s->size;
+}
+
+/* { dg-final { scan-assembler-not "strlen" } } */
+
index 494b472e121cfcef37019295f5f7a5733f2245cd..407a4ef97d2591287cf8f04a1f4b6ad773de4794 100644 (file)
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "gimple-fold.h"
 #include "tree-eh.h"
+#include "tree-inline.h"
 #include "gimple-iterator.h"
 #include "tree-cfg.h"
 #include "tree-into-ssa.h"
@@ -776,16 +777,27 @@ record_temporary_equivalences (edge e,
 
       /* Record the simple NAME = VALUE equivalence.  */
       tree rhs = edge_info->rhs;
-      record_equality (lhs, rhs, const_and_copies);
 
-      /* We already recorded that LHS = RHS, with canonicalization,
-        value chain following, etc.
+      /* If this is a SSA_NAME = SSA_NAME equivalence and one operand is
+        cheaper to compute than the other, then set up the equivalence
+        such that we replace the expensive one with the cheap one.
 
-        We also want to record RHS = LHS, but without any canonicalization
-        or value chain following.  */
-      if (TREE_CODE (rhs) == SSA_NAME)
-       const_and_copies->record_const_or_copy_raw (rhs, lhs,
-                                                   SSA_NAME_VALUE (rhs));
+        If they are the same cost to compute, then do not record anything.  */
+      if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs) == SSA_NAME)
+       {
+         gimple *rhs_def = SSA_NAME_DEF_STMT (rhs);
+         int rhs_cost = estimate_num_insns (rhs_def, &eni_size_weights);
+
+         gimple *lhs_def = SSA_NAME_DEF_STMT (lhs);
+         int lhs_cost = estimate_num_insns (lhs_def, &eni_size_weights);
+
+         if (rhs_cost > lhs_cost)
+           record_equality (rhs, lhs, const_and_copies);
+         else if (rhs_cost < lhs_cost)
+           record_equality (lhs, rhs, const_and_copies);
+       }
+      else
+       record_equality (lhs, rhs, const_and_copies);
 
       /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was
         set via a widening type conversion, then we may be able to record
index 7b9ca78a878443374589a52d85be038622b7e4f8..6e1fd582814ac0d65c50819f681cb2920879befd 100644 (file)
@@ -116,6 +116,102 @@ vuse_eq (ao_ref *, tree vuse1, unsigned int cnt, void *data)
   return NULL;
 }
 
+/* We looked for STMT in the hash table, but did not find it.
+
+   If STMT is an assignment from a binary operator, we may know something
+   about the operands relationship to each other which would allow
+   us to derive a constant value for the RHS of STMT.  */
+
+tree
+avail_exprs_stack::simplify_binary_operation (gimple *stmt,
+                                             class expr_hash_elt element)
+{
+  if (is_gimple_assign (stmt))
+    {
+      struct hashable_expr *expr = element.expr ();
+      if (expr->kind == EXPR_BINARY)
+       {
+         enum tree_code code = expr->ops.binary.op;
+
+         switch (code)
+           {
+           /* For these cases, if we know the operands
+              are equal, then we know the result.  */
+           case MIN_EXPR:
+           case MAX_EXPR:
+           case BIT_IOR_EXPR:
+           case BIT_AND_EXPR:
+           case BIT_XOR_EXPR:
+           case MINUS_EXPR:
+           case TRUNC_DIV_EXPR:
+           case CEIL_DIV_EXPR:
+           case FLOOR_DIV_EXPR:
+           case ROUND_DIV_EXPR:
+           case EXACT_DIV_EXPR:
+           case TRUNC_MOD_EXPR:
+           case CEIL_MOD_EXPR:
+           case FLOOR_MOD_EXPR:
+           case ROUND_MOD_EXPR:
+             {
+               /* Build a simple equality expr and query the hash table
+                  for it.  */
+               struct hashable_expr expr;
+               expr.type = boolean_type_node;
+               expr.kind = EXPR_BINARY;
+               expr.ops.binary.op = EQ_EXPR;
+               expr.ops.binary.opnd0 = gimple_assign_rhs1 (stmt);
+               expr.ops.binary.opnd1 = gimple_assign_rhs2 (stmt);
+               class expr_hash_elt element2 (&expr, NULL_TREE);
+               expr_hash_elt **slot
+                 = m_avail_exprs->find_slot (&element2, NO_INSERT);
+               tree result_type = TREE_TYPE (gimple_assign_lhs (stmt));
+
+               /* If the query was successful and returned a nonzero
+                  result, then we know that the operands of the binary
+                  expression are the same.  In many cases this allows
+                  us to compute a constant result of the expression
+                  at compile time, even if we do not know the exact
+                  values of the operands.  */
+               if (slot && *slot && integer_onep ((*slot)->lhs ()))
+                 {
+                   switch (code)
+                     {
+                     case MIN_EXPR:
+                     case MAX_EXPR:
+                     case BIT_IOR_EXPR:
+                     case BIT_AND_EXPR:
+                       return gimple_assign_rhs1 (stmt);
+
+                     case BIT_XOR_EXPR:
+                     case MINUS_EXPR:
+                     case TRUNC_MOD_EXPR:
+                     case CEIL_MOD_EXPR:
+                     case FLOOR_MOD_EXPR:
+                     case ROUND_MOD_EXPR:
+                       return build_zero_cst (result_type);
+
+                     case TRUNC_DIV_EXPR:
+                     case CEIL_DIV_EXPR:
+                     case FLOOR_DIV_EXPR:
+                     case ROUND_DIV_EXPR:
+                     case EXACT_DIV_EXPR:
+                       return build_one_cst (result_type);
+
+                     default:
+                       gcc_unreachable ();
+                     }
+                 }
+               break;
+             }
+
+             default:
+               break;
+           }
+       }
+    }
+  return NULL_TREE;
+}
+
 /* Search for an existing instance of STMT in the AVAIL_EXPRS_STACK table.
    If found, return its LHS. Otherwise insert STMT in the table and
    return NULL_TREE.
@@ -160,6 +256,12 @@ avail_exprs_stack::lookup_avail_expr (gimple *stmt, bool insert, bool tbaa_p)
     }
   else if (*slot == NULL)
     {
+      /* If we did not find the expression in the hash table, we may still
+        be able to produce a result for some expressions.  */
+      tree alt = avail_exprs_stack::simplify_binary_operation (stmt, element);
+      if (alt)
+       return alt;
+
       class expr_hash_elt *element2 = new expr_hash_elt (element);
       *slot = element2;
 
index df304aedbf4f05a7523e4cbaae7777a2ab51172f..e3d7bff6913380b495d6d75a794c4d415c7529dc 100644 (file)
@@ -156,6 +156,11 @@ class avail_exprs_stack
   vec<std::pair<expr_hash_elt_t, expr_hash_elt_t> > m_stack;
   hash_table<expr_elt_hasher> *m_avail_exprs;
 
+  /* For some assignments where the RHS is a binary operator, if we know
+     a equality relationship between the operands, we may be able to compute
+     a result, even if we don't know the exact value of the operands.  */
+  tree simplify_binary_operation (gimple *, class expr_hash_elt);
+
   /* We do not allow copying this object or initializing one
      from another.  */
   avail_exprs_stack& operator= (const avail_exprs_stack&);
@@ -185,10 +190,6 @@ class const_and_copies
      may follow the value chain for the RHS.  */
   void record_const_or_copy (tree, tree);
 
-  /* Record a single const/copy pair that can be unwound.  This version
-     does not follow the value chain for the RHS.  */
-  void record_const_or_copy_raw (tree, tree, tree);
-
   /* Special entry point when we want to provide an explicit previous
      value for the first argument.  Try to get rid of this in the future. 
 
@@ -196,6 +197,10 @@ class const_and_copies
   void record_const_or_copy (tree, tree, tree);
 
  private:
+  /* Record a single const/copy pair that can be unwound.  This version
+     does not follow the value chain for the RHS.  */
+  void record_const_or_copy_raw (tree, tree, tree);
+
   vec<tree> m_stack;
   const_and_copies& operator= (const const_and_copies&);
   const_and_copies (class const_and_copies &);