OSDN Git Service

* config/pdp11/pdp11.md (various): Fix conditions on a number of
[pf3gnuchains/gcc-fork.git] / gcc / tree-sra.c
index e97970c..3328261 100644 (file)
@@ -189,6 +189,10 @@ struct access
      statement?  This flag is propagated down the access tree.  */
   unsigned grp_assignment_read : 1;
 
+  /* Does this group contain a write access that comes from an assignment
+     statement?  This flag is propagated down the access tree.  */
+  unsigned grp_assignment_write : 1;
+
   /* Other passes of the analysis use this bit to make function
      analyze_access_subtree create scalar replacements for this group if
      possible.  */
@@ -216,6 +220,9 @@ struct access
      cannot be called from within FOR_EACH_REFERENCED_VAR. */
   unsigned grp_to_be_replaced : 1;
 
+  /* Should TREE_NO_WARNING of a replacement be set?  */
+  unsigned grp_no_warning : 1;
+
   /* Is it possible that the group refers to data which might be (directly or
      otherwise) modified?  */
   unsigned grp_maybe_modified : 1;
@@ -361,15 +368,17 @@ dump_access (FILE *f, struct access *access, bool grp)
   if (grp)
     fprintf (f, ", grp_write = %d, total_scalarization = %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_assignment_write = %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_covered, access->grp_unscalarizable_region,
-            access->grp_unscalarized_data, access->grp_partial_lhs,
-            access->grp_to_be_replaced, access->grp_maybe_modified,
+            access->grp_assignment_write, access->grp_covered,
+            access->grp_unscalarizable_region, access->grp_unscalarized_data,
+            access->grp_partial_lhs, access->grp_to_be_replaced,
+            access->grp_maybe_modified,
             access->grp_not_necessarilly_dereferenced);
   else
     fprintf (f, ", write = %d, total_scalarization = %d, "
@@ -774,12 +783,13 @@ create_access (tree expr, gimple stmt, bool write)
          disqualify_candidate (base, "Encountered a variable sized access.");
          return NULL;
        }
-      if ((offset % BITS_PER_UNIT) != 0 || (size % BITS_PER_UNIT) != 0)
+      if (TREE_CODE (expr) == COMPONENT_REF
+         && DECL_BIT_FIELD (TREE_OPERAND (expr, 1)))
        {
-         disqualify_candidate (base,
-                               "Encountered an acces not aligned to a byte.");
+         disqualify_candidate (base, "Encountered a bit-field access.");
          return NULL;
        }
+      gcc_checking_assert ((offset % BITS_PER_UNIT) == 0);
 
       if (ptr)
        mark_parm_dereference (base, offset + size, stmt);
@@ -811,14 +821,12 @@ create_access (tree expr, gimple stmt, bool write)
 
 /* Return true iff TYPE is a RECORD_TYPE with fields that are either of gimple
    register types or (recursively) records with only these two kinds of fields.
-   It also returns false if any of these records has a zero-size field as its
-   last field or has a bit-field.  */
+   It also returns false if any of these records contains a bit-field.  */
 
 static bool
 type_consists_of_records_p (tree type)
 {
   tree fld;
-  bool last_fld_has_zero_size = false;
 
   if (TREE_CODE (type) != RECORD_TYPE)
     return false;
@@ -834,13 +842,8 @@ type_consists_of_records_p (tree type)
        if (!is_gimple_reg_type (ft)
            && !type_consists_of_records_p (ft))
          return false;
-
-       last_fld_has_zero_size = tree_low_cst (DECL_SIZE (fld), 1) == 0;
       }
 
-  if (last_fld_has_zero_size)
-    return false;
-
   return true;
 }
 
@@ -1022,6 +1025,9 @@ build_accesses_from_assign (gimple stmt)
   racc = build_access_from_expr_1 (rhs, stmt, false);
   lacc = build_access_from_expr_1 (lhs, stmt, true);
 
+  if (lacc)
+    lacc->grp_assignment_write = 1;
+
   if (racc)
     {
       racc->grp_assignment_read = 1;
@@ -1574,8 +1580,7 @@ sort_and_splice_var_accesses (tree var)
   access_count = VEC_length (access_p, access_vec);
 
   /* Sort by <OFFSET, SIZE>.  */
-  qsort (VEC_address (access_p, access_vec), access_count, sizeof (access_p),
-        compare_access_positions);
+  VEC_qsort (access_p, access_vec, compare_access_positions);
 
   i = 0;
   while (i < access_count)
@@ -1584,6 +1589,7 @@ sort_and_splice_var_accesses (tree var)
       bool grp_write = access->write;
       bool grp_read = !access->write;
       bool grp_assignment_read = access->grp_assignment_read;
+      bool grp_assignment_write = access->grp_assignment_write;
       bool multiple_reads = false;
       bool total_scalarization = access->total_scalarization;
       bool grp_partial_lhs = access->grp_partial_lhs;
@@ -1618,6 +1624,7 @@ sort_and_splice_var_accesses (tree var)
                grp_read = true;
            }
          grp_assignment_read |= ac2->grp_assignment_read;
+         grp_assignment_write |= ac2->grp_assignment_write;
          grp_partial_lhs |= ac2->grp_partial_lhs;
          unscalarizable_region |= ac2->grp_unscalarizable_region;
          total_scalarization |= ac2->total_scalarization;
@@ -1637,6 +1644,7 @@ sort_and_splice_var_accesses (tree var)
       access->grp_write = grp_write;
       access->grp_read = grp_read;
       access->grp_assignment_read = grp_assignment_read;
+      access->grp_assignment_write = grp_assignment_write;
       access->grp_hint = multiple_reads || total_scalarization;
       access->grp_partial_lhs = grp_partial_lhs;
       access->grp_unscalarizable_region = unscalarizable_region;
@@ -1713,7 +1721,10 @@ create_access_replacement (struct access *access, bool rename)
          }
       SET_DECL_DEBUG_EXPR (repl, debug_expr);
       DECL_DEBUG_EXPR_IS_FROM (repl) = 1;
-      TREE_NO_WARNING (repl) = TREE_NO_WARNING (access->base);
+      if (access->grp_no_warning)
+       TREE_NO_WARNING (repl) = 1;
+      else
+       TREE_NO_WARNING (repl) = TREE_NO_WARNING (access->base);
     }
   else
     TREE_NO_WARNING (repl) = 1;
@@ -1822,17 +1833,50 @@ expr_with_var_bounded_array_refs_p (tree expr)
   return false;
 }
 
-enum mark_read_status { SRA_MR_NOT_READ, SRA_MR_READ, SRA_MR_ASSIGN_READ};
+enum mark_rw_status { SRA_MRRW_NOTHING, SRA_MRRW_DIRECT, SRA_MRRW_ASSIGN};
 
 /* Analyze the subtree of accesses rooted in ROOT, scheduling replacements when
    both seeming beneficial and when ALLOW_REPLACEMENTS allows it.  Also set all
    sorts of access flags appropriately along the way, notably always set
    grp_read and grp_assign_read according to MARK_READ and grp_write when
-   MARK_WRITE is true.  */
+   MARK_WRITE is true.
+
+   Creating a replacement for a scalar access is considered beneficial if its
+   grp_hint is set (this means we are either attempting total scalarization or
+   there is more than one direct read access) or according to the following
+   table:
+
+   Access written to individually (once or more times)
+   |
+   |   Parent written to in an assignment statement
+   |   |
+   |   |       Access read individually _once_
+   |   |       |
+   |           |       |       Parent read in an assignment statement
+   |   |       |       |
+   |           |       |       |       Scalarize       Comment
+-----------------------------------------------------------------------------
+   0   0       0       0                       No access for the scalar
+   0   0       0       1                       No access for the scalar
+   0   0       1       0       No              Single read - won't help
+   0   0       1       1       No              The same case
+   0   1       0       0                       No access for the scalar
+   0   1       0       1                       No access for the scalar
+   0   1       1       0       Yes             s = *g; return s.i;
+   0   1       1       1       Yes             The same case as above
+   1   0       0       0       No              Won't help
+   1   0       0       1       Yes             s.i = 1; *g = s;
+   1   0       1       0       Yes             s.i = 5; g = s.i;
+   1   0       1       1       Yes             The same case as above
+   1   1       0       0       No              Won't help.
+   1   1       0       1       Yes             s.i = 1; *g = s;
+   1   1       1       0       Yes             s = *g; return s.i;
+   1   1       1       1       Yes             Any of the above yeses  */
 
 static bool
 analyze_access_subtree (struct access *root, bool allow_replacements,
-                       enum mark_read_status mark_read, bool mark_write)
+                       enum mark_rw_status mark_read,
+                       enum mark_rw_status mark_write)
 {
   struct access *child;
   HOST_WIDE_INT limit = root->offset + root->size;
@@ -1840,23 +1884,31 @@ analyze_access_subtree (struct access *root, bool allow_replacements,
   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 (mark_read == SRA_MR_ASSIGN_READ)
+  if (root->grp_assignment_read)
+    mark_read = SRA_MRRW_ASSIGN;
+  else if (mark_read == SRA_MRRW_ASSIGN)
     {
       root->grp_read = 1;
       root->grp_assignment_read = 1;
     }
-  if (mark_read == SRA_MR_READ)
+  else if (mark_read == SRA_MRRW_DIRECT)
     root->grp_read = 1;
-  else if (root->grp_assignment_read)
-    mark_read = SRA_MR_ASSIGN_READ;
   else if (root->grp_read)
-    mark_read = SRA_MR_READ;
+    mark_read = SRA_MRRW_DIRECT;
 
-  if (mark_write)
-    root->grp_write = true;
+  if (root->grp_assignment_write)
+    mark_write = SRA_MRRW_ASSIGN;
+  else if (mark_write == SRA_MRRW_ASSIGN)
+    {
+      root->grp_write = 1;
+      root->grp_assignment_write = 1;
+    }
+  else if (mark_write == SRA_MRRW_DIRECT)
+    root->grp_write = 1;
   else if (root->grp_write)
-    mark_write = true;
+    mark_write = SRA_MRRW_DIRECT;
 
   if (root->grp_unscalarizable_region)
     allow_replacements = false;
@@ -1881,7 +1933,8 @@ analyze_access_subtree (struct access *root, bool allow_replacements,
 
   if (allow_replacements && scalar && !root->first_child
       && (root->grp_hint
-         || (root->grp_write && (direct_read || root->grp_assignment_read))))
+         || ((direct_write || root->grp_assignment_write)
+             && (direct_read || root->grp_assignment_read))))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
@@ -1920,7 +1973,8 @@ analyze_access_trees (struct access *access)
 
   while (access)
     {
-      if (analyze_access_subtree (access, true, SRA_MR_NOT_READ, false))
+      if (analyze_access_subtree (access, true,
+                                 SRA_MRRW_NOTHING, SRA_MRRW_NOTHING))
        ret = true;
       access = access->next_grp;
     }
@@ -1969,12 +2023,17 @@ create_artificial_child_access (struct access *parent, struct access *model,
   tree expr = parent->base;
 
   gcc_assert (!model->grp_unscalarizable_region);
-  if (!build_user_friendly_ref_for_offset (&expr, TREE_TYPE (expr), new_offset,
-                                          model->type))
-    return NULL;
 
   access = (struct access *) pool_alloc (access_pool);
   memset (access, 0, sizeof (struct access));
+  if (!build_user_friendly_ref_for_offset (&expr, TREE_TYPE (expr), new_offset,
+                                          model->type))
+    {
+      access->grp_no_warning = true;
+      expr = build_ref_for_model (EXPR_LOCATION (parent->base), parent->base,
+                                 new_offset, model, NULL, false);
+    }
+
   access->base = parent->base;
   access->expr = expr;
   access->offset = new_offset;
@@ -2015,11 +2074,16 @@ propagate_subaccesses_across_link (struct access *lacc, struct access *racc)
     {
       tree t = lacc->base;
 
+      lacc->type = racc->type;
       if (build_user_friendly_ref_for_offset (&t, TREE_TYPE (t), lacc->offset,
                                              racc->type))
+       lacc->expr = t;
+      else
        {
-         lacc->expr = t;
-         lacc->type = racc->type;
+         lacc->expr = build_ref_for_model (EXPR_LOCATION (lacc->base),
+                                           lacc->base, lacc->offset,
+                                           racc, NULL, false);
+         lacc->grp_no_warning = true;
        }
       return false;
     }
@@ -2169,12 +2233,12 @@ analyze_all_variable_accesses (void)
 }
 
 /* Generate statements copying scalar replacements of accesses within a subtree
-   into or out of AGG.  ACCESS is the first child of the root of the subtree to
-   be processed.  AGG is an aggregate type expression (can be a declaration but
-   does not have to be, it can for example also be a mem_ref or a series of
-   handled components).  TOP_OFFSET is the offset of the processed subtree
-   which has to be subtracted from offsets of individual accesses to get
-   corresponding offsets for AGG.  If CHUNK_SIZE is non-null, copy only
+   into or out of AGG.  ACCESS, all its children, siblings and their children
+   are to be processed.  AGG is an aggregate type expression (can be a
+   declaration but does not have to be, it can for example also be a mem_ref or
+   a series of handled components).  TOP_OFFSET is the offset of the processed
+   subtree which has to be subtracted from offsets of individual accesses to
+   get corresponding offsets for AGG.  If CHUNK_SIZE is non-null, copy only
    replacements in the interval <start_offset, start_offset + chunk_size>,
    otherwise copy all.  GSI is a statement iterator used to place the new
    statements.  WRITE should be true when the statements should write from AGG
@@ -2405,11 +2469,11 @@ enum unscalarized_data_handling { SRA_UDH_NONE,  /* Nothing done so far. */
                                  SRA_UDH_LEFT }; /* Data flushed to the LHS. */
 
 /* Store all replacements in the access tree rooted in TOP_RACC either to their
-   base aggregate if there are unscalarized data or directly to LHS
-   otherwise.  */
+   base aggregate if there are unscalarized data or directly to LHS of the
+   statement that is pointed to by GSI otherwise.  */
 
 static enum unscalarized_data_handling
-handle_unscalarized_data_in_subtree (struct access *top_racc, tree lhs,
+handle_unscalarized_data_in_subtree (struct access *top_racc,
                                     gimple_stmt_iterator *gsi)
 {
   if (top_racc->grp_unscalarized_data)
@@ -2421,6 +2485,7 @@ handle_unscalarized_data_in_subtree (struct access *top_racc, tree lhs,
     }
   else
     {
+      tree lhs = gimple_assign_lhs (gsi_stmt (*gsi));
       generate_subtree_copies (top_racc->first_child, lhs, top_racc->offset,
                               0, 0, gsi, false, false,
                               gimple_location (gsi_stmt (*gsi)));
@@ -2429,33 +2494,30 @@ handle_unscalarized_data_in_subtree (struct access *top_racc, tree lhs,
 }
 
 
-/* Try to generate statements to load all sub-replacements in an access
-   (sub)tree (LACC is the first child) from scalar replacements in the TOP_RACC
-   (sub)tree.  If that is not possible, refresh the TOP_RACC base aggregate and
-   load the accesses from it.  LEFT_OFFSET is the offset of the left whole
-   subtree being copied, RIGHT_OFFSET is the same thing for the right subtree.
-   NEW_GSI is stmt iterator used for statement insertions after the original
-   assignment, OLD_GSI is used to insert statements before the assignment.
-   *REFRESHED keeps the information whether we have needed to refresh
-   replacements of the LHS and from which side of the assignments this takes
-   place.  */
+/* Try to generate statements to load all sub-replacements in an access subtree
+   formed by children of LACC from scalar replacements in the TOP_RACC subtree.
+   If that is not possible, refresh the TOP_RACC base aggregate and load the
+   accesses from it.  LEFT_OFFSET is the offset of the left whole subtree being
+   copied. NEW_GSI is stmt iterator used for statement insertions after the
+   original assignment, OLD_GSI is used to insert statements before the
+   assignment.  *REFRESHED keeps the information whether we have needed to
+   refresh replacements of the LHS and from which side of the assignments this
+   takes place.  */
 
 static void
 load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
                                 HOST_WIDE_INT left_offset,
-                                HOST_WIDE_INT right_offset,
                                 gimple_stmt_iterator *old_gsi,
                                 gimple_stmt_iterator *new_gsi,
-                                enum unscalarized_data_handling *refreshed,
-                                tree lhs)
+                                enum unscalarized_data_handling *refreshed)
 {
   location_t loc = gimple_location (gsi_stmt (*old_gsi));
-  do
+  for (lacc = lacc->first_child; lacc; lacc = lacc->next_sibling)
     {
       if (lacc->grp_to_be_replaced)
        {
          struct access *racc;
-         HOST_WIDE_INT offset = lacc->offset - left_offset + right_offset;
+         HOST_WIDE_INT offset = lacc->offset - left_offset + top_racc->offset;
          gimple stmt;
          tree rhs;
 
@@ -2471,7 +2533,7 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
              /* No suitable access on the right hand side, need to load from
                 the aggregate.  See if we have to update it first... */
              if (*refreshed == SRA_UDH_NONE)
-               *refreshed = handle_unscalarized_data_in_subtree (top_racc, lhs,
+               *refreshed = handle_unscalarized_data_in_subtree (top_racc,
                                                                  old_gsi);
 
              if (*refreshed == SRA_UDH_LEFT)
@@ -2490,16 +2552,13 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
        }
       else if (*refreshed == SRA_UDH_NONE
               && lacc->grp_read && !lacc->grp_covered)
-       *refreshed = handle_unscalarized_data_in_subtree (top_racc, lhs,
+       *refreshed = handle_unscalarized_data_in_subtree (top_racc,
                                                          old_gsi);
 
       if (lacc->first_child)
-       load_assign_lhs_subreplacements (lacc->first_child, top_racc,
-                                        left_offset, right_offset,
-                                        old_gsi, new_gsi, refreshed, lhs);
-      lacc = lacc->next_sibling;
+       load_assign_lhs_subreplacements (lacc, top_racc, left_offset,
+                                        old_gsi, new_gsi, refreshed);
     }
-  while (lacc);
 }
 
 /* Result code for SRA assignment modification.  */
@@ -2714,14 +2773,12 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
          enum unscalarized_data_handling refreshed;
 
          if (lacc->grp_read && !lacc->grp_covered)
-           refreshed = handle_unscalarized_data_in_subtree (racc, lhs, gsi);
+           refreshed = handle_unscalarized_data_in_subtree (racc, gsi);
          else
            refreshed = SRA_UDH_NONE;
 
-         load_assign_lhs_subreplacements (lacc->first_child, racc,
-                                          lacc->offset, racc->offset,
-                                          &orig_gsi, gsi, &refreshed,
-                                          lhs);
+         load_assign_lhs_subreplacements (lacc, racc, lacc->offset,
+                                          &orig_gsi, gsi, &refreshed);
          if (refreshed != SRA_UDH_RIGHT)
            {
              gsi_next (gsi);
@@ -3466,8 +3523,7 @@ splice_param_accesses (tree parm, bool *ro_grp)
     return &no_accesses_representant;
   access_count = VEC_length (access_p, access_vec);
 
-  qsort (VEC_address (access_p, access_vec), access_count, sizeof (access_p),
-        compare_access_positions);
+  VEC_qsort (access_p, access_vec, compare_access_positions);
 
   i = 0;
   total_size = 0;