OSDN Git Service

PR debug/44668
[pf3gnuchains/gcc-fork.git] / gcc / tree-sra.c
index 166338f..84d950f 100644 (file)
@@ -77,18 +77,19 @@ along with GCC; see the file COPYING3.  If not see
 #include "alloc-pool.h"
 #include "tm.h"
 #include "tree.h"
-#include "expr.h"
 #include "gimple.h"
 #include "cgraph.h"
 #include "tree-flow.h"
 #include "ipa-prop.h"
-#include "diagnostic.h"
+#include "tree-pretty-print.h"
 #include "statistics.h"
 #include "tree-dump.h"
 #include "timevar.h"
 #include "params.h"
 #include "target.h"
 #include "flags.h"
+#include "dbgcnt.h"
+#include "tree-inline.h"
 
 /* Enumeration of all aggregate reductions we can do.  */
 enum sra_mode { SRA_MODE_EARLY_IPA,   /* early call regularization */
@@ -357,13 +358,13 @@ dump_access (FILE *f, struct access *access, bool grp)
   print_generic_expr (f, access->type, 0);
   if (grp)
     fprintf (f, ", grp_write = %d, total_scalarization = %d, "
-            "grp_read = %d, grp_hint = %d, "
+            "grp_read = %d, grp_hint = %d, grp_assignment_read = %d,"
             "grp_covered = %d, grp_unscalarizable_region = %d, "
             "grp_unscalarized_data = %d, grp_partial_lhs = %d, "
             "grp_to_be_replaced = %d, grp_maybe_modified = %d, "
             "grp_not_necessarilly_dereferenced = %d\n",
             access->grp_write, access->total_scalarization,
-            access->grp_read, access->grp_hint,
+            access->grp_read, access->grp_hint, access->grp_assignment_read,
             access->grp_covered, access->grp_unscalarizable_region,
             access->grp_unscalarized_data, access->grp_partial_lhs,
             access->grp_to_be_replaced, access->grp_maybe_modified,
@@ -1586,14 +1587,15 @@ sort_and_splice_var_accesses (tree var)
    ACCESS->replacement.  */
 
 static tree
-create_access_replacement (struct access *access)
+create_access_replacement (struct access *access, bool rename)
 {
   tree repl;
 
   repl = create_tmp_var (access->type, "SR");
   get_var_ann (repl);
   add_referenced_var (repl);
-  mark_sym_for_renaming (repl);
+  if (rename)
+    mark_sym_for_renaming (repl);
 
   if (!access->grp_partial_lhs
       && (TREE_CODE (access->type) == COMPLEX_TYPE
@@ -1609,11 +1611,38 @@ create_access_replacement (struct access *access)
       && !DECL_ARTIFICIAL (access->base))
     {
       char *pretty_name = make_fancy_name (access->expr);
+      tree debug_expr = unshare_expr (access->expr), d;
 
       DECL_NAME (repl) = get_identifier (pretty_name);
       obstack_free (&name_obstack, pretty_name);
 
-      SET_DECL_DEBUG_EXPR (repl, access->expr);
+      /* Get rid of any SSA_NAMEs embedded in debug_expr,
+        as DECL_DEBUG_EXPR isn't considered when looking for still
+        used SSA_NAMEs and thus they could be freed.  All debug info
+        generation cares is whether something is constant or variable
+        and that get_ref_base_and_extent works properly on the
+        expression.  */
+      for (d = debug_expr; handled_component_p (d); d = TREE_OPERAND (d, 0))
+       switch (TREE_CODE (d))
+         {
+         case ARRAY_REF:
+         case ARRAY_RANGE_REF:
+           if (TREE_OPERAND (d, 1)
+               && TREE_CODE (TREE_OPERAND (d, 1)) == SSA_NAME)
+             TREE_OPERAND (d, 1) = SSA_NAME_VAR (TREE_OPERAND (d, 1));
+           if (TREE_OPERAND (d, 3)
+               && TREE_CODE (TREE_OPERAND (d, 3)) == SSA_NAME)
+             TREE_OPERAND (d, 3) = SSA_NAME_VAR (TREE_OPERAND (d, 3));
+           /* FALLTHRU */
+         case COMPONENT_REF:
+           if (TREE_OPERAND (d, 2)
+               && TREE_CODE (TREE_OPERAND (d, 2)) == SSA_NAME)
+             TREE_OPERAND (d, 2) = SSA_NAME_VAR (TREE_OPERAND (d, 2));
+           break;
+         default:
+           break;
+         }
+      SET_DECL_DEBUG_EXPR (repl, debug_expr);
       DECL_DEBUG_EXPR_IS_FROM (repl) = 1;
       TREE_NO_WARNING (repl) = TREE_NO_WARNING (access->base);
     }
@@ -1642,15 +1671,30 @@ get_access_replacement (struct access *access)
   gcc_assert (access->grp_to_be_replaced);
 
   if (!access->replacement_decl)
-    access->replacement_decl = create_access_replacement (access);
+    access->replacement_decl = create_access_replacement (access, true);
   return access->replacement_decl;
 }
 
+/* Return ACCESS scalar replacement, create it if it does not exist yet but do
+   not mark it for renaming.  */
+
+static inline tree
+get_unrenamed_access_replacement (struct access *access)
+{
+  gcc_assert (!access->grp_to_be_replaced);
+
+  if (!access->replacement_decl)
+    access->replacement_decl = create_access_replacement (access, false);
+  return access->replacement_decl;
+}
+
+
 /* Build a subtree of accesses rooted in *ACCESS, and move the pointer in the
    linked list along the way.  Stop when *ACCESS is NULL or the access pointed
-   to it is not "within" the root.  */
+   to it is not "within" the root.  Return false iff some accesses partially
+   overlap.  */
 
-static void
+static bool
 build_access_subtree (struct access **access)
 {
   struct access *root = *access, *last_child = NULL;
@@ -1665,24 +1709,32 @@ build_access_subtree (struct access **access)
        last_child->next_sibling = *access;
       last_child = *access;
 
-      build_access_subtree (access);
+      if (!build_access_subtree (access))
+       return false;
     }
+
+  if (*access && (*access)->offset < limit)
+    return false;
+
+  return true;
 }
 
 /* Build a tree of access representatives, ACCESS is the pointer to the first
-   one, others are linked in a list by the next_grp field.  Decide about scalar
-   replacements on the way, return true iff any are to be created.  */
+   one, others are linked in a list by the next_grp field.  Return false iff
+   some accesses partially overlap.  */
 
-static void
+static bool
 build_access_trees (struct access *access)
 {
   while (access)
     {
       struct access *root = access;
 
-      build_access_subtree (&access);
+      if (!build_access_subtree (&access))
+       return false;
       root->next_grp = access;
     }
+  return true;
 }
 
 /* Return true if expr contains some ARRAY_REFs into a variable bounded
@@ -1750,7 +1802,8 @@ analyze_access_subtree (struct access *root, bool allow_replacements,
       else
        covered_to += child->size;
 
-      sth_created |= analyze_access_subtree (child, allow_replacements,
+      sth_created |= analyze_access_subtree (child,
+                                            allow_replacements && !scalar,
                                             mark_read, mark_write);
 
       root->grp_unscalarized_data |= child->grp_unscalarized_data;
@@ -2020,9 +2073,7 @@ analyze_all_variable_accesses (void)
       struct access *access;
 
       access = sort_and_splice_var_accesses (var);
-      if (access)
-       build_access_trees (access);
-      else
+      if (!access || !build_access_trees (access))
        disqualify_candidate (var,
                              "No or inhibitingly overlapping accesses.");
     }
@@ -2480,29 +2531,21 @@ sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
 }
 
 /* Create a new suitable default definition SSA_NAME and replace all uses of
-   SSA with it.  */
+   SSA with it, RACC is access describing the uninitialized part of an
+   aggregate that is being loaded.  */
 
 static void
-replace_uses_with_default_def_ssa_name (tree ssa)
+replace_uses_with_default_def_ssa_name (tree ssa, struct access *racc)
 {
-  tree repl, decl = SSA_NAME_VAR (ssa);
-  if (TREE_CODE (decl) == PARM_DECL)
-    {
-      tree tmp = create_tmp_reg (TREE_TYPE (decl), "SR");
+  tree repl, decl;
 
-      get_var_ann (tmp);
-      add_referenced_var (tmp);
-      repl = make_ssa_name (tmp, gimple_build_nop ());
-      set_default_def (tmp, repl);
-    }
-  else
+  decl = get_unrenamed_access_replacement (racc);
+
+  repl = gimple_default_def (cfun, decl);
+  if (!repl)
     {
-      repl = gimple_default_def (cfun, decl);
-      if (!repl)
-       {
-         repl = make_ssa_name (decl, gimple_build_nop ());
-         set_default_def (decl, repl);
-       }
+      repl = make_ssa_name (decl, gimple_build_nop ());
+      set_default_def (decl, repl);
     }
 
   replace_uses_by (ssa, repl);
@@ -2690,7 +2733,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
                                             false, false);
                  gcc_assert (*stmt == gsi_stmt (*gsi));
                  if (TREE_CODE (lhs) == SSA_NAME)
-                   replace_uses_with_default_def_ssa_name (lhs);
+                   replace_uses_with_default_def_ssa_name (lhs, racc);
 
                  unlink_stmt_vdef (*stmt);
                  gsi_remove (gsi, true);
@@ -2895,7 +2938,7 @@ late_intra_sra (void)
 static bool
 gate_intra_sra (void)
 {
-  return flag_tree_sra != 0;
+  return flag_tree_sra != 0 && dbg_cnt (tree_sra);
 }
 
 
@@ -3840,6 +3883,7 @@ replace_removed_params_ssa_names (gimple stmt,
     gimple_phi_set_result (stmt, name);
 
   replace_uses_by (lhs, name);
+  release_ssa_name (lhs);
   return true;
 }
 
@@ -4123,7 +4167,8 @@ all_callers_have_enough_arguments_p (struct cgraph_node *node)
 /* Convert all callers of NODE to pass parameters as given in ADJUSTMENTS.  */
 
 static void
-convert_callers (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
+convert_callers (struct cgraph_node *node, tree old_decl,
+                ipa_parm_adjustment_vec adjustments)
 {
   tree old_cur_fndecl = current_function_decl;
   struct cgraph_edge *cs;
@@ -4170,10 +4215,11 @@ convert_callers (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
          if (gimple_code (stmt) != GIMPLE_CALL)
            continue;
          call_fndecl = gimple_call_fndecl (stmt);
-         if (call_fndecl && cgraph_get_node (call_fndecl) == node)
+         if (call_fndecl == old_decl)
            {
              if (dump_file)
                fprintf (dump_file, "Adjusting recursive call");
+             gimple_call_set_fndecl (stmt, node->decl);
              ipa_modify_call_arguments (NULL, stmt, adjustments);
            }
        }
@@ -4182,43 +4228,38 @@ convert_callers (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
   return;
 }
 
-/* Create an abstract origin declaration for OLD_DECL and make it an abstract
-   origin of the provided decl so that there are preserved parameters for debug
-   information.  */
-
-static void
-create_abstract_origin (tree old_decl)
-{
-  if (!DECL_ABSTRACT_ORIGIN (old_decl))
-    {
-      tree new_decl = copy_node (old_decl);
-
-      DECL_ABSTRACT (new_decl) = 1;
-      SET_DECL_ASSEMBLER_NAME (new_decl, NULL_TREE);
-      SET_DECL_RTL (new_decl, NULL);
-      DECL_STRUCT_FUNCTION (new_decl) = NULL;
-      DECL_ARTIFICIAL (old_decl) = 1;
-      DECL_ABSTRACT_ORIGIN (old_decl) = new_decl;
-    }
-}
-
 /* Perform all the modification required in IPA-SRA for NODE to have parameters
    as given in ADJUSTMENTS.  */
 
 static void
 modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
 {
-  struct cgraph_node *alias;
-  for (alias = node->same_body; alias; alias = alias->next)
-    ipa_modify_formal_parameters (alias->decl, adjustments, "ISRA");
-  /* current_function_decl must be handled last, after same_body aliases,
-     as following functions will use what it computed.  */
-  create_abstract_origin (current_function_decl);
+  struct cgraph_node *new_node;
+  struct cgraph_edge *cs;
+  VEC (cgraph_edge_p, heap) * redirect_callers;
+  int node_callers;
+
+  node_callers = 0;
+  for (cs = node->callers; cs != NULL; cs = cs->next_caller)
+    node_callers++;
+  redirect_callers = VEC_alloc (cgraph_edge_p, heap, node_callers);
+  for (cs = node->callers; cs != NULL; cs = cs->next_caller)
+    VEC_quick_push (cgraph_edge_p, redirect_callers, cs);
+
+  rebuild_cgraph_edges ();
+  pop_cfun ();
+  current_function_decl = NULL_TREE;
+
+  new_node = cgraph_function_versioning (node, redirect_callers, NULL, NULL,
+                                        NULL, NULL, "isra");
+  current_function_decl = new_node->decl;
+  push_cfun (DECL_STRUCT_FUNCTION (new_node->decl));
+
   ipa_modify_formal_parameters (current_function_decl, adjustments, "ISRA");
   ipa_sra_modify_function_body (adjustments);
   sra_ipa_reset_debug_stmts (adjustments);
-  convert_callers (node, adjustments);
-  cgraph_make_node_local (node);
+  convert_callers (new_node, node->decl, adjustments);
+  cgraph_make_node_local (new_node);
   return;
 }
 
@@ -4236,6 +4277,13 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
       return false;
     }
 
+  if (!tree_versionable_function_p (node->decl))
+    {
+      if (dump_file)
+       fprintf (dump_file, "Function not local to this compilation unit.\n");
+      return false;
+    }
+
   if (DECL_VIRTUAL_P (current_function_decl))
     {
       if (dump_file)