re PR tree-optimization/34172 (Missed store ccp optimization)
authorRichard Guenther <rguenther@suse.de>
Fri, 14 Mar 2008 17:05:48 +0000 (17:05 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Fri, 14 Mar 2008 17:05:48 +0000 (17:05 +0000)
2008-03-14  Richard Guenther  <rguenther@suse.de>

PR tree-optimization/34172
* tree-flow.h (refs_may_alias_p): Declare.
(get_single_def_stmt): Likewise.
(get_single_def_stmt_from_phi): Likewise.
(get_single_def_stmt_with_phi): Likewise.
* tree-dfa.c (refs_may_alias_p): New function.
(get_single_def_stmt): Likewise.
(get_single_def_stmt_from_phi): Likewise.
(get_single_def_stmt_with_phi): Likewise.
* tree-ssa-sccvn.c (get_def_ref_stmt_vuses): New function.
(vn_reference_lookup_1): New helper function.
(vn_reference_lookup): Walk the virtual use-def chain to
continue searching for a match if the def does not alias the
reference we are looking for.

* gcc.dg/tree-ssa/ssa-fre-11.c: New testcase.
* gcc.dg/tree-ssa/ssa-fre-12.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-13.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-14.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-15.c: Likewise.
* gcc.dg/tree-ssa/20031106-4.c: Remove XFAIL.

From-SVN: r133222

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/20031106-4.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-11.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-12.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-13.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-14.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-15.c [new file with mode: 0644]
gcc/tree-dfa.c
gcc/tree-flow.h
gcc/tree-ssa-sccvn.c

index b54a308bbd28574dd390b58eb669f86bf695de82..0da79075f657cb318c726e7f01d697433b17e221 100644 (file)
@@ -1,3 +1,20 @@
+2008-03-14  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/34172
+       * tree-flow.h (refs_may_alias_p): Declare.
+       (get_single_def_stmt): Likewise.
+       (get_single_def_stmt_from_phi): Likewise.
+       (get_single_def_stmt_with_phi): Likewise.
+       * tree-dfa.c (refs_may_alias_p): New function.
+       (get_single_def_stmt): Likewise.
+       (get_single_def_stmt_from_phi): Likewise.
+       (get_single_def_stmt_with_phi): Likewise.
+       * tree-ssa-sccvn.c (get_def_ref_stmt_vuses): New function.
+       (vn_reference_lookup_1): New helper function.
+       (vn_reference_lookup): Walk the virtual use-def chain to
+       continue searching for a match if the def does not alias the
+       reference we are looking for.
+
 2008-03-14  David Edelsohn  <edelsohn@gnu.org>
 
        * doc/install.texi (Binaries): Remove UCLA archive.  Add HVCC
index cf5edb6c4c173120b73c6ec29d90b62731d42972..f93230a95ae6006d688255ca90db282fe50173d3 100644 (file)
@@ -1,3 +1,13 @@
+2008-03-14  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/34172
+       * gcc.dg/tree-ssa/ssa-fre-11.c: New testcase.
+       * gcc.dg/tree-ssa/ssa-fre-12.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-fre-13.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-fre-14.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-fre-15.c: Likewise.
+       * gcc.dg/tree-ssa/20031106-4.c: Remove XFAIL.
+
 2008-03-14  Uros Bizjak  <ubizjak@gmail.com>
 
        PR libcpp/35322:
index 369b7b3c043fb6fc3cfd2c4d84d871566d739212..d727886917053ad59d78fce44ab59778b6cf3f15 100644 (file)
@@ -26,5 +26,5 @@ void foo (struct s*  r)
 }
 
 /* There should be no link_error calls.  */
-/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" } } */
 /* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-11.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-11.c
new file mode 100644 (file)
index 0000000..50bb5d9
--- /dev/null
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-fre-details" } */
+
+struct
+{
+  int x;
+  int y;
+} S[100];
+
+int z[100];
+
+int
+foo (int y)
+{
+  int x;
+
+  S[5].x = 4;
+  S[5].y = 0;
+
+  x = S[5].x;
+
+  return (x);
+}
+
+/* { dg-final { scan-tree-dump "Replaced S\\\[5\\\].x with 4" "fre" } } */
+/* { dg-final { cleanup-tree-dump "fre" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-12.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-12.c
new file mode 100644 (file)
index 0000000..50bb5d9
--- /dev/null
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-fre-details" } */
+
+struct
+{
+  int x;
+  int y;
+} S[100];
+
+int z[100];
+
+int
+foo (int y)
+{
+  int x;
+
+  S[5].x = 4;
+  S[5].y = 0;
+
+  x = S[5].x;
+
+  return (x);
+}
+
+/* { dg-final { scan-tree-dump "Replaced S\\\[5\\\].x with 4" "fre" } } */
+/* { dg-final { cleanup-tree-dump "fre" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-13.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-13.c
new file mode 100644 (file)
index 0000000..3253afe
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fstrict-aliasing -fno-tree-sra --param max-aliased-vops=0 --param max-fields-for-field-sensitive=0 -fdump-tree-fre-details" } */
+
+/* Should be optimized, propagating &a into (*p)[i] with parameters
+     --param max-aliased-vops=0 --param max-fields-for-field-sensitive=0
+   which means max 1 VOP per stmt and no SFTs.  */
+
+/* For this testcase we need TBAA to work.  */
+
+struct Foo
+{
+  void *data;
+  int size;
+};
+void foo(double (*q)[4], struct Foo *tmp1)
+{
+  double a[4];
+  int i;
+  tmp1->data = &a;
+  tmp1->size = 4;
+  for (i=0; i<4; ++i)
+    {
+      double (*p)[4] = tmp1->data;
+      (*p)[i] = (*q)[i];
+    }
+}
+
+/* { dg-final { scan-tree-dump "Inserted .* &a" "fre" } } */
+/* { dg-final { scan-tree-dump "Replaced tmp1_.\\\(D\\\)->data" "fre" } } */
+/* { dg-final { cleanup-tree-dump "fre" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-14.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-14.c
new file mode 100644 (file)
index 0000000..d2d5e01
--- /dev/null
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fno-tree-sra --param max-aliased-vops=0 --param max-fields-for-field-sensitive=0 -fdump-tree-fre-details" } */
+
+/* Should be optimized, propagating &a into (*p)[i] with parameters
+     --param max-aliased-vops=0 --param max-fields-for-field-sensitive=0
+   which means max 1 VOP per stmt and no SFTs.  */
+
+struct Foo
+{
+  void *data;
+  double size;
+};
+void foo(double (*q)[4])
+{
+  struct Foo tmp1;
+  double a[4];
+  int i;
+  tmp1.data = &a;
+  tmp1.size = 4;
+  for (i=0; i<4; ++i)
+    {
+      double (*p)[4] = tmp1.data;
+      (*p)[i] = (*q)[i];
+      /* We want a PHI for the VOP for accessing tmp1.data, so place
+        this store to tmp1 here.  */
+      tmp1.size -= 1.0;
+    }
+}
+
+/* { dg-final { scan-tree-dump "Inserted .* &a" "fre" } } */
+/* { dg-final { scan-tree-dump "Replaced tmp1.data" "fre" } } */
+/* { dg-final { cleanup-tree-dump "fre" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-15.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-15.c
new file mode 100644 (file)
index 0000000..1a286f1
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fno-tree-sra --param max-aliased-vops=0 --param max-fields-for-field-sensitive=0 -fdump-tree-fre-details" } */
+
+/* Should be optimized, propagating &a into (*p)[i] with parameters
+     --param max-aliased-vops=0 --param max-fields-for-field-sensitive=0
+   which means max 1 VOP per stmt and no SFTs.  */
+
+struct Foo
+{
+  void *data;
+  double size;
+};
+void foo(double (*q)[4])
+{
+  struct Foo tmp1;
+  double a[4];
+  int i;
+  tmp1.data = &a;
+  for (i=0; i<4; ++i)
+    {
+      double (*p)[4] = tmp1.data;
+      (*p)[i] = (*q)[i];
+      /* We want a PHI for the VOP for accessing tmp1.data, so place
+        this store to tmp1 here.  */
+      tmp1.size -= 1.0;
+    }
+}
+
+/* { dg-final { scan-tree-dump "Replaced" "fre" } } */
+/* { dg-final { cleanup-tree-dump "fre" } } */
index 346f6f3803cee4dec82d277870174d1caaae7424..349581671a57507ad581a4bf4148706ef699171d 100644 (file)
@@ -1046,3 +1046,165 @@ stmt_references_abnormal_ssa_name (tree stmt)
   return false;
 }
 
+/* Return true, if the two memory references REF1 and REF2 may alias.  */
+
+bool
+refs_may_alias_p (tree ref1, tree ref2)
+{
+  tree base1, base2;
+  HOST_WIDE_INT offset1 = 0, offset2 = 0;
+  HOST_WIDE_INT size1 = -1, size2 = -1;
+  HOST_WIDE_INT max_size1 = -1, max_size2 = -1;
+
+  gcc_assert ((SSA_VAR_P (ref1)
+              || handled_component_p (ref1)
+              || TREE_CODE (ref1) == INDIRECT_REF)
+             && (SSA_VAR_P (ref2)
+                 || handled_component_p (ref2)
+                 || TREE_CODE (ref2) == INDIRECT_REF));
+
+  /* Defer to TBAA if possible.  */
+  if (flag_strict_aliasing
+      && !alias_sets_conflict_p (get_alias_set (ref1), get_alias_set (ref2)))
+    return false;
+
+  /* Decompose the references into their base objects and the access.  */
+  base1 = ref1;
+  if (handled_component_p (ref1))
+    base1 = get_ref_base_and_extent (ref1, &offset1, &size1, &max_size1);
+  base2 = ref2;
+  if (handled_component_p (ref2))
+    base2 = get_ref_base_and_extent (ref2, &offset2, &size2, &max_size2);
+
+  /* If both references are based on different variables, they cannot alias.
+     If both references are based on the same variable, they cannot alias if
+     if the accesses do not overlap.  */
+  if (SSA_VAR_P (base1)
+      && SSA_VAR_P (base2)
+      && (!operand_equal_p (base1, base2, 0)
+         || !ranges_overlap_p (offset1, max_size1, offset2, max_size2)))
+    return false;
+
+  /* If both references are through pointers and both pointers are equal
+     then they do not alias if the accesses do not overlap.  */
+  if (TREE_CODE (base1) == INDIRECT_REF
+      && TREE_CODE (base2) == INDIRECT_REF
+      && operand_equal_p (TREE_OPERAND (base1, 0),
+                         TREE_OPERAND (base2, 0), 0)
+      && !ranges_overlap_p (offset1, max_size1, offset2, max_size2))
+    return false;
+
+  return true;
+}
+
+/* Given a stmt STMT that references memory, return the single stmt
+   that is reached by following the VUSE -> VDEF link.  Returns
+   NULL_TREE, if there is no single stmt that defines all VUSEs of
+   STMT.
+   Note that for a stmt with a single virtual operand this may return
+   a PHI node as well.  Note that if all VUSEs are default definitions
+   this function will return an empty statement.  */
+
+tree
+get_single_def_stmt (tree stmt)
+{
+  tree def_stmt = NULL_TREE;
+  tree use;
+  ssa_op_iter iter;
+
+  FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_VIRTUAL_USES)
+    {
+      tree tmp = SSA_NAME_DEF_STMT (use);
+
+      /* ???  This is too simplistic for multiple virtual operands
+        reaching different PHI nodes of the same basic blocks or for
+        reaching all default definitions.  */
+      if (def_stmt
+         && def_stmt != tmp
+         && !(IS_EMPTY_STMT (def_stmt)
+              && IS_EMPTY_STMT (tmp)))
+       return NULL_TREE;
+
+      def_stmt = tmp;
+    }
+
+  return def_stmt;
+}
+
+/* Given a PHI node of virtual operands, tries to eliminate cyclic
+   reached definitions if they do not alias REF and returns the
+   defining statement of the single virtual operand that flows in
+   from a non-backedge.  Returns NULL_TREE if such statement within
+   the above conditions cannot be found.  */
+
+tree
+get_single_def_stmt_from_phi (tree ref, tree phi)
+{
+  tree def_arg = NULL_TREE;
+  int i;
+
+  /* Find the single PHI argument that is not flowing in from a
+     back edge and verify that the loop-carried definitions do
+     not alias the reference we look for.  */
+  for (i = 0; i < PHI_NUM_ARGS (phi); ++i)
+    {
+      tree arg = PHI_ARG_DEF (phi, i);
+      tree def_stmt;
+
+      if (!(PHI_ARG_EDGE (phi, i)->flags & EDGE_DFS_BACK))
+       {
+         /* Multiple non-back edges?  Do not try to handle this.  */
+         if (def_arg)
+           return NULL_TREE;
+         def_arg = arg;
+         continue;
+       }
+
+      /* Follow the definitions back to the original PHI node.  Bail
+        out once a definition is found that may alias REF.  */
+      def_stmt = SSA_NAME_DEF_STMT (arg);
+      do
+       {
+         if (TREE_CODE (def_stmt) != GIMPLE_MODIFY_STMT
+             || refs_may_alias_p (ref, GIMPLE_STMT_OPERAND (def_stmt, 0)))
+           return NULL_TREE;
+         /* ???  This will only work, reaching the PHI node again if
+            there is a single virtual operand on def_stmt.  */
+         def_stmt = get_single_def_stmt (def_stmt);
+         if (!def_stmt)
+           return NULL_TREE;
+       }
+      while (def_stmt != phi);
+    }
+
+  return SSA_NAME_DEF_STMT (def_arg);
+}
+
+/* Return the single reference statement defining all virtual uses
+   on STMT or NULL_TREE, if there are multiple defining statements.
+   Take into account only definitions that alias REF if following
+   back-edges when looking through a loop PHI node.  */
+
+tree
+get_single_def_stmt_with_phi (tree ref, tree stmt)
+{
+  switch (NUM_SSA_OPERANDS (stmt, SSA_OP_VIRTUAL_USES))
+    {
+    case 0:
+      gcc_unreachable ();
+
+    case 1:
+      {
+       tree def_stmt = SSA_NAME_DEF_STMT (SINGLE_SSA_TREE_OPERAND
+                                            (stmt, SSA_OP_VIRTUAL_USES));
+       /* We can handle lookups over PHI nodes only for a single
+          virtual operand.  */
+       if (TREE_CODE (def_stmt) == PHI_NODE)
+         return get_single_def_stmt_from_phi (ref, def_stmt);
+       return def_stmt;
+      }
+
+    default:
+      return get_single_def_stmt (stmt);
+    }
+}
index 1e3c92a91dc081f171f197aecf0c29475139c7d4..274e740496ed8dfa604b734a8965ec213b896812 100644 (file)
@@ -824,6 +824,10 @@ extern tree make_rename_temp (tree, const char *);
 extern void set_default_def (tree, tree);
 extern tree gimple_default_def (struct function *, tree);
 extern bool stmt_references_abnormal_ssa_name (tree);
+extern bool refs_may_alias_p (tree, tree);
+extern tree get_single_def_stmt (tree);
+extern tree get_single_def_stmt_from_phi (tree, tree);
+extern tree get_single_def_stmt_with_phi (tree, tree);
 
 /* In tree-phinodes.c  */
 extern void reserve_phi_args_for_new_edge (basic_block);
index 20d1498a2c994365436004a491b26a3c1ffe3e4e..3b42c241fb9bcfeed8e8e42c122f5f0d1d35d4a2 100644 (file)
@@ -662,6 +662,74 @@ valueize_vuses (VEC (tree, gc) *orig)
   return orig;
 }
 
+/* Return the single reference statement defining all virtual uses
+   in VUSES or NULL_TREE, if there are multiple defining statements.
+   Take into account only definitions that alias REF if following
+   back-edges.  */
+
+static tree
+get_def_ref_stmt_vuses (tree ref, VEC (tree, gc) *vuses)
+{
+  tree def_stmt, vuse;
+  unsigned int i;
+
+  gcc_assert (VEC_length (tree, vuses) >= 1);
+
+  def_stmt = SSA_NAME_DEF_STMT (VEC_index (tree, vuses, 0));
+  if (TREE_CODE (def_stmt) == PHI_NODE)
+    {
+      /* We can only handle lookups over PHI nodes for a single
+        virtual operand.  */
+      if (VEC_length (tree, vuses) == 1)
+       {
+         def_stmt = get_single_def_stmt_from_phi (ref, def_stmt);
+         goto cont;
+       }
+      else
+       return NULL_TREE;
+    }
+
+  /* Verify each VUSE reaches the same defining stmt.  */
+  for (i = 1; VEC_iterate (tree, vuses, i, vuse); ++i)
+    {
+      tree tmp = SSA_NAME_DEF_STMT (vuse);
+      if (tmp != def_stmt)
+       return NULL_TREE;
+    }
+
+  /* Now see if the definition aliases ref, and loop until it does.  */
+cont:
+  while (def_stmt
+        && TREE_CODE (def_stmt) == GIMPLE_MODIFY_STMT
+        && !get_call_expr_in (def_stmt)
+        && !refs_may_alias_p (ref, GIMPLE_STMT_OPERAND (def_stmt, 0)))
+    def_stmt = get_single_def_stmt_with_phi (ref, def_stmt);
+
+  return def_stmt;
+}
+
+/* Lookup a SCCVN reference operation VR in the current hash table.
+   Returns the resulting value number if it exists in the hash table,
+   NULL_TREE otherwise.  */
+
+static tree
+vn_reference_lookup_1 (vn_reference_t vr)
+{
+  void **slot;
+  hashval_t hash;
+
+  hash = vr->hashcode;
+  slot = htab_find_slot_with_hash (current_info->references, vr,
+                                  hash, NO_INSERT);
+  if (!slot && current_info == optimistic_info)
+    slot = htab_find_slot_with_hash (valid_info->references, vr,
+                                    hash, NO_INSERT);
+  if (slot)
+    return ((vn_reference_t)*slot)->result;
+
+  return NULL_TREE;
+}
+
 /* Lookup OP in the current hash table, and return the resulting
    value number if it exists in the hash table.  Return NULL_TREE if
    it does not exist in the hash table. */
@@ -669,21 +737,35 @@ valueize_vuses (VEC (tree, gc) *orig)
 tree
 vn_reference_lookup (tree op, VEC (tree, gc) *vuses)
 {
-  void **slot;
   struct vn_reference_s vr1;
+  tree result, def_stmt;
 
   vr1.vuses = valueize_vuses (vuses);
   vr1.operands = valueize_refs (shared_reference_ops_from_ref (op));
   vr1.hashcode = vn_reference_compute_hash (&vr1);
-  slot = htab_find_slot_with_hash (current_info->references, &vr1, vr1.hashcode,
-                                  NO_INSERT);
-  if (!slot && current_info == optimistic_info)
-    slot = htab_find_slot_with_hash (valid_info->references, &vr1, vr1.hashcode,
-                                    NO_INSERT);
-  if (!slot)
-    return NULL_TREE;
+  result = vn_reference_lookup_1 (&vr1);
+
+  /* If there is a single defining statement for all virtual uses, we can
+     use that, following virtual use-def chains.  */
+  if (!result
+      && vr1.vuses
+      && VEC_length (tree, vr1.vuses) >= 1
+      && !get_call_expr_in (op)
+      && (def_stmt = get_def_ref_stmt_vuses (op, vr1.vuses))
+      && TREE_CODE (def_stmt) == GIMPLE_MODIFY_STMT
+      /* If there is a call involved, op must be assumed to
+        be clobbered.  */
+      && !get_call_expr_in (def_stmt))
+    {
+      /* We are now at an aliasing definition for the vuses we want to
+        look up.  Re-do the lookup with the vdefs for this stmt.  */
+      vdefs_to_vec (def_stmt, &vuses);
+      vr1.vuses = valueize_vuses (vuses);
+      vr1.hashcode = vn_reference_compute_hash (&vr1);
+      result = vn_reference_lookup_1 (&vr1);
+    }
 
-  return ((vn_reference_t)*slot)->result;
+  return result;
 }
 
 /* Insert OP into the current hash table with a value number of
@@ -1632,10 +1714,9 @@ visit_use (tree use)
                  print_generic_expr (dump_file, simplified, 0);
                  if (TREE_CODE (lhs) == SSA_NAME)
                    fprintf (dump_file, " has constants %d\n",
-                            VN_INFO (lhs)->has_constants);
+                            expr_has_constants (simplified));
                  else
                    fprintf (dump_file, "\n");
-
                }
            }
          /* Setting value numbers to constants will occasionally