Fix memory order description in atomic ops built-ins docs.
[gcc.git] / gcc / tree-sra.c
index 8dd5cb497c2498daf061f592fe33dcc44b6c1cfd..4b0d2a8b389492d2009e3f4fd643dba1d3330e35 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, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 2008-2015 Free Software Foundation, Inc.
    Contributed by Martin Jambor <mjambor@suse.cz>
 
 This file is part of GCC.
@@ -74,22 +74,76 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "hash-map.h"
+#include "hash-table.h"
 #include "alloc-pool.h"
 #include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
 #include "tree.h"
+#include "fold-const.h"
+#include "predict.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "tree-eh.h"
+#include "gimple-expr.h"
+#include "is-a.h"
 #include "gimple.h"
-#include "cgraph.h"
-#include "tree-flow.h"
+#include "stor-layout.h"
+#include "gimplify.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
+#include "gimple-walk.h"
+#include "bitmap.h"
+#include "gimple-ssa.h"
+#include "tree-cfg.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
+#include "hashtab.h"
+#include "rtl.h"
+#include "flags.h"
+#include "statistics.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
+#include "expr.h"
+#include "tree-dfa.h"
+#include "tree-ssa.h"
 #include "tree-pass.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
+#include "cgraph.h"
+#include "symbol-summary.h"
 #include "ipa-prop.h"
-#include "statistics.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"
+#include "ipa-utils.h"
+#include "builtins.h"
 
 /* Enumeration of all aggregate reductions we can do.  */
 enum sra_mode { SRA_MODE_EARLY_IPA,   /* early call regularization */
@@ -250,8 +304,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;
@@ -268,21 +320,47 @@ struct assign_link
 /* Alloc pool for allocating assign link structures.  */
 static alloc_pool link_pool;
 
-/* Base (tree) -> Vector (VEC(access_p,heap) *) map.  */
-static struct pointer_map_t *base_access_vec;
+/* Base (tree) -> Vector (vec<access_p> *) map.  */
+static hash_map<tree, auto_vec<access_p> > *base_access_vec;
+
+/* Candidate hash table helpers.  */
+
+struct uid_decl_hasher : typed_noop_remove <tree_node>
+{
+  typedef tree_node *value_type;
+  typedef tree_node *compare_type;
+  static inline hashval_t hash (const tree_node *);
+  static inline bool equal (const tree_node *, const tree_node *);
+};
+
+/* Hash a tree in a uid_decl_map.  */
+
+inline hashval_t
+uid_decl_hasher::hash (const tree_node *item)
+{
+  return item->decl_minimal.uid;
+}
+
+/* Return true if the DECL_UID in both trees are equal.  */
+
+inline bool
+uid_decl_hasher::equal (const tree_node *a, const tree_node *b)
+{
+  return (a->decl_minimal.uid == b->decl_minimal.uid);
+}
 
 /* Set of candidates.  */
 static bitmap candidate_bitmap;
-static htab_t candidates;
+static hash_table<uid_decl_hasher> *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);
tree_node t;
+ t.decl_minimal.uid = uid;
+ return candidates->find_with_hash (&t, static_cast <hashval_t> (uid));
 }
 
 /* Bitmap of candidates which we should try to entirely scalarize away and
@@ -468,16 +546,10 @@ access_has_replacements_p (struct access *acc)
 /* 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;
-
-  slot = pointer_map_contains (base_access_vec, base);
-  if (!slot)
-    return NULL;
-  else
-    return *(VEC (access_p, heap) **) slot;
+  return base_access_vec->get (base);
 }
 
 /* Find an access with required OFFSET and SIZE in a subtree of accesses rooted
@@ -504,13 +576,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
@@ -613,48 +685,35 @@ static void
 sra_initialize (void)
 {
   candidate_bitmap = BITMAP_ALLOC (NULL);
-  candidates = htab_create (VEC_length (tree, cfun->local_decls) / 2,
-                           uid_decl_map_hash, uid_decl_map_eq, NULL);
+  candidates = new hash_table<uid_decl_hasher>
+    (vec_safe_length (cfun->local_decls) / 2);
   should_scalarize_away_bitmap = BITMAP_ALLOC (NULL);
   cannot_scalarize_away_bitmap = BITMAP_ALLOC (NULL);
   gcc_obstack_init (&name_obstack);
   access_pool = create_alloc_pool ("SRA accesses", sizeof (struct access), 16);
   link_pool = create_alloc_pool ("SRA links", sizeof (struct assign_link), 16);
-  base_access_vec = pointer_map_create ();
+  base_access_vec = new hash_map<tree, auto_vec<access_p> >;
   memset (&sra_stats, 0, sizeof (sra_stats));
   encountered_apply_args = false;
   encountered_recursive_call = false;
   encountered_unchangable_recursive_call = false;
 }
 
-/* Hook fed to pointer_map_traverse, deallocate stored vectors.  */
-
-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);
-
-  return true;
-}
-
 /* Deallocate all general structures.  */
 
 static void
 sra_deinitialize (void)
 {
   BITMAP_FREE (candidate_bitmap);
-  htab_delete (candidates);
+  delete candidates;
+  candidates = NULL;
   BITMAP_FREE (should_scalarize_away_bitmap);
   BITMAP_FREE (cannot_scalarize_away_bitmap);
   free_alloc_pool (access_pool);
   free_alloc_pool (link_pool);
   obstack_free (&name_obstack, NULL);
 
-  pointer_map_traverse (base_access_vec, delete_base_accesses, NULL);
-  pointer_map_destroy (base_access_vec);
+  delete base_access_vec;
 }
 
 /* Remove DECL from candidates for SRA and write REASON to the dump file if
@@ -663,9 +722,7 @@ static void
 disqualify_candidate (tree decl, const char *reason)
 {
   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));
+    candidates->remove_elt_with_hash (decl, DECL_UID (decl));
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -709,16 +766,21 @@ type_internals_preclude_sra_p (tree type, const char **msg)
                *msg = "zero structure field size";
                return true;
              }
-           if (!host_integerp (DECL_FIELD_OFFSET (fld), 1))
+           if (!tree_fits_uhwi_p (DECL_FIELD_OFFSET (fld)))
              {
                *msg = "structure field offset not fixed";
                return true;
              }
-           if (!host_integerp (DECL_SIZE (fld), 1))
+           if (!tree_fits_uhwi_p (DECL_SIZE (fld)))
              {
                *msg = "structure field size not fixed";
                return true;
-             }       
+             }
+           if (!tree_fits_shwi_p (bit_position (fld)))
+             {
+               *msg = "structure field size too big";
+               return true;
+             }
            if (AGGREGATE_TYPE_P (ft)
                    && int_bit_position (fld) % BITS_PER_UNIT != 0)
              {
@@ -800,9 +862,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;
   struct access *access;
-  void **slot;
 
   access = (struct access *) pool_alloc (access_pool);
   memset (access, 0, sizeof (struct access));
@@ -810,16 +870,7 @@ create_access_1 (tree base, HOST_WIDE_INT offset, HOST_WIDE_INT size)
   access->offset = offset;
   access->size = size;
 
-  slot = pointer_map_contains (base_access_vec, base);
-  if (slot)
-    vec = (VEC (access_p, heap) *) *slot;
-  else
-    vec = VEC_alloc (access_p, heap, 32);
-
-  VEC_safe_push (access_p, heap, vec, access);
-
-  *((struct VEC (access_p,heap) **)
-       pointer_map_insert (base_access_vec, base)) = vec;
+  base_access_vec->get_or_insert (base).safe_push (access);
 
   return access;
 }
@@ -951,7 +1002,7 @@ completely_scalarize_record (tree base, tree decl, HOST_WIDE_INT offset,
            struct access *access;
            HOST_WIDE_INT size;
 
-           size = tree_low_cst (DECL_SIZE (fld), 1);
+           size = tree_to_uhwi (DECL_SIZE (fld));
            access = create_access_1 (base, pos, size);
            access->expr = nref;
            access->type = ft;
@@ -970,7 +1021,7 @@ completely_scalarize_record (tree base, tree decl, HOST_WIDE_INT offset,
 static void
 completely_scalarize_var (tree var)
 {
-  HOST_WIDE_INT size = tree_low_cst (DECL_SIZE (var), 1);
+  HOST_WIDE_INT size = tree_to_uhwi (DECL_SIZE (var));
   struct access *access;
 
   access = create_access_1 (var, 0, size);
@@ -981,6 +1032,21 @@ completely_scalarize_var (tree var)
   completely_scalarize_record (var, var, 0, var);
 }
 
+/* Return true if REF has an VIEW_CONVERT_EXPR somewhere in it.  */
+
+static inline bool
+contains_view_convert_expr_p (const_tree ref)
+{
+  while (handled_component_p (ref))
+    {
+      if (TREE_CODE (ref) == VIEW_CONVERT_EXPR)
+       return true;
+      ref = TREE_OPERAND (ref, 0);
+    }
+
+  return false;
+}
+
 /* Search the given tree for a declaration by skipping handled components and
    exclude it from the candidates.  */
 
@@ -1029,6 +1095,11 @@ build_access_from_expr_1 (tree expr, gimple stmt, bool write)
                               "component.");
       return NULL;
     }
+  if (TREE_THIS_VOLATILE (expr))
+    {
+      disqualify_base_of_expr (expr, "part of a volatile reference.");
+      return NULL;
+    }
 
   switch (TREE_CODE (expr))
     {
@@ -1079,17 +1150,41 @@ build_access_from_expr (tree expr, gimple stmt, bool write)
   return false;
 }
 
-/* Disqualify LHS and RHS for scalarization if STMT must end its basic block in
-   modes in which it matters, return true iff they have been disqualified.  RHS
-   may be NULL, in that case ignore it.  If we scalarize an aggregate in
-   intra-SRA we may need to add statements after each statement.  This is not
-   possible if a statement unconditionally has to end the basic block.  */
+/* Return the single non-EH successor edge of BB or NULL if there is none or
+   more than one.  */
+
+static edge
+single_non_eh_succ (basic_block bb)
+{
+  edge e, res = NULL;
+  edge_iterator ei;
+
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    if (!(e->flags & EDGE_EH))
+      {
+       if (res)
+         return NULL;
+       res = e;
+      }
+
+  return res;
+}
+
+/* Disqualify LHS and RHS for scalarization if STMT has to terminate its BB and
+   there is no alternative spot where to put statements SRA might need to
+   generate after it.  The spot we are looking for is an edge leading to a
+   single non-EH successor, if it exists and is indeed single.  RHS may be
+   NULL, in that case ignore it.  */
+
 static bool
-disqualify_ops_if_throwing_stmt (gimple stmt, tree lhs, tree rhs)
+disqualify_if_bad_bb_terminating_stmt (gimple stmt, tree lhs, tree rhs)
 {
   if ((sra_mode == SRA_MODE_EARLY_INTRA || sra_mode == SRA_MODE_INTRA)
-      && (stmt_can_throw_internal (stmt) || stmt_ends_bb_p (stmt)))
+      && stmt_ends_bb_p (stmt))
     {
+      if (single_non_eh_succ (gimple_bb (stmt)))
+       return false;
+
       disqualify_base_of_expr (lhs, "LHS of a throwing stmt.");
       if (rhs)
        disqualify_base_of_expr (rhs, "RHS of a throwing stmt.");
@@ -1117,7 +1212,7 @@ build_accesses_from_assign (gimple stmt)
   lhs = gimple_assign_lhs (stmt);
   rhs = gimple_assign_rhs1 (stmt);
 
-  if (disqualify_ops_if_throwing_stmt (stmt, lhs, rhs))
+  if (disqualify_if_bad_bb_terminating_stmt (stmt, lhs, rhs))
     return false;
 
   racc = build_access_from_expr_1 (rhs, stmt, false);
@@ -1160,8 +1255,7 @@ build_accesses_from_assign (gimple stmt)
    GIMPLE_ASM operands with memory constrains which cannot be scalarized.  */
 
 static bool
-asm_visit_addr (gimple stmt ATTRIBUTE_UNUSED, tree op,
-               void *data ATTRIBUTE_UNUSED)
+asm_visit_addr (gimple, tree op, tree, void *)
 {
   op = get_base_address (op);
   if (op
@@ -1172,12 +1266,26 @@ asm_visit_addr (gimple stmt ATTRIBUTE_UNUSED, tree op,
 }
 
 /* Return true iff callsite CALL has at least as many actual arguments as there
-   are formal parameters of the function currently processed by IPA-SRA.  */
+   are formal parameters of the function currently processed by IPA-SRA and
+   that their types match.  */
 
 static inline bool
-callsite_has_enough_arguments_p (gimple call)
+callsite_arguments_match_p (gimple call)
 {
-  return gimple_call_num_args (call) >= (unsigned) func_param_count;
+  if (gimple_call_num_args (call) < (unsigned) func_param_count)
+    return false;
+
+  tree parm;
+  int i;
+  for (parm = DECL_ARGUMENTS (current_function_decl), i = 0;
+       parm;
+       parm = DECL_CHAIN (parm), i++)
+    {
+      tree arg = gimple_call_arg (call, i);
+      if (!useless_type_conversion_p (TREE_TYPE (parm), TREE_TYPE (arg)))
+       return false;
+    }
+  return true;
 }
 
 /* Scan function and look for interesting expressions and create access
@@ -1189,7 +1297,7 @@ scan_function (void)
   basic_block bb;
   bool ret = false;
 
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, cfun)
     {
       gimple_stmt_iterator gsi;
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
@@ -1203,7 +1311,7 @@ scan_function (void)
          switch (gimple_code (stmt))
            {
            case GIMPLE_RETURN:
-             t = gimple_return_retval (stmt);
+             t = gimple_return_retval (as_a <greturn *> (stmt));
              if (t != NULL_TREE)
                ret |= build_access_from_expr (t, stmt, false);
              if (final_bbs)
@@ -1229,11 +1337,10 @@ scan_function (void)
                      if (DECL_BUILT_IN_CLASS (dest) == BUILT_IN_NORMAL
                          && DECL_FUNCTION_CODE (dest) == BUILT_IN_APPLY_ARGS)
                        encountered_apply_args = true;
-                     if (cgraph_get_node (dest)
-                         == cgraph_get_node (current_function_decl))
+                     if (recursive_call_p (current_function_decl, dest))
                        {
                          encountered_recursive_call = true;
-                         if (!callsite_has_enough_arguments_p (stmt))
+                         if (!callsite_arguments_match_p (stmt))
                            encountered_unchangable_recursive_call = true;
                        }
                    }
@@ -1244,26 +1351,29 @@ scan_function (void)
                }
 
              t = gimple_call_lhs (stmt);
-             if (t && !disqualify_ops_if_throwing_stmt (stmt, t, NULL))
+             if (t && !disqualify_if_bad_bb_terminating_stmt (stmt, t, NULL))
                ret |= build_access_from_expr (t, stmt, true);
              break;
 
            case GIMPLE_ASM:
-             walk_stmt_load_store_addr_ops (stmt, NULL, NULL, NULL,
-                                            asm_visit_addr);
-             if (final_bbs)
-               bitmap_set_bit (final_bbs, bb->index);
+             {
+               gasm *asm_stmt = as_a <gasm *> (stmt);
+               walk_stmt_load_store_addr_ops (asm_stmt, NULL, NULL, NULL,
+                                              asm_visit_addr);
+               if (final_bbs)
+                 bitmap_set_bit (final_bbs, bb->index);
 
-             for (i = 0; i < gimple_asm_ninputs (stmt); i++)
-               {
-                 t = TREE_VALUE (gimple_asm_input_op (stmt, i));
-                 ret |= build_access_from_expr (t, stmt, false);
-               }
-             for (i = 0; i < gimple_asm_noutputs (stmt); i++)
-               {
-                 t = TREE_VALUE (gimple_asm_output_op (stmt, i));
-                 ret |= build_access_from_expr (t, stmt, true);
-               }
+               for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++)
+                 {
+                   t = TREE_VALUE (gimple_asm_input_op (asm_stmt, i));
+                   ret |= build_access_from_expr (t, asm_stmt, false);
+                 }
+               for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++)
+                 {
+                   t = TREE_VALUE (gimple_asm_output_op (asm_stmt, i));
+                   ret |= build_access_from_expr (t, asm_stmt, true);
+                 }
+             }
              break;
 
            default:
@@ -1427,7 +1537,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,
@@ -1436,23 +1549,24 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
 {
   tree prev_base = base;
   tree off;
+  tree mem_ref;
   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
      offset such as array[var_index].  */
   if (!base)
     {
-      gimple stmt;
+      gassign *stmt;
       tree tmp, addr;
 
       gcc_checking_assert (gsi);
-      tmp = make_ssa_name (build_pointer_type (TREE_TYPE (prev_base)), NULL);
+      tmp = make_ssa_name (build_pointer_type (TREE_TYPE (prev_base)));
       addr = build_fold_addr_expr (unshare_expr (prev_base));
       STRIP_USELESS_TYPE_CONVERSION (addr);
       stmt = gimple_build_assign (tmp, addr);
@@ -1480,28 +1594,18 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
       base = build_fold_addr_expr (unshare_expr (base));
     }
 
-  /* If prev_base were always an originally performed access
-     we can extract more optimistic alignment information
-     by looking at the access mode.  That would constrain the
-     alignment of base + base_offset which we would need to
-     adjust according to offset.  */
-  if (!get_pointer_alignment_1 (base, &align, &misalign))
-    {
-      gcc_assert (misalign == 0);
-      if (TREE_CODE (prev_base) == MEM_REF
-         || TREE_CODE (prev_base) == TARGET_MEM_REF)
-       align = TYPE_ALIGN (TREE_TYPE (prev_base));
-    }
-  misalign += (tree_to_double_int (off)
-              .sext (TYPE_PRECISION (TREE_TYPE (off))).low
-              * BITS_PER_UNIT);
-  misalign = misalign & (align - 1);
+  misalign = (misalign + offset) & (align - 1);
   if (misalign != 0)
     align = (misalign & -misalign);
-  if (align < TYPE_ALIGN (exp_type))
+  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);
+  mem_ref = fold_build2_loc (loc, MEM_REF, exp_type, base, off);
+  if (TREE_THIS_VOLATILE (prev_base))
+    TREE_THIS_VOLATILE (mem_ref) = 1;
+  if (TREE_SIDE_EFFECTS (prev_base))
+    TREE_SIDE_EFFECTS (mem_ref) = 1;
+  return mem_ref;
 }
 
 /* Construct a memory reference to a part of an aggregate BASE at the given
@@ -1605,14 +1709,14 @@ build_user_friendly_ref_for_offset (tree *res, tree type, HOST_WIDE_INT offset,
                continue;
 
              tr_pos = bit_position (fld);
-             if (!tr_pos || !host_integerp (tr_pos, 1))
+             if (!tr_pos || !tree_fits_uhwi_p (tr_pos))
                continue;
-             pos = TREE_INT_CST_LOW (tr_pos);
+             pos = tree_to_uhwi (tr_pos);
              gcc_assert (TREE_CODE (type) == RECORD_TYPE || pos == 0);
              tr_size = DECL_SIZE (fld);
-             if (!tr_size || !host_integerp (tr_size, 1))
+             if (!tr_size || !tree_fits_uhwi_p (tr_size))
                continue;
-             size = TREE_INT_CST_LOW (tr_size);
+             size = tree_to_uhwi (tr_size);
              if (size == 0)
                {
                  if (pos != offset)
@@ -1635,9 +1739,9 @@ build_user_friendly_ref_for_offset (tree *res, tree type, HOST_WIDE_INT offset,
 
        case ARRAY_TYPE:
          tr_size = TYPE_SIZE (TREE_TYPE (type));
-         if (!tr_size || !host_integerp (tr_size, 1))
+         if (!tr_size || !tree_fits_uhwi_p (tr_size))
            return false;
-         el_size = tree_low_cst (tr_size, 1);
+         el_size = tree_to_uhwi (tr_size);
 
          minidx = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
          if (TREE_CODE (minidx) != INTEGER_CST || el_size == 0)
@@ -1691,7 +1795,7 @@ maybe_add_sra_candidate (tree var)
 {
   tree type = TREE_TYPE (var);
   const char *msg;
-  void **slot;
+  tree_node **slot;
 
   if (!AGGREGATE_TYPE_P (type)) 
     {
@@ -1713,12 +1817,12 @@ maybe_add_sra_candidate (tree var)
       reject (var, "has incomplete type");
       return false;
     }
-  if (!host_integerp (TYPE_SIZE (type), 1))
+  if (!tree_fits_uhwi_p (TYPE_SIZE (type)))
     {
       reject (var, "type size not fixed");
       return false;
     }
-  if (tree_low_cst (TYPE_SIZE (type), 1) == 0)
+  if (tree_to_uhwi (TYPE_SIZE (type)) == 0)
     {
       reject (var, "type size is zero");
       return false;
@@ -1739,8 +1843,8 @@ maybe_add_sra_candidate (tree var)
     }
 
   bitmap_set_bit (candidate_bitmap, DECL_UID (var));
-  slot = htab_find_slot_with_hash (candidates, var, DECL_UID (var), INSERT);
-  *slot = (void *) var;
+  slot = candidates->find_slot_with_hash (var, DECL_UID (var), INSERT);
+  *slot = var;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -1789,22 +1893,22 @@ 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
@@ -1834,7 +1938,7 @@ 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)
@@ -1889,7 +1993,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;
 }
 
@@ -1904,11 +2008,15 @@ create_access_replacement (struct access *access)
 
   if (access->grp_to_be_debug_replaced)
     {
-      repl = create_tmp_var_raw (access->type, NULL);
+      repl = create_tmp_var_raw (access->type);
       DECL_CONTEXT (repl) = current_function_decl;
     }
   else
-    repl = create_tmp_var (access->type, "SR");
+    /* Drop any special alignment on the type if it's not on the main
+       variant.  This avoids issues with weirdo ABIs like AAPCS.  */
+    repl = create_tmp_var (build_qualified_type
+                            (TYPE_MAIN_VARIANT (access->type),
+                             TYPE_QUALS (access->type)), "SR");
   if (TREE_CODE (access->type) == COMPLEX_TYPE
       || TREE_CODE (access->type) == VECTOR_TYPE)
     {
@@ -1928,7 +2036,7 @@ create_access_replacement (struct access *access)
       && !DECL_ARTIFICIAL (access->base))
     {
       char *pretty_name = make_fancy_name (access->expr);
-      tree debug_expr = unshare_expr (access->expr), d;
+      tree debug_expr = unshare_expr_without_location (access->expr), d;
       bool fail = false;
 
       DECL_NAME (repl) = get_identifier (pretty_name);
@@ -1972,7 +2080,7 @@ create_access_replacement (struct access *access)
       if (!fail)
        {
          SET_DECL_DEBUG_EXPR (repl, debug_expr);
-         DECL_DEBUG_EXPR_IS_FROM (repl) = 1;
+         DECL_HAS_DEBUG_EXPR_P (repl) = 1;
        }
       if (access->grp_no_warning)
        TREE_NO_WARNING (repl) = 1;
@@ -2011,8 +2119,7 @@ create_access_replacement (struct access *access)
 static inline tree
 get_access_replacement (struct access *access)
 {
-  if (!access->replacement_decl)
-    access->replacement_decl = create_access_replacement (access);
+  gcc_checking_assert (access->replacement_decl);
   return access->replacement_decl;
 }
 
@@ -2074,7 +2181,7 @@ expr_with_var_bounded_array_refs_p (tree expr)
   while (handled_component_p (expr))
     {
       if (TREE_CODE (expr) == ARRAY_REF
-         && !host_integerp (array_ref_low_bound (expr), 0))
+         && !tree_fits_shwi_p (array_ref_low_bound (expr)))
        return true;
       expr = TREE_OPERAND (expr, 0);
     }
@@ -2168,7 +2275,6 @@ analyze_access_subtree (struct access *root, struct access *parent,
          || ((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.  */
@@ -2187,41 +2293,37 @@ analyze_access_subtree (struct access *root, struct access *parent,
          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 ",
-                  (unsigned) root->offset, (unsigned) root->size);
-         fprintf (dump_file, " to be replaced%s.\n",
-                  new_integer_type ? " with an integer": "");
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             fprintf (dump_file, "Changing the type of a replacement for ");
+             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 an integer.\n");
+           }
        }
 
       root->grp_to_be_replaced = 1;
+      root->replacement_decl = create_access_replacement (root);
       sth_created = true;
       hole = false;
     }
   else
     {
-      if (MAY_HAVE_DEBUG_STMTS && allow_replacements
+      if (allow_replacements
          && scalar && !root->first_child
-         && (root->grp_scalar_write || root->grp_assignment_write))
+         && (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);
-         root->grp_to_be_debug_replaced = 1;
-         if (dump_file && (dump_flags & TDF_DETAILS))
+         sth_created = true;
+         if (MAY_HAVE_DEBUG_STMTS)
            {
-             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");
+             root->grp_to_be_debug_replaced = 1;
+             root->replacement_decl = create_access_replacement (root);
            }
        }
 
@@ -2231,17 +2333,11 @@ analyze_access_subtree (struct access *root, struct access *parent,
        root->grp_total_scalarization = 0;
     }
 
-  if (sth_created
-      && (!hole || root->grp_total_scalarization))
-    {
-      root->grp_covered = 1;
-      return true;
-    }
-  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
@@ -2440,10 +2536,12 @@ analyze_all_variable_accesses (void)
   int res = 0;
   bitmap tmp = BITMAP_ALLOC (NULL);
   bitmap_iterator bi;
-  unsigned i, max_total_scalarization_size;
-
-  max_total_scalarization_size = UNITS_PER_WORD * BITS_PER_UNIT
-    * MOVE_RATIO (optimize_function_for_speed_p (cfun));
+  unsigned i;
+  unsigned max_scalarization_size
+    = (optimize_function_for_size_p (cfun)
+       ? PARAM_VALUE (PARAM_SRA_MAX_SCALARIZATION_SIZE_SIZE)
+       : PARAM_VALUE (PARAM_SRA_MAX_SCALARIZATION_SIZE_SPEED))
+      * BITS_PER_UNIT;
 
   EXECUTE_IF_SET_IN_BITMAP (candidate_bitmap, 0, i, bi)
     if (bitmap_bit_p (should_scalarize_away_bitmap, i)
@@ -2454,8 +2552,8 @@ analyze_all_variable_accesses (void)
        if (TREE_CODE (var) == VAR_DECL
            && type_consists_of_records_p (TREE_TYPE (var)))
          {
-           if ((unsigned) tree_low_cst (TYPE_SIZE (TREE_TYPE (var)), 1)
-               <= max_total_scalarization_size)
+           if (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (var)))
+               <= max_scalarization_size)
              {
                completely_scalarize_var (var);
                if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2552,7 +2650,7 @@ generate_subtree_copies (struct access *access, tree agg,
              || access->offset + access->size > start_offset))
        {
          tree expr, repl = get_access_replacement (access);
-         gimple stmt;
+         gassign *stmt;
 
          expr = build_ref_for_model (loc, agg, access->offset - top_offset,
                                      access, gsi, insert_after);
@@ -2590,7 +2688,7 @@ generate_subtree_copies (struct access *access, tree agg,
               && (chunk_size == 0
                   || access->offset + access->size > start_offset))
        {
-         gimple ds;
+         gdebug *ds;
          tree drhs = build_debug_ref_for_model (loc, agg,
                                                 access->offset - top_offset,
                                                 access);
@@ -2626,7 +2724,7 @@ init_subtree_with_zero (struct access *access, gimple_stmt_iterator *gsi,
 
   if (access->grp_to_be_replaced)
     {
-      gimple stmt;
+      gassign *stmt;
 
       stmt = gimple_build_assign (get_access_replacement (access),
                                  build_zero_cst (access->type));
@@ -2639,9 +2737,10 @@ init_subtree_with_zero (struct access *access, gimple_stmt_iterator *gsi,
     }
   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));
+      gdebug *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
@@ -2652,6 +2751,37 @@ init_subtree_with_zero (struct access *access, gimple_stmt_iterator *gsi,
     init_subtree_with_zero (child, gsi, insert_after, loc);
 }
 
+/* Clobber all scalar replacements in an access subtree.  ACCESS is the the
+   root of the subtree to be processed.  GSI is the statement iterator used
+   for inserting statements which are added after the current statement if
+   INSERT_AFTER is true or before it otherwise.  */
+
+static void
+clobber_subtree (struct access *access, gimple_stmt_iterator *gsi,
+               bool insert_after, location_t loc)
+
+{
+  struct access *child;
+
+  if (access->grp_to_be_replaced)
+    {
+      tree rep = get_access_replacement (access);
+      tree clobber = build_constructor (access->type, NULL);
+      TREE_THIS_VOLATILE (clobber) = 1;
+      gimple stmt = gimple_build_assign (rep, clobber);
+
+      if (insert_after)
+       gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
+      else
+       gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
+      update_stmt (stmt);
+      gimple_set_location (stmt, loc);
+    }
+
+  for (child = access->first_child; child; child = child->next_sibling)
+    clobber_subtree (child, gsi, insert_after, loc);
+}
+
 /* Search for an access representative for the given expression EXPR and
    return it or NULL if it cannot be found.  */
 
@@ -2688,7 +2818,7 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
 {
   location_t loc;
   struct access *access;
-  tree type, bfr;
+  tree type, bfr, orig_expr;
 
   if (TREE_CODE (*expr) == BIT_FIELD_REF)
     {
@@ -2704,8 +2834,16 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
   if (!access)
     return false;
   type = TREE_TYPE (*expr);
+  orig_expr = *expr;
 
   loc = gimple_location (gsi_stmt (*gsi));
+  gimple_stmt_iterator alt_gsi = gsi_none ();
+  if (write && stmt_ends_bb_p (gsi_stmt (*gsi)))
+    {
+      alt_gsi = gsi_start_edge (single_non_eh_succ (gsi_bb (*gsi)));
+      gsi = &alt_gsi;
+    }
+
   if (access->grp_to_be_replaced)
     {
       tree repl = get_access_replacement (access);
@@ -2723,12 +2861,11 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
        {
          tree ref;
 
-         ref = build_ref_for_model (loc, access->base, access->offset, access,
-                                    NULL, false);
+         ref = build_ref_for_model (loc, orig_expr, 0, access, gsi, false);
 
          if (write)
            {
-             gimple stmt;
+             gassign *stmt;
 
              if (access->grp_partial_lhs)
                ref = force_gimple_operand_gsi (gsi, ref, true, NULL_TREE,
@@ -2739,7 +2876,7 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
            }
          else
            {
-             gimple stmt;
+             gassign *stmt;
 
              if (access->grp_partial_lhs)
                repl = force_gimple_operand_gsi (gsi, repl, true, NULL_TREE,
@@ -2755,9 +2892,9 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
     }
   else if (write && access->grp_to_be_debug_replaced)
     {
-      gimple ds = gimple_build_debug_bind (get_access_replacement (access),
-                                          NULL_TREE,
-                                          gsi_stmt (*gsi));
+      gdebug *ds = gimple_build_debug_bind (get_access_replacement (access),
+                                           NULL_TREE,
+                                           gsi_stmt (*gsi));
       gsi_insert_after (gsi, ds, GSI_NEW_STMT);
     }
 
@@ -2765,17 +2902,17 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
     {
       HOST_WIDE_INT start_offset, chunk_size;
       if (bfr
-         && host_integerp (TREE_OPERAND (bfr, 1), 1)
-         && host_integerp (TREE_OPERAND (bfr, 2), 1))
+         && tree_fits_uhwi_p (TREE_OPERAND (bfr, 1))
+         && tree_fits_uhwi_p (TREE_OPERAND (bfr, 2)))
        {
-         chunk_size = tree_low_cst (TREE_OPERAND (bfr, 1), 1);
+         chunk_size = tree_to_uhwi (TREE_OPERAND (bfr, 1));
          start_offset = access->offset
-           + tree_low_cst (TREE_OPERAND (bfr, 2), 1);
+           + tree_to_uhwi (TREE_OPERAND (bfr, 2));
        }
       else
        start_offset = chunk_size = 0;
 
-      generate_subtree_copies (access->first_child, access->base, 0,
+      generate_subtree_copies (access->first_child, orig_expr, access->offset,
                               start_offset, chunk_size, gsi, write, write,
                               loc);
     }
@@ -2789,128 +2926,157 @@ enum unscalarized_data_handling { SRA_UDH_NONE,  /* Nothing done so far. */
                                  SRA_UDH_RIGHT, /* Data flushed to the RHS. */
                                  SRA_UDH_LEFT }; /* Data flushed to the LHS. */
 
+struct subreplacement_assignment_data
+{
+  /* Offset of the access representing the lhs of the assignment.  */
+  HOST_WIDE_INT left_offset;
+
+  /* LHS and RHS of the original assignment.  */
+  tree assignment_lhs, assignment_rhs;
+
+  /* Access representing the rhs of the whole assignment.  */
+  struct access *top_racc;
+
+  /* Stmt iterator used for statement insertions after the original assignment.
+   It points to the main GSI used to traverse a BB during function body
+   modification.  */
+  gimple_stmt_iterator *new_gsi;
+
+  /* Stmt iterator used for statement insertions before the original
+   assignment.  Keeps on pointing to the original statement.  */
+  gimple_stmt_iterator old_gsi;
+
+  /* Location of the assignment.   */
+  location_t loc;
+
+  /* Keeps the information whether we have needed to refresh replacements of
+   the LHS and from which side of the assignments this takes place.  */
+  enum unscalarized_data_handling refreshed;
+};
+
 /* Store all replacements in the access tree rooted in TOP_RACC either to their
    base aggregate if there are unscalarized data or directly to LHS of the
    statement that is pointed to by GSI otherwise.  */
 
-static enum unscalarized_data_handling
-handle_unscalarized_data_in_subtree (struct access *top_racc,
-                                    gimple_stmt_iterator *gsi)
+static void
+handle_unscalarized_data_in_subtree (struct subreplacement_assignment_data *sad)
 {
-  if (top_racc->grp_unscalarized_data)
+  tree src;
+  if (sad->top_racc->grp_unscalarized_data)
     {
-      generate_subtree_copies (top_racc->first_child, top_racc->base, 0, 0, 0,
-                              gsi, false, false,
-                              gimple_location (gsi_stmt (*gsi)));
-      return SRA_UDH_RIGHT;
+      src = sad->assignment_rhs;
+      sad->refreshed = SRA_UDH_RIGHT;
     }
   else
     {
-      tree lhs = gimple_assign_lhs (gsi_stmt (*gsi));
-      generate_subtree_copies (top_racc->first_child, lhs, top_racc->offset,
-                              0, 0, gsi, false, false,
-                              gimple_location (gsi_stmt (*gsi)));
-      return SRA_UDH_LEFT;
+      src = sad->assignment_lhs;
+      sad->refreshed = SRA_UDH_LEFT;
     }
+  generate_subtree_copies (sad->top_racc->first_child, src,
+                          sad->top_racc->offset, 0, 0,
+                          &sad->old_gsi, false, false, sad->loc);
 }
 
-
 /* Try to generate statements to load all sub-replacements in an access subtree
-   formed by children of LACC from scalar replacements in the TOP_RACC subtree.
-   If that is not possible, refresh the TOP_RACC base aggregate and load the
-   accesses from it.  LEFT_OFFSET is the offset of the left whole subtree being
-   copied. NEW_GSI is stmt iterator used for statement insertions after the
-   original assignment, OLD_GSI is used to insert statements before the
-   assignment.  *REFRESHED keeps the information whether we have needed to
-   refresh replacements of the LHS and from which side of the assignments this
-   takes place.  */
+   formed by children of LACC from scalar replacements in the SAD->top_racc
+   subtree.  If that is not possible, refresh the SAD->top_racc base aggregate
+   and load the accesses from it.  */
 
 static void
-load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
-                                HOST_WIDE_INT left_offset,
-                                gimple_stmt_iterator *old_gsi,
-                                gimple_stmt_iterator *new_gsi,
-                                enum unscalarized_data_handling *refreshed)
+load_assign_lhs_subreplacements (struct access *lacc,
+                                struct subreplacement_assignment_data *sad)
 {
-  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;
+      HOST_WIDE_INT offset;
+      offset = lacc->offset - sad->left_offset + sad->top_racc->offset;
 
       if (lacc->grp_to_be_replaced)
        {
          struct access *racc;
-         gimple stmt;
+         gassign *stmt;
          tree rhs;
 
-         racc = find_access_in_subtree (top_racc, offset, lacc->size);
+         racc = find_access_in_subtree (sad->top_racc, offset, lacc->size);
          if (racc && racc->grp_to_be_replaced)
            {
              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);
+               rhs = fold_build1_loc (sad->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);
+               rhs = force_gimple_operand_gsi (&sad->old_gsi, rhs, true,
+                                               NULL_TREE, true, GSI_SAME_STMT);
            }
          else
            {
              /* No suitable access on the right hand side, need to load from
                 the aggregate.  See if we have to update it first... */
-             if (*refreshed == SRA_UDH_NONE)
-               *refreshed = handle_unscalarized_data_in_subtree (top_racc,
-                                                                 old_gsi);
+             if (sad->refreshed == SRA_UDH_NONE)
+               handle_unscalarized_data_in_subtree (sad);
 
-             if (*refreshed == SRA_UDH_LEFT)
-               rhs = build_ref_for_model (loc, lacc->base, lacc->offset, lacc,
-                                           new_gsi, true);
+             if (sad->refreshed == SRA_UDH_LEFT)
+               rhs = build_ref_for_model (sad->loc, sad->assignment_lhs,
+                                          lacc->offset - sad->left_offset,
+                                          lacc, sad->new_gsi, true);
              else
-               rhs = build_ref_for_model (loc, top_racc->base, offset, lacc,
-                                           new_gsi, true);
+               rhs = build_ref_for_model (sad->loc, sad->assignment_rhs,
+                                          lacc->offset - sad->left_offset,
+                                          lacc, sad->new_gsi, true);
              if (lacc->grp_partial_lhs)
-               rhs = force_gimple_operand_gsi (new_gsi, rhs, true, NULL_TREE,
+               rhs = force_gimple_operand_gsi (sad->new_gsi,
+                                               rhs, true, NULL_TREE,
                                                false, GSI_NEW_STMT);
            }
 
          stmt = gimple_build_assign (get_access_replacement (lacc), rhs);
-         gsi_insert_after (new_gsi, stmt, GSI_NEW_STMT);
-         gimple_set_location (stmt, loc);
+         gsi_insert_after (sad->new_gsi, stmt, GSI_NEW_STMT);
+         gimple_set_location (stmt, sad->loc);
          update_stmt (stmt);
          sra_stats.subreplacements++;
        }
       else
        {
-         if (*refreshed == SRA_UDH_NONE
+         if (sad->refreshed == SRA_UDH_NONE
              && lacc->grp_read && !lacc->grp_covered)
-           *refreshed = handle_unscalarized_data_in_subtree (top_racc,
-                                                             old_gsi);
+           handle_unscalarized_data_in_subtree (sad);
+
          if (lacc && lacc->grp_to_be_debug_replaced)
            {
-             gimple ds;
+             gdebug *ds;
              tree drhs;
-             struct access *racc = find_access_in_subtree (top_racc, offset,
+             struct access *racc = find_access_in_subtree (sad->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);
+               {
+                 if (racc->grp_write)
+                   drhs = get_access_replacement (racc);
+                 else
+                   drhs = NULL;
+               }
+             else if (sad->refreshed == SRA_UDH_LEFT)
+               drhs = build_debug_ref_for_model (sad->loc, lacc->base,
+                                                 lacc->offset, lacc);
+             else if (sad->refreshed == SRA_UDH_RIGHT)
+               drhs = build_debug_ref_for_model (sad->loc, sad->top_racc->base,
+                                                 offset, lacc);
              else
                drhs = NULL_TREE;
+             if (drhs
+                 && !useless_type_conversion_p (lacc->type, TREE_TYPE (drhs)))
+               drhs = fold_build1_loc (sad->loc, VIEW_CONVERT_EXPR,
+                                       lacc->type, drhs);
              ds = gimple_build_debug_bind (get_access_replacement (lacc),
-                                           drhs, gsi_stmt (*old_gsi));
-             gsi_insert_after (new_gsi, ds, GSI_NEW_STMT);
+                                           drhs, gsi_stmt (sad->old_gsi));
+             gsi_insert_after (sad->new_gsi, ds, GSI_NEW_STMT);
            }
        }
 
       if (lacc->first_child)
-       load_assign_lhs_subreplacements (lacc, top_racc, left_offset,
-                                        old_gsi, new_gsi, refreshed);
+       load_assign_lhs_subreplacements (lacc, sad);
     }
 }
 
@@ -2925,39 +3091,36 @@ enum assignment_mod_result { SRA_AM_NONE,       /* nothing done for the stmt */
    the same values as sra_modify_assign.  */
 
 static enum assignment_mod_result
-sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
+sra_modify_constructor_assign (gimple stmt, gimple_stmt_iterator *gsi)
 {
-  tree lhs = gimple_assign_lhs (*stmt);
-  struct access *acc;
-  location_t loc;
-
-  acc = get_access_for_expr (lhs);
+  tree lhs = gimple_assign_lhs (stmt);
+  struct access *acc = get_access_for_expr (lhs);
   if (!acc)
     return SRA_AM_NONE;
+  location_t loc = gimple_location (stmt);
 
-  if (gimple_clobber_p (*stmt))
+  if (gimple_clobber_p (stmt))
     {
-      /* Remove clobbers of fully scalarized variables, otherwise
-        do nothing.  */
+      /* Clobber the replacement variable.  */
+      clobber_subtree (acc, gsi, !acc->grp_covered, loc);
+      /* Remove clobbers of fully scalarized variables, they are dead.  */
       if (acc->grp_covered)
        {
-         unlink_stmt_vdef (*stmt);
+         unlink_stmt_vdef (stmt);
          gsi_remove (gsi, true);
-         release_defs (*stmt);
+         release_defs (stmt);
          return SRA_AM_REMOVED;
        }
       else
-       return SRA_AM_NONE;
+       return SRA_AM_MODIFIED;
     }
 
-  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.  */
       if (access_has_children_p (acc))
-       generate_subtree_copies (acc->first_child, acc->base, 0, 0, 0, gsi,
+       generate_subtree_copies (acc->first_child, lhs, acc->offset, 0, 0, gsi,
                                 true, true, loc);
       return SRA_AM_MODIFIED;
     }
@@ -2965,9 +3128,9 @@ sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
   if (acc->grp_covered)
     {
       init_subtree_with_zero (acc, gsi, false, loc);
-      unlink_stmt_vdef (*stmt);
+      unlink_stmt_vdef (stmt);
       gsi_remove (gsi, true);
-      release_defs (*stmt);
+      release_defs (stmt);
       return SRA_AM_REMOVED;
     }
   else
@@ -2984,24 +3147,11 @@ sra_modify_constructor_assign (gimple *stmt, gimple_stmt_iterator *gsi)
 static tree
 get_repl_default_def_ssa_name (struct access *racc)
 {
-  return get_or_create_ssa_default_def (cfun, get_access_replacement (racc));
-}
-
-/* Return true if REF has a COMPONENT_REF with a bit-field field declaration
-   somewhere in it.  */
-
-static inline bool
-contains_bitfld_comp_ref_p (const_tree ref)
-{
-  while (handled_component_p (ref))
-    {
-      if (TREE_CODE (ref) == COMPONENT_REF
-          && DECL_BIT_FIELD (TREE_OPERAND (ref, 1)))
-        return true;
-      ref = TREE_OPERAND (ref, 0);
-    }
-
-  return false;
+  gcc_checking_assert (!racc->grp_to_be_replaced
+                      && !racc->grp_to_be_debug_replaced);
+  if (!racc->replacement_decl)
+    racc->replacement_decl = create_access_replacement (racc);
+  return get_or_create_ssa_default_def (cfun, racc->replacement_decl);
 }
 
 /* Return true if REF has an VIEW_CONVERT_EXPR or a COMPONENT_REF with a
@@ -3029,7 +3179,7 @@ contains_vce_or_bfcref_p (const_tree ref)
    copying.  */
 
 static enum assignment_mod_result
-sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
+sra_modify_assign (gimple stmt, gimple_stmt_iterator *gsi)
 {
   struct access *lacc, *racc;
   tree lhs, rhs;
@@ -3038,10 +3188,10 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
   location_t loc;
   gimple_stmt_iterator orig_gsi = *gsi;
 
-  if (!gimple_assign_single_p (*stmt))
+  if (!gimple_assign_single_p (stmt))
     return SRA_AM_NONE;
-  lhs = gimple_assign_lhs (*stmt);
-  rhs = gimple_assign_rhs1 (*stmt);
+  lhs = gimple_assign_lhs (stmt);
+  rhs = gimple_assign_rhs1 (stmt);
 
   if (TREE_CODE (rhs) == CONSTRUCTOR)
     return sra_modify_constructor_assign (stmt, gsi);
@@ -3050,9 +3200,9 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
       || TREE_CODE (rhs) == IMAGPART_EXPR || TREE_CODE (lhs) == IMAGPART_EXPR
       || TREE_CODE (rhs) == BIT_FIELD_REF || TREE_CODE (lhs) == BIT_FIELD_REF)
     {
-      modify_this_stmt = sra_modify_expr (gimple_assign_rhs1_ptr (*stmt),
+      modify_this_stmt = sra_modify_expr (gimple_assign_rhs1_ptr (stmt),
                                          gsi, false);
-      modify_this_stmt |= sra_modify_expr (gimple_assign_lhs_ptr (*stmt),
+      modify_this_stmt |= sra_modify_expr (gimple_assign_lhs_ptr (stmt),
                                           gsi, true);
       return modify_this_stmt ? SRA_AM_MODIFIED : SRA_AM_NONE;
     }
@@ -3062,11 +3212,11 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
   if (!lacc && !racc)
     return SRA_AM_NONE;
 
-  loc = gimple_location (*stmt);
+  loc = gimple_location (stmt);
   if (lacc && lacc->grp_to_be_replaced)
     {
       lhs = get_access_replacement (lacc);
-      gimple_assign_set_lhs (*stmt, lhs);
+      gimple_assign_set_lhs (stmt, lhs);
       modify_this_stmt = true;
       if (lacc->grp_partial_lhs)
        force_gimple_rhs = true;
@@ -3099,15 +3249,13 @@ 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))
-             && !contains_bitfld_comp_ref_p (lhs)
-             && !access_has_children_p (lacc))
+             && !contains_bitfld_component_ref_p (lhs))
            {
              lhs = build_ref_for_model (loc, lhs, 0, racc, gsi, false);
-             gimple_assign_set_lhs (*stmt, lhs);
+             gimple_assign_set_lhs (stmt, lhs);
            }
          else if (AGGREGATE_TYPE_P (TREE_TYPE (rhs))
-                  && !contains_vce_or_bfcref_p (rhs)
-                  && !access_has_children_p (racc))
+                  && !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)))
@@ -3123,8 +3271,20 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
 
   if (lacc && lacc->grp_to_be_debug_replaced)
     {
-      gimple ds = gimple_build_debug_bind (get_access_replacement (lacc),
-                                          unshare_expr (rhs), *stmt);
+      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);
+       }
+      gdebug *ds = gimple_build_debug_bind (dlhs, drhs, stmt);
       gsi_insert_before (gsi, ds, GSI_SAME_STMT);
     }
 
@@ -3162,16 +3322,25 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
      This is what the first branch does.  */
 
   if (modify_this_stmt
-      || gimple_has_volatile_ops (*stmt)
+      || gimple_has_volatile_ops (stmt)
       || contains_vce_or_bfcref_p (rhs)
-      || contains_vce_or_bfcref_p (lhs))
+      || contains_vce_or_bfcref_p (lhs)
+      || stmt_ends_bb_p (stmt))
     {
       if (access_has_children_p (racc))
-       generate_subtree_copies (racc->first_child, racc->base, 0, 0, 0,
+       generate_subtree_copies (racc->first_child, rhs, racc->offset, 0, 0,
                                 gsi, false, false, loc);
       if (access_has_children_p (lacc))
-       generate_subtree_copies (lacc->first_child, lacc->base, 0, 0, 0,
-                                gsi, true, true, loc);
+       {
+         gimple_stmt_iterator alt_gsi = gsi_none ();
+         if (stmt_ends_bb_p (stmt))
+           {
+             alt_gsi = gsi_start_edge (single_non_eh_succ (gsi_bb (*gsi)));
+             gsi = &alt_gsi;
+           }
+         generate_subtree_copies (lacc->first_child, lhs, lacc->offset, 0, 0,
+                                  gsi, true, true, loc);
+       }
       sra_stats.separate_lhs_rhs_handling++;
 
       /* This gimplification must be done after generate_subtree_copies,
@@ -3180,11 +3349,11 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
       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)
+      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));
+         gcc_assert (stmt == gsi_stmt (orig_gsi));
        }
 
       return modify_this_stmt ? SRA_AM_MODIFIED : SRA_AM_NONE;
@@ -3199,22 +3368,27 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
          && !lacc->grp_unscalarizable_region
          && !racc->grp_unscalarizable_region)
        {
-         gimple_stmt_iterator orig_gsi = *gsi;
-         enum unscalarized_data_handling refreshed;
+         struct subreplacement_assignment_data sad;
+
+         sad.left_offset = lacc->offset;
+         sad.assignment_lhs = lhs;
+         sad.assignment_rhs = rhs;
+         sad.top_racc = racc;
+         sad.old_gsi = *gsi;
+         sad.new_gsi = gsi;
+         sad.loc = gimple_location (stmt);
+         sad.refreshed = SRA_UDH_NONE;
 
          if (lacc->grp_read && !lacc->grp_covered)
-           refreshed = handle_unscalarized_data_in_subtree (racc, gsi);
-         else
-           refreshed = SRA_UDH_NONE;
+           handle_unscalarized_data_in_subtree (&sad);
 
-         load_assign_lhs_subreplacements (lacc, racc, lacc->offset,
-                                          &orig_gsi, gsi, &refreshed);
-         if (refreshed != SRA_UDH_RIGHT)
+         load_assign_lhs_subreplacements (lacc, &sad);
+         if (sad.refreshed != SRA_UDH_RIGHT)
            {
              gsi_next (gsi);
-             unlink_stmt_vdef (*stmt);
-             gsi_remove (&orig_gsi, true);
-             release_defs (*stmt);
+             unlink_stmt_vdef (stmt);
+             gsi_remove (&sad.old_gsi, true);
+             release_defs (stmt);
              sra_stats.deleted++;
              return SRA_AM_REMOVED;
            }
@@ -3227,22 +3401,22 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
              if (dump_file)
                {
                  fprintf (dump_file, "Removing load: ");
-                 print_gimple_stmt (dump_file, *stmt, 0, 0);
+                 print_gimple_stmt (dump_file, stmt, 0, 0);
                }
              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);
+             gcc_assert (stmt == gsi_stmt (*gsi));
+             unlink_stmt_vdef (stmt);
              gsi_remove (gsi, true);
-             release_defs (*stmt);
+             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,
+           generate_subtree_copies (racc->first_child, rhs, racc->offset, 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
@@ -3266,7 +3440,7 @@ sra_modify_function_body (void)
   bool cfg_changed = false;
   basic_block bb;
 
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, cfun)
     {
       gimple_stmt_iterator gsi = gsi_start_bb (bb);
       while (!gsi_end_p (gsi))
@@ -3280,13 +3454,13 @@ sra_modify_function_body (void)
          switch (gimple_code (stmt))
            {
            case GIMPLE_RETURN:
-             t = gimple_return_retval_ptr (stmt);
+             t = gimple_return_retval_ptr (as_a <greturn *> (stmt));
              if (*t != NULL_TREE)
                modified |= sra_modify_expr (t, &gsi, false);
              break;
 
            case GIMPLE_ASSIGN:
-             assign_result = sra_modify_assign (&stmt, &gsi);
+             assign_result = sra_modify_assign (stmt, &gsi);
              modified |= assign_result == SRA_AM_MODIFIED;
              deleted = assign_result == SRA_AM_REMOVED;
              break;
@@ -3307,16 +3481,19 @@ sra_modify_function_body (void)
              break;
 
            case GIMPLE_ASM:
-             for (i = 0; i < gimple_asm_ninputs (stmt); i++)
-               {
-                 t = &TREE_VALUE (gimple_asm_input_op (stmt, i));
-                 modified |= sra_modify_expr (t, &gsi, false);
-               }
-             for (i = 0; i < gimple_asm_noutputs (stmt); i++)
-               {
-                 t = &TREE_VALUE (gimple_asm_output_op (stmt, i));
-                 modified |= sra_modify_expr (t, &gsi, true);
-               }
+             {
+               gasm *asm_stmt = as_a <gasm *> (stmt);
+               for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++)
+                 {
+                   t = &TREE_VALUE (gimple_asm_input_op (asm_stmt, i));
+                   modified |= sra_modify_expr (t, &gsi, false);
+                 }
+               for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++)
+                 {
+                   t = &TREE_VALUE (gimple_asm_output_op (asm_stmt, i));
+                   modified |= sra_modify_expr (t, &gsi, true);
+                 }
+             }
              break;
 
            default:
@@ -3335,6 +3512,7 @@ sra_modify_function_body (void)
        }
     }
 
+  gsi_commit_edge_inserts ();
   return cfg_changed;
 }
 
@@ -3353,7 +3531,7 @@ initialize_parameter_reductions (void)
        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)))
@@ -3362,7 +3540,7 @@ initialize_parameter_reductions (void)
       if (!access_vec)
        continue;
 
-      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,
@@ -3371,7 +3549,7 @@ initialize_parameter_reductions (void)
 
   seq = gsi_seq (gsi);
   if (seq)
-    gsi_insert_seq_on_edge_immediate (single_succ_edge (ENTRY_BLOCK_PTR), seq);
+    gsi_insert_seq_on_edge_immediate (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)), seq);
 }
 
 /* The "main" function of intraprocedural SRA passes.  Runs the analysis and if
@@ -3438,50 +3616,78 @@ gate_intra_sra (void)
 }
 
 
-struct gimple_opt_pass pass_sra_early =
+namespace {
+
+const pass_data pass_data_sra_early =
 {
- {
-  GIMPLE_PASS,
-  "esra",                              /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_intra_sra,                      /* gate */
-  early_intra_sra,                     /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_TREE_SRA,                         /* tv_id */
-  PROP_cfg | PROP_ssa,                  /* properties_required */
-  0,                                   /* properties_provided */
-  0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  TODO_update_ssa
-  | TODO_ggc_collect
-  | TODO_verify_ssa                    /* todo_flags_finish */
- }
+  GIMPLE_PASS, /* type */
+  "esra", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_SRA, /* tv_id */
+  ( PROP_cfg | PROP_ssa ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_update_ssa, /* todo_flags_finish */
 };
 
-struct gimple_opt_pass pass_sra =
+class pass_sra_early : public gimple_opt_pass
+{
+public:
+  pass_sra_early (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_sra_early, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return gate_intra_sra (); }
+  virtual unsigned int execute (function *) { return early_intra_sra (); }
+
+}; // class pass_sra_early
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_sra_early (gcc::context *ctxt)
+{
+  return new pass_sra_early (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_sra =
 {
- {
-  GIMPLE_PASS,
-  "sra",                               /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_intra_sra,                      /* gate */
-  late_intra_sra,                      /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_TREE_SRA,                         /* tv_id */
-  PROP_cfg | PROP_ssa,                  /* properties_required */
-  0,                                   /* properties_provided */
-  0,                                   /* properties_destroyed */
-  TODO_update_address_taken,           /* todo_flags_start */
-  TODO_update_ssa
-  | TODO_ggc_collect
-  | TODO_verify_ssa                    /* todo_flags_finish */
- }
+  GIMPLE_PASS, /* type */
+  "sra", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_SRA, /* tv_id */
+  ( PROP_cfg | PROP_ssa ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  TODO_update_address_taken, /* todo_flags_start */
+  TODO_update_ssa, /* todo_flags_finish */
 };
 
+class pass_sra : public gimple_opt_pass
+{
+public:
+  pass_sra (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_sra, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return gate_intra_sra (); }
+  virtual unsigned int execute (function *) { return late_intra_sra (); }
+
+}; // class pass_sra
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_sra (gcc::context *ctxt)
+{
+  return new pass_sra (ctxt);
+}
+
 
 /* Return true iff PARM (which must be a parm_decl) is an unused scalar
    parameter.  */
@@ -3594,7 +3800,7 @@ find_param_candidates (void)
        parm = DECL_CHAIN (parm))
     {
       tree type = TREE_TYPE (parm);
-      void **slot;
+      tree_node **slot;
 
       count++;
 
@@ -3626,16 +3832,15 @@ find_param_candidates (void)
        continue;
 
       if (!COMPLETE_TYPE_P (type)
-         || !host_integerp (TYPE_SIZE (type), 1)
-          || tree_low_cst (TYPE_SIZE (type), 1) == 0
+         || !tree_fits_uhwi_p (TYPE_SIZE (type))
+          || tree_to_uhwi (TYPE_SIZE (type)) == 0
          || (AGGREGATE_TYPE_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;
+      slot = candidates->find_slot_with_hash (parm, DECL_UID (parm), INSERT);
+      *slot = parm;
 
       ret = true;
       if (dump_file && (dump_flags & TDF_DETAILS))
@@ -3668,7 +3873,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;
 
@@ -3676,7 +3881,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)
        {
@@ -3715,25 +3920,24 @@ analyze_modified_params (VEC (access_p, heap) *representatives)
 static void
 propagate_dereference_distances (void)
 {
-  VEC (basic_block, heap) *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);
-  FOR_EACH_BB (bb)
+  auto_vec<basic_block> queue (last_basic_block_for_fn (cfun));
+  queue.quick_push (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+  FOR_EACH_BB_FN (bb, cfun)
     {
-      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))
@@ -3749,7 +3953,7 @@ propagate_dereference_distances (void)
          {
            int succ_idx = e->dest->index * func_param_count + i;
 
-           if (e->src == EXIT_BLOCK_PTR)
+           if (e->src == EXIT_BLOCK_PTR_FOR_FN (cfun))
              continue;
 
            if (first)
@@ -3775,11 +3979,9 @@ 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);
 }
 
 /* Dump a dereferences TABLE with heading STR to file F.  */
@@ -3789,11 +3991,12 @@ dump_dereferences_table (FILE *f, const char *str, HOST_WIDE_INT *table)
 {
   basic_block bb;
 
-  fprintf (dump_file, str);
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
+  fprintf (dump_file, "%s", str);
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun),
+                 EXIT_BLOCK_PTR_FOR_FN (cfun), next_bb)
     {
       fprintf (f, "%4i  %i   ", bb->index, bitmap_bit_p (final_bbs, bb->index));
-      if (bb != EXIT_BLOCK_PTR)
+      if (bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
        {
          int i;
          for (i = 0; i < func_param_count; i++)
@@ -3826,7 +4029,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;
 
@@ -3844,8 +4047,8 @@ 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);
-      int idx = ENTRY_BLOCK_PTR->index * func_param_count + i;
+      struct access *repr = representatives[i];
+      int idx = ENTRY_BLOCK_PTR_FOR_FN (cfun)->index * func_param_count + i;
 
       if (!repr || no_accesses_p (repr))
        continue;
@@ -3871,19 +4074,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;
@@ -3896,12 +4099,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
@@ -3913,6 +4117,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;
 }
 
@@ -3930,14 +4138,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;
@@ -3946,9 +4154,9 @@ splice_param_accesses (tree parm, bool *ro_grp)
     {
       bool modification;
       tree a1_alias_type;
-      access = VEC_index (access_p, access_vec, i);
+      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);
 
@@ -3959,7 +4167,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. */
@@ -3971,7 +4179,7 @@ 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)))
@@ -3996,9 +4204,9 @@ splice_param_accesses (tree parm, bool *ro_grp)
     }
 
   if (POINTER_TYPE_P (TREE_TYPE (parm)))
-    agg_size = tree_low_cst (TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm))), 1);
+    agg_size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm))));
   else
-    agg_size = tree_low_cst (TYPE_SIZE (TREE_TYPE (parm)), 1);
+    agg_size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (parm)));
   if (total_size >= agg_size)
     return NULL;
 
@@ -4017,13 +4225,13 @@ decide_one_param_reduction (struct access *repr)
   tree parm;
 
   parm = repr->base;
-  cur_parm_size = tree_low_cst (TYPE_SIZE (TREE_TYPE (parm)), 1);
+  cur_parm_size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (parm)));
   gcc_assert (cur_parm_size > 0);
 
   if (POINTER_TYPE_P (TREE_TYPE (parm)))
     {
       by_ref = true;
-      agg_size = tree_low_cst (TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm))), 1);
+      agg_size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm))));
     }
   else
     {
@@ -4097,13 +4305,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;
@@ -4111,8 +4319,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;
        }
@@ -4121,7 +4328,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;
        }
@@ -4129,7 +4336,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))
            {
@@ -4147,13 +4354,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;
     }
 
@@ -4163,13 +4369,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 ();
 }
@@ -4180,21 +4386,21 @@ 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))
        {
@@ -4204,10 +4410,11 @@ turn_representatives_into_adjustments (VEC (access_p, heap) *representatives,
          adj.base_index = get_param_index (parm, parms);
          adj.base = parm;
          if (!repr)
-           adj.copy_param = 1;
+           adj.op = IPA_PARM_OP_COPY;
          else
-           adj.remove_param = 1;
-         VEC_quick_push (ipa_parm_adjustment_t, adjustments, adj);
+           adj.op = IPA_PARM_OP_REMOVE;
+         adj.arg_prefix = "ISRA";
+         adjustments.quick_push (adj);
        }
       else
        {
@@ -4226,11 +4433,12 @@ turn_representatives_into_adjustments (VEC (access_p, heap) *representatives,
              adj.by_ref = (POINTER_TYPE_P (TREE_TYPE (repr->base))
                            && (repr->grp_maybe_modified
                                || repr->grp_not_necessarilly_dereferenced));
-             VEC_quick_push (ipa_parm_adjustment_t, adjustments, adj);
+             adj.arg_prefix = "ISRA";
+             adjustments.quick_push (adj);
            }
        }
     }
-  VEC_free (tree, heap, parms);
+  parms.release ();
   return adjustments;
 }
 
@@ -4243,12 +4451,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.  */
@@ -4260,7 +4468,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))
        {
@@ -4269,7 +4477,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;
@@ -4282,7 +4490,7 @@ analyze_all_param_acesses (void)
 
              if (new_components == 0)
                {
-                 VEC_replace (access_p, representatives, i, NULL);
+                 representatives[i] = NULL;
                  adjustments_count++;
                }
              else
@@ -4312,9 +4520,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;
 }
 
@@ -4350,13 +4558,13 @@ 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);
-      if (!adj->copy_param && adj->base == base)
+      adj = &adjustments[i];
+      if (adj->op != IPA_PARM_OP_COPY && adj->base == base)
        return adj;
     }
 
@@ -4413,102 +4621,22 @@ replace_removed_params_ssa_names (gimple stmt,
   else if (is_gimple_call (stmt))
     gimple_call_set_lhs (stmt, name);
   else
-    gimple_phi_set_result (stmt, name);
+    gimple_phi_set_result (as_a <gphi *> (stmt), name);
 
   replace_uses_by (lhs, name);
   release_ssa_name (lhs);
   return true;
 }
 
-/* If the expression *EXPR should be replaced by a reduction of a parameter, do
-   so.  ADJUSTMENTS is a pointer to a vector of adjustments.  CONVERT
-   specifies whether the function should care about type incompatibility the
-   current and new expressions.  If it is false, the function will leave
-   incompatibility issues to the caller.  Return true iff the expression
-   was modified. */
-
-static bool
-sra_ipa_modify_expr (tree *expr, bool convert,
-                    ipa_parm_adjustment_vec adjustments)
-{
-  int i, len;
-  struct ipa_parm_adjustment *adj, *cand = NULL;
-  HOST_WIDE_INT offset, size, max_size;
-  tree base, src;
-
-  len = VEC_length (ipa_parm_adjustment_t, adjustments);
-
-  if (TREE_CODE (*expr) == BIT_FIELD_REF
-      || TREE_CODE (*expr) == IMAGPART_EXPR
-      || TREE_CODE (*expr) == REALPART_EXPR)
-    {
-      expr = &TREE_OPERAND (*expr, 0);
-      convert = true;
-    }
-
-  base = get_ref_base_and_extent (*expr, &offset, &size, &max_size);
-  if (!base || size == -1 || max_size == -1)
-    return false;
-
-  if (TREE_CODE (base) == MEM_REF)
-    {
-      offset += mem_ref_offset (base).low * BITS_PER_UNIT;
-      base = TREE_OPERAND (base, 0);
-    }
-
-  base = get_ssa_base_param (base);
-  if (!base || TREE_CODE (base) != PARM_DECL)
-    return false;
-
-  for (i = 0; i < len; i++)
-    {
-      adj = &VEC_index (ipa_parm_adjustment_t, adjustments, i);
-
-      if (adj->base == base &&
-         (adj->offset == offset || adj->remove_param))
-       {
-         cand = adj;
-         break;
-       }
-    }
-  if (!cand || cand->copy_param || cand->remove_param)
-    return false;
-
-  if (cand->by_ref)
-    src = build_simple_mem_ref (cand->reduction);
-  else
-    src = cand->reduction;
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "About to replace expr ");
-      print_generic_expr (dump_file, *expr, 0);
-      fprintf (dump_file, " with ");
-      print_generic_expr (dump_file, src, 0);
-      fprintf (dump_file, "\n");
-    }
-
-  if (convert && !useless_type_conversion_p (TREE_TYPE (*expr), cand->type))
-    {
-      tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*expr), src);
-      *expr = vce;
-    }
-  else
-    *expr = src;
-  return true;
-}
-
-/* If the statement pointed to by STMT_PTR contains any expressions that need
-   to replaced with a different one as noted by ADJUSTMENTS, do so.  Handle any
-   potential type incompatibilities (GSI is used to accommodate conversion
-   statements and must point to the statement).  Return true iff the statement
-   was modified.  */
+/* If the statement STMT contains any expressions that need to replaced with a
+   different one as noted by ADJUSTMENTS, do so.  Handle any potential type
+   incompatibilities (GSI is used to accommodate conversion statements and must
+   point to the statement).  Return true iff the statement was modified.  */
 
 static bool
-sra_ipa_modify_assign (gimple *stmt_ptr, gimple_stmt_iterator *gsi,
+sra_ipa_modify_assign (gimple stmt, gimple_stmt_iterator *gsi,
                       ipa_parm_adjustment_vec adjustments)
 {
-  gimple stmt = *stmt_ptr;
   tree *lhs_p, *rhs_p;
   bool any;
 
@@ -4518,8 +4646,8 @@ sra_ipa_modify_assign (gimple *stmt_ptr, gimple_stmt_iterator *gsi,
   rhs_p = gimple_assign_rhs1_ptr (stmt);
   lhs_p = gimple_assign_lhs_ptr (stmt);
 
-  any = sra_ipa_modify_expr (rhs_p, false, adjustments);
-  any |= sra_ipa_modify_expr (lhs_p, false, adjustments);
+  any = ipa_modify_expr (rhs_p, false, adjustments);
+  any |= ipa_modify_expr (lhs_p, false, adjustments);
   if (any)
     {
       tree new_rhs = NULL_TREE;
@@ -4532,7 +4660,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),
@@ -4564,13 +4693,13 @@ sra_ipa_modify_assign (gimple *stmt_ptr, gimple_stmt_iterator *gsi,
 /* Traverse the function body and all modifications as described in
    ADJUSTMENTS.  Return true iff the CFG has been changed.  */
 
-static bool
+bool
 ipa_sra_modify_function_body (ipa_parm_adjustment_vec adjustments)
 {
   bool cfg_changed = false;
   basic_block bb;
 
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, cfun)
     {
       gimple_stmt_iterator gsi;
 
@@ -4588,13 +4717,13 @@ ipa_sra_modify_function_body (ipa_parm_adjustment_vec adjustments)
          switch (gimple_code (stmt))
            {
            case GIMPLE_RETURN:
-             t = gimple_return_retval_ptr (stmt);
+             t = gimple_return_retval_ptr (as_a <greturn *> (stmt));
              if (*t != NULL_TREE)
-               modified |= sra_ipa_modify_expr (t, true, adjustments);
+               modified |= ipa_modify_expr (t, true, adjustments);
              break;
 
            case GIMPLE_ASSIGN:
-             modified |= sra_ipa_modify_assign (&stmt, &gsi, adjustments);
+             modified |= sra_ipa_modify_assign (stmt, &gsi, adjustments);
              modified |= replace_removed_params_ssa_names (stmt, adjustments);
              break;
 
@@ -4603,29 +4732,32 @@ ipa_sra_modify_function_body (ipa_parm_adjustment_vec adjustments)
              for (i = 0; i < gimple_call_num_args (stmt); i++)
                {
                  t = gimple_call_arg_ptr (stmt, i);
-                 modified |= sra_ipa_modify_expr (t, true, adjustments);
+                 modified |= ipa_modify_expr (t, true, adjustments);
                }
 
              if (gimple_call_lhs (stmt))
                {
                  t = gimple_call_lhs_ptr (stmt);
-                 modified |= sra_ipa_modify_expr (t, false, adjustments);
+                 modified |= ipa_modify_expr (t, false, adjustments);
                  modified |= replace_removed_params_ssa_names (stmt,
                                                                adjustments);
                }
              break;
 
            case GIMPLE_ASM:
-             for (i = 0; i < gimple_asm_ninputs (stmt); i++)
-               {
-                 t = &TREE_VALUE (gimple_asm_input_op (stmt, i));
-                 modified |= sra_ipa_modify_expr (t, true, adjustments);
-               }
-             for (i = 0; i < gimple_asm_noutputs (stmt); i++)
-               {
-                 t = &TREE_VALUE (gimple_asm_output_op (stmt, i));
-                 modified |= sra_ipa_modify_expr (t, false, adjustments);
-               }
+             {
+               gasm *asm_stmt = as_a <gasm *> (stmt);
+               for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++)
+                 {
+                   t = &TREE_VALUE (gimple_asm_input_op (asm_stmt, i));
+                   modified |= ipa_modify_expr (t, true, adjustments);
+                 }
+               for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++)
+                 {
+                   t = &TREE_VALUE (gimple_asm_output_op (asm_stmt, i));
+                   modified |= ipa_modify_expr (t, false, adjustments);
+                 }
+             }
              break;
 
            default:
@@ -4655,28 +4787,37 @@ sra_ipa_reset_debug_stmts (ipa_parm_adjustment_vec adjustments)
   int i, len;
   gimple_stmt_iterator *gsip = NULL, gsi;
 
-  if (MAY_HAVE_DEBUG_STMTS && single_succ_p (ENTRY_BLOCK_PTR))
+  if (MAY_HAVE_DEBUG_STMTS && single_succ_p (ENTRY_BLOCK_PTR_FOR_FN (cfun)))
     {
-      gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR));
+      gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
       gsip = &gsi;
     }
-  len = VEC_length (ipa_parm_adjustment_t, adjustments);
+  len = adjustments.length ();
   for (i = 0; i < len; i++)
     {
       struct ipa_parm_adjustment *adj;
       imm_use_iterator ui;
-      gimple stmt, def_temp;
+      gimple stmt;
+      gdebug *def_temp;
       tree name, vexpr, copy = NULL_TREE;
       use_operand_p use_p;
 
-      adj = &VEC_index (ipa_parm_adjustment_t, adjustments, i);
-      if (adj->copy_param || !is_gimple_reg (adj->base))
+      adj = &adjustments[i];
+      if (adj->op == IPA_PARM_OP_COPY || !is_gimple_reg (adj->base))
        continue;
       name = ssa_default_def (cfun, adj->base);
       vexpr = NULL;
       if (name)
        FOR_EACH_IMM_USE_STMT (stmt, ui, name)
          {
+           if (gimple_clobber_p (stmt))
+             {
+               gimple_stmt_iterator cgsi = gsi_for_stmt (stmt);
+               unlink_stmt_vdef (stmt);
+               gsi_remove (&cgsi, true);
+               release_defs (stmt);
+               continue;
+             }
            /* All other users must have been removed by
               ipa_sra_modify_function_body.  */
            gcc_assert (is_gimple_debug (stmt));
@@ -4737,16 +4878,31 @@ sra_ipa_reset_debug_stmts (ipa_parm_adjustment_vec adjustments)
     }
 }
 
-/* Return false iff all callers have at least as many actual arguments as there
-   are formal parameters in the current function.  */
+/* Return false if all callers have at least as many actual arguments as there
+   are formal parameters in the current function and that their types
+   match.  */
+
+static bool
+some_callers_have_mismatched_arguments_p (struct cgraph_node *node,
+                                         void *data ATTRIBUTE_UNUSED)
+{
+  struct cgraph_edge *cs;
+  for (cs = node->callers; cs; cs = cs->next_caller)
+    if (!cs->call_stmt || !callsite_arguments_match_p (cs->call_stmt))
+      return true;
+
+  return false;
+}
+
+/* Return false if all callers have vuse attached to a call statement.  */
 
 static bool
-not_all_callers_have_enough_arguments_p (struct cgraph_node *node,
-                                        void *data ATTRIBUTE_UNUSED)
+some_callers_have_no_vuse_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))
+    if (!cs->call_stmt || !gimple_vuse (cs->call_stmt))
       return true;
 
   return false;
@@ -4758,28 +4914,29 @@ static bool
 convert_callers_for_node (struct cgraph_node *node,
                          void *data)
 {
-  ipa_parm_adjustment_vec adjustments = (ipa_parm_adjustment_vec)data;
+  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)
     {
-      push_cfun (DECL_STRUCT_FUNCTION (cs->caller->symbol.decl));
+      push_cfun (DECL_STRUCT_FUNCTION (cs->caller->decl));
 
       if (dump_file)
-       fprintf (dump_file, "Adjusting call (%i -> %i) %s -> %s\n",
-                cs->caller->uid, cs->callee->uid,
-                xstrdup (cgraph_node_name (cs->caller)),
-                xstrdup (cgraph_node_name (cs->callee)));
+       fprintf (dump_file, "Adjusting call %s/%i -> %s/%i\n",
+                xstrdup (cs->caller->name ()),
+                cs->caller->order,
+                xstrdup (cs->callee->name ()),
+                cs->callee->order);
 
-      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)
-       && gimple_in_ssa_p (DECL_STRUCT_FUNCTION (cs->caller->symbol.decl)))
+       && gimple_in_ssa_p (DECL_STRUCT_FUNCTION (cs->caller->decl)))
       compute_inline_parameters (cs->caller, true);
   BITMAP_FREE (recomputed_callers);
 
@@ -4794,28 +4951,29 @@ convert_callers (struct cgraph_node *node, tree old_decl,
 {
   basic_block this_block;
 
-  cgraph_for_node_and_aliases (node, convert_callers_for_node,
-                              adjustments, false);
+  node->call_for_symbol_and_aliases (convert_callers_for_node,
+                                    &adjustments, false);
 
   if (!encountered_recursive_call)
     return;
 
-  FOR_EACH_BB (this_block)
+  FOR_EACH_BB_FN (this_block, cfun)
     {
       gimple_stmt_iterator gsi;
 
       for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi))
         {
-         gimple stmt = gsi_stmt (gsi);
+         gcall *stmt;
          tree call_fndecl;
-         if (gimple_code (stmt) != GIMPLE_CALL)
+         stmt = dyn_cast <gcall *> (gsi_stmt (gsi));
+         if (!stmt)
            continue;
          call_fndecl = gimple_call_fndecl (stmt);
          if (call_fndecl == old_decl)
            {
              if (dump_file)
                fprintf (dump_file, "Adjusting recursive call");
-             gimple_call_set_fndecl (stmt, node->symbol.decl);
+             gimple_call_set_fndecl (stmt, node->decl);
              ipa_modify_call_arguments (NULL, stmt, adjustments);
            }
        }
@@ -4832,25 +4990,86 @@ modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
 {
   struct cgraph_node *new_node;
   bool cfg_changed;
-  VEC (cgraph_edge_p, heap) * redirect_callers = collect_callers_of_node (node);
 
-  rebuild_cgraph_edges ();
+  cgraph_edge::rebuild_edges ();
   free_dominance_info (CDI_DOMINATORS);
   pop_cfun ();
 
-  new_node = cgraph_function_versioning (node, redirect_callers, NULL, NULL,
-                                        false, NULL, NULL, "isra");
-  VEC_free (cgraph_edge_p, heap, redirect_callers);
-
-  push_cfun (DECL_STRUCT_FUNCTION (new_node->symbol.decl));
-  ipa_modify_formal_parameters (current_function_decl, adjustments, "ISRA");
+  /* This must be done after rebuilding cgraph edges for node above.
+     Otherwise any recursive calls to node that are recorded in
+     redirect_callers will be corrupted.  */
+  vec<cgraph_edge *> redirect_callers = node->collect_callers ();
+  new_node = node->create_version_clone_with_body (redirect_callers, NULL,
+                                                  NULL, false, NULL, NULL,
+                                                  "isra");
+  redirect_callers.release ();
+
+  push_cfun (DECL_STRUCT_FUNCTION (new_node->decl));
+  ipa_modify_formal_parameters (current_function_decl, adjustments);
   cfg_changed = ipa_sra_modify_function_body (adjustments);
   sra_ipa_reset_debug_stmts (adjustments);
-  convert_callers (new_node, node->symbol.decl, adjustments);
-  cgraph_make_node_local (new_node);
+  convert_callers (new_node, node->decl, adjustments);
+  new_node->make_local ();
   return cfg_changed;
 }
 
+/* Means of communication between ipa_sra_check_caller and
+   ipa_sra_preliminary_function_checks.  */
+
+struct ipa_sra_check_caller_data
+{
+  bool has_callers;
+  bool bad_arg_alignment;
+  bool has_thunk;
+};
+
+/* If NODE has a caller, mark that fact in DATA which is pointer to
+   ipa_sra_check_caller_data.  Also check all aggregate arguments in all known
+   calls if they are unit aligned and if not, set the appropriate flag in DATA
+   too. */
+
+static bool
+ipa_sra_check_caller (struct cgraph_node *node, void *data)
+{
+  if (!node->callers)
+    return false;
+
+  struct ipa_sra_check_caller_data *iscc;
+  iscc = (struct ipa_sra_check_caller_data *) data;
+  iscc->has_callers = true;
+
+  for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller)
+    {
+      if (cs->caller->thunk.thunk_p)
+       {
+         iscc->has_thunk = true;
+         return true;
+       }
+      gimple call_stmt = cs->call_stmt;
+      unsigned count = gimple_call_num_args (call_stmt);
+      for (unsigned i = 0; i < count; i++)
+       {
+         tree arg = gimple_call_arg (call_stmt, i);
+         if (is_gimple_reg (arg))
+             continue;
+
+         tree offset;
+         HOST_WIDE_INT bitsize, bitpos;
+         machine_mode mode;
+         int unsignedp, volatilep = 0;
+         get_inner_reference (arg, &bitsize, &bitpos, &offset, &mode,
+                              &unsignedp, &volatilep, false);
+         if (bitpos % BITS_PER_UNIT)
+           {
+             iscc->bad_arg_alignment = true;
+             return true;
+           }
+       }
+    }
+
+  return false;
+}
+
 /* Return false the function is apparently unsuitable for IPA-SRA based on it's
    attributes, return true otherwise.  NODE is the cgraph node of the current
    function.  */
@@ -4858,7 +5077,7 @@ modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
 static bool
 ipa_sra_preliminary_function_checks (struct cgraph_node *node)
 {
-  if (!cgraph_node_can_be_local_p (node))
+  if (!node->can_be_local_p ())
     {
       if (dump_file)
        fprintf (dump_file, "Function not local to this compilation unit.\n");
@@ -4872,13 +5091,21 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
       return false;
     }
 
-  if (!tree_versionable_function_p (node->symbol.decl))
+  if (!tree_versionable_function_p (node->decl))
     {
       if (dump_file)
        fprintf (dump_file, "Function is not versionable.\n");
       return false;
     }
 
+  if (!opt_for_fn (node->decl, optimize)
+      || !opt_for_fn (node->decl, flag_ipa_sra))
+    {
+      if (dump_file)
+       fprintf (dump_file, "Function not optimized.\n");
+      return false;
+    }
+
   if (DECL_VIRTUAL_P (current_function_decl))
     {
       if (dump_file)
@@ -4886,15 +5113,36 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
       return false;
     }
 
-  if ((DECL_COMDAT (node->symbol.decl) || DECL_EXTERNAL (node->symbol.decl))
-      && inline_summary(node)->size >= MAX_INLINE_INSNS_AUTO)
+  if ((DECL_ONE_ONLY (node->decl) || DECL_EXTERNAL (node->decl))
+      && inline_summaries->get (node)->size >= MAX_INLINE_INSNS_AUTO)
     {
       if (dump_file)
        fprintf (dump_file, "Function too big to be made truly local.\n");
       return false;
     }
 
-  if (!node->callers)
+  if (cfun->stdarg)
+    {
+      if (dump_file)
+       fprintf (dump_file, "Function uses stdarg. \n");
+      return false;
+    }
+
+  if (TYPE_ATTRIBUTES (TREE_TYPE (node->decl)))
+    return false;
+
+  if (DECL_DISREGARD_INLINE_LIMITS (node->decl))
+    {
+      if (dump_file)
+       fprintf (dump_file, "Always inline function will be inlined "
+                "anyway. \n");
+      return false;
+    }
+
+  struct ipa_sra_check_caller_data iscc;
+  memset (&iscc, 0, sizeof(iscc));
+  node->call_for_symbol_and_aliases (ipa_sra_check_caller, &iscc, true);
+  if (!iscc.has_callers)
     {
       if (dump_file)
        fprintf (dump_file,
@@ -4902,15 +5150,21 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
       return false;
     }
 
-  if (cfun->stdarg)
+  if (iscc.bad_arg_alignment)
     {
       if (dump_file)
-       fprintf (dump_file, "Function uses stdarg. \n");
+       fprintf (dump_file,
+                "A function call has an argument with non-unit alignment.\n");
       return false;
     }
 
-  if (TYPE_ATTRIBUTES (TREE_TYPE (node->symbol.decl)))
-    return false;
+  if (iscc.has_thunk)
+    {
+      if (dump_file)
+       fprintf (dump_file,
+                "A has thunk.\n");
+      return false;
+    }
 
   return true;
 }
@@ -4920,7 +5174,7 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
 static unsigned int
 ipa_early_sra (void)
 {
-  struct cgraph_node *node = cgraph_get_node (current_function_decl);
+  struct cgraph_node *node = cgraph_node::get (current_function_decl);
   ipa_parm_adjustment_vec adjustments;
   int ret = 0;
 
@@ -4937,18 +5191,27 @@ ipa_early_sra (void)
       goto simple_out;
     }
 
-  if (cgraph_for_node_and_aliases (node, not_all_callers_have_enough_arguments_p,
-                                  NULL, true))
+  if (node->call_for_symbol_and_aliases
+       (some_callers_have_mismatched_arguments_p, NULL, true))
     {
       if (dump_file)
        fprintf (dump_file, "There are callers with insufficient number of "
-                "arguments.\n");
+                "arguments or arguments with type mismatches.\n");
+      goto simple_out;
+    }
+
+  if (node->call_for_symbol_and_aliases
+       (some_callers_have_no_vuse_p, NULL, true))
+    {
+      if (dump_file)
+       fprintf (dump_file, "There are callers with no VUSE attached "
+                "to a call stmt.\n");
       goto simple_out;
     }
 
   bb_dereferences = XCNEWVEC (HOST_WIDE_INT,
                                 func_param_count
-                                * last_basic_block_for_function (cfun));
+                                * last_basic_block_for_fn (cfun));
   final_bbs = BITMAP_ALLOC (NULL);
 
   scan_function ();
@@ -4968,7 +5231,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);
@@ -4977,7 +5240,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);
@@ -4996,29 +5259,38 @@ ipa_early_sra (void)
   return ret;
 }
 
-/* Return if early ipa sra shall be performed.  */
-static bool
-ipa_early_sra_gate (void)
-{
-  return flag_ipa_sra && dbg_cnt (eipa_sra);
-}
+namespace {
 
-struct gimple_opt_pass pass_early_ipa_sra =
+const pass_data pass_data_early_ipa_sra =
 {
- {
-  GIMPLE_PASS,
-  "eipa_sra",                          /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  ipa_early_sra_gate,                  /* gate */
-  ipa_early_sra,                       /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_IPA_SRA,                          /* tv_id */
-  0,                                   /* properties_required */
-  0,                                   /* properties_provided */
-  0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  TODO_dump_symtab                     /* todo_flags_finish */
- }
+  GIMPLE_PASS, /* type */
+  "eipa_sra", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_IPA_SRA, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_dump_symtab, /* todo_flags_finish */
 };
+
+class pass_early_ipa_sra : public gimple_opt_pass
+{
+public:
+  pass_early_ipa_sra (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_early_ipa_sra, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return flag_ipa_sra && dbg_cnt (eipa_sra); }
+  virtual unsigned int execute (function *) { return ipa_early_sra (); }
+
+}; // class pass_early_ipa_sra
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_early_ipa_sra (gcc::context *ctxt)
+{
+  return new pass_early_ipa_sra (ctxt);
+}