OSDN Git Service

2008-05-14 Paul Thomas <pault@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / tree-dfa.c
index f66a50c..622930f 100644 (file)
@@ -96,8 +96,10 @@ find_referenced_vars (void)
   return 0;
 }
 
-struct tree_opt_pass pass_referenced_vars =
+struct gimple_opt_pass pass_referenced_vars =
 {
+ {
+  GIMPLE_PASS,
   NULL,                                        /* name */
   NULL,                                        /* gate */
   find_referenced_vars,                        /* execute */
@@ -109,8 +111,8 @@ struct tree_opt_pass pass_referenced_vars =
   PROP_referenced_vars,                        /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  0,                                    /* todo_flags_finish */
-  0                                    /* letter */
+  0                                     /* todo_flags_finish */
+ }
 };
 
 
@@ -270,42 +272,6 @@ debug_referenced_vars (void)
 }
 
 
-/* Dump sub-variables for VAR to FILE.  */
-
-void
-dump_subvars_for (FILE *file, tree var)
-{
-  subvar_t sv = get_subvars_for_var (var);
-  tree subvar;
-  unsigned int i;
-
-  if (!sv)
-    return;
-
-  fprintf (file, "{ ");
-
-  for (i = 0; VEC_iterate (tree, sv, i, subvar); ++i)
-    {
-      print_generic_expr (file, subvar, dump_flags);
-      fprintf (file, "@" HOST_WIDE_INT_PRINT_UNSIGNED, SFT_OFFSET (subvar));
-      if (SFT_BASE_FOR_COMPONENTS_P (subvar))
-        fprintf (file, "[B]");
-      fprintf (file, " ");
-    }
-
-  fprintf (file, "}");
-}
-
-
-/* Dumb sub-variables for VAR to stderr.  */
-
-void
-debug_subvars_for (tree var)
-{
-  dump_subvars_for (stderr, var);
-}
-
-
 /* Dump variable VAR and its may-aliases to FILE.  */
 
 void
@@ -401,12 +367,6 @@ dump_variable (FILE *file, tree var)
       dump_may_aliases_for (file, var);
     }
 
-  if (get_subvars_for_var (var))
-    {
-      fprintf (file, ", sub-vars: ");
-      dump_subvars_for (file, var);
-    }
-
   if (!is_gimple_reg (var))
     {
       if (memory_partition (var))
@@ -420,16 +380,6 @@ dump_variable (FILE *file, tree var)
          fprintf (file, ", partition symbols: ");
          dump_decl_set (file, MPT_SYMBOLS (var));
        }
-
-      if (TREE_CODE (var) == STRUCT_FIELD_TAG)
-       {
-         fprintf (file, ", offset: " HOST_WIDE_INT_PRINT_UNSIGNED,
-                  SFT_OFFSET (var));
-         fprintf (file, ", base for components: %s",
-                  SFT_BASE_FOR_COMPONENTS_P (var) ? "NO" : "YES");
-         fprintf (file, ", partitionable: %s",
-                  SFT_UNPARTITIONABLE_P (var) ? "NO" : "YES");
-       }
     }
 
   fprintf (file, "\n");
@@ -641,16 +591,12 @@ find_vars_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 tree 
 referenced_var_lookup (unsigned int uid)
 {
-  tree var;
-
-  gcc_assert (bitmap_bit_p (gimple_referenced_vars (cfun), uid));
-
-  /* For now also assert that the variable is really referenced.
-     Otherwise callers need to deal with the result from this function
-     being NULL.  */
-  var = lookup_decl_from_uid (uid);
-  gcc_assert (var);
-  return var;
+  tree h;
+  struct tree_decl_minimal in;
+  in.uid = uid;
+  h = (tree) htab_find_with_hash (gimple_referenced_vars (cfun), &in, uid);
+  gcc_assert (h || uid == 0);
+  return h;
 }
 
 /* Check if TO is in the referenced_vars hash table and insert it if not.  
@@ -659,13 +605,23 @@ referenced_var_lookup (unsigned int uid)
 bool
 referenced_var_check_and_insert (tree to)
 { 
+  tree h, *loc;
+  struct tree_decl_minimal in;
   unsigned int uid = DECL_UID (to);
 
-  if (bitmap_bit_p (gimple_referenced_vars (cfun), uid))
-    return false;
-
-  bitmap_set_bit (gimple_referenced_vars (cfun), uid);
+  in.uid = uid;
+  h = (tree) htab_find_with_hash (gimple_referenced_vars (cfun), &in, uid);
+  if (h)
+    {
+      /* DECL_UID has already been entered in the table.  Verify that it is
+        the same entry as TO.  See PR 27793.  */
+      gcc_assert (h == to);
+      return false;
+    }
 
+  loc = (tree *) htab_find_slot_with_hash (gimple_referenced_vars (cfun),
+                                          &in, uid, INSERT);
+  *loc = to;
   return true;
 }
 
@@ -755,26 +711,19 @@ void
 remove_referenced_var (tree var)
 {
   var_ann_t v_ann;
+  struct tree_decl_minimal in;
+  void **loc;
   unsigned int uid = DECL_UID (var);
-  subvar_t sv;
-
-  /* If we remove a var, we should also remove its subvars, as we kill
-     their parent var and its annotation.  */
-  if (var_can_have_subvars (var)
-      && (sv = get_subvars_for_var (var)))
-    {
-      unsigned int i;
-      tree subvar;
-      for (i = 0; VEC_iterate (tree, sv, i, subvar); ++i)
-        remove_referenced_var (subvar);
-    }
 
   clear_call_clobbered (var);
   if ((v_ann = var_ann (var)))
     ggc_free (v_ann);
   var->base.ann = NULL;
   gcc_assert (DECL_P (var));
-  bitmap_clear_bit (gimple_referenced_vars (cfun), uid);
+  in.uid = uid;
+  loc = htab_find_slot_with_hash (gimple_referenced_vars (cfun), &in, uid,
+                                 NO_INSERT);
+  htab_clear_slot (gimple_referenced_vars (cfun), loc);
 }
 
 
@@ -1035,3 +984,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);
+    }
+}