OSDN Git Service

2013-02-15 Vladimir Makarov <vmakarov@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-sra.c
index 88199f1..234dde2 100644 (file)
@@ -1,7 +1,7 @@
 /* Scalar Replacement of Aggregates (SRA) converts some structure
    references into scalar references, exposing them to the scalar
    optimizers.
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008-2013 Free Software Foundation, Inc.
    Contributed by Martin Jambor <mjambor@suse.cz>
 
 This file is part of GCC.
@@ -76,22 +76,20 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "alloc-pool.h"
 #include "tm.h"
-#include "toplev.h"
 #include "tree.h"
 #include "gimple.h"
 #include "cgraph.h"
 #include "tree-flow.h"
+#include "tree-pass.h"
 #include "ipa-prop.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"
 #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 */
@@ -170,9 +168,8 @@ struct access
   /* Is this particular access write access? */
   unsigned write : 1;
 
-  /* Is this access an artificial one created to scalarize some record
-     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;
@@ -193,6 +190,18 @@ 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;
+
+  /* Is this access an artificial one created to scalarize some record
+     entirely? */
+  unsigned grp_total_scalarization : 1;
+
   /* Other passes of the analysis use this bit to make function
      analyze_access_subtree create scalar replacements for this group if
      possible.  */
@@ -215,11 +224,13 @@ struct access
      BIT_FIELD_REF?  */
   unsigned grp_partial_lhs : 1;
 
-  /* Set when a scalar replacement should be created for this variable.  We do
-     the decision and creation at different places because create_tmp_var
-     cannot be called from within FOR_EACH_REFERENCED_VAR. */
+  /* Set when a scalar replacement should be created for this variable.  */
   unsigned grp_to_be_replaced : 1;
 
+  /* Set when we want a replacement for the sole purpose of having it in
+     generated debug statements.  */
+  unsigned grp_to_be_debug_replaced : 1;
+
   /* Should TREE_NO_WARNING of a replacement be set?  */
   unsigned grp_no_warning : 1;
 
@@ -239,8 +250,6 @@ struct access
 
 typedef struct access *access_p;
 
-DEF_VEC_P (access_p);
-DEF_VEC_ALLOC_P (access_p, heap);
 
 /* Alloc pool for allocating access structures.  */
 static alloc_pool access_pool;
@@ -257,11 +266,22 @@ struct assign_link
 /* Alloc pool for allocating assign link structures.  */
 static alloc_pool link_pool;
 
-/* Base (tree) -> Vector (VEC(access_p,heap) *) map.  */
+/* Base (tree) -> Vector (vec<access_p> *) map.  */
 static struct pointer_map_t *base_access_vec;
 
-/* Bitmap of candidates.  */
+/* Set of candidates.  */
 static bitmap candidate_bitmap;
+static htab_t candidates;
+
+/* For a candidate UID return the candidates decl.  */
+
+static inline tree
+candidate (unsigned uid)
+{
+ struct tree_decl_minimal t;
+ t.uid = uid;
+ return (tree) htab_find_with_hash (candidates, &t, uid);
+}
 
 /* Bitmap of candidates which we should try to entirely scalarize away and
    those which cannot be (because they are and need be used as a whole).  */
@@ -366,24 +386,26 @@ 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, ", grp_read = %d, grp_write = %d, grp_assignment_read = %d, "
+            "grp_assignment_write = %d, grp_scalar_read = %d, "
+            "grp_scalar_write = %d, grp_total_scalarization = %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_to_be_debug_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->grp_read, access->grp_write, access->grp_assignment_read,
+            access->grp_assignment_write, access->grp_scalar_read,
+            access->grp_scalar_write, access->grp_total_scalarization,
+            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,
+            access->grp_to_be_debug_replaced, access->grp_maybe_modified,
             access->grp_not_necessarilly_dereferenced);
   else
-    fprintf (f, ", write = %d, total_scalarization = %d, "
+    fprintf (f, ", write = %d, grp_total_scalarization = %d, "
             "grp_partial_lhs = %d\n",
-            access->write, access->total_scalarization,
+            access->write, access->grp_total_scalarization,
             access->grp_partial_lhs);
 }
 
@@ -427,10 +449,24 @@ access_has_children_p (struct access *acc)
   return acc && acc->first_child;
 }
 
+/* Return true iff ACC is (partly) covered by at least one replacement.  */
+
+static bool
+access_has_replacements_p (struct access *acc)
+{
+  struct access *child;
+  if (acc->grp_to_be_replaced)
+    return true;
+  for (child = acc->first_child; child; child = child->next_sibling)
+    if (access_has_replacements_p (child))
+      return true;
+  return false;
+}
+
 /* Return a vector of pointers to accesses for the variable given in BASE or
    NULL if there is none.  */
 
-static VEC (access_p, heap) *
+static vec<access_p> *
 get_base_access_vector (tree base)
 {
   void **slot;
@@ -439,7 +475,7 @@ get_base_access_vector (tree base)
   if (!slot)
     return NULL;
   else
-    return *(VEC (access_p, heap) **) slot;
+    return *(vec<access_p> **) slot;
 }
 
 /* Find an access with required OFFSET and SIZE in a subtree of accesses rooted
@@ -466,13 +502,13 @@ find_access_in_subtree (struct access *access, HOST_WIDE_INT offset,
 static struct access *
 get_first_repr_for_decl (tree base)
 {
-  VEC (access_p, heap) *access_vec;
+  vec<access_p> *access_vec;
 
   access_vec = get_base_access_vector (base);
   if (!access_vec)
     return NULL;
 
-  return VEC_index (access_p, access_vec, 0);
+  return (*access_vec)[0];
 }
 
 /* Find an access representative for the variable BASE and given OFFSET and
@@ -575,6 +611,8 @@ static void
 sra_initialize (void)
 {
   candidate_bitmap = BITMAP_ALLOC (NULL);
+  candidates = htab_create (vec_safe_length (cfun->local_decls) / 2,
+                           uid_decl_map_hash, uid_decl_map_eq, NULL);
   should_scalarize_away_bitmap = BITMAP_ALLOC (NULL);
   cannot_scalarize_away_bitmap = BITMAP_ALLOC (NULL);
   gcc_obstack_init (&name_obstack);
@@ -593,10 +631,8 @@ static bool
 delete_base_accesses (const void *key ATTRIBUTE_UNUSED, void **value,
                     void *data ATTRIBUTE_UNUSED)
 {
-  VEC (access_p, heap) *access_vec;
-  access_vec = (VEC (access_p, heap) *) *value;
-  VEC_free (access_p, heap, access_vec);
-
+  vec<access_p> *access_vec = (vec<access_p> *) *value;
+  vec_free (access_vec);
   return true;
 }
 
@@ -606,6 +642,7 @@ static void
 sra_deinitialize (void)
 {
   BITMAP_FREE (candidate_bitmap);
+  htab_delete (candidates);
   BITMAP_FREE (should_scalarize_away_bitmap);
   BITMAP_FREE (cannot_scalarize_away_bitmap);
   free_alloc_pool (access_pool);
@@ -621,7 +658,10 @@ sra_deinitialize (void)
 static void
 disqualify_candidate (tree decl, const char *reason)
 {
-  bitmap_clear_bit (candidate_bitmap, DECL_UID (decl));
+  if (bitmap_clear_bit (candidate_bitmap, DECL_UID (decl)))
+    htab_clear_slot (candidates,
+                    htab_find_slot_with_hash (candidates, decl,
+                                              DECL_UID (decl), NO_INSERT));
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -635,7 +675,7 @@ disqualify_candidate (tree decl, const char *reason)
    scalarization.  */
 
 static bool
-type_internals_preclude_sra_p (tree type)
+type_internals_preclude_sra_p (tree type, const char **msg)
 {
   tree fld;
   tree et;
@@ -650,15 +690,44 @@ type_internals_preclude_sra_p (tree type)
          {
            tree ft = TREE_TYPE (fld);
 
-           if (TREE_THIS_VOLATILE (fld)
-               || !DECL_FIELD_OFFSET (fld) || !DECL_SIZE (fld)
-               || !host_integerp (DECL_FIELD_OFFSET (fld), 1)
-               || !host_integerp (DECL_SIZE (fld), 1)
-               || (DECL_BIT_FIELD (fld) && AGGREGATE_TYPE_P (ft)))
-             return true;
-
+           if (TREE_THIS_VOLATILE (fld))
+             {
+               *msg = "volatile structure field";
+               return true;
+             }
+           if (!DECL_FIELD_OFFSET (fld))
+             {
+               *msg = "no structure field offset";
+               return true;
+             }
+           if (!DECL_SIZE (fld))
+             {
+               *msg = "zero structure field size";
+               return true;
+             }
+           if (!host_integerp (DECL_FIELD_OFFSET (fld), 1))
+             {
+               *msg = "structure field offset not fixed";
+               return true;
+             }
+           if (!host_integerp (DECL_SIZE (fld), 1))
+             {
+               *msg = "structure field size not fixed";
+               return true;
+             }
+           if (!host_integerp (bit_position (fld), 0))
+             {
+               *msg = "structure field size too big";
+               return true;
+             }
            if (AGGREGATE_TYPE_P (ft)
-               && type_internals_preclude_sra_p (ft))
+                   && int_bit_position (fld) % BITS_PER_UNIT != 0)
+             {
+               *msg = "structure field is bit field";
+               return true;
+             }
+
+           if (AGGREGATE_TYPE_P (ft) && type_internals_preclude_sra_p (ft, msg))
              return true;
          }
 
@@ -667,10 +736,16 @@ type_internals_preclude_sra_p (tree type)
     case ARRAY_TYPE:
       et = TREE_TYPE (type);
 
-      if (AGGREGATE_TYPE_P (et))
-       return type_internals_preclude_sra_p (et);
-      else
-       return false;
+      if (TYPE_VOLATILE (et))
+       {
+         *msg = "element type is volatile";
+         return true;
+       }
+
+      if (AGGREGATE_TYPE_P (et) && type_internals_preclude_sra_p (et, msg))
+       return true;
+
+      return false;
 
     default:
       return false;
@@ -726,7 +801,7 @@ mark_parm_dereference (tree base, HOST_WIDE_INT dist, gimple stmt)
 static struct access *
 create_access_1 (tree base, HOST_WIDE_INT offset, HOST_WIDE_INT size)
 {
-  VEC (access_p, heap) *vec;
+  vec<access_p> *v;
   struct access *access;
   void **slot;
 
@@ -738,14 +813,14 @@ create_access_1 (tree base, HOST_WIDE_INT offset, HOST_WIDE_INT size)
 
   slot = pointer_map_contains (base_access_vec, base);
   if (slot)
-    vec = (VEC (access_p, heap) *) *slot;
+    v = (vec<access_p> *) *slot;
   else
-    vec = VEC_alloc (access_p, heap, 32);
+    vec_alloc (v, 32);
 
-  VEC_safe_push (access_p, heap, vec, access);
+  v->safe_push (access);
 
-  *((struct VEC (access_p,heap) **)
-       pointer_map_insert (base_access_vec, base)) = vec;
+  *((vec<access_p> **)
+       pointer_map_insert (base_access_vec, base)) = v;
 
   return access;
 }
@@ -816,6 +891,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;
 }
 
@@ -877,7 +956,7 @@ completely_scalarize_record (tree base, tree decl, HOST_WIDE_INT offset,
            access = create_access_1 (base, pos, size);
            access->expr = nref;
            access->type = ft;
-           access->total_scalarization = 1;
+           access->grp_total_scalarization = 1;
            /* Accesses for intraprocedural SRA can have their stmt NULL.  */
          }
        else
@@ -885,6 +964,23 @@ completely_scalarize_record (tree base, tree decl, HOST_WIDE_INT offset,
       }
 }
 
+/* Create total_scalarization accesses for all scalar type fields in VAR and
+   for VAR a a whole.  VAR must be of a RECORD_TYPE conforming to
+   type_consists_of_records_p.   */
+
+static void
+completely_scalarize_var (tree var)
+{
+  HOST_WIDE_INT size = tree_low_cst (DECL_SIZE (var), 1);
+  struct access *access;
+
+  access = create_access_1 (var, 0, size);
+  access->expr = var;
+  access->type = TREE_TYPE (var);
+  access->grp_total_scalarization = 1;
+
+  completely_scalarize_record (var, var, 0, var);
+}
 
 /* Search the given tree for a declaration by skipping handled components and
    exclude it from the candidates.  */
@@ -1003,7 +1099,7 @@ disqualify_ops_if_throwing_stmt (gimple stmt, tree lhs, tree rhs)
   return false;
 }
 
-/* Scan expressions occuring in STMT, create access structures for all accesses
+/* Scan expressions occurring in STMT, create access structures for all accesses
    to candidates for scalarization and remove those candidates which occur in
    statements or expressions that prevent them from being split apart.  Return
    true if any access has been inserted.  */
@@ -1014,7 +1110,9 @@ build_accesses_from_assign (gimple stmt)
   tree lhs, rhs;
   struct access *lacc, *racc;
 
-  if (!gimple_assign_single_p (stmt))
+  if (!gimple_assign_single_p (stmt)
+      /* Scope clobbers don't influence scalarization.  */
+      || gimple_clobber_p (stmt))
     return false;
 
   lhs = gimple_assign_lhs (stmt);
@@ -1042,8 +1140,6 @@ build_accesses_from_assign (gimple stmt)
       && !lacc->grp_unscalarizable_region
       && !racc->grp_unscalarizable_region
       && AGGREGATE_TYPE_P (TREE_TYPE (lhs))
-      /* FIXME: Turn the following line into an assert after PR 40058 is
-        fixed.  */
       && lacc->size == racc->size
       && useless_type_conversion_p (lacc->type, racc->type))
     {
@@ -1332,7 +1428,10 @@ make_fancy_name (tree expr)
    EXP_TYPE at the given OFFSET.  If BASE is something for which
    get_addr_base_and_unit_offset returns NULL, gsi must be non-NULL and is used
    to insert new statements either before or below the current one as specified
-   by INSERT_AFTER.  This function is not capable of handling bitfields.  */
+   by INSERT_AFTER.  This function is not capable of handling bitfields.
+
+   BASE must be either a declaration or a memory reference that has correct
+   alignment ifformation embeded in it (e.g. a pre-existing one in SRA).  */
 
 tree
 build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
@@ -1342,9 +1441,11 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
   tree prev_base = base;
   tree off;
   HOST_WIDE_INT base_offset;
+  unsigned HOST_WIDE_INT misalign;
+  unsigned int align;
 
   gcc_checking_assert (offset % BITS_PER_UNIT == 0);
-
+  get_object_alignment_1 (base, &align, &misalign);
   base = get_addr_base_and_unit_offset (base, &base_offset);
 
   /* get_addr_base_and_unit_offset returns NULL for references with a variable
@@ -1355,18 +1456,15 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
       tree tmp, addr;
 
       gcc_checking_assert (gsi);
-      tmp = create_tmp_reg (build_pointer_type (TREE_TYPE (prev_base)), NULL);
-      add_referenced_var (tmp);
-      tmp = make_ssa_name (tmp, NULL);
+      tmp = make_ssa_name (build_pointer_type (TREE_TYPE (prev_base)), 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;
       if (insert_after)
        gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
       else
        gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
-      update_stmt (stmt);
 
       off = build_int_cst (reference_alias_ptr_type (prev_base),
                           offset / BITS_PER_UNIT);
@@ -1376,7 +1474,7 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
     {
       off = build_int_cst (TREE_TYPE (TREE_OPERAND (base, 1)),
                           base_offset + offset / BITS_PER_UNIT);
-      off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), off, 0);
+      off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), off);
       base = unshare_expr (TREE_OPERAND (base, 0));
     }
   else
@@ -1386,12 +1484,18 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
       base = build_fold_addr_expr (unshare_expr (base));
     }
 
+  misalign = (misalign + offset) & (align - 1);
+  if (misalign != 0)
+    align = (misalign & -misalign);
+  if (align < TYPE_ALIGN (exp_type))
+    exp_type = build_aligned_type (exp_type, align);
+
   return fold_build2_loc (loc, MEM_REF, exp_type, base, off);
 }
 
 /* Construct a memory reference to a part of an aggregate BASE at the given
    OFFSET and of the same type as MODEL.  In case this is a reference to a
-   component, the function will replicate the last COMPONENT_REF of model's
+   bit-field, the function will replicate the last component_ref of model's
    expr to access it.  GSI and INSERT_AFTER have the same meaning as in
    build_ref_for_offset.  */
 
@@ -1400,20 +1504,60 @@ build_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset,
                     struct access *model, gimple_stmt_iterator *gsi,
                     bool insert_after)
 {
-  if (TREE_CODE (model->expr) == COMPONENT_REF)
+  if (TREE_CODE (model->expr) == COMPONENT_REF
+      && DECL_BIT_FIELD (TREE_OPERAND (model->expr, 1)))
     {
-      tree t, exp_type;
-      offset -= int_bit_position (TREE_OPERAND (model->expr, 1));
+      /* This access represents a bit-field.  */
+      tree t, exp_type, fld = TREE_OPERAND (model->expr, 1);
+
+      offset -= int_bit_position (fld);
       exp_type = TREE_TYPE (TREE_OPERAND (model->expr, 0));
       t = build_ref_for_offset (loc, base, offset, exp_type, gsi, insert_after);
-      return fold_build3_loc (loc, COMPONENT_REF, model->type, t,
-                             TREE_OPERAND (model->expr, 1), NULL_TREE);
+      return fold_build3_loc (loc, COMPONENT_REF, TREE_TYPE (fld), t, fld,
+                             NULL_TREE);
     }
   else
     return build_ref_for_offset (loc, base, offset, model->type,
                                 gsi, insert_after);
 }
 
+/* Attempt to build a memory reference that we could but into a gimple
+   debug_bind statement.  Similar to build_ref_for_model but punts if it has to
+   create statements and return s NULL instead.  This function also ignores
+   alignment issues and so its results should never end up in non-debug
+   statements.  */
+
+static tree
+build_debug_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset,
+                          struct access *model)
+{
+  HOST_WIDE_INT base_offset;
+  tree off;
+
+  if (TREE_CODE (model->expr) == COMPONENT_REF
+      && DECL_BIT_FIELD (TREE_OPERAND (model->expr, 1)))
+    return NULL_TREE;
+
+  base = get_addr_base_and_unit_offset (base, &base_offset);
+  if (!base)
+    return NULL_TREE;
+  if (TREE_CODE (base) == MEM_REF)
+    {
+      off = build_int_cst (TREE_TYPE (TREE_OPERAND (base, 1)),
+                          base_offset + offset / BITS_PER_UNIT);
+      off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), off);
+      base = unshare_expr (TREE_OPERAND (base, 0));
+    }
+  else
+    {
+      off = build_int_cst (reference_alias_ptr_type (base),
+                          base_offset + offset / BITS_PER_UNIT);
+      base = build_fold_addr_expr (unshare_expr (base));
+    }
+
+  return fold_build2_loc (loc, MEM_REF, model->type, base, off);
+}
+
 /* Construct a memory reference consisting of component_refs and array_refs to
    a part of an aggregate *RES (which is of type TYPE).  The requested part
    should have type EXP_TYPE at be the given OFFSET.  This function might not
@@ -1444,17 +1588,20 @@ build_user_friendly_ref_for_offset (tree *res, tree type, HOST_WIDE_INT offset,
          for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
            {
              HOST_WIDE_INT pos, size;
-             tree expr, *expr_ptr;
+             tree tr_pos, expr, *expr_ptr;
 
              if (TREE_CODE (fld) != FIELD_DECL)
                continue;
 
-             pos = int_bit_position (fld);
+             tr_pos = bit_position (fld);
+             if (!tr_pos || !host_integerp (tr_pos, 1))
+               continue;
+             pos = TREE_INT_CST_LOW (tr_pos);
              gcc_assert (TREE_CODE (type) == RECORD_TYPE || pos == 0);
              tr_size = DECL_SIZE (fld);
              if (!tr_size || !host_integerp (tr_size, 1))
                continue;
-             size = tree_low_cst (tr_size, 1);
+             size = TREE_INT_CST_LOW (tr_size);
              if (size == 0)
                {
                  if (pos != offset)
@@ -1486,7 +1633,7 @@ build_user_friendly_ref_for_offset (tree *res, tree type, HOST_WIDE_INT offset,
            return false;
          index = build_int_cst (TYPE_DOMAIN (type), offset / el_size);
          if (!integer_zerop (minidx))
-           index = int_const_binop (PLUS_EXPR, index, minidx, 0);
+           index = int_const_binop (PLUS_EXPR, index, minidx);
          *res = build4 (ARRAY_REF, TREE_TYPE (type), *res, index,
                         NULL_TREE, NULL_TREE);
          offset = offset % el_size;
@@ -1513,45 +1660,108 @@ is_va_list_type (tree type)
   return TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (va_list_type_node);
 }
 
+/* Print message to dump file why a variable was rejected. */
+
+static void
+reject (tree var, const char *msg)
+{
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Rejected (%d): %s: ", DECL_UID (var), msg);
+      print_generic_expr (dump_file, var, 0);
+      fprintf (dump_file, "\n");
+    }
+}
+
+/* Return true if VAR is a candidate for SRA.  */
+
+static bool
+maybe_add_sra_candidate (tree var)
+{
+  tree type = TREE_TYPE (var);
+  const char *msg;
+  void **slot;
+
+  if (!AGGREGATE_TYPE_P (type)) 
+    {
+      reject (var, "not aggregate");
+      return false;
+    }
+  if (needs_to_live_in_memory (var))
+    {
+      reject (var, "needs to live in memory");
+      return false;
+    }
+  if (TREE_THIS_VOLATILE (var))
+    {
+      reject (var, "is volatile");
+      return false;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      reject (var, "has incomplete type");
+      return false;
+    }
+  if (!host_integerp (TYPE_SIZE (type), 1))
+    {
+      reject (var, "type size not fixed");
+      return false;
+    }
+  if (tree_low_cst (TYPE_SIZE (type), 1) == 0)
+    {
+      reject (var, "type size is zero");
+      return false;
+    }
+  if (type_internals_preclude_sra_p (type, &msg))
+    {
+      reject (var, msg);
+      return false;
+    }
+  if (/* Fix for PR 41089.  tree-stdarg.c needs to have va_lists intact but
+        we also want to schedule it rather late.  Thus we ignore it in
+        the early pass. */
+      (sra_mode == SRA_MODE_EARLY_INTRA
+       && is_va_list_type (type)))
+    {
+      reject (var, "is va_list");
+      return false;
+    }
+
+  bitmap_set_bit (candidate_bitmap, DECL_UID (var));
+  slot = htab_find_slot_with_hash (candidates, var, DECL_UID (var), INSERT);
+  *slot = (void *) var;
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Candidate (%d): ", DECL_UID (var));
+      print_generic_expr (dump_file, var, 0);
+      fprintf (dump_file, "\n");
+    }
+
+  return true;
+}
+
 /* The very first phase of intraprocedural SRA.  It marks in candidate_bitmap
    those with type which is suitable for scalarization.  */
 
 static bool
 find_var_candidates (void)
 {
-  tree var, type;
-  referenced_var_iterator rvi;
+  tree var, parm;
+  unsigned int i;
   bool ret = false;
 
-  FOR_EACH_REFERENCED_VAR (var, rvi)
+  for (parm = DECL_ARGUMENTS (current_function_decl);
+       parm;
+       parm = DECL_CHAIN (parm))
+    ret |= maybe_add_sra_candidate (parm);
+
+  FOR_EACH_LOCAL_DECL (cfun, i, var)
     {
-      if (TREE_CODE (var) != VAR_DECL && TREE_CODE (var) != PARM_DECL)
+      if (TREE_CODE (var) != VAR_DECL)
         continue;
-      type = TREE_TYPE (var);
-
-      if (!AGGREGATE_TYPE_P (type)
-         || needs_to_live_in_memory (var)
-         || TREE_THIS_VOLATILE (var)
-         || !COMPLETE_TYPE_P (type)
-         || !host_integerp (TYPE_SIZE (type), 1)
-          || tree_low_cst (TYPE_SIZE (type), 1) == 0
-         || type_internals_preclude_sra_p (type)
-         /* Fix for PR 41089.  tree-stdarg.c needs to have va_lists intact but
-             we also want to schedule it rather late.  Thus we ignore it in
-             the early pass. */
-         || (sra_mode == SRA_MODE_EARLY_INTRA
-             && is_va_list_type (type)))
-       continue;
-
-      bitmap_set_bit (candidate_bitmap, DECL_UID (var));
 
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "Candidate (%d): ", DECL_UID (var));
-         print_generic_expr (dump_file, var, 0);
-         fprintf (dump_file, "\n");
-       }
-      ret = true;
+      ret |= maybe_add_sra_candidate (var);
     }
 
   return ret;
@@ -1568,28 +1778,32 @@ sort_and_splice_var_accesses (tree var)
 {
   int i, j, access_count;
   struct access *res, **prev_acc_ptr = &res;
-  VEC (access_p, heap) *access_vec;
+  vec<access_p> *access_vec;
   bool first = true;
   HOST_WIDE_INT low = -1, high = 0;
 
   access_vec = get_base_access_vector (var);
   if (!access_vec)
     return NULL;
-  access_count = VEC_length (access_p, access_vec);
+  access_count = access_vec->length ();
 
   /* Sort by <OFFSET, SIZE>.  */
-  VEC_qsort (access_p, access_vec, compare_access_positions);
+  access_vec->qsort (compare_access_positions);
 
   i = 0;
   while (i < access_count)
     {
-      struct access *access = VEC_index (access_p, access_vec, i);
+      struct access *access = (*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 total_scalarization = access->total_scalarization;
+      bool multiple_scalar_reads = false;
+      bool total_scalarization = access->grp_total_scalarization;
       bool grp_partial_lhs = access->grp_partial_lhs;
       bool first_scalar = is_gimple_reg_type (access->type);
       bool unscalarizable_region = access->grp_unscalarizable_region;
@@ -1609,23 +1823,31 @@ sort_and_splice_var_accesses (tree var)
       j = i + 1;
       while (j < access_count)
        {
-         struct access *ac2 = VEC_index (access_p, access_vec, j);
+         struct access *ac2 = (*access_vec)[j];
          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;
          grp_partial_lhs |= ac2->grp_partial_lhs;
          unscalarizable_region |= ac2->grp_unscalarizable_region;
-         total_scalarization |= ac2->total_scalarization;
+         total_scalarization |= ac2->grp_total_scalarization;
          relink_to_new_repr (access, ac2);
 
          /* If there are both aggregate-type and scalar-type accesses with
@@ -1641,9 +1863,12 @@ 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_total_scalarization = total_scalarization;
       access->grp_partial_lhs = grp_partial_lhs;
       access->grp_unscalarizable_region = unscalarizable_region;
       if (access->first_link)
@@ -1653,7 +1878,7 @@ sort_and_splice_var_accesses (tree var)
       prev_acc_ptr = &access->next_grp;
     }
 
-  gcc_assert (res == VEC_index (access_p, access_vec, 0));
+  gcc_assert (res == (*access_vec)[0]);
   return res;
 }
 
@@ -1662,20 +1887,26 @@ sort_and_splice_var_accesses (tree var)
    ACCESS->replacement.  */
 
 static tree
-create_access_replacement (struct access *access, bool rename)
+create_access_replacement (struct access *access)
 {
   tree repl;
 
-  repl = create_tmp_var (access->type, "SR");
-  get_var_ann (repl);
-  add_referenced_var (repl);
-  if (rename)
-    mark_sym_for_renaming (repl);
-
-  if (!access->grp_partial_lhs
-      && (TREE_CODE (access->type) == COMPLEX_TYPE
-         || TREE_CODE (access->type) == VECTOR_TYPE))
-    DECL_GIMPLE_REG_P (repl) = 1;
+  if (access->grp_to_be_debug_replaced)
+    {
+      repl = create_tmp_var_raw (access->type, NULL);
+      DECL_CONTEXT (repl) = current_function_decl;
+    }
+  else
+    repl = create_tmp_var (access->type, "SR");
+  if (TREE_CODE (access->type) == COMPLEX_TYPE
+      || TREE_CODE (access->type) == VECTOR_TYPE)
+    {
+      if (!access->grp_partial_lhs)
+       DECL_GIMPLE_REG_P (repl) = 1;
+    }
+  else if (access->grp_partial_lhs
+          && is_gimple_reg_type (access->type))
+    TREE_ADDRESSABLE (repl) = 1;
 
   DECL_SOURCE_LOCATION (repl) = DECL_SOURCE_LOCATION (access->base);
   DECL_ARTIFICIAL (repl) = 1;
@@ -1687,6 +1918,7 @@ create_access_replacement (struct access *access, bool rename)
     {
       char *pretty_name = make_fancy_name (access->expr);
       tree debug_expr = unshare_expr (access->expr), d;
+      bool fail = false;
 
       DECL_NAME (repl) = get_identifier (pretty_name);
       obstack_free (&name_obstack, pretty_name);
@@ -1696,29 +1928,41 @@ create_access_replacement (struct access *access, bool rename)
         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))
+        expression.  It cannot handle accesses at a non-constant offset
+        though, so just give up in those cases.  */
+      for (d = debug_expr;
+          !fail && (handled_component_p (d) || TREE_CODE (d) == MEM_REF);
+          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));
+               && TREE_CODE (TREE_OPERAND (d, 1)) != INTEGER_CST)
+             fail = true;
            if (TREE_OPERAND (d, 3)
-               && TREE_CODE (TREE_OPERAND (d, 3)) == SSA_NAME)
-             TREE_OPERAND (d, 3) = SSA_NAME_VAR (TREE_OPERAND (d, 3));
+               && TREE_CODE (TREE_OPERAND (d, 3)) != INTEGER_CST)
+             fail = true;
            /* 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));
+               && TREE_CODE (TREE_OPERAND (d, 2)) != INTEGER_CST)
+             fail = true;
+           break;
+         case MEM_REF:
+           if (TREE_CODE (TREE_OPERAND (d, 0)) != ADDR_EXPR)
+             fail = true;
+           else
+             d = TREE_OPERAND (d, 0);
            break;
          default:
            break;
          }
-      SET_DECL_DEBUG_EXPR (repl, debug_expr);
-      DECL_DEBUG_EXPR_IS_FROM (repl) = 1;
+      if (!fail)
+       {
+         SET_DECL_DEBUG_EXPR (repl, debug_expr);
+         DECL_DEBUG_EXPR_IS_FROM (repl) = 1;
+       }
       if (access->grp_no_warning)
        TREE_NO_WARNING (repl) = 1;
       else
@@ -1729,12 +1973,22 @@ create_access_replacement (struct access *access, bool rename)
 
   if (dump_file)
     {
-      fprintf (dump_file, "Created a replacement for ");
-      print_generic_expr (dump_file, access->base, 0);
-      fprintf (dump_file, " offset: %u, size: %u: ",
-              (unsigned) access->offset, (unsigned) access->size);
-      print_generic_expr (dump_file, repl, 0);
-      fprintf (dump_file, "\n");
+      if (access->grp_to_be_debug_replaced)
+       {
+         fprintf (dump_file, "Created a debug-only replacement for ");
+         print_generic_expr (dump_file, access->base, 0);
+         fprintf (dump_file, " offset: %u, size: %u\n",
+                  (unsigned) access->offset, (unsigned) access->size);
+       }
+      else
+       {
+         fprintf (dump_file, "Created a replacement for ");
+         print_generic_expr (dump_file, access->base, 0);
+         fprintf (dump_file, " offset: %u, size: %u: ",
+                  (unsigned) access->offset, (unsigned) access->size);
+         print_generic_expr (dump_file, repl, 0);
+         fprintf (dump_file, "\n");
+       }
     }
   sra_stats.replacements++;
 
@@ -1746,23 +2000,8 @@ create_access_replacement (struct access *access, bool rename)
 static inline tree
 get_access_replacement (struct access *access)
 {
-  gcc_assert (access->grp_to_be_replaced);
-
-  if (!access->replacement_decl)
-    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);
+    access->replacement_decl = create_access_replacement (access);
   return access->replacement_decl;
 }
 
@@ -1831,8 +2070,6 @@ expr_with_var_bounded_array_refs_p (tree expr)
   return false;
 }
 
-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
@@ -1844,13 +2081,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
 -----------------------------------------------------------------------------
@@ -1872,41 +2109,28 @@ enum mark_rw_status { SRA_MRRW_NOTHING, SRA_MRRW_DIRECT, SRA_MRRW_ASSIGN};
    1   1       1       1       Yes             Any of the above yeses  */
 
 static bool
-analyze_access_subtree (struct access *root, bool allow_replacements,
-                       enum mark_rw_status mark_read,
-                       enum mark_rw_status mark_write)
+analyze_access_subtree (struct access *root, struct access *parent,
+                       bool allow_replacements)
 {
   struct access *child;
   HOST_WIDE_INT limit = root->offset + root->size;
   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;
-  else if (mark_read == SRA_MRRW_ASSIGN)
-    {
-      root->grp_read = 1;
-      root->grp_assignment_read = 1;
-    }
-  else if (mark_read == SRA_MRRW_DIRECT)
-    root->grp_read = 1;
-  else if (root->grp_read)
-    mark_read = SRA_MRRW_DIRECT;
 
-  if (root->grp_assignment_write)
-    mark_write = SRA_MRRW_ASSIGN;
-  else if (mark_write == SRA_MRRW_ASSIGN)
+  if (parent)
     {
-      root->grp_write = 1;
-      root->grp_assignment_write = 1;
+      if (parent->grp_read)
+       root->grp_read = 1;
+      if (parent->grp_assignment_read)
+       root->grp_assignment_read = 1;
+      if (parent->grp_write)
+       root->grp_write = 1;
+      if (parent->grp_assignment_write)
+       root->grp_assignment_write = 1;
+      if (parent->grp_total_scalarization)
+       root->grp_total_scalarization = 1;
     }
-  else if (mark_write == SRA_MRRW_DIRECT)
-    root->grp_write = 1;
-  else if (root->grp_write)
-    mark_write = SRA_MRRW_DIRECT;
 
   if (root->grp_unscalarizable_region)
     allow_replacements = false;
@@ -1916,50 +2140,98 @@ analyze_access_subtree (struct access *root, bool allow_replacements,
 
   for (child = root->first_child; child; child = child->next_sibling)
     {
-      if (!hole && child->offset < covered_to)
-       hole = true;
-      else
-       covered_to += child->size;
-
-      sth_created |= analyze_access_subtree (child,
-                                            allow_replacements && !scalar,
-                                            mark_read, mark_write);
+      hole |= covered_to < child->offset;
+      sth_created |= analyze_access_subtree (child, root,
+                                            allow_replacements && !scalar);
 
       root->grp_unscalarized_data |= child->grp_unscalarized_data;
-      hole |= !child->grp_covered;
+      root->grp_total_scalarization &= child->grp_total_scalarization;
+      if (child->grp_covered)
+       covered_to += child->size;
+      else
+       hole = true;
     }
 
   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))))
     {
+      bool new_integer_type;
+      /* Always create access replacements that cover the whole access.
+         For integral types this means the precision has to match.
+        Avoid assumptions based on the integral type kind, too.  */
+      if (INTEGRAL_TYPE_P (root->type)
+         && (TREE_CODE (root->type) != INTEGER_TYPE
+             || TYPE_PRECISION (root->type) != root->size)
+         /* But leave bitfield accesses alone.  */
+         && (TREE_CODE (root->expr) != COMPONENT_REF
+             || !DECL_BIT_FIELD (TREE_OPERAND (root->expr, 1))))
+       {
+         tree rt = root->type;
+         gcc_assert ((root->offset % BITS_PER_UNIT) == 0
+                     && (root->size % BITS_PER_UNIT) == 0);
+         root->type = build_nonstandard_integer_type (root->size,
+                                                      TYPE_UNSIGNED (rt));
+         root->expr = build_ref_for_offset (UNKNOWN_LOCATION,
+                                            root->base, root->offset,
+                                            root->type, NULL, false);
+         new_integer_type = true;
+       }
+      else
+       new_integer_type = false;
+
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
          fprintf (dump_file, "Marking ");
          print_generic_expr (dump_file, root->base, 0);
-         fprintf (dump_file, " offset: %u, size: %u: ",
+         fprintf (dump_file, " offset: %u, size: %u ",
                   (unsigned) root->offset, (unsigned) root->size);
-         fprintf (dump_file, " to be replaced.\n");
+         fprintf (dump_file, " to be replaced%s.\n",
+                  new_integer_type ? " with an integer": "");
        }
 
       root->grp_to_be_replaced = 1;
       sth_created = true;
       hole = false;
     }
-  else if (covered_to < limit)
-    hole = true;
-
-  if (sth_created && !hole)
+  else
     {
-      root->grp_covered = 1;
-      return true;
+      if (allow_replacements
+         && scalar && !root->first_child
+         && (root->grp_scalar_write || root->grp_assignment_write)
+         && !bitmap_bit_p (cannot_scalarize_away_bitmap,
+                           DECL_UID (root->base)))
+       {
+         gcc_checking_assert (!root->grp_scalar_read
+                              && !root->grp_assignment_read);
+         sth_created = true;
+         if (MAY_HAVE_DEBUG_STMTS)
+           {
+             root->grp_to_be_debug_replaced = 1;
+             if (dump_file && (dump_flags & TDF_DETAILS))
+               {
+                 fprintf (dump_file, "Marking ");
+                 print_generic_expr (dump_file, root->base, 0);
+                 fprintf (dump_file, " offset: %u, size: %u ",
+                          (unsigned) root->offset, (unsigned) root->size);
+                 fprintf (dump_file, " to be replaced with debug "
+                          "statements.\n");
+               }
+           }
+       }
+
+      if (covered_to < limit)
+       hole = true;
+      if (scalar)
+       root->grp_total_scalarization = 0;
     }
-  if (root->grp_write || TREE_CODE (root->base) == PARM_DECL)
+
+  if (!hole || root->grp_total_scalarization)
+    root->grp_covered = 1;
+  else if (root->grp_write || TREE_CODE (root->base) == PARM_DECL)
     root->grp_unscalarized_data = 1; /* not covered and written to */
-  if (sth_created)
-    return true;
-  return false;
+  return sth_created;
 }
 
 /* Analyze all access trees linked by next_grp by the means of
@@ -1971,8 +2243,7 @@ analyze_access_trees (struct access *access)
 
   while (access)
     {
-      if (analyze_access_subtree (access, true,
-                                 SRA_MRRW_NOTHING, SRA_MRRW_NOTHING))
+      if (analyze_access_subtree (access, NULL, true))
        ret = true;
       access = access->next_grp;
     }
@@ -2067,21 +2338,23 @@ propagate_subaccesses_across_link (struct access *lacc, struct access *racc)
       || racc->grp_unscalarizable_region)
     return false;
 
-  if (!lacc->first_child && !racc->first_child
-      && is_gimple_reg_type (racc->type))
+  if (is_gimple_reg_type (racc->type))
     {
-      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
+      if (!lacc->first_child && !racc->first_child)
        {
-         lacc->expr = build_ref_for_model (EXPR_LOCATION (lacc->base),
-                                           lacc->base, lacc->offset,
-                                           racc, NULL, false);
-         lacc->grp_no_warning = true;
+         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 = build_ref_for_model (EXPR_LOCATION (lacc->base),
+                                               lacc->base, lacc->offset,
+                                               racc, NULL, false);
+             lacc->grp_no_warning = true;
+           }
        }
       return false;
     }
@@ -2166,19 +2439,27 @@ analyze_all_variable_accesses (void)
     if (bitmap_bit_p (should_scalarize_away_bitmap, i)
        && !bitmap_bit_p (cannot_scalarize_away_bitmap, i))
       {
-       tree var = referenced_var (i);
+       tree var = candidate (i);
 
        if (TREE_CODE (var) == VAR_DECL
-           && ((unsigned) tree_low_cst (TYPE_SIZE (TREE_TYPE (var)), 1)
-               <= max_total_scalarization_size)
            && type_consists_of_records_p (TREE_TYPE (var)))
          {
-           completely_scalarize_record (var, var, 0, var);
-           if (dump_file && (dump_flags & TDF_DETAILS))
+           if ((unsigned) tree_low_cst (TYPE_SIZE (TREE_TYPE (var)), 1)
+               <= max_total_scalarization_size)
              {
-               fprintf (dump_file, "Will attempt to totally scalarize ");
+               completely_scalarize_var (var);
+               if (dump_file && (dump_flags & TDF_DETAILS))
+                 {
+                   fprintf (dump_file, "Will attempt to totally scalarize ");
+                   print_generic_expr (dump_file, var, 0);
+                   fprintf (dump_file, " (UID: %u): \n", DECL_UID (var));
+                 }
+             }
+           else if (dump_file && (dump_flags & TDF_DETAILS))
+             {
+               fprintf (dump_file, "Too big to totally scalarize: ");
                print_generic_expr (dump_file, var, 0);
-               fprintf (dump_file, " (UID: %u)\n", DECL_UID (var));
+               fprintf (dump_file, " (UID: %u)\n", DECL_UID (var));
              }
          }
       }
@@ -2186,7 +2467,7 @@ analyze_all_variable_accesses (void)
   bitmap_copy (tmp, candidate_bitmap);
   EXECUTE_IF_SET_IN_BITMAP (tmp, 0, i, bi)
     {
-      tree var = referenced_var (i);
+      tree var = candidate (i);
       struct access *access;
 
       access = sort_and_splice_var_accesses (var);
@@ -2200,7 +2481,7 @@ analyze_all_variable_accesses (void)
   bitmap_copy (tmp, candidate_bitmap);
   EXECUTE_IF_SET_IN_BITMAP (tmp, 0, i, bi)
     {
-      tree var = referenced_var (i);
+      tree var = candidate (i);
       struct access *access = get_first_repr_for_decl (var);
 
       if (analyze_access_trees (access))
@@ -2294,6 +2575,22 @@ generate_subtree_copies (struct access *access, tree agg,
          update_stmt (stmt);
          sra_stats.subtree_copies++;
        }
+      else if (write
+              && access->grp_to_be_debug_replaced
+              && (chunk_size == 0
+                  || access->offset + access->size > start_offset))
+       {
+         gimple ds;
+         tree drhs = build_debug_ref_for_model (loc, agg,
+                                                access->offset - top_offset,
+                                                access);
+         ds = gimple_build_debug_bind (get_access_replacement (access),
+                                       drhs, gsi_stmt (*gsi));
+         if (insert_after)
+           gsi_insert_after (gsi, ds, GSI_NEW_STMT);
+         else
+           gsi_insert_before (gsi, ds, GSI_SAME_STMT);
+       }
 
       if (access->first_child)
        generate_subtree_copies (access->first_child, agg, top_offset,
@@ -2330,6 +2627,16 @@ init_subtree_with_zero (struct access *access, gimple_stmt_iterator *gsi,
       update_stmt (stmt);
       gimple_set_location (stmt, loc);
     }
+  else if (access->grp_to_be_debug_replaced)
+    {
+      gimple ds = gimple_build_debug_bind (get_access_replacement (access),
+                                          build_zero_cst (access->type),
+                                          gsi_stmt (*gsi));
+      if (insert_after)
+       gsi_insert_after (gsi, ds, GSI_NEW_STMT);
+      else
+       gsi_insert_before (gsi, ds, GSI_SAME_STMT);
+    }
 
   for (child = access->first_child; child; child = child->next_sibling)
     init_subtree_with_zero (child, gsi, insert_after, loc);
@@ -2436,6 +2743,13 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
        *expr = repl;
       sra_stats.exprs++;
     }
+  else if (write && access->grp_to_be_debug_replaced)
+    {
+      gimple ds = gimple_build_debug_bind (get_access_replacement (access),
+                                          NULL_TREE,
+                                          gsi_stmt (*gsi));
+      gsi_insert_after (gsi, ds, GSI_NEW_STMT);
+    }
 
   if (access->first_child)
     {
@@ -2511,10 +2825,11 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
   location_t loc = gimple_location (gsi_stmt (*old_gsi));
   for (lacc = lacc->first_child; lacc; lacc = lacc->next_sibling)
     {
+      HOST_WIDE_INT offset = lacc->offset - left_offset + top_racc->offset;
+
       if (lacc->grp_to_be_replaced)
        {
          struct access *racc;
-         HOST_WIDE_INT offset = lacc->offset - left_offset + top_racc->offset;
          gimple stmt;
          tree rhs;
 
@@ -2524,6 +2839,10 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
              rhs = get_access_replacement (racc);
              if (!useless_type_conversion_p (lacc->type, racc->type))
                rhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR, lacc->type, rhs);
+
+             if (racc->grp_partial_lhs && lacc->grp_partial_lhs)
+               rhs = force_gimple_operand_gsi (old_gsi, rhs, true, NULL_TREE,
+                                               true, GSI_SAME_STMT);
            }
          else
            {
@@ -2539,6 +2858,9 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
              else
                rhs = build_ref_for_model (loc, top_racc->base, offset, lacc,
                                            new_gsi, true);
+             if (lacc->grp_partial_lhs)
+               rhs = force_gimple_operand_gsi (new_gsi, rhs, true, NULL_TREE,
+                                               false, GSI_NEW_STMT);
            }
 
          stmt = gimple_build_assign (get_access_replacement (lacc), rhs);
@@ -2547,10 +2869,34 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
          update_stmt (stmt);
          sra_stats.subreplacements++;
        }
-      else if (*refreshed == SRA_UDH_NONE
-              && lacc->grp_read && !lacc->grp_covered)
-       *refreshed = handle_unscalarized_data_in_subtree (top_racc,
-                                                         old_gsi);
+      else
+       {
+         if (*refreshed == SRA_UDH_NONE
+             && lacc->grp_read && !lacc->grp_covered)
+           *refreshed = handle_unscalarized_data_in_subtree (top_racc,
+                                                             old_gsi);
+         if (lacc && lacc->grp_to_be_debug_replaced)
+           {
+             gimple ds;
+             tree drhs;
+             struct access *racc = find_access_in_subtree (top_racc, offset,
+                                                           lacc->size);
+
+             if (racc && racc->grp_to_be_replaced)
+               drhs = get_access_replacement (racc);
+             else if (*refreshed == SRA_UDH_LEFT)
+               drhs = build_debug_ref_for_model (loc, lacc->base, lacc->offset,
+                                                 lacc);
+             else if (*refreshed == SRA_UDH_RIGHT)
+               drhs = build_debug_ref_for_model (loc, top_racc->base, offset,
+                                                 lacc);
+             else
+               drhs = NULL_TREE;
+             ds = gimple_build_debug_bind (get_access_replacement (lacc),
+                                           drhs, gsi_stmt (*old_gsi));
+             gsi_insert_after (new_gsi, ds, GSI_NEW_STMT);
+           }
+       }
 
       if (lacc->first_child)
        load_assign_lhs_subreplacements (lacc, top_racc, left_offset,
@@ -2579,9 +2925,23 @@ sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
   if (!acc)
     return SRA_AM_NONE;
 
+  if (gimple_clobber_p (*stmt))
+    {
+      /* Remove clobbers of fully scalarized variables, otherwise
+        do nothing.  */
+      if (acc->grp_covered)
+       {
+         unlink_stmt_vdef (*stmt);
+         gsi_remove (gsi, true);
+         release_defs (*stmt);
+         return SRA_AM_REMOVED;
+       }
+      else
+       return SRA_AM_NONE;
+    }
+
   loc = gimple_location (*stmt);
-  if (VEC_length (constructor_elt,
-                 CONSTRUCTOR_ELTS (gimple_assign_rhs1 (*stmt))) > 0)
+  if (vec_safe_length (CONSTRUCTOR_ELTS (gimple_assign_rhs1 (*stmt))) > 0)
     {
       /* I have never seen this code path trigger but if it can happen the
         following should handle it gracefully.  */
@@ -2596,6 +2956,7 @@ sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
       init_subtree_with_zero (acc, gsi, false, loc);
       unlink_stmt_vdef (*stmt);
       gsi_remove (gsi, true);
+      release_defs (*stmt);
       return SRA_AM_REMOVED;
     }
   else
@@ -2612,18 +2973,42 @@ sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
 static tree
 get_repl_default_def_ssa_name (struct access *racc)
 {
-  tree repl, decl;
+  return get_or_create_ssa_default_def (cfun, get_access_replacement (racc));
+}
 
-  decl = get_unrenamed_access_replacement (racc);
+/* Return true if REF has a COMPONENT_REF with a bit-field field declaration
+   somewhere in it.  */
 
-  repl = gimple_default_def (cfun, decl);
-  if (!repl)
+static inline bool
+contains_bitfld_comp_ref_p (const_tree ref)
+{
+  while (handled_component_p (ref))
     {
-      repl = make_ssa_name (decl, gimple_build_nop ());
-      set_default_def (decl, repl);
+      if (TREE_CODE (ref) == COMPONENT_REF
+          && DECL_BIT_FIELD (TREE_OPERAND (ref, 1)))
+        return true;
+      ref = TREE_OPERAND (ref, 0);
     }
 
-  return repl;
+  return false;
+}
+
+/* Return true if REF has an VIEW_CONVERT_EXPR or a COMPONENT_REF with a
+   bit-field field declaration somewhere in it.  */
+
+static inline bool
+contains_vce_or_bfcref_p (const_tree ref)
+{
+  while (handled_component_p (ref))
+    {
+      if (TREE_CODE (ref) == VIEW_CONVERT_EXPR
+         || (TREE_CODE (ref) == COMPONENT_REF
+             && DECL_BIT_FIELD (TREE_OPERAND (ref, 1))))
+       return true;
+      ref = TREE_OPERAND (ref, 0);
+    }
+
+  return false;
 }
 
 /* Examine both sides of the assignment statement pointed to by STMT, replace
@@ -2685,6 +3070,15 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
        force_gimple_rhs = true;
       sra_stats.exprs++;
     }
+  else if (racc
+          && !racc->grp_unscalarized_data
+          && TREE_CODE (lhs) == SSA_NAME
+          && !access_has_replacements_p (racc))
+    {
+      rhs = get_repl_default_def_ssa_name (racc);
+      modify_this_stmt = true;
+      sra_stats.exprs++;
+    }
 
   if (modify_this_stmt)
     {
@@ -2694,17 +3088,14 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
             ???  This should move to fold_stmt which we simply should
             call after building a VIEW_CONVERT_EXPR here.  */
          if (AGGREGATE_TYPE_P (TREE_TYPE (lhs))
-             && !access_has_children_p (lacc))
+             && !contains_bitfld_comp_ref_p (lhs))
            {
-             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_view_convert_expr_p (rhs)
-                  && !access_has_children_p (racc))
-           rhs = build_ref_for_offset (loc, rhs, 0, TREE_TYPE (lhs),
-                                       gsi, false);
+                  && !contains_vce_or_bfcref_p (rhs))
+           rhs = build_ref_for_model (loc, rhs, 0, lacc, gsi, false);
 
          if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
            {
@@ -2717,6 +3108,25 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
        }
     }
 
+  if (lacc && lacc->grp_to_be_debug_replaced)
+    {
+      tree dlhs = get_access_replacement (lacc);
+      tree drhs = unshare_expr (rhs);
+      if (!useless_type_conversion_p (TREE_TYPE (dlhs), TREE_TYPE (drhs)))
+       {
+         if (AGGREGATE_TYPE_P (TREE_TYPE (drhs))
+             && !contains_vce_or_bfcref_p (drhs))
+           drhs = build_debug_ref_for_model (loc, drhs, 0, lacc);
+         if (drhs
+             && !useless_type_conversion_p (TREE_TYPE (dlhs),
+                                            TREE_TYPE (drhs)))
+           drhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR,
+                                   TREE_TYPE (dlhs), drhs);
+       }
+      gimple ds = gimple_build_debug_bind (dlhs, drhs, *stmt);
+      gsi_insert_before (gsi, ds, GSI_SAME_STMT);
+    }
+
   /* From this point on, the function deals with assignments in between
      aggregates when at least one has scalar reductions of some of its
      components.  There are three possible scenarios: Both the LHS and RHS have
@@ -2750,9 +3160,10 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
      there to do the copying and then load the scalar replacements of the LHS.
      This is what the first branch does.  */
 
-  if (gimple_has_volatile_ops (*stmt)
-      || contains_view_convert_expr_p (rhs)
-      || contains_view_convert_expr_p (lhs))
+  if (modify_this_stmt
+      || gimple_has_volatile_ops (*stmt)
+      || contains_vce_or_bfcref_p (rhs)
+      || contains_vce_or_bfcref_p (lhs))
     {
       if (access_has_children_p (racc))
        generate_subtree_copies (racc->first_child, racc->base, 0, 0, 0,
@@ -2761,10 +3172,31 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
        generate_subtree_copies (lacc->first_child, lacc->base, 0, 0, 0,
                                 gsi, true, true, loc);
       sra_stats.separate_lhs_rhs_handling++;
+
+      /* This gimplification must be done after generate_subtree_copies,
+        lest we insert the subtree copies in the middle of the gimplified
+        sequence.  */
+      if (force_gimple_rhs)
+       rhs = force_gimple_operand_gsi (&orig_gsi, rhs, true, NULL_TREE,
+                                       true, GSI_SAME_STMT);
+      if (gimple_assign_rhs1 (*stmt) != rhs)
+       {
+         modify_this_stmt = true;
+         gimple_assign_set_rhs_from_tree (&orig_gsi, rhs);
+         gcc_assert (*stmt == gsi_stmt (orig_gsi));
+       }
+
+      return modify_this_stmt ? SRA_AM_MODIFIED : SRA_AM_NONE;
     }
   else
     {
-      if (access_has_children_p (lacc) && access_has_children_p (racc))
+      if (access_has_children_p (lacc)
+         && access_has_children_p (racc)
+         /* When an access represents an unscalarizable region, it usually
+            represents accesses with variable offset and thus must not be used
+            to generate new memory accesses.  */
+         && !lacc->grp_unscalarizable_region
+         && !racc->grp_unscalarizable_region)
        {
          gimple_stmt_iterator orig_gsi = *gsi;
          enum unscalarized_data_handling refreshed;
@@ -2781,67 +3213,46 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
              gsi_next (gsi);
              unlink_stmt_vdef (*stmt);
              gsi_remove (&orig_gsi, true);
+             release_defs (*stmt);
              sra_stats.deleted++;
              return SRA_AM_REMOVED;
            }
        }
       else
        {
-         if (racc)
+         if (access_has_children_p (racc)
+             && !racc->grp_unscalarized_data)
            {
-             if (!racc->grp_to_be_replaced && !racc->grp_unscalarized_data)
+             if (dump_file)
                {
-                 if (dump_file)
-                   {
-                     fprintf (dump_file, "Removing load: ");
-                     print_gimple_stmt (dump_file, *stmt, 0, 0);
-                   }
-
-                 if (TREE_CODE (lhs) == SSA_NAME)
-                   {
-                     rhs = get_repl_default_def_ssa_name (racc);
-                     if (!useless_type_conversion_p (TREE_TYPE (lhs),
-                                                     TREE_TYPE (rhs)))
-                       rhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR,
-                                              TREE_TYPE (lhs), rhs);
-                   }
-                 else
-                   {
-                     if (racc->first_child)
-                       generate_subtree_copies (racc->first_child, lhs,
-                                                racc->offset, 0, 0, gsi,
-                                                false, false, loc);
-
-                     gcc_assert (*stmt == gsi_stmt (*gsi));
-                     unlink_stmt_vdef (*stmt);
-                     gsi_remove (gsi, true);
-                     sra_stats.deleted++;
-                     return SRA_AM_REMOVED;
-                   }
+                 fprintf (dump_file, "Removing load: ");
+                 print_gimple_stmt (dump_file, *stmt, 0, 0);
                }
-             else if (racc->first_child)
-               generate_subtree_copies (racc->first_child, lhs, racc->offset,
-                                        0, 0, gsi, false, true, loc);
+             generate_subtree_copies (racc->first_child, lhs,
+                                      racc->offset, 0, 0, gsi,
+                                      false, false, loc);
+             gcc_assert (*stmt == gsi_stmt (*gsi));
+             unlink_stmt_vdef (*stmt);
+             gsi_remove (gsi, true);
+             release_defs (*stmt);
+             sra_stats.deleted++;
+             return SRA_AM_REMOVED;
            }
+         /* Restore the aggregate RHS from its components so the
+            prevailing aggregate copy does the right thing.  */
+         if (access_has_children_p (racc))
+           generate_subtree_copies (racc->first_child, racc->base, 0, 0, 0,
+                                    gsi, false, false, loc);
+         /* Re-load the components of the aggregate copy destination.
+            But use the RHS aggregate to load from to expose more
+            optimization opportunities.  */
          if (access_has_children_p (lacc))
            generate_subtree_copies (lacc->first_child, rhs, lacc->offset,
                                     0, 0, gsi, true, true, loc);
        }
-    }
 
-  /* This gimplification must be done after generate_subtree_copies, lest we
-     insert the subtree copies in the middle of the gimplified sequence.  */
-  if (force_gimple_rhs)
-    rhs = force_gimple_operand_gsi (&orig_gsi, rhs, true, NULL_TREE,
-                                   true, GSI_SAME_STMT);
-  if (gimple_assign_rhs1 (*stmt) != rhs)
-    {
-      modify_this_stmt = true;
-      gimple_assign_set_rhs_from_tree (&orig_gsi, rhs);
-      gcc_assert (*stmt == gsi_stmt (orig_gsi));
+      return SRA_AM_NONE;
     }
-
-  return modify_this_stmt ? SRA_AM_MODIFIED : SRA_AM_NONE;
 }
 
 /* Traverse the function body and all modifications as decided in
@@ -2936,11 +3347,12 @@ initialize_parameter_reductions (void)
   gimple_seq seq = NULL;
   tree parm;
 
+  gsi = gsi_start (seq);
   for (parm = DECL_ARGUMENTS (current_function_decl);
        parm;
        parm = DECL_CHAIN (parm))
     {
-      VEC (access_p, heap) *access_vec;
+      vec<access_p> *access_vec;
       struct access *access;
 
       if (!bitmap_bit_p (candidate_bitmap, DECL_UID (parm)))
@@ -2949,19 +3361,14 @@ initialize_parameter_reductions (void)
       if (!access_vec)
        continue;
 
-      if (!seq)
-       {
-         seq = gimple_seq_alloc ();
-         gsi = gsi_start (seq);
-       }
-
-      for (access = VEC_index (access_p, access_vec, 0);
+      for (access = (*access_vec)[0];
           access;
           access = access->next_grp)
        generate_subtree_copies (access, parm, 0, 0, 0, &gsi, true, true,
                                 EXPR_LOCATION (parm));
     }
 
+  seq = gsi_seq (gsi);
   if (seq)
     gsi_insert_seq_on_edge_immediate (single_succ_edge (ENTRY_BLOCK_PTR), seq);
 }
@@ -3035,6 +3442,7 @@ struct gimple_opt_pass pass_sra_early =
  {
   GIMPLE_PASS,
   "esra",                              /* name */
+  OPTGROUP_NONE,                        /* optinfo_flags */
   gate_intra_sra,                      /* gate */
   early_intra_sra,                     /* execute */
   NULL,                                        /* sub */
@@ -3045,8 +3453,7 @@ struct gimple_opt_pass pass_sra_early =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func
-  | TODO_update_ssa
+  TODO_update_ssa
   | TODO_ggc_collect
   | TODO_verify_ssa                    /* todo_flags_finish */
  }
@@ -3057,6 +3464,7 @@ struct gimple_opt_pass pass_sra =
  {
   GIMPLE_PASS,
   "sra",                               /* name */
+  OPTGROUP_NONE,                        /* optinfo_flags */
   gate_intra_sra,                      /* gate */
   late_intra_sra,                      /* execute */
   NULL,                                        /* sub */
@@ -3067,8 +3475,7 @@ struct gimple_opt_pass pass_sra =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   TODO_update_address_taken,           /* todo_flags_start */
-  TODO_dump_func
-  | TODO_update_ssa
+  TODO_update_ssa
   | TODO_ggc_collect
   | TODO_verify_ssa                    /* todo_flags_finish */
  }
@@ -3083,7 +3490,7 @@ is_unused_scalar_param (tree parm)
 {
   tree name;
   return (is_gimple_reg (parm)
-         && (!(name = gimple_default_def (cfun, parm))
+         && (!(name = ssa_default_def (cfun, parm))
              || has_zero_uses (name)));
 }
 
@@ -3097,7 +3504,7 @@ ptr_parm_has_direct_uses (tree parm)
 {
   imm_use_iterator ui;
   gimple stmt;
-  tree name = gimple_default_def (cfun, parm);
+  tree name = ssa_default_def (cfun, parm);
   bool ret = false;
 
   FOR_EACH_IMM_USE_STMT (stmt, ui, name)
@@ -3118,7 +3525,8 @@ ptr_parm_has_direct_uses (tree parm)
              && TREE_OPERAND (lhs, 0) == name
              && integer_zerop (TREE_OPERAND (lhs, 1))
              && types_compatible_p (TREE_TYPE (lhs),
-                                    TREE_TYPE (TREE_TYPE (name))))
+                                    TREE_TYPE (TREE_TYPE (name)))
+             && !TREE_THIS_VOLATILE (lhs))
            uses_ok++;
        }
       if (gimple_assign_single_p (stmt))
@@ -3130,7 +3538,8 @@ ptr_parm_has_direct_uses (tree parm)
              && TREE_OPERAND (rhs, 0) == name
              && integer_zerop (TREE_OPERAND (rhs, 1))
              && types_compatible_p (TREE_TYPE (rhs),
-                                    TREE_TYPE (TREE_TYPE (name))))
+                                    TREE_TYPE (TREE_TYPE (name)))
+             && !TREE_THIS_VOLATILE (rhs))
            uses_ok++;
        }
       else if (is_gimple_call (stmt))
@@ -3145,7 +3554,8 @@ ptr_parm_has_direct_uses (tree parm)
                  && TREE_OPERAND (arg, 0) == name
                  && integer_zerop (TREE_OPERAND (arg, 1))
                  && types_compatible_p (TREE_TYPE (arg),
-                                        TREE_TYPE (TREE_TYPE (name))))
+                                        TREE_TYPE (TREE_TYPE (name)))
+                 && !TREE_THIS_VOLATILE (arg))
                uses_ok++;
            }
        }
@@ -3176,12 +3586,14 @@ find_param_candidates (void)
   tree parm;
   int count = 0;
   bool ret = false;
+  const char *msg;
 
   for (parm = DECL_ARGUMENTS (current_function_decl);
        parm;
        parm = DECL_CHAIN (parm))
     {
       tree type = TREE_TYPE (parm);
+      void **slot;
 
       count++;
 
@@ -3216,10 +3628,14 @@ find_param_candidates (void)
          || !host_integerp (TYPE_SIZE (type), 1)
           || tree_low_cst (TYPE_SIZE (type), 1) == 0
          || (AGGREGATE_TYPE_P (type)
-             && type_internals_preclude_sra_p (type)))
+             && type_internals_preclude_sra_p (type, &msg)))
        continue;
 
       bitmap_set_bit (candidate_bitmap, DECL_UID (parm));
+      slot = htab_find_slot_with_hash (candidates, parm,
+                                      DECL_UID (parm), INSERT);
+      *slot = (void *) parm;
+
       ret = true;
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
@@ -3251,7 +3667,7 @@ mark_maybe_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED,
    current function.  */
 
 static void
-analyze_modified_params (VEC (access_p, heap) *representatives)
+analyze_modified_params (vec<access_p> representatives)
 {
   int i;
 
@@ -3259,7 +3675,7 @@ analyze_modified_params (VEC (access_p, heap) *representatives)
     {
       struct access *repr;
 
-      for (repr = VEC_index (access_p, representatives, i);
+      for (repr = representatives[i];
           repr;
           repr = repr->next_grp)
        {
@@ -3298,25 +3714,25 @@ analyze_modified_params (VEC (access_p, heap) *representatives)
 static void
 propagate_dereference_distances (void)
 {
-  VEC (basic_block, heap) *queue;
+  vec<basic_block> queue;
   basic_block bb;
 
-  queue = VEC_alloc (basic_block, heap, last_basic_block_for_function (cfun));
-  VEC_quick_push (basic_block, queue, ENTRY_BLOCK_PTR);
+  queue.create (last_basic_block_for_function (cfun));
+  queue.quick_push (ENTRY_BLOCK_PTR);
   FOR_EACH_BB (bb)
     {
-      VEC_quick_push (basic_block, queue, bb);
+      queue.quick_push (bb);
       bb->aux = bb;
     }
 
-  while (!VEC_empty (basic_block, queue))
+  while (!queue.is_empty ())
     {
       edge_iterator ei;
       edge e;
       bool change = false;
       int i;
 
-      bb = VEC_pop (basic_block, queue);
+      bb = queue.pop ();
       bb->aux = NULL;
 
       if (bitmap_bit_p (final_bbs, bb->index))
@@ -3358,11 +3774,11 @@ propagate_dereference_distances (void)
              continue;
 
            e->src->aux = e->src;
-           VEC_quick_push (basic_block, queue, e->src);
+           queue.quick_push (e->src);
          }
     }
 
-  VEC_free (basic_block, heap, queue);
+  queue.release ();
 }
 
 /* Dump a dereferences TABLE with heading STR to file F.  */
@@ -3409,7 +3825,7 @@ dump_dereferences_table (FILE *f, const char *str, HOST_WIDE_INT *table)
    distances of each representative of a (fraction of a) parameter.  */
 
 static void
-analyze_caller_dereference_legality (VEC (access_p, heap) *representatives)
+analyze_caller_dereference_legality (vec<access_p> representatives)
 {
   int i;
 
@@ -3427,7 +3843,7 @@ analyze_caller_dereference_legality (VEC (access_p, heap) *representatives)
 
   for (i = 0; i < func_param_count; i++)
     {
-      struct access *repr = VEC_index (access_p, representatives, i);
+      struct access *repr = representatives[i];
       int idx = ENTRY_BLOCK_PTR->index * func_param_count + i;
 
       if (!repr || no_accesses_p (repr))
@@ -3454,19 +3870,19 @@ unmodified_by_ref_scalar_representative (tree parm)
 {
   int i, access_count;
   struct access *repr;
-  VEC (access_p, heap) *access_vec;
+  vec<access_p> *access_vec;
 
   access_vec = get_base_access_vector (parm);
   gcc_assert (access_vec);
-  repr = VEC_index (access_p, access_vec, 0);
+  repr = (*access_vec)[0];
   if (repr->write)
     return NULL;
   repr->group_representative = repr;
 
-  access_count = VEC_length (access_p, access_vec);
+  access_count = access_vec->length ();
   for (i = 1; i < access_count; i++)
     {
-      struct access *access = VEC_index (access_p, access_vec, i);
+      struct access *access = (*access_vec)[i];
       if (access->write)
        return NULL;
       access->group_representative = repr;
@@ -3479,12 +3895,13 @@ unmodified_by_ref_scalar_representative (tree parm)
   return repr;
 }
 
-/* Return true iff this access precludes IPA-SRA of the parameter it is
-   associated with. */
+/* Return true iff this ACCESS precludes IPA-SRA of the parameter it is
+   associated with.  REQ_ALIGN is the minimum required alignment.  */
 
 static bool
-access_precludes_ipa_sra_p (struct access *access)
+access_precludes_ipa_sra_p (struct access *access, unsigned int req_align)
 {
+  unsigned int exp_align;
   /* 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
@@ -3496,6 +3913,10 @@ access_precludes_ipa_sra_p (struct access *access)
          || gimple_code (access->stmt) == GIMPLE_ASM))
     return true;
 
+  exp_align = get_object_alignment (access->expr);
+  if (exp_align < req_align)
+    return true;
+
   return false;
 }
 
@@ -3513,14 +3934,14 @@ splice_param_accesses (tree parm, bool *ro_grp)
   int i, j, access_count, group_count;
   int agg_size, total_size = 0;
   struct access *access, *res, **prev_acc_ptr = &res;
-  VEC (access_p, heap) *access_vec;
+  vec<access_p> *access_vec;
 
   access_vec = get_base_access_vector (parm);
   if (!access_vec)
     return &no_accesses_representant;
-  access_count = VEC_length (access_p, access_vec);
+  access_count = access_vec->length ();
 
-  VEC_qsort (access_p, access_vec, compare_access_positions);
+  access_vec->qsort (compare_access_positions);
 
   i = 0;
   total_size = 0;
@@ -3528,10 +3949,12 @@ splice_param_accesses (tree parm, bool *ro_grp)
   while (i < access_count)
     {
       bool modification;
-      access = VEC_index (access_p, access_vec, i);
+      tree a1_alias_type;
+      access = (*access_vec)[i];
       modification = access->write;
-      if (access_precludes_ipa_sra_p (access))
+      if (access_precludes_ipa_sra_p (access, TYPE_ALIGN (access->type)))
        return NULL;
+      a1_alias_type = reference_alias_ptr_type (access->expr);
 
       /* Access is about to become group representative unless we find some
         nasty overlap which would preclude us from breaking this parameter
@@ -3540,7 +3963,7 @@ splice_param_accesses (tree parm, bool *ro_grp)
       j = i + 1;
       while (j < access_count)
        {
-         struct access *ac2 = VEC_index (access_p, access_vec, j);
+         struct access *ac2 = (*access_vec)[j];
          if (ac2->offset != access->offset)
            {
              /* All or nothing law for parameters. */
@@ -3552,7 +3975,11 @@ splice_param_accesses (tree parm, bool *ro_grp)
          else if (ac2->size != access->size)
            return NULL;
 
-         if (access_precludes_ipa_sra_p (ac2))
+         if (access_precludes_ipa_sra_p (ac2, TYPE_ALIGN (access->type))
+             || (ac2->type != access->type
+                 && (TREE_ADDRESSABLE (ac2->type)
+                     || TREE_ADDRESSABLE (access->type)))
+             || (reference_alias_ptr_type (ac2->expr) != a1_alias_type))
            return NULL;
 
          modification |= ac2->write;
@@ -3624,13 +4051,25 @@ 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;
+
+      /* Do not decompose a non-BLKmode param in a way that would
+         create BLKmode params.  Especially for by-reference passing
+        (thus, pointer-type param) this is hardly worthwhile.  */
+      if (DECL_MODE (parm) != BLKmode
+         && TYPE_MODE (repr->type) == BLKmode)
+       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);
@@ -3662,13 +4101,13 @@ enum ipa_splicing_result { NO_GOOD_ACCESS, UNUSED_PARAMS, BY_VAL_ACCESSES,
    IPA-SRA.  Return result based on what representatives have been found. */
 
 static enum ipa_splicing_result
-splice_all_param_accesses (VEC (access_p, heap) **representatives)
+splice_all_param_accesses (vec<access_p> &representatives)
 {
   enum ipa_splicing_result result = NO_GOOD_ACCESS;
   tree parm;
   struct access *repr;
 
-  *representatives = VEC_alloc (access_p, heap, func_param_count);
+  representatives.create (func_param_count);
 
   for (parm = DECL_ARGUMENTS (current_function_decl);
        parm;
@@ -3676,8 +4115,7 @@ splice_all_param_accesses (VEC (access_p, heap) **representatives)
     {
       if (is_unused_scalar_param (parm))
        {
-         VEC_quick_push (access_p, *representatives,
-                         &no_accesses_representant);
+         representatives.quick_push (&no_accesses_representant);
          if (result == NO_GOOD_ACCESS)
            result = UNUSED_PARAMS;
        }
@@ -3686,7 +4124,7 @@ splice_all_param_accesses (VEC (access_p, heap) **representatives)
               && bitmap_bit_p (candidate_bitmap, DECL_UID (parm)))
        {
          repr = unmodified_by_ref_scalar_representative (parm);
-         VEC_quick_push (access_p, *representatives, repr);
+         representatives.quick_push (repr);
          if (repr)
            result = UNMODIF_BY_REF_ACCESSES;
        }
@@ -3694,7 +4132,7 @@ splice_all_param_accesses (VEC (access_p, heap) **representatives)
        {
          bool ro_grp = false;
          repr = splice_param_accesses (parm, &ro_grp);
-         VEC_quick_push (access_p, *representatives, repr);
+         representatives.quick_push (repr);
 
          if (repr && !no_accesses_p (repr))
            {
@@ -3712,13 +4150,12 @@ splice_all_param_accesses (VEC (access_p, heap) **representatives)
            result = UNUSED_PARAMS;
        }
       else
-       VEC_quick_push (access_p, *representatives, NULL);
+       representatives.quick_push (NULL);
     }
 
   if (result == NO_GOOD_ACCESS)
     {
-      VEC_free (access_p, heap, *representatives);
-      *representatives = NULL;
+      representatives.release ();
       return NO_GOOD_ACCESS;
     }
 
@@ -3728,13 +4165,13 @@ splice_all_param_accesses (VEC (access_p, heap) **representatives)
 /* Return the index of BASE in PARMS.  Abort if it is not found.  */
 
 static inline int
-get_param_index (tree base, VEC(tree, heap) *parms)
+get_param_index (tree base, vec<tree> parms)
 {
   int i, len;
 
-  len = VEC_length (tree, parms);
+  len = parms.length ();
   for (i = 0; i < len; i++)
-    if (VEC_index (tree, parms, i) == base)
+    if (parms[i] == base)
       return i;
   gcc_unreachable ();
 }
@@ -3745,57 +4182,57 @@ get_param_index (tree base, VEC(tree, heap) *parms)
    final number of adjustments.  */
 
 static ipa_parm_adjustment_vec
-turn_representatives_into_adjustments (VEC (access_p, heap) *representatives,
+turn_representatives_into_adjustments (vec<access_p> representatives,
                                       int adjustments_count)
 {
-  VEC (tree, heap) *parms;
+  vec<tree> parms;
   ipa_parm_adjustment_vec adjustments;
   tree parm;
   int i;
 
   gcc_assert (adjustments_count > 0);
   parms = ipa_get_vector_of_formal_parms (current_function_decl);
-  adjustments = VEC_alloc (ipa_parm_adjustment_t, heap, adjustments_count);
+  adjustments.create (adjustments_count);
   parm = DECL_ARGUMENTS (current_function_decl);
   for (i = 0; i < func_param_count; i++, parm = DECL_CHAIN (parm))
     {
-      struct access *repr = VEC_index (access_p, representatives, i);
+      struct access *repr = representatives[i];
 
       if (!repr || no_accesses_p (repr))
        {
-         struct ipa_parm_adjustment *adj;
+         struct ipa_parm_adjustment adj;
 
-         adj = VEC_quick_push (ipa_parm_adjustment_t, adjustments, NULL);
-         memset (adj, 0, sizeof (*adj));
-         adj->base_index = get_param_index (parm, parms);
-         adj->base = parm;
+         memset (&adj, 0, sizeof (adj));
+         adj.base_index = get_param_index (parm, parms);
+         adj.base = parm;
          if (!repr)
-           adj->copy_param = 1;
+           adj.copy_param = 1;
          else
-           adj->remove_param = 1;
+           adj.remove_param = 1;
+         adjustments.quick_push (adj);
        }
       else
        {
-         struct ipa_parm_adjustment *adj;
+         struct ipa_parm_adjustment adj;
          int index = get_param_index (parm, parms);
 
          for (; repr; repr = repr->next_grp)
            {
-             adj = VEC_quick_push (ipa_parm_adjustment_t, adjustments, NULL);
-             memset (adj, 0, sizeof (*adj));
+             memset (&adj, 0, sizeof (adj));
              gcc_assert (repr->base == parm);
-             adj->base_index = index;
-             adj->base = repr->base;
-             adj->type = repr->type;
-             adj->offset = repr->offset;
-             adj->by_ref = (POINTER_TYPE_P (TREE_TYPE (repr->base))
-                            && (repr->grp_maybe_modified
-                                || repr->grp_not_necessarilly_dereferenced));
-
+             adj.base_index = index;
+             adj.base = repr->base;
+             adj.type = repr->type;
+             adj.alias_ptr_type = reference_alias_ptr_type (repr->expr);
+             adj.offset = repr->offset;
+             adj.by_ref = (POINTER_TYPE_P (TREE_TYPE (repr->base))
+                           && (repr->grp_maybe_modified
+                               || repr->grp_not_necessarilly_dereferenced));
+             adjustments.quick_push (adj);
            }
        }
     }
-  VEC_free (tree, heap, parms);
+  parms.release ();
   return adjustments;
 }
 
@@ -3808,12 +4245,12 @@ analyze_all_param_acesses (void)
   enum ipa_splicing_result repr_state;
   bool proceed = false;
   int i, adjustments_count = 0;
-  VEC (access_p, heap) *representatives;
+  vec<access_p> representatives;
   ipa_parm_adjustment_vec adjustments;
 
-  repr_state = splice_all_param_accesses (&representatives);
+  repr_state = splice_all_param_accesses (representatives);
   if (repr_state == NO_GOOD_ACCESS)
-    return NULL;
+    return ipa_parm_adjustment_vec();
 
   /* If there are any parameters passed by reference which are not modified
      directly, we need to check whether they can be modified indirectly.  */
@@ -3825,7 +4262,7 @@ analyze_all_param_acesses (void)
 
   for (i = 0; i < func_param_count; i++)
     {
-      struct access *repr = VEC_index (access_p, representatives, i);
+      struct access *repr = representatives[i];
 
       if (repr && !no_accesses_p (repr))
        {
@@ -3834,7 +4271,7 @@ analyze_all_param_acesses (void)
              adjustments_count++;
              if (repr->grp_not_necessarilly_dereferenced
                  || repr->grp_maybe_modified)
-               VEC_replace (access_p, representatives, i, NULL);
+               representatives[i] = NULL;
              else
                {
                  proceed = true;
@@ -3847,7 +4284,7 @@ analyze_all_param_acesses (void)
 
              if (new_components == 0)
                {
-                 VEC_replace (access_p, representatives, i, NULL);
+                 representatives[i] = NULL;
                  adjustments_count++;
                }
              else
@@ -3877,9 +4314,9 @@ analyze_all_param_acesses (void)
     adjustments = turn_representatives_into_adjustments (representatives,
                                                         adjustments_count);
   else
-    adjustments = NULL;
+    adjustments = ipa_parm_adjustment_vec();
 
-  VEC_free (access_p, heap, representatives);
+  representatives.release ();
   return adjustments;
 }
 
@@ -3899,8 +4336,6 @@ get_replaced_param_substitute (struct ipa_parm_adjustment *adj)
       DECL_NAME (repl) = get_identifier (pretty_name);
       obstack_free (&name_obstack, pretty_name);
 
-      get_var_ann (repl);
-      add_referenced_var (repl);
       adj->new_ssa_base = repl;
     }
   else
@@ -3917,12 +4352,12 @@ get_adjustment_for_base (ipa_parm_adjustment_vec adjustments, tree base)
 {
   int i, len;
 
-  len = VEC_length (ipa_parm_adjustment_t, adjustments);
+  len = adjustments.length ();
   for (i = 0; i < len; i++)
     {
       struct ipa_parm_adjustment *adj;
 
-      adj = VEC_index (ipa_parm_adjustment_t, adjustments, i);
+      adj = &adjustments[i];
       if (!adj->copy_param && adj->base == base)
        return adj;
     }
@@ -3953,8 +4388,10 @@ replace_removed_params_ssa_names (gimple stmt,
 
   if (TREE_CODE (lhs) != SSA_NAME)
     return false;
+
   decl = SSA_NAME_VAR (lhs);
-  if (TREE_CODE (decl) != PARM_DECL)
+  if (decl == NULL_TREE
+      || TREE_CODE (decl) != PARM_DECL)
     return false;
 
   adj = get_adjustment_for_base (adjustments, decl);
@@ -4001,7 +4438,7 @@ sra_ipa_modify_expr (tree *expr, bool convert,
   HOST_WIDE_INT offset, size, max_size;
   tree base, src;
 
-  len = VEC_length (ipa_parm_adjustment_t, adjustments);
+  len = adjustments.length ();
 
   if (TREE_CODE (*expr) == BIT_FIELD_REF
       || TREE_CODE (*expr) == IMAGPART_EXPR
@@ -4027,7 +4464,7 @@ sra_ipa_modify_expr (tree *expr, bool convert,
 
   for (i = 0; i < len; i++)
     {
-      adj = VEC_index (ipa_parm_adjustment_t, adjustments, i);
+      adj = &adjustments[i];
 
       if (adj->base == base &&
          (adj->offset == offset || adj->remove_param))
@@ -4097,7 +4534,8 @@ sra_ipa_modify_assign (gimple *stmt_ptr, gimple_stmt_iterator *gsi,
              if (is_gimple_reg_type (TREE_TYPE (*lhs_p)))
                *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p));
              else
-               *rhs_p = build_constructor (TREE_TYPE (*lhs_p), 0);
+               *rhs_p = build_constructor (TREE_TYPE (*lhs_p),
+                                           NULL);
            }
          else
            new_rhs = fold_build1_loc (gimple_location (stmt),
@@ -4218,80 +4656,149 @@ static void
 sra_ipa_reset_debug_stmts (ipa_parm_adjustment_vec adjustments)
 {
   int i, len;
+  gimple_stmt_iterator *gsip = NULL, gsi;
 
-  len = VEC_length (ipa_parm_adjustment_t, adjustments);
+  if (MAY_HAVE_DEBUG_STMTS && single_succ_p (ENTRY_BLOCK_PTR))
+    {
+      gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR));
+      gsip = &gsi;
+    }
+  len = adjustments.length ();
   for (i = 0; i < len; i++)
     {
       struct ipa_parm_adjustment *adj;
       imm_use_iterator ui;
-      gimple stmt;
-      tree name;
+      gimple stmt, def_temp;
+      tree name, vexpr, copy = NULL_TREE;
+      use_operand_p use_p;
 
-      adj = VEC_index (ipa_parm_adjustment_t, adjustments, i);
+      adj = &adjustments[i];
       if (adj->copy_param || !is_gimple_reg (adj->base))
        continue;
-      name = gimple_default_def (cfun, adj->base);
-      if (!name)
-       continue;
-      FOR_EACH_IMM_USE_STMT (stmt, ui, name)
+      name = ssa_default_def (cfun, adj->base);
+      vexpr = NULL;
+      if (name)
+       FOR_EACH_IMM_USE_STMT (stmt, ui, name)
+         {
+           /* All other users must have been removed by
+              ipa_sra_modify_function_body.  */
+           gcc_assert (is_gimple_debug (stmt));
+           if (vexpr == NULL && gsip != NULL)
+             {
+               gcc_assert (TREE_CODE (adj->base) == PARM_DECL);
+               vexpr = make_node (DEBUG_EXPR_DECL);
+               def_temp = gimple_build_debug_source_bind (vexpr, adj->base,
+                                                          NULL);
+               DECL_ARTIFICIAL (vexpr) = 1;
+               TREE_TYPE (vexpr) = TREE_TYPE (name);
+               DECL_MODE (vexpr) = DECL_MODE (adj->base);
+               gsi_insert_before (gsip, def_temp, GSI_SAME_STMT);
+             }
+           if (vexpr)
+             {
+               FOR_EACH_IMM_USE_ON_STMT (use_p, ui)
+                 SET_USE (use_p, vexpr);
+             }
+           else
+             gimple_debug_bind_reset_value (stmt);
+           update_stmt (stmt);
+         }
+      /* Create a VAR_DECL for debug info purposes.  */
+      if (!DECL_IGNORED_P (adj->base))
        {
-         /* All other users must have been removed by
-            ipa_sra_modify_function_body.  */
-         gcc_assert (is_gimple_debug (stmt));
-         gimple_debug_bind_reset_value (stmt);
-         update_stmt (stmt);
+         copy = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
+                            VAR_DECL, DECL_NAME (adj->base),
+                            TREE_TYPE (adj->base));
+         if (DECL_PT_UID_SET_P (adj->base))
+           SET_DECL_PT_UID (copy, DECL_PT_UID (adj->base));
+         TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (adj->base);
+         TREE_READONLY (copy) = TREE_READONLY (adj->base);
+         TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (adj->base);
+         DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (adj->base);
+         DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (adj->base);
+         DECL_IGNORED_P (copy) = DECL_IGNORED_P (adj->base);
+         DECL_ABSTRACT_ORIGIN (copy) = DECL_ORIGIN (adj->base);
+         DECL_SEEN_IN_BIND_EXPR_P (copy) = 1;
+         SET_DECL_RTL (copy, 0);
+         TREE_USED (copy) = 1;
+         DECL_CONTEXT (copy) = current_function_decl;
+         add_local_decl (cfun, copy);
+         DECL_CHAIN (copy) =
+           BLOCK_VARS (DECL_INITIAL (current_function_decl));
+         BLOCK_VARS (DECL_INITIAL (current_function_decl)) = copy;
+       }
+      if (gsip != NULL && copy && target_for_debug_bind (adj->base))
+       {
+         gcc_assert (TREE_CODE (adj->base) == PARM_DECL);
+         if (vexpr)
+           def_temp = gimple_build_debug_bind (copy, vexpr, NULL);
+         else
+           def_temp = gimple_build_debug_source_bind (copy, adj->base,
+                                                      NULL);
+         gsi_insert_before (gsip, def_temp, GSI_SAME_STMT);
        }
     }
 }
 
-/* Return true iff all callers have at least as many actual arguments as there
+/* Return false iff all callers have at least as many actual arguments as there
    are formal parameters in the current function.  */
 
 static bool
-all_callers_have_enough_arguments_p (struct cgraph_node *node)
+not_all_callers_have_enough_arguments_p (struct cgraph_node *node,
+                                        void *data ATTRIBUTE_UNUSED)
 {
   struct cgraph_edge *cs;
   for (cs = node->callers; cs; cs = cs->next_caller)
     if (!callsite_has_enough_arguments_p (cs->call_stmt))
-      return false;
+      return true;
 
-  return true;
+  return false;
 }
 
+/* Convert all callers of NODE.  */
 
-/* Convert all callers of NODE to pass parameters as given in ADJUSTMENTS.  */
-
-static void
-convert_callers (struct cgraph_node *node, tree old_decl,
-                ipa_parm_adjustment_vec adjustments)
+static bool
+convert_callers_for_node (struct cgraph_node *node,
+                         void *data)
 {
-  tree old_cur_fndecl = current_function_decl;
-  struct cgraph_edge *cs;
-  basic_block this_block;
+  ipa_parm_adjustment_vec *adjustments = (ipa_parm_adjustment_vec *) data;
   bitmap recomputed_callers = BITMAP_ALLOC (NULL);
+  struct cgraph_edge *cs;
 
   for (cs = node->callers; cs; cs = cs->next_caller)
     {
-      current_function_decl = cs->caller->decl;
-      push_cfun (DECL_STRUCT_FUNCTION (cs->caller->decl));
+      push_cfun (DECL_STRUCT_FUNCTION (cs->caller->symbol.decl));
 
       if (dump_file)
        fprintf (dump_file, "Adjusting call (%i -> %i) %s -> %s\n",
                 cs->caller->uid, cs->callee->uid,
-                cgraph_node_name (cs->caller),
-                cgraph_node_name (cs->callee));
+                xstrdup (cgraph_node_name (cs->caller)),
+                xstrdup (cgraph_node_name (cs->callee)));
 
-      ipa_modify_call_arguments (cs, cs->call_stmt, adjustments);
+      ipa_modify_call_arguments (cs, cs->call_stmt, *adjustments);
 
       pop_cfun ();
     }
 
   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->symbol.decl)))
+      compute_inline_parameters (cs->caller, true);
   BITMAP_FREE (recomputed_callers);
 
-  current_function_decl = old_cur_fndecl;
+  return true;
+}
+
+/* Convert all callers of NODE to pass parameters as given in ADJUSTMENTS.  */
+
+static void
+convert_callers (struct cgraph_node *node, tree old_decl,
+                ipa_parm_adjustment_vec adjustments)
+{
+  basic_block this_block;
+
+  cgraph_for_node_and_aliases (node, convert_callers_for_node,
+                              &adjustments, false);
 
   if (!encountered_recursive_call)
     return;
@@ -4311,7 +4818,7 @@ convert_callers (struct cgraph_node *node, tree old_decl,
            {
              if (dump_file)
                fprintf (dump_file, "Adjusting recursive call");
-             gimple_call_set_fndecl (stmt, node->decl);
+             gimple_call_set_fndecl (stmt, node->symbol.decl);
              ipa_modify_call_arguments (NULL, stmt, adjustments);
            }
        }
@@ -4327,31 +4834,23 @@ static bool
 modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
 {
   struct cgraph_node *new_node;
-  struct cgraph_edge *cs;
   bool cfg_changed;
-  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);
+  vec<cgraph_edge_p> redirect_callers = collect_callers_of_node (node);
 
   rebuild_cgraph_edges ();
+  free_dominance_info (CDI_DOMINATORS);
   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));
+  new_node = cgraph_function_versioning (node, redirect_callers,
+                                        NULL,
+                                        NULL, false, NULL, NULL, "isra");
+  redirect_callers.release ();
 
+  push_cfun (DECL_STRUCT_FUNCTION (new_node->symbol.decl));
   ipa_modify_formal_parameters (current_function_decl, adjustments, "ISRA");
   cfg_changed = ipa_sra_modify_function_body (adjustments);
   sra_ipa_reset_debug_stmts (adjustments);
-  convert_callers (new_node, node->decl, adjustments);
+  convert_callers (new_node, node->symbol.decl, adjustments);
   cgraph_make_node_local (new_node);
   return cfg_changed;
 }
@@ -4370,7 +4869,14 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
       return false;
     }
 
-  if (!tree_versionable_function_p (node->decl))
+  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->symbol.decl))
     {
       if (dump_file)
        fprintf (dump_file, "Function is not versionable.\n");
@@ -4384,8 +4890,8 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
       return false;
     }
 
-  if ((DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))
-      && node->global.size >= MAX_INLINE_INSNS_AUTO)
+  if ((DECL_COMDAT (node->symbol.decl) || DECL_EXTERNAL (node->symbol.decl))
+      && inline_summary(node)->size >= MAX_INLINE_INSNS_AUTO)
     {
       if (dump_file)
        fprintf (dump_file, "Function too big to be made truly local.\n");
@@ -4407,7 +4913,7 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
       return false;
     }
 
-  if (TYPE_ATTRIBUTES (TREE_TYPE (node->decl)))
+  if (TYPE_ATTRIBUTES (TREE_TYPE (node->symbol.decl)))
     return false;
 
   return true;
@@ -4418,7 +4924,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;
 
@@ -4435,7 +4941,8 @@ ipa_early_sra (void)
       goto simple_out;
     }
 
-  if (!all_callers_have_enough_arguments_p (node))
+  if (cgraph_for_node_and_aliases (node, not_all_callers_have_enough_arguments_p,
+                                  NULL, true))
     {
       if (dump_file)
        fprintf (dump_file, "There are callers with insufficient number of "
@@ -4465,7 +4972,7 @@ ipa_early_sra (void)
     }
 
   adjustments = analyze_all_param_acesses ();
-  if (!adjustments)
+  if (!adjustments.exists ())
     goto out;
   if (dump_file)
     ipa_dump_param_adjustments (dump_file, adjustments, current_function_decl);
@@ -4474,7 +4981,7 @@ ipa_early_sra (void)
     ret = TODO_update_ssa | TODO_cleanup_cfg;
   else
     ret = TODO_update_ssa;
-  VEC_free (ipa_parm_adjustment_t, heap, adjustments);
+  adjustments.release ();
 
   statistics_counter_event (cfun, "Unused parameters deleted",
                            sra_stats.deleted_unused_parameters);
@@ -4505,6 +5012,7 @@ struct gimple_opt_pass pass_early_ipa_sra =
  {
   GIMPLE_PASS,
   "eipa_sra",                          /* name */
+  OPTGROUP_NONE,                        /* optinfo_flags */
   ipa_early_sra_gate,                  /* gate */
   ipa_early_sra,                       /* execute */
   NULL,                                        /* sub */
@@ -4515,8 +5023,6 @@ struct gimple_opt_pass pass_early_ipa_sra =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_dump_cgraph    /* todo_flags_finish */
+  TODO_dump_symtab                     /* todo_flags_finish */
  }
 };
-
-