OSDN Git Service

2011-04-29 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-sra.c
index 14fef47..e13a9f8 100644 (file)
@@ -91,6 +91,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "tree-inline.h"
 #include "gimple-pretty-print.h"
+#include "ipa-inline.h"
 
 /* Enumeration of all aggregate reductions we can do.  */
 enum sra_mode { SRA_MODE_EARLY_IPA,   /* early call regularization */
@@ -173,6 +174,9 @@ struct access
      entirely? */
   unsigned total_scalarization : 1;
 
+  /* Is this access an access to a non-addressable field? */
+  unsigned non_addressable : 1;
+
   /* Is this access currently in the work queue?  */
   unsigned grp_queued : 1;
 
@@ -192,6 +196,14 @@ struct access
      statement?  This flag is propagated down the access tree.  */
   unsigned grp_assignment_write : 1;
 
+  /* Does this group contain a read access through a scalar type?  This flag is
+     not propagated in the access tree in any direction.  */
+  unsigned grp_scalar_read : 1;
+
+  /* Does this group contain a write access through a scalar type?  This flag
+     is not propagated in the access tree in any direction.  */
+  unsigned grp_scalar_write : 1;
+
   /* Other passes of the analysis use this bit to make function
      analyze_access_subtree create scalar replacements for this group if
      possible.  */
@@ -365,16 +377,18 @@ dump_access (FILE *f, struct access *access, bool grp)
   fprintf (f, ", type = ");
   print_generic_expr (f, access->type, 0);
   if (grp)
-    fprintf (f, ", grp_write = %d, total_scalarization = %d, "
-            "grp_read = %d, grp_hint = %d, grp_assignment_read = %d,"
-            "grp_assignment_write = %d, grp_covered = %d, "
+    fprintf (f, ", total_scalarization = %d, grp_read = %d, grp_write = %d, "
+            "grp_assignment_read = %d, grp_assignment_write = %d, "
+            "grp_scalar_read = %d, grp_scalar_write = %d, "
+            "grp_hint = %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_assignment_read,
-            access->grp_assignment_write, access->grp_covered,
+            access->total_scalarization, access->grp_read, access->grp_write,
+            access->grp_assignment_read, access->grp_assignment_write,
+            access->grp_scalar_read, access->grp_scalar_write,
+            access->grp_hint, access->grp_covered,
             access->grp_unscalarizable_region, access->grp_unscalarized_data,
             access->grp_partial_lhs, access->grp_to_be_replaced,
             access->grp_maybe_modified,
@@ -816,6 +830,10 @@ create_access (tree expr, gimple stmt, bool write)
   access->grp_unscalarizable_region = unscalarizable_region;
   access->stmt = stmt;
 
+  if (TREE_CODE (expr) == COMPONENT_REF
+      && DECL_NONADDRESSABLE_P (TREE_OPERAND (expr, 1)))
+    access->non_addressable = 1;
+
   return access;
 }
 
@@ -1359,6 +1377,7 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
       add_referenced_var (tmp);
       tmp = make_ssa_name (tmp, NULL);
       addr = build_fold_addr_expr (unshare_expr (prev_base));
+      STRIP_USELESS_TYPE_CONVERSION (addr);
       stmt = gimple_build_assign (tmp, addr);
       gimple_set_location (stmt, loc);
       SSA_NAME_DEF_STMT (tmp) = stmt;
@@ -1523,7 +1542,7 @@ find_var_candidates (void)
   referenced_var_iterator rvi;
   bool ret = false;
 
-  FOR_EACH_REFERENCED_VAR (var, rvi)
+  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
     {
       if (TREE_CODE (var) != VAR_DECL && TREE_CODE (var) != PARM_DECL)
         continue;
@@ -1586,9 +1605,13 @@ sort_and_splice_var_accesses (tree var)
       struct access *access = VEC_index (access_p, access_vec, i);
       bool grp_write = access->write;
       bool grp_read = !access->write;
+      bool grp_scalar_write = access->write
+       && is_gimple_reg_type (access->type);
+      bool grp_scalar_read = !access->write
+       && is_gimple_reg_type (access->type);
       bool grp_assignment_read = access->grp_assignment_read;
       bool grp_assignment_write = access->grp_assignment_write;
-      bool multiple_reads = false;
+      bool multiple_scalar_reads = false;
       bool total_scalarization = access->total_scalarization;
       bool grp_partial_lhs = access->grp_partial_lhs;
       bool first_scalar = is_gimple_reg_type (access->type);
@@ -1613,13 +1636,21 @@ sort_and_splice_var_accesses (tree var)
          if (ac2->offset != access->offset || ac2->size != access->size)
            break;
          if (ac2->write)
-           grp_write = true;
+           {
+             grp_write = true;
+             grp_scalar_write = (grp_scalar_write
+                                 || is_gimple_reg_type (ac2->type));
+           }
          else
            {
-             if (grp_read)
-               multiple_reads = true;
-             else
-               grp_read = true;
+             grp_read = true;
+             if (is_gimple_reg_type (ac2->type))
+               {
+                 if (grp_scalar_read)
+                   multiple_scalar_reads = true;
+                 else
+                   grp_scalar_read = true;
+               }
            }
          grp_assignment_read |= ac2->grp_assignment_read;
          grp_assignment_write |= ac2->grp_assignment_write;
@@ -1641,9 +1672,11 @@ sort_and_splice_var_accesses (tree var)
       access->group_representative = access;
       access->grp_write = grp_write;
       access->grp_read = grp_read;
+      access->grp_scalar_read = grp_scalar_read;
+      access->grp_scalar_write = grp_scalar_write;
       access->grp_assignment_read = grp_assignment_read;
       access->grp_assignment_write = grp_assignment_write;
-      access->grp_hint = multiple_reads || total_scalarization;
+      access->grp_hint = multiple_scalar_reads || total_scalarization;
       access->grp_partial_lhs = grp_partial_lhs;
       access->grp_unscalarizable_region = unscalarizable_region;
       if (access->first_link)
@@ -1844,13 +1877,13 @@ enum mark_rw_status { SRA_MRRW_NOTHING, SRA_MRRW_DIRECT, SRA_MRRW_ASSIGN};
    there is more than one direct read access) or according to the following
    table:
 
-   Access written to individually (once or more times)
+   Access written to through a scalar type (once or more times)
    |
-   |   Parent written to in an assignment statement
+   |   Written to in an assignment statement
    |   |
-   |   |       Access read individually _once_
+   |   |       Access read as scalar _once_
    |   |       |
-   |           |       |       Parent read in an assignment statement
+   |           |       |       Read in an assignment statement
    |   |       |       |
    |           |       |       |       Scalarize       Comment
 -----------------------------------------------------------------------------
@@ -1881,8 +1914,6 @@ analyze_access_subtree (struct access *root, bool allow_replacements,
   HOST_WIDE_INT covered_to = root->offset;
   bool scalar = is_gimple_reg_type (root->type);
   bool hole = false, sth_created = false;
-  bool direct_read = root->grp_read;
-  bool direct_write = root->grp_write;
 
   if (root->grp_assignment_read)
     mark_read = SRA_MRRW_ASSIGN;
@@ -1931,8 +1962,8 @@ analyze_access_subtree (struct access *root, bool allow_replacements,
 
   if (allow_replacements && scalar && !root->first_child
       && (root->grp_hint
-         || ((direct_write || root->grp_assignment_write)
-             && (direct_read || root->grp_assignment_read))))
+         || ((root->grp_scalar_read || root->grp_assignment_read)
+             && (root->grp_scalar_write || root->grp_assignment_write))))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
@@ -2732,15 +2763,13 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
              && !contains_bitfld_comp_ref_p (lhs)
              && !access_has_children_p (lacc))
            {
-             lhs = build_ref_for_offset (loc, lhs, 0, TREE_TYPE (rhs),
-                                         gsi, false);
+             lhs = build_ref_for_model (loc, lhs, 0, racc, gsi, false);
              gimple_assign_set_lhs (*stmt, lhs);
            }
          else if (AGGREGATE_TYPE_P (TREE_TYPE (rhs))
                   && !contains_vce_or_bfcref_p (rhs)
                   && !access_has_children_p (racc))
-           rhs = build_ref_for_offset (loc, rhs, 0, TREE_TYPE (lhs),
-                                       gsi, false);
+           rhs = build_ref_for_model (loc, rhs, 0, lacc, gsi, false);
 
          if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
            {
@@ -3666,13 +3695,18 @@ decide_one_param_reduction (struct access *repr)
   for (; repr; repr = repr->next_grp)
     {
       gcc_assert (parm == repr->base);
-      new_param_count++;
+
+      /* Taking the address of a non-addressable field is verboten.  */
+      if (by_ref && repr->non_addressable)
+       return 0;
 
       if (!by_ref || (!repr->grp_maybe_modified
                      && !repr->grp_not_necessarilly_dereferenced))
        total_size += repr->size;
       else
        total_size += cur_parm_size;
+
+      new_param_count++;
     }
 
   gcc_assert (new_param_count > 0);
@@ -4330,8 +4364,9 @@ convert_callers (struct cgraph_node *node, tree old_decl,
     }
 
   for (cs = node->callers; cs; cs = cs->next_caller)
-    if (bitmap_set_bit (recomputed_callers, cs->caller->uid))
-      compute_inline_parameters (cs->caller);
+    if (bitmap_set_bit (recomputed_callers, cs->caller->uid)
+       && gimple_in_ssa_p (DECL_STRUCT_FUNCTION (cs->caller->decl)))
+      compute_inline_parameters (cs->caller, true);
   BITMAP_FREE (recomputed_callers);
 
   current_function_decl = old_cur_fndecl;
@@ -4413,6 +4448,13 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
       return false;
     }
 
+  if (!node->local.can_change_signature)
+    {
+      if (dump_file)
+       fprintf (dump_file, "Function can not change signature.\n");
+      return false;
+    }
+
   if (!tree_versionable_function_p (node->decl))
     {
       if (dump_file)
@@ -4428,7 +4470,7 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
     }
 
   if ((DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))
-      && node->global.size >= MAX_INLINE_INSNS_AUTO)
+      && inline_summary(node)->size >= MAX_INLINE_INSNS_AUTO)
     {
       if (dump_file)
        fprintf (dump_file, "Function too big to be made truly local.\n");
@@ -4461,7 +4503,7 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
 static unsigned int
 ipa_early_sra (void)
 {
-  struct cgraph_node *node = cgraph_node (current_function_decl);
+  struct cgraph_node *node = cgraph_get_node (current_function_decl);
   ipa_parm_adjustment_vec adjustments;
   int ret = 0;