OSDN Git Service

2009-10-15 Sebastian Pop <sebastian.pop@amd.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-sra.c
index dd3f680..5203685 100644 (file)
@@ -125,7 +125,9 @@ struct access
   HOST_WIDE_INT size;
   tree base;
 
-  /* Expression.  */
+  /* Expression.  It is context dependent so do not use it to create new
+     expressions to access the original aggregate.  See PR 42154 for a
+     testcase.  */
   tree expr;
   /* Type.  */
   tree type;
@@ -144,7 +146,9 @@ struct access
      points to the first one.  */
   struct access *first_child;
 
-  /* Pointer to the next sibling in the access tree as described above.  */
+  /* In intraprocedural SRA, pointer to the next sibling in the access tree as
+     described above.  In IPA-SRA this is a pointer to the next access
+     belonging to the same group (having the same representative).  */
   struct access *next_sibling;
 
   /* Pointers to the first and last element in the linked list of assign
@@ -1231,8 +1235,6 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset,
        case UNION_TYPE:
        case QUAL_UNION_TYPE:
        case RECORD_TYPE:
-         /* ??? Some records used to be half-unions in Ada so the code treats
-            the 3 container types the same.  This has been fixed in Ada.  */
          for (fld = TYPE_FIELDS (type); fld; fld = TREE_CHAIN (fld))
            {
              HOST_WIDE_INT pos, size;
@@ -1243,7 +1245,10 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset,
 
              pos = int_bit_position (fld);
              gcc_assert (TREE_CODE (type) == RECORD_TYPE || pos == 0);
-             size = tree_low_cst (DECL_SIZE (fld), 1);
+             tr_size = DECL_SIZE (fld);
+             if (!tr_size || !host_integerp (tr_size, 1))
+               continue;
+             size = tree_low_cst (tr_size, 1);
              if (pos > offset || (pos + size) <= offset)
                continue;
 
@@ -1301,7 +1306,8 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset,
 /* Construct an expression that would reference a part of aggregate *EXPR of
    type TYPE at the given OFFSET of the type EXP_TYPE.  If EXPR is NULL, the
    function only determines whether it can build such a reference without
-   actually doing it.
+   actually doing it, otherwise, the tree it points to is unshared first and
+   then used as a base for furhter sub-references.
 
    FIXME: Eventually this should be replaced with
    maybe_fold_offset_to_reference() from tree-ssa-ccp.c but that requires a
@@ -1314,6 +1320,9 @@ build_ref_for_offset (tree *expr, tree type, HOST_WIDE_INT offset,
 {
   location_t loc = expr ? EXPR_LOCATION (*expr) : UNKNOWN_LOCATION;
 
+  if (expr)
+    *expr = unshare_expr (*expr);
+
   if (allow_ptr && POINTER_TYPE_P (type))
     {
       type = TREE_TYPE (type);
@@ -1756,7 +1765,7 @@ create_artificial_child_access (struct access *parent, struct access *model,
    access but LACC is not, change the type of the latter, if possible.  */
 
 static bool
-propagate_subacesses_accross_link (struct access *lacc, struct access *racc)
+propagate_subaccesses_across_link (struct access *lacc, struct access *racc)
 {
   struct access *rchild;
   HOST_WIDE_INT norm_delta = lacc->offset - racc->offset;
@@ -1797,7 +1806,7 @@ propagate_subacesses_accross_link (struct access *lacc, struct access *racc)
              rchild->grp_hint = 1;
              new_acc->grp_hint |= new_acc->grp_read;
              if (rchild->first_child)
-               ret |= propagate_subacesses_accross_link (new_acc, rchild);
+               ret |= propagate_subaccesses_across_link (new_acc, rchild);
            }
          continue;
        }
@@ -1815,7 +1824,7 @@ propagate_subacesses_accross_link (struct access *lacc, struct access *racc)
        {
          ret = true;
          if (racc->first_child)
-           propagate_subacesses_accross_link (new_acc, rchild);
+           propagate_subaccesses_across_link (new_acc, rchild);
        }
     }
 
@@ -1841,7 +1850,7 @@ propagate_all_subaccesses (void)
          if (!bitmap_bit_p (candidate_bitmap, DECL_UID (lacc->base)))
            continue;
          lacc = lacc->group_representative;
-         if (propagate_subacesses_accross_link (lacc, racc)
+         if (propagate_subaccesses_across_link (lacc, racc)
              && lacc->first_link)
            add_access_to_work_queue (lacc);
        }
@@ -1957,7 +1966,7 @@ generate_subtree_copies (struct access *access, tree agg,
 {
   do
     {
-      tree expr = unshare_expr (agg);
+      tree expr = agg;
 
       if (chunk_size && access->offset >= start_offset + chunk_size)
        return;
@@ -2106,10 +2115,17 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write,
         gcc.c-torture/compile/20011217-1.c.  */
       if (!is_gimple_reg_type (type))
        {
-         gimple stmt;
+         tree ref = access->base;
+         bool ok;
+
+         ok = build_ref_for_offset (&ref, TREE_TYPE (ref),
+                                    access->offset, access->type, false);
+         gcc_assert (ok);
+
          if (write)
            {
-             tree ref = unshare_expr (access->expr);
+             gimple stmt;
+
              if (access->grp_partial_lhs)
                ref = force_gimple_operand_gsi (gsi, ref, true, NULL_TREE,
                                                 false, GSI_NEW_STMT);
@@ -2118,10 +2134,12 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write,
            }
          else
            {
+             gimple stmt;
+
              if (access->grp_partial_lhs)
                repl = force_gimple_operand_gsi (gsi, repl, true, NULL_TREE,
                                                 true, GSI_SAME_STMT);
-             stmt = gimple_build_assign (unshare_expr (access->expr), repl);
+             stmt = gimple_build_assign (ref, repl);
              gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
            }
        }
@@ -2220,8 +2238,6 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
            }
          else
            {
-             bool repl_found;
-
              /* 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)
@@ -2229,10 +2245,20 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
                                                                  lhs, old_gsi);
 
              if (*refreshed == SRA_UDH_LEFT)
-               rhs = unshare_expr (lacc->expr);
+               {
+                 bool repl_found;
+
+                 rhs = lacc->base;
+                 repl_found = build_ref_for_offset (&rhs, TREE_TYPE (rhs),
+                                                    lacc->offset, lacc->type,
+                                                    false);
+                 gcc_assert (repl_found);
+               }
              else
                {
-                 rhs = unshare_expr (top_racc->base);
+                 bool repl_found;
+
+                 rhs = top_racc->base;
                  repl_found = build_ref_for_offset (&rhs,
                                                     TREE_TYPE (top_racc->base),
                                                     offset, lacc->type, false);
@@ -2369,7 +2395,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi,
          if (AGGREGATE_TYPE_P (TREE_TYPE (lhs))
              && !access_has_children_p (lacc))
            {
-             tree expr = unshare_expr (lhs);
+             tree expr = lhs;
              if (build_ref_for_offset (&expr, TREE_TYPE (lhs), 0,
                                        TREE_TYPE (rhs), false))
                {
@@ -2380,7 +2406,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi,
          else if (AGGREGATE_TYPE_P (TREE_TYPE (rhs))
                   && !access_has_children_p (racc))
            {
-             tree expr = unshare_expr (rhs);
+             tree expr = rhs;
              if (build_ref_for_offset (&expr, TREE_TYPE (rhs), 0,
                                        TREE_TYPE (lhs), false))
                rhs = expr;
@@ -2813,33 +2839,34 @@ analyze_modified_params (VEC (access_p, heap) *representatives)
 
   for (i = 0; i < func_param_count; i++)
     {
-      struct access *repr = VEC_index (access_p, representatives, i);
-      VEC (access_p, heap) *access_vec;
-      int j, access_count;
-      tree parm;
-
-      if (!repr || no_accesses_p (repr))
-       continue;
-      parm = repr->base;
-      if (!POINTER_TYPE_P (TREE_TYPE (parm))
-         || repr->grp_maybe_modified)
-       continue;
+      struct access *repr;
 
-      access_vec = get_base_access_vector (parm);
-      access_count = VEC_length (access_p, access_vec);
-      for (j = 0; j < access_count; j++)
+      for (repr = VEC_index (access_p, representatives, i);
+          repr;
+          repr = repr->next_grp)
        {
          struct access *access;
+         bitmap visited;
          ao_ref ar;
 
-         /* All accesses are read ones, otherwise grp_maybe_modified would be
-            trivially set.  */
-         access = VEC_index (access_p, access_vec, j);
-         ao_ref_init (&ar, access->expr);
-         walk_aliased_vdefs (&ar, gimple_vuse (access->stmt),
-                             mark_maybe_modified, repr, NULL);
-         if (repr->grp_maybe_modified)
-           break;
+         if (no_accesses_p (repr))
+           continue;
+         if (!POINTER_TYPE_P (TREE_TYPE (repr->base))
+             || repr->grp_maybe_modified)
+           continue;
+
+         ao_ref_init (&ar, repr->expr);
+         visited = BITMAP_ALLOC (NULL);
+         for (access = repr; access; access = access->next_sibling)
+           {
+             /* All accesses are read ones, otherwise grp_maybe_modified would
+                be trivially set.  */
+             walk_aliased_vdefs (&ar, gimple_vuse (access->stmt),
+                                 mark_maybe_modified, repr, &visited);
+             if (repr->grp_maybe_modified)
+               break;
+           }
+         BITMAP_FREE (visited);
        }
     }
 }
@@ -3008,26 +3035,53 @@ static struct access *
 unmodified_by_ref_scalar_representative (tree parm)
 {
   int i, access_count;
-  struct access *access;
+  struct access *repr;
   VEC (access_p, heap) *access_vec;
 
   access_vec = get_base_access_vector (parm);
   gcc_assert (access_vec);
-  access_count = VEC_length (access_p, access_vec);
+  repr = VEC_index (access_p, access_vec, 0);
+  if (repr->write)
+    return NULL;
+  repr->group_representative = repr;
 
-  for (i = 0; i < access_count; i++)
+  access_count = VEC_length (access_p, access_vec);
+  for (i = 1; i < access_count; i++)
     {
-      access = VEC_index (access_p, access_vec, i);
+      struct access *access = VEC_index (access_p, access_vec, i);
       if (access->write)
        return NULL;
+      access->group_representative = repr;
+      access->next_sibling = repr->next_sibling;
+      repr->next_sibling = access;
     }
 
-  access = VEC_index (access_p, access_vec, 0);
-  access->grp_read = 1;
-  access->grp_scalar_ptr = 1;
-  return access;
+  repr->grp_read = 1;
+  repr->grp_scalar_ptr = 1;
+  return repr;
+}
+
+/* Return true iff this access precludes IPA-SRA of the parameter it is
+   associated with. */
+
+static bool
+access_precludes_ipa_sra_p (struct access *access)
+{
+  /* Avoid issues such as the second simple testcase in PR 42025.  The problem
+     is incompatible assign in a call statement (and possibly even in asm
+     statements).  This can be relaxed by using a new temporary but only for
+     non-TREE_ADDRESSABLE types and is probably not worth the complexity. (In
+     intraprocedural SRA we deal with this by keeping the old aggregate around,
+     something we cannot do in IPA-SRA.)  */
+  if (access->write
+      && (is_gimple_call (access->stmt)
+         || gimple_code (access->stmt) == GIMPLE_ASM))
+    return true;
+
+  return false;
 }
 
+
 /* Sort collected accesses for parameter PARM, identify representatives for
    each accessed region and link them together.  Return NULL if there are
    different but overlapping accesses, return the special ptr value meaning
@@ -3059,6 +3113,8 @@ splice_param_accesses (tree parm, bool *ro_grp)
       bool modification;
       access = VEC_index (access_p, access_vec, i);
       modification = access->write;
+      if (access_precludes_ipa_sra_p (access))
+       return NULL;
 
       /* Access is about to become group representative unless we find some
         nasty overlap which would preclude us from breaking this parameter
@@ -3079,7 +3135,13 @@ splice_param_accesses (tree parm, bool *ro_grp)
          else if (ac2->size != access->size)
            return NULL;
 
+         if (access_precludes_ipa_sra_p (ac2))
+           return NULL;
+
          modification |= ac2->write;
+         ac2->group_representative = access;
+         ac2->next_sibling = access->next_sibling;
+         access->next_sibling = ac2;
          j++;
        }
 
@@ -3506,13 +3568,19 @@ replace_removed_params_ssa_names (gimple stmt, void *data)
   return true;
 }
 
-/* Callback for scan_function.  If the expression *EXPR should be replaced by a
-   reduction of a parameter, do so.  DATA is a pointer to a vector of
-   adjustments.  */
+/* Callback for scan_function and helper to sra_ipa_modify_assign.  If the
+   expression *EXPR should be replaced by a reduction of a parameter, do so.
+   DATA is a pointer to a vector of adjustments.  DONT_CONVERT specifies
+   whether the function should care about type incompatibility the current and
+   new expressions.  If it is true, the function will leave incompatibility
+   issues to the caller.
+
+   When called directly by scan_function, DONT_CONVERT is true when the EXPR is
+   a write (LHS) expression.  */
 
 static bool
 sra_ipa_modify_expr (tree *expr, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED,
-                    bool write ATTRIBUTE_UNUSED, void *data)
+                    bool dont_convert, void *data)
 {
   ipa_parm_adjustment_vec adjustments;
   int i, len;
@@ -3526,10 +3594,10 @@ sra_ipa_modify_expr (tree *expr, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED,
   if (TREE_CODE (*expr) == BIT_FIELD_REF
       || TREE_CODE (*expr) == IMAGPART_EXPR
       || TREE_CODE (*expr) == REALPART_EXPR)
-    expr = &TREE_OPERAND (*expr, 0);
-  while (TREE_CODE (*expr) == NOP_EXPR
-        || TREE_CODE (*expr) == VIEW_CONVERT_EXPR)
-    expr = &TREE_OPERAND (*expr, 0);
+    {
+      expr = &TREE_OPERAND (*expr, 0);
+      dont_convert = false;
+    }
 
   base = get_ref_base_and_extent (*expr, &offset, &size, &max_size);
   if (!base || size == -1 || max_size == -1)
@@ -3577,13 +3645,14 @@ sra_ipa_modify_expr (tree *expr, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED,
       fprintf (dump_file, "\n");
     }
 
-  if (!useless_type_conversion_p (TREE_TYPE (*expr), cand->type))
+  if (!dont_convert
+      && !useless_type_conversion_p (TREE_TYPE (*expr), cand->type))
     {
       tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*expr), src);
       *expr = vce;
     }
-    else
-      *expr = src;
+  else
+    *expr = src;
   return true;
 }
 
@@ -3591,20 +3660,37 @@ sra_ipa_modify_expr (tree *expr, gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED,
    essentially the same function like sra_ipa_modify_expr.  */
 
 static enum scan_assign_result
-sra_ipa_modify_assign (gimple *stmt_ptr,
-                      gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED, void *data)
+sra_ipa_modify_assign (gimple *stmt_ptr, gimple_stmt_iterator *gsi, void *data)
 {
   gimple stmt = *stmt_ptr;
-  bool any = false;
+  tree *lhs_p, *rhs_p;
+  bool any;
 
   if (!gimple_assign_single_p (stmt))
     return SRA_SA_NONE;
 
-  any |= sra_ipa_modify_expr (gimple_assign_rhs1_ptr (stmt), gsi, false,
-                             data);
-  any |= sra_ipa_modify_expr (gimple_assign_lhs_ptr (stmt), gsi, true, data);
+  rhs_p = gimple_assign_rhs1_ptr (stmt);
+  lhs_p = gimple_assign_lhs_ptr (stmt);
+
+  any = sra_ipa_modify_expr (rhs_p, gsi, true, data);
+  any |= sra_ipa_modify_expr (lhs_p, gsi, true, data);
+  if (any)
+    {
+      if (!useless_type_conversion_p (TREE_TYPE (*lhs_p), TREE_TYPE (*rhs_p)))
+       {
+         location_t loc = gimple_location (stmt);
+         tree vce = fold_build1_loc (loc, VIEW_CONVERT_EXPR,
+                                     TREE_TYPE (*lhs_p), *rhs_p);
+         tree tmp = force_gimple_operand_gsi (gsi, vce, true, NULL_TREE,
+                                              true, GSI_SAME_STMT);
+
+         gimple_assign_set_rhs_from_tree (gsi, tmp);
+       }
+
+      return SRA_SA_PROCESSED;
+    }
 
-  return any ? SRA_SA_PROCESSED : SRA_SA_NONE;
+  return SRA_SA_NONE;
 }
 
 /* Call gimple_debug_bind_reset_value on all debug statements describing