OSDN Git Service

Implement new syscall package.
[pf3gnuchains/gcc-fork.git] / gcc / tree-sra.c
index e97970c..c83f480 100644 (file)
@@ -1,7 +1,7 @@
 /* Scalar Replacement of Aggregates (SRA) converts some structure
    references into scalar references, exposing them to the scalar
    optimizers.
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
    Contributed by Martin Jambor <mjambor@suse.cz>
 
 This file is part of GCC.
@@ -76,7 +76,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "alloc-pool.h"
 #include "tm.h"
-#include "toplev.h"
 #include "tree.h"
 #include "gimple.h"
 #include "cgraph.h"
@@ -92,6 +91,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "tree-inline.h"
 #include "gimple-pretty-print.h"
+#include "ipa-inline.h"
 
 /* Enumeration of all aggregate reductions we can do.  */
 enum sra_mode { SRA_MODE_EARLY_IPA,   /* early call regularization */
@@ -170,9 +170,8 @@ struct access
   /* Is this particular access write access? */
   unsigned write : 1;
 
-  /* Is this access an artificial one created to scalarize some record
-     entirely? */
-  unsigned total_scalarization : 1;
+  /* Is this access an access to a non-addressable field? */
+  unsigned non_addressable : 1;
 
   /* Is this access currently in the work queue?  */
   unsigned grp_queued : 1;
@@ -189,6 +188,22 @@ struct access
      statement?  This flag is propagated down the access tree.  */
   unsigned grp_assignment_read : 1;
 
+  /* Does this group contain a write access that comes from an assignment
+     statement?  This flag is propagated down the access tree.  */
+  unsigned grp_assignment_write : 1;
+
+  /* Does this group contain a read access through a scalar type?  This flag is
+     not propagated in the access tree in any direction.  */
+  unsigned grp_scalar_read : 1;
+
+  /* Does this group contain a write access through a scalar type?  This flag
+     is not propagated in the access tree in any direction.  */
+  unsigned grp_scalar_write : 1;
+
+  /* Is this access an artificial one created to scalarize some record
+     entirely? */
+  unsigned grp_total_scalarization : 1;
+
   /* Other passes of the analysis use this bit to make function
      analyze_access_subtree create scalar replacements for this group if
      possible.  */
@@ -216,6 +231,9 @@ struct access
      cannot be called from within FOR_EACH_REFERENCED_VAR. */
   unsigned grp_to_be_replaced : 1;
 
+  /* Should TREE_NO_WARNING of a replacement be set?  */
+  unsigned grp_no_warning : 1;
+
   /* Is it possible that the group refers to data which might be (directly or
      otherwise) modified?  */
   unsigned grp_maybe_modified : 1;
@@ -359,22 +377,26 @@ dump_access (FILE *f, struct access *access, bool grp)
   fprintf (f, ", type = ");
   print_generic_expr (f, access->type, 0);
   if (grp)
-    fprintf (f, ", grp_write = %d, total_scalarization = %d, "
-            "grp_read = %d, grp_hint = %d, grp_assignment_read = %d,"
-            "grp_covered = %d, grp_unscalarizable_region = %d, "
-            "grp_unscalarized_data = %d, grp_partial_lhs = %d, "
-            "grp_to_be_replaced = %d, grp_maybe_modified = %d, "
+    fprintf (f, ", grp_read = %d, grp_write = %d, grp_assignment_read = %d, "
+            "grp_assignment_write = %d, grp_scalar_read = %d, "
+            "grp_scalar_write = %d, grp_total_scalarization = %d, "
+            "grp_hint = %d, grp_covered = %d, "
+            "grp_unscalarizable_region = %d, grp_unscalarized_data = %d, "
+            "grp_partial_lhs = %d, grp_to_be_replaced = %d, "
+            "grp_maybe_modified = %d, "
             "grp_not_necessarilly_dereferenced = %d\n",
-            access->grp_write, access->total_scalarization,
-            access->grp_read, access->grp_hint, access->grp_assignment_read,
-            access->grp_covered, access->grp_unscalarizable_region,
-            access->grp_unscalarized_data, access->grp_partial_lhs,
-            access->grp_to_be_replaced, access->grp_maybe_modified,
+            access->grp_read, access->grp_write, access->grp_assignment_read,
+            access->grp_assignment_write, access->grp_scalar_read,
+            access->grp_scalar_write, access->grp_total_scalarization,
+            access->grp_hint, access->grp_covered,
+            access->grp_unscalarizable_region, access->grp_unscalarized_data,
+            access->grp_partial_lhs, access->grp_to_be_replaced,
+            access->grp_maybe_modified,
             access->grp_not_necessarilly_dereferenced);
   else
-    fprintf (f, ", write = %d, total_scalarization = %d, "
+    fprintf (f, ", write = %d, grp_total_scalarization = %d, "
             "grp_partial_lhs = %d\n",
-            access->write, access->total_scalarization,
+            access->write, access->grp_total_scalarization,
             access->grp_partial_lhs);
 }
 
@@ -626,7 +648,7 @@ disqualify_candidate (tree decl, const char *reason)
    scalarization.  */
 
 static bool
-type_internals_preclude_sra_p (tree type)
+type_internals_preclude_sra_p (tree type, const char **msg)
 {
   tree fld;
   tree et;
@@ -641,14 +663,39 @@ type_internals_preclude_sra_p (tree type)
          {
            tree ft = TREE_TYPE (fld);
 
-           if (TREE_THIS_VOLATILE (fld)
-               || !DECL_FIELD_OFFSET (fld) || !DECL_SIZE (fld)
-               || !host_integerp (DECL_FIELD_OFFSET (fld), 1)
-               || !host_integerp (DECL_SIZE (fld), 1))
-             return true;
-
+           if (TREE_THIS_VOLATILE (fld))
+             {
+               *msg = "volatile structure field";
+               return true;
+             }
+           if (!DECL_FIELD_OFFSET (fld))
+             {
+               *msg = "no structure field offset";
+               return true;
+             }
+           if (!DECL_SIZE (fld))
+             {
+               *msg = "zero structure field size";
+               return true;
+             }
+           if (!host_integerp (DECL_FIELD_OFFSET (fld), 1))
+             {
+               *msg = "structure field offset not fixed";
+               return true;
+             }
+           if (!host_integerp (DECL_SIZE (fld), 1))
+             {
+               *msg = "structure field size not fixed";
+               return true;
+             }       
            if (AGGREGATE_TYPE_P (ft)
-               && type_internals_preclude_sra_p (ft))
+                   && int_bit_position (fld) % BITS_PER_UNIT != 0)
+             {
+               *msg = "structure field is bit field";
+               return true;
+             }
+
+           if (AGGREGATE_TYPE_P (ft) && type_internals_preclude_sra_p (ft, msg))
              return true;
          }
 
@@ -657,10 +704,16 @@ type_internals_preclude_sra_p (tree type)
     case ARRAY_TYPE:
       et = TREE_TYPE (type);
 
-      if (AGGREGATE_TYPE_P (et))
-       return type_internals_preclude_sra_p (et);
-      else
-       return false;
+      if (TYPE_VOLATILE (et))
+       {
+         *msg = "element type is volatile";
+         return true;
+       }
+
+      if (AGGREGATE_TYPE_P (et) && type_internals_preclude_sra_p (et, msg))
+       return true;
+
+      return false;
 
     default:
       return false;
@@ -774,12 +827,13 @@ create_access (tree expr, gimple stmt, bool write)
          disqualify_candidate (base, "Encountered a variable sized access.");
          return NULL;
        }
-      if ((offset % BITS_PER_UNIT) != 0 || (size % BITS_PER_UNIT) != 0)
+      if (TREE_CODE (expr) == COMPONENT_REF
+         && DECL_BIT_FIELD (TREE_OPERAND (expr, 1)))
        {
-         disqualify_candidate (base,
-                               "Encountered an acces not aligned to a byte.");
+         disqualify_candidate (base, "Encountered a bit-field access.");
          return NULL;
        }
+      gcc_checking_assert ((offset % BITS_PER_UNIT) == 0);
 
       if (ptr)
        mark_parm_dereference (base, offset + size, stmt);
@@ -805,20 +859,22 @@ create_access (tree expr, gimple stmt, bool write)
   access->grp_unscalarizable_region = unscalarizable_region;
   access->stmt = stmt;
 
+  if (TREE_CODE (expr) == COMPONENT_REF
+      && DECL_NONADDRESSABLE_P (TREE_OPERAND (expr, 1)))
+    access->non_addressable = 1;
+
   return access;
 }
 
 
 /* Return true iff TYPE is a RECORD_TYPE with fields that are either of gimple
    register types or (recursively) records with only these two kinds of fields.
-   It also returns false if any of these records has a zero-size field as its
-   last field or has a bit-field.  */
+   It also returns false if any of these records contains a bit-field.  */
 
 static bool
 type_consists_of_records_p (tree type)
 {
   tree fld;
-  bool last_fld_has_zero_size = false;
 
   if (TREE_CODE (type) != RECORD_TYPE)
     return false;
@@ -834,13 +890,8 @@ type_consists_of_records_p (tree type)
        if (!is_gimple_reg_type (ft)
            && !type_consists_of_records_p (ft))
          return false;
-
-       last_fld_has_zero_size = tree_low_cst (DECL_SIZE (fld), 1) == 0;
       }
 
-  if (last_fld_has_zero_size)
-    return false;
-
   return true;
 }
 
@@ -873,7 +924,7 @@ completely_scalarize_record (tree base, tree decl, HOST_WIDE_INT offset,
            access = create_access_1 (base, pos, size);
            access->expr = nref;
            access->type = ft;
-           access->total_scalarization = 1;
+           access->grp_total_scalarization = 1;
            /* Accesses for intraprocedural SRA can have their stmt NULL.  */
          }
        else
@@ -881,6 +932,23 @@ completely_scalarize_record (tree base, tree decl, HOST_WIDE_INT offset,
       }
 }
 
+/* Create total_scalarization accesses for all scalar type fields in VAR and
+   for VAR a a whole.  VAR must be of a RECORD_TYPE conforming to
+   type_consists_of_records_p.   */
+
+static void
+completely_scalarize_var (tree var)
+{
+  HOST_WIDE_INT size = tree_low_cst (DECL_SIZE (var), 1);
+  struct access *access;
+
+  access = create_access_1 (var, 0, size);
+  access->expr = var;
+  access->type = TREE_TYPE (var);
+  access->grp_total_scalarization = 1;
+
+  completely_scalarize_record (var, var, 0, var);
+}
 
 /* Search the given tree for a declaration by skipping handled components and
    exclude it from the candidates.  */
@@ -999,6 +1067,31 @@ disqualify_ops_if_throwing_stmt (gimple stmt, tree lhs, tree rhs)
   return false;
 }
 
+/* Return true iff type of EXP is not sufficiently aligned.  */
+
+static bool
+tree_non_mode_aligned_mem_p (tree exp)
+{
+  enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
+  unsigned int align;
+
+  if (TREE_CODE (exp) == VIEW_CONVERT_EXPR)
+    exp = TREE_OPERAND (exp, 0);
+
+  if (TREE_CODE (exp) == SSA_NAME
+      || TREE_CODE (exp) == MEM_REF
+      || mode == BLKmode
+      || is_gimple_min_invariant (exp)
+      || !STRICT_ALIGNMENT)
+    return false;
+
+  align = get_object_alignment (exp);
+  if (GET_MODE_ALIGNMENT (mode) > align)
+    return true;
+
+  return false;
+}
+
 /* Scan expressions occuring in STMT, create access structures for all accesses
    to candidates for scalarization and remove those candidates which occur in
    statements or expressions that prevent them from being split apart.  Return
@@ -1022,12 +1115,19 @@ build_accesses_from_assign (gimple stmt)
   racc = build_access_from_expr_1 (rhs, stmt, false);
   lacc = build_access_from_expr_1 (lhs, stmt, true);
 
+  if (lacc)
+    {
+      lacc->grp_assignment_write = 1;
+      lacc->grp_unscalarizable_region |= tree_non_mode_aligned_mem_p (rhs);
+    }
+
   if (racc)
     {
       racc->grp_assignment_read = 1;
       if (should_scalarize_away_bitmap && !gimple_has_volatile_ops (stmt)
          && !is_gimple_reg_type (racc->type))
        bitmap_set_bit (should_scalarize_away_bitmap, DECL_UID (racc->base));
+      racc->grp_unscalarizable_region |= tree_non_mode_aligned_mem_p (lhs);
     }
 
   if (lacc && racc
@@ -1352,6 +1452,7 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
       add_referenced_var (tmp);
       tmp = make_ssa_name (tmp, NULL);
       addr = build_fold_addr_expr (unshare_expr (prev_base));
+      STRIP_USELESS_TYPE_CONVERSION (addr);
       stmt = gimple_build_assign (tmp, addr);
       gimple_set_location (stmt, loc);
       SSA_NAME_DEF_STMT (tmp) = stmt;
@@ -1369,7 +1470,7 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
     {
       off = build_int_cst (TREE_TYPE (TREE_OPERAND (base, 1)),
                           base_offset + offset / BITS_PER_UNIT);
-      off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), off, 0);
+      off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), off);
       base = unshare_expr (TREE_OPERAND (base, 0));
     }
   else
@@ -1384,7 +1485,7 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
 
 /* Construct a memory reference to a part of an aggregate BASE at the given
    OFFSET and of the same type as MODEL.  In case this is a reference to a
-   bit-field, the function will replicate the last component_ref of model's
+   component, the function will replicate the last COMPONENT_REF of model's
    expr to access it.  GSI and INSERT_AFTER have the same meaning as in
    build_ref_for_offset.  */
 
@@ -1393,17 +1494,18 @@ build_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset,
                     struct access *model, gimple_stmt_iterator *gsi,
                     bool insert_after)
 {
-  if (TREE_CODE (model->expr) == COMPONENT_REF
-      && DECL_BIT_FIELD (TREE_OPERAND (model->expr, 1)))
+  if (TREE_CODE (model->expr) == COMPONENT_REF)
     {
-      /* This access represents a bit-field.  */
-      tree t, exp_type;
+      tree t, exp_type, fld = TREE_OPERAND (model->expr, 1);
+      tree cr_offset = component_ref_field_offset (model->expr);
 
-      offset -= int_bit_position (TREE_OPERAND (model->expr, 1));
+      gcc_assert (cr_offset && host_integerp (cr_offset, 1));
+      offset -= TREE_INT_CST_LOW (cr_offset) * BITS_PER_UNIT;
+      offset -= TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (fld));
       exp_type = TREE_TYPE (TREE_OPERAND (model->expr, 0));
       t = build_ref_for_offset (loc, base, offset, exp_type, gsi, insert_after);
-      return fold_build3_loc (loc, COMPONENT_REF, model->type, t,
-                             TREE_OPERAND (model->expr, 1), NULL_TREE);
+      return fold_build3_loc (loc, COMPONENT_REF, TREE_TYPE (fld), t, fld,
+                             TREE_OPERAND (model->expr, 2));
     }
   else
     return build_ref_for_offset (loc, base, offset, model->type,
@@ -1482,7 +1584,7 @@ build_user_friendly_ref_for_offset (tree *res, tree type, HOST_WIDE_INT offset,
            return false;
          index = build_int_cst (TYPE_DOMAIN (type), offset / el_size);
          if (!integer_zerop (minidx))
-           index = int_const_binop (PLUS_EXPR, index, minidx, 0);
+           index = int_const_binop (PLUS_EXPR, index, minidx);
          *res = build4 (ARRAY_REF, TREE_TYPE (type), *res, index,
                         NULL_TREE, NULL_TREE);
          offset = offset % el_size;
@@ -1509,6 +1611,19 @@ is_va_list_type (tree type)
   return TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (va_list_type_node);
 }
 
+/* Print message to dump file why a variable was rejected. */
+
+static void
+reject (tree var, const char *msg)
+{
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "Rejected (%d): %s: ", DECL_UID (var), msg);
+      print_generic_expr (dump_file, var, 0);
+      fprintf (dump_file, "\n");
+    }
+}
+
 /* The very first phase of intraprocedural SRA.  It marks in candidate_bitmap
    those with type which is suitable for scalarization.  */
 
@@ -1518,26 +1633,58 @@ find_var_candidates (void)
   tree var, type;
   referenced_var_iterator rvi;
   bool ret = false;
+  const char *msg;
 
-  FOR_EACH_REFERENCED_VAR (var, rvi)
+  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
     {
       if (TREE_CODE (var) != VAR_DECL && TREE_CODE (var) != PARM_DECL)
         continue;
       type = TREE_TYPE (var);
 
-      if (!AGGREGATE_TYPE_P (type)
-         || needs_to_live_in_memory (var)
-         || TREE_THIS_VOLATILE (var)
-         || !COMPLETE_TYPE_P (type)
-         || !host_integerp (TYPE_SIZE (type), 1)
-          || tree_low_cst (TYPE_SIZE (type), 1) == 0
-         || type_internals_preclude_sra_p (type)
-         /* Fix for PR 41089.  tree-stdarg.c needs to have va_lists intact but
+      if (!AGGREGATE_TYPE_P (type)) 
+        {
+          reject (var, "not aggregate");
+          continue;
+       }
+      if (needs_to_live_in_memory (var))
+        {
+          reject (var, "needs to live in memory");
+          continue;
+        }
+      if (TREE_THIS_VOLATILE (var))
+        {
+          reject (var, "is volatile");
+         continue;
+        }
+      if (!COMPLETE_TYPE_P (type))
+        {
+          reject (var, "has incomplete type");
+         continue;
+        }
+      if (!host_integerp (TYPE_SIZE (type), 1))
+        {
+          reject (var, "type size not fixed");
+         continue;
+        }
+      if (tree_low_cst (TYPE_SIZE (type), 1) == 0)
+        {
+          reject (var, "type size is zero");
+          continue;
+        }
+      if (type_internals_preclude_sra_p (type, &msg))
+       {
+         reject (var, msg);
+         continue;
+       }
+      if (/* Fix for PR 41089.  tree-stdarg.c needs to have va_lists intact but
              we also want to schedule it rather late.  Thus we ignore it in
              the early pass. */
-         || (sra_mode == SRA_MODE_EARLY_INTRA
+         (sra_mode == SRA_MODE_EARLY_INTRA
              && is_va_list_type (type)))
-       continue;
+        {
+         reject (var, "is va_list");
+         continue;
+       }
 
       bitmap_set_bit (candidate_bitmap, DECL_UID (var));
 
@@ -1574,8 +1721,7 @@ sort_and_splice_var_accesses (tree var)
   access_count = VEC_length (access_p, access_vec);
 
   /* Sort by <OFFSET, SIZE>.  */
-  qsort (VEC_address (access_p, access_vec), access_count, sizeof (access_p),
-        compare_access_positions);
+  VEC_qsort (access_p, access_vec, compare_access_positions);
 
   i = 0;
   while (i < access_count)
@@ -1583,9 +1729,14 @@ sort_and_splice_var_accesses (tree var)
       struct access *access = VEC_index (access_p, access_vec, i);
       bool grp_write = access->write;
       bool grp_read = !access->write;
+      bool grp_scalar_write = access->write
+       && is_gimple_reg_type (access->type);
+      bool grp_scalar_read = !access->write
+       && is_gimple_reg_type (access->type);
       bool grp_assignment_read = access->grp_assignment_read;
-      bool multiple_reads = false;
-      bool total_scalarization = access->total_scalarization;
+      bool grp_assignment_write = access->grp_assignment_write;
+      bool multiple_scalar_reads = false;
+      bool total_scalarization = access->grp_total_scalarization;
       bool grp_partial_lhs = access->grp_partial_lhs;
       bool first_scalar = is_gimple_reg_type (access->type);
       bool unscalarizable_region = access->grp_unscalarizable_region;
@@ -1609,18 +1760,27 @@ sort_and_splice_var_accesses (tree var)
          if (ac2->offset != access->offset || ac2->size != access->size)
            break;
          if (ac2->write)
-           grp_write = true;
+           {
+             grp_write = true;
+             grp_scalar_write = (grp_scalar_write
+                                 || is_gimple_reg_type (ac2->type));
+           }
          else
            {
-             if (grp_read)
-               multiple_reads = true;
-             else
-               grp_read = true;
+             grp_read = true;
+             if (is_gimple_reg_type (ac2->type))
+               {
+                 if (grp_scalar_read)
+                   multiple_scalar_reads = true;
+                 else
+                   grp_scalar_read = true;
+               }
            }
          grp_assignment_read |= ac2->grp_assignment_read;
+         grp_assignment_write |= ac2->grp_assignment_write;
          grp_partial_lhs |= ac2->grp_partial_lhs;
          unscalarizable_region |= ac2->grp_unscalarizable_region;
-         total_scalarization |= ac2->total_scalarization;
+         total_scalarization |= ac2->grp_total_scalarization;
          relink_to_new_repr (access, ac2);
 
          /* If there are both aggregate-type and scalar-type accesses with
@@ -1636,8 +1796,12 @@ sort_and_splice_var_accesses (tree var)
       access->group_representative = access;
       access->grp_write = grp_write;
       access->grp_read = grp_read;
+      access->grp_scalar_read = grp_scalar_read;
+      access->grp_scalar_write = grp_scalar_write;
       access->grp_assignment_read = grp_assignment_read;
-      access->grp_hint = multiple_reads || total_scalarization;
+      access->grp_assignment_write = grp_assignment_write;
+      access->grp_hint = multiple_scalar_reads || total_scalarization;
+      access->grp_total_scalarization = total_scalarization;
       access->grp_partial_lhs = grp_partial_lhs;
       access->grp_unscalarizable_region = unscalarizable_region;
       if (access->first_link)
@@ -1661,7 +1825,6 @@ create_access_replacement (struct access *access, bool rename)
   tree repl;
 
   repl = create_tmp_var (access->type, "SR");
-  get_var_ann (repl);
   add_referenced_var (repl);
   if (rename)
     mark_sym_for_renaming (repl);
@@ -1713,7 +1876,10 @@ create_access_replacement (struct access *access, bool rename)
          }
       SET_DECL_DEBUG_EXPR (repl, debug_expr);
       DECL_DEBUG_EXPR_IS_FROM (repl) = 1;
-      TREE_NO_WARNING (repl) = TREE_NO_WARNING (access->base);
+      if (access->grp_no_warning)
+       TREE_NO_WARNING (repl) = 1;
+      else
+       TREE_NO_WARNING (repl) = TREE_NO_WARNING (access->base);
     }
   else
     TREE_NO_WARNING (repl) = 1;
@@ -1822,41 +1988,67 @@ expr_with_var_bounded_array_refs_p (tree expr)
   return false;
 }
 
-enum mark_read_status { SRA_MR_NOT_READ, SRA_MR_READ, SRA_MR_ASSIGN_READ};
-
 /* Analyze the subtree of accesses rooted in ROOT, scheduling replacements when
    both seeming beneficial and when ALLOW_REPLACEMENTS allows it.  Also set all
    sorts of access flags appropriately along the way, notably always set
    grp_read and grp_assign_read according to MARK_READ and grp_write when
-   MARK_WRITE is true.  */
+   MARK_WRITE is true.
+
+   Creating a replacement for a scalar access is considered beneficial if its
+   grp_hint is set (this means we are either attempting total scalarization or
+   there is more than one direct read access) or according to the following
+   table:
+
+   Access written to through a scalar type (once or more times)
+   |
+   |   Written to in an assignment statement
+   |   |
+   |   |       Access read as scalar _once_
+   |   |       |
+   |           |       |       Read in an assignment statement
+   |   |       |       |
+   |           |       |       |       Scalarize       Comment
+-----------------------------------------------------------------------------
+   0   0       0       0                       No access for the scalar
+   0   0       0       1                       No access for the scalar
+   0   0       1       0       No              Single read - won't help
+   0   0       1       1       No              The same case
+   0   1       0       0                       No access for the scalar
+   0   1       0       1                       No access for the scalar
+   0   1       1       0       Yes             s = *g; return s.i;
+   0   1       1       1       Yes             The same case as above
+   1   0       0       0       No              Won't help
+   1   0       0       1       Yes             s.i = 1; *g = s;
+   1   0       1       0       Yes             s.i = 5; g = s.i;
+   1   0       1       1       Yes             The same case as above
+   1   1       0       0       No              Won't help.
+   1   1       0       1       Yes             s.i = 1; *g = s;
+   1   1       1       0       Yes             s = *g; return s.i;
+   1   1       1       1       Yes             Any of the above yeses  */
 
 static bool
-analyze_access_subtree (struct access *root, bool allow_replacements,
-                       enum mark_read_status mark_read, bool mark_write)
+analyze_access_subtree (struct access *root, struct access *parent,
+                       bool allow_replacements)
 {
   struct access *child;
   HOST_WIDE_INT limit = root->offset + root->size;
   HOST_WIDE_INT covered_to = root->offset;
   bool scalar = is_gimple_reg_type (root->type);
   bool hole = false, sth_created = false;
-  bool direct_read = root->grp_read;
 
-  if (mark_read == SRA_MR_ASSIGN_READ)
+  if (parent)
     {
-      root->grp_read = 1;
-      root->grp_assignment_read = 1;
+      if (parent->grp_read)
+       root->grp_read = 1;
+      if (parent->grp_assignment_read)
+       root->grp_assignment_read = 1;
+      if (parent->grp_write)
+       root->grp_write = 1;
+      if (parent->grp_assignment_write)
+       root->grp_assignment_write = 1;
+      if (parent->grp_total_scalarization)
+       root->grp_total_scalarization = 1;
     }
-  if (mark_read == SRA_MR_READ)
-    root->grp_read = 1;
-  else if (root->grp_assignment_read)
-    mark_read = SRA_MR_ASSIGN_READ;
-  else if (root->grp_read)
-    mark_read = SRA_MR_READ;
-
-  if (mark_write)
-    root->grp_write = true;
-  else if (root->grp_write)
-    mark_write = true;
 
   if (root->grp_unscalarizable_region)
     allow_replacements = false;
@@ -1866,40 +2058,58 @@ analyze_access_subtree (struct access *root, bool allow_replacements,
 
   for (child = root->first_child; child; child = child->next_sibling)
     {
-      if (!hole && child->offset < covered_to)
-       hole = true;
-      else
-       covered_to += child->size;
-
-      sth_created |= analyze_access_subtree (child,
-                                            allow_replacements && !scalar,
-                                            mark_read, mark_write);
+      hole |= covered_to < child->offset;
+      sth_created |= analyze_access_subtree (child, root,
+                                            allow_replacements && !scalar);
 
       root->grp_unscalarized_data |= child->grp_unscalarized_data;
-      hole |= !child->grp_covered;
+      root->grp_total_scalarization &= child->grp_total_scalarization;
+      if (child->grp_covered)
+       covered_to += child->size;
+      else
+       hole = true;
     }
 
   if (allow_replacements && scalar && !root->first_child
       && (root->grp_hint
-         || (root->grp_write && (direct_read || root->grp_assignment_read))))
+         || ((root->grp_scalar_read || root->grp_assignment_read)
+             && (root->grp_scalar_write || root->grp_assignment_write))))
     {
+      bool new_integer_type;
+      if (TREE_CODE (root->type) == ENUMERAL_TYPE)
+       {
+         tree rt = root->type;
+         root->type = build_nonstandard_integer_type (TYPE_PRECISION (rt),
+                                                      TYPE_UNSIGNED (rt));
+         new_integer_type = true;
+       }
+      else
+       new_integer_type = false;
+
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
          fprintf (dump_file, "Marking ");
          print_generic_expr (dump_file, root->base, 0);
-         fprintf (dump_file, " offset: %u, size: %u: ",
+         fprintf (dump_file, " offset: %u, size: %u ",
                   (unsigned) root->offset, (unsigned) root->size);
-         fprintf (dump_file, " to be replaced.\n");
+         fprintf (dump_file, " to be replaced%s.\n",
+                  new_integer_type ? " with an integer": "");
        }
 
       root->grp_to_be_replaced = 1;
       sth_created = true;
       hole = false;
     }
-  else if (covered_to < limit)
-    hole = true;
+  else
+    {
+      if (covered_to < limit)
+       hole = true;
+      if (scalar)
+       root->grp_total_scalarization = 0;
+    }
 
-  if (sth_created && !hole)
+  if (sth_created
+      && (!hole || root->grp_total_scalarization))
     {
       root->grp_covered = 1;
       return true;
@@ -1920,7 +2130,7 @@ analyze_access_trees (struct access *access)
 
   while (access)
     {
-      if (analyze_access_subtree (access, true, SRA_MR_NOT_READ, false))
+      if (analyze_access_subtree (access, NULL, true))
        ret = true;
       access = access->next_grp;
     }
@@ -1969,12 +2179,17 @@ create_artificial_child_access (struct access *parent, struct access *model,
   tree expr = parent->base;
 
   gcc_assert (!model->grp_unscalarizable_region);
-  if (!build_user_friendly_ref_for_offset (&expr, TREE_TYPE (expr), new_offset,
-                                          model->type))
-    return NULL;
 
   access = (struct access *) pool_alloc (access_pool);
   memset (access, 0, sizeof (struct access));
+  if (!build_user_friendly_ref_for_offset (&expr, TREE_TYPE (expr), new_offset,
+                                          model->type))
+    {
+      access->grp_no_warning = true;
+      expr = build_ref_for_model (EXPR_LOCATION (parent->base), parent->base,
+                                 new_offset, model, NULL, false);
+    }
+
   access->base = parent->base;
   access->expr = expr;
   access->offset = new_offset;
@@ -2015,11 +2230,16 @@ propagate_subaccesses_across_link (struct access *lacc, struct access *racc)
     {
       tree t = lacc->base;
 
+      lacc->type = racc->type;
       if (build_user_friendly_ref_for_offset (&t, TREE_TYPE (t), lacc->offset,
                                              racc->type))
+       lacc->expr = t;
+      else
        {
-         lacc->expr = t;
-         lacc->type = racc->type;
+         lacc->expr = build_ref_for_model (EXPR_LOCATION (lacc->base),
+                                           lacc->base, lacc->offset,
+                                           racc, NULL, false);
+         lacc->grp_no_warning = true;
        }
       return false;
     }
@@ -2107,16 +2327,24 @@ analyze_all_variable_accesses (void)
        tree var = referenced_var (i);
 
        if (TREE_CODE (var) == VAR_DECL
-           && ((unsigned) tree_low_cst (TYPE_SIZE (TREE_TYPE (var)), 1)
-               <= max_total_scalarization_size)
            && type_consists_of_records_p (TREE_TYPE (var)))
          {
-           completely_scalarize_record (var, var, 0, var);
-           if (dump_file && (dump_flags & TDF_DETAILS))
+           if ((unsigned) tree_low_cst (TYPE_SIZE (TREE_TYPE (var)), 1)
+               <= max_total_scalarization_size)
              {
-               fprintf (dump_file, "Will attempt to totally scalarize ");
+               completely_scalarize_var (var);
+               if (dump_file && (dump_flags & TDF_DETAILS))
+                 {
+                   fprintf (dump_file, "Will attempt to totally scalarize ");
+                   print_generic_expr (dump_file, var, 0);
+                   fprintf (dump_file, " (UID: %u): \n", DECL_UID (var));
+                 }
+             }
+           else if (dump_file && (dump_flags & TDF_DETAILS))
+             {
+               fprintf (dump_file, "Too big to totally scalarize: ");
                print_generic_expr (dump_file, var, 0);
-               fprintf (dump_file, " (UID: %u)\n", DECL_UID (var));
+               fprintf (dump_file, " (UID: %u)\n", DECL_UID (var));
              }
          }
       }
@@ -2169,12 +2397,12 @@ analyze_all_variable_accesses (void)
 }
 
 /* Generate statements copying scalar replacements of accesses within a subtree
-   into or out of AGG.  ACCESS is the first child of the root of the subtree to
-   be processed.  AGG is an aggregate type expression (can be a declaration but
-   does not have to be, it can for example also be a mem_ref or a series of
-   handled components).  TOP_OFFSET is the offset of the processed subtree
-   which has to be subtracted from offsets of individual accesses to get
-   corresponding offsets for AGG.  If CHUNK_SIZE is non-null, copy only
+   into or out of AGG.  ACCESS, all its children, siblings and their children
+   are to be processed.  AGG is an aggregate type expression (can be a
+   declaration but does not have to be, it can for example also be a mem_ref or
+   a series of handled components).  TOP_OFFSET is the offset of the processed
+   subtree which has to be subtracted from offsets of individual accesses to
+   get corresponding offsets for AGG.  If CHUNK_SIZE is non-null, copy only
    replacements in the interval <start_offset, start_offset + chunk_size>,
    otherwise copy all.  GSI is a statement iterator used to place the new
    statements.  WRITE should be true when the statements should write from AGG
@@ -2260,8 +2488,7 @@ init_subtree_with_zero (struct access *access, gimple_stmt_iterator *gsi,
       gimple stmt;
 
       stmt = gimple_build_assign (get_access_replacement (access),
-                                 fold_convert (access->type,
-                                               integer_zero_node));
+                                 build_zero_cst (access->type));
       if (insert_after)
        gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
       else
@@ -2405,11 +2632,11 @@ enum unscalarized_data_handling { SRA_UDH_NONE,  /* Nothing done so far. */
                                  SRA_UDH_LEFT }; /* Data flushed to the LHS. */
 
 /* Store all replacements in the access tree rooted in TOP_RACC either to their
-   base aggregate if there are unscalarized data or directly to LHS
-   otherwise.  */
+   base aggregate if there are unscalarized data or directly to LHS of the
+   statement that is pointed to by GSI otherwise.  */
 
 static enum unscalarized_data_handling
-handle_unscalarized_data_in_subtree (struct access *top_racc, tree lhs,
+handle_unscalarized_data_in_subtree (struct access *top_racc,
                                     gimple_stmt_iterator *gsi)
 {
   if (top_racc->grp_unscalarized_data)
@@ -2421,6 +2648,7 @@ handle_unscalarized_data_in_subtree (struct access *top_racc, tree lhs,
     }
   else
     {
+      tree lhs = gimple_assign_lhs (gsi_stmt (*gsi));
       generate_subtree_copies (top_racc->first_child, lhs, top_racc->offset,
                               0, 0, gsi, false, false,
                               gimple_location (gsi_stmt (*gsi)));
@@ -2429,33 +2657,30 @@ handle_unscalarized_data_in_subtree (struct access *top_racc, tree lhs,
 }
 
 
-/* Try to generate statements to load all sub-replacements in an access
-   (sub)tree (LACC is the first child) from scalar replacements in the TOP_RACC
-   (sub)tree.  If that is not possible, refresh the TOP_RACC base aggregate and
-   load the accesses from it.  LEFT_OFFSET is the offset of the left whole
-   subtree being copied, RIGHT_OFFSET is the same thing for the right subtree.
-   NEW_GSI is stmt iterator used for statement insertions after the original
-   assignment, OLD_GSI is used to insert statements before the assignment.
-   *REFRESHED keeps the information whether we have needed to refresh
-   replacements of the LHS and from which side of the assignments this takes
-   place.  */
+/* Try to generate statements to load all sub-replacements in an access subtree
+   formed by children of LACC from scalar replacements in the TOP_RACC subtree.
+   If that is not possible, refresh the TOP_RACC base aggregate and load the
+   accesses from it.  LEFT_OFFSET is the offset of the left whole subtree being
+   copied. NEW_GSI is stmt iterator used for statement insertions after the
+   original assignment, OLD_GSI is used to insert statements before the
+   assignment.  *REFRESHED keeps the information whether we have needed to
+   refresh replacements of the LHS and from which side of the assignments this
+   takes place.  */
 
 static void
 load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
                                 HOST_WIDE_INT left_offset,
-                                HOST_WIDE_INT right_offset,
                                 gimple_stmt_iterator *old_gsi,
                                 gimple_stmt_iterator *new_gsi,
-                                enum unscalarized_data_handling *refreshed,
-                                tree lhs)
+                                enum unscalarized_data_handling *refreshed)
 {
   location_t loc = gimple_location (gsi_stmt (*old_gsi));
-  do
+  for (lacc = lacc->first_child; lacc; lacc = lacc->next_sibling)
     {
       if (lacc->grp_to_be_replaced)
        {
          struct access *racc;
-         HOST_WIDE_INT offset = lacc->offset - left_offset + right_offset;
+         HOST_WIDE_INT offset = lacc->offset - left_offset + top_racc->offset;
          gimple stmt;
          tree rhs;
 
@@ -2471,7 +2696,7 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
              /* No suitable access on the right hand side, need to load from
                 the aggregate.  See if we have to update it first... */
              if (*refreshed == SRA_UDH_NONE)
-               *refreshed = handle_unscalarized_data_in_subtree (top_racc, lhs,
+               *refreshed = handle_unscalarized_data_in_subtree (top_racc,
                                                                  old_gsi);
 
              if (*refreshed == SRA_UDH_LEFT)
@@ -2490,16 +2715,13 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
        }
       else if (*refreshed == SRA_UDH_NONE
               && lacc->grp_read && !lacc->grp_covered)
-       *refreshed = handle_unscalarized_data_in_subtree (top_racc, lhs,
+       *refreshed = handle_unscalarized_data_in_subtree (top_racc,
                                                          old_gsi);
 
       if (lacc->first_child)
-       load_assign_lhs_subreplacements (lacc->first_child, top_racc,
-                                        left_offset, right_offset,
-                                        old_gsi, new_gsi, refreshed, lhs);
-      lacc = lacc->next_sibling;
+       load_assign_lhs_subreplacements (lacc, top_racc, left_offset,
+                                        old_gsi, new_gsi, refreshed);
     }
-  while (lacc);
 }
 
 /* Result code for SRA assignment modification.  */
@@ -2570,6 +2792,41 @@ get_repl_default_def_ssa_name (struct access *racc)
   return repl;
 }
 
+/* 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;
+}
+
+/* Return true if REF has an VIEW_CONVERT_EXPR or a COMPONENT_REF with a
+   bit-field field declaration somewhere in it.  */
+
+static inline bool
+contains_vce_or_bfcref_p (const_tree ref)
+{
+  while (handled_component_p (ref))
+    {
+      if (TREE_CODE (ref) == VIEW_CONVERT_EXPR
+         || (TREE_CODE (ref) == COMPONENT_REF
+             && DECL_BIT_FIELD (TREE_OPERAND (ref, 1))))
+       return true;
+      ref = TREE_OPERAND (ref, 0);
+    }
+
+  return false;
+}
+
 /* Examine both sides of the assignment statement pointed to by STMT, replace
    them with a scalare replacement if there is one and generate copying of
    replacements if scalarized aggregates have been used in the assignment.  GSI
@@ -2638,17 +2895,16 @@ 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))
            {
-             lhs = build_ref_for_offset (loc, lhs, 0, TREE_TYPE (rhs),
-                                         gsi, false);
+             lhs = build_ref_for_model (loc, lhs, 0, racc, gsi, false);
              gimple_assign_set_lhs (*stmt, lhs);
            }
          else if (AGGREGATE_TYPE_P (TREE_TYPE (rhs))
-                  && !contains_view_convert_expr_p (rhs)
+                  && !contains_vce_or_bfcref_p (rhs)
                   && !access_has_children_p (racc))
-           rhs = build_ref_for_offset (loc, rhs, 0, TREE_TYPE (lhs),
-                                       gsi, false);
+           rhs = build_ref_for_model (loc, rhs, 0, lacc, gsi, false);
 
          if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
            {
@@ -2694,9 +2950,10 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
      there to do the copying and then load the scalar replacements of the LHS.
      This is what the first branch does.  */
 
-  if (gimple_has_volatile_ops (*stmt)
-      || contains_view_convert_expr_p (rhs)
-      || contains_view_convert_expr_p (lhs))
+  if (modify_this_stmt
+      || gimple_has_volatile_ops (*stmt)
+      || contains_vce_or_bfcref_p (rhs)
+      || contains_vce_or_bfcref_p (lhs))
     {
       if (access_has_children_p (racc))
        generate_subtree_copies (racc->first_child, racc->base, 0, 0, 0,
@@ -2714,14 +2971,12 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
          enum unscalarized_data_handling refreshed;
 
          if (lacc->grp_read && !lacc->grp_covered)
-           refreshed = handle_unscalarized_data_in_subtree (racc, lhs, gsi);
+           refreshed = handle_unscalarized_data_in_subtree (racc, gsi);
          else
            refreshed = SRA_UDH_NONE;
 
-         load_assign_lhs_subreplacements (lacc->first_child, racc,
-                                          lacc->offset, racc->offset,
-                                          &orig_gsi, gsi, &refreshed,
-                                          lhs);
+         load_assign_lhs_subreplacements (lacc, racc, lacc->offset,
+                                          &orig_gsi, gsi, &refreshed);
          if (refreshed != SRA_UDH_RIGHT)
            {
              gsi_next (gsi);
@@ -2991,8 +3246,7 @@ struct gimple_opt_pass pass_sra_early =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func
-  | TODO_update_ssa
+  TODO_update_ssa
   | TODO_ggc_collect
   | TODO_verify_ssa                    /* todo_flags_finish */
  }
@@ -3013,8 +3267,7 @@ struct gimple_opt_pass pass_sra =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   TODO_update_address_taken,           /* todo_flags_start */
-  TODO_dump_func
-  | TODO_update_ssa
+  TODO_update_ssa
   | TODO_ggc_collect
   | TODO_verify_ssa                    /* todo_flags_finish */
  }
@@ -3064,7 +3317,8 @@ ptr_parm_has_direct_uses (tree parm)
              && TREE_OPERAND (lhs, 0) == name
              && integer_zerop (TREE_OPERAND (lhs, 1))
              && types_compatible_p (TREE_TYPE (lhs),
-                                    TREE_TYPE (TREE_TYPE (name))))
+                                    TREE_TYPE (TREE_TYPE (name)))
+             && !TREE_THIS_VOLATILE (lhs))
            uses_ok++;
        }
       if (gimple_assign_single_p (stmt))
@@ -3076,7 +3330,8 @@ ptr_parm_has_direct_uses (tree parm)
              && TREE_OPERAND (rhs, 0) == name
              && integer_zerop (TREE_OPERAND (rhs, 1))
              && types_compatible_p (TREE_TYPE (rhs),
-                                    TREE_TYPE (TREE_TYPE (name))))
+                                    TREE_TYPE (TREE_TYPE (name)))
+             && !TREE_THIS_VOLATILE (rhs))
            uses_ok++;
        }
       else if (is_gimple_call (stmt))
@@ -3091,7 +3346,8 @@ ptr_parm_has_direct_uses (tree parm)
                  && TREE_OPERAND (arg, 0) == name
                  && integer_zerop (TREE_OPERAND (arg, 1))
                  && types_compatible_p (TREE_TYPE (arg),
-                                        TREE_TYPE (TREE_TYPE (name))))
+                                        TREE_TYPE (TREE_TYPE (name)))
+                 && !TREE_THIS_VOLATILE (arg))
                uses_ok++;
            }
        }
@@ -3122,6 +3378,7 @@ find_param_candidates (void)
   tree parm;
   int count = 0;
   bool ret = false;
+  const char *msg;
 
   for (parm = DECL_ARGUMENTS (current_function_decl);
        parm;
@@ -3162,7 +3419,7 @@ find_param_candidates (void)
          || !host_integerp (TYPE_SIZE (type), 1)
           || tree_low_cst (TYPE_SIZE (type), 1) == 0
          || (AGGREGATE_TYPE_P (type)
-             && type_internals_preclude_sra_p (type)))
+             && type_internals_preclude_sra_p (type, &msg)))
        continue;
 
       bitmap_set_bit (candidate_bitmap, DECL_UID (parm));
@@ -3442,6 +3699,9 @@ access_precludes_ipa_sra_p (struct access *access)
          || gimple_code (access->stmt) == GIMPLE_ASM))
     return true;
 
+  if (tree_non_mode_aligned_mem_p (access->expr))
+    return true;
+
   return false;
 }
 
@@ -3466,8 +3726,7 @@ splice_param_accesses (tree parm, bool *ro_grp)
     return &no_accesses_representant;
   access_count = VEC_length (access_p, access_vec);
 
-  qsort (VEC_address (access_p, access_vec), access_count, sizeof (access_p),
-        compare_access_positions);
+  VEC_qsort (access_p, access_vec, compare_access_positions);
 
   i = 0;
   total_size = 0;
@@ -3475,10 +3734,12 @@ splice_param_accesses (tree parm, bool *ro_grp)
   while (i < access_count)
     {
       bool modification;
+      tree a1_alias_type;
       access = VEC_index (access_p, access_vec, i);
       modification = access->write;
       if (access_precludes_ipa_sra_p (access))
        return NULL;
+      a1_alias_type = reference_alias_ptr_type (access->expr);
 
       /* Access is about to become group representative unless we find some
         nasty overlap which would preclude us from breaking this parameter
@@ -3499,7 +3760,11 @@ splice_param_accesses (tree parm, bool *ro_grp)
          else if (ac2->size != access->size)
            return NULL;
 
-         if (access_precludes_ipa_sra_p (ac2))
+         if (access_precludes_ipa_sra_p (ac2)
+             || (ac2->type != access->type
+                 && (TREE_ADDRESSABLE (ac2->type)
+                     || TREE_ADDRESSABLE (access->type)))
+             || (reference_alias_ptr_type (ac2->expr) != a1_alias_type))
            return NULL;
 
          modification |= ac2->write;
@@ -3571,13 +3836,18 @@ decide_one_param_reduction (struct access *repr)
   for (; repr; repr = repr->next_grp)
     {
       gcc_assert (parm == repr->base);
-      new_param_count++;
+
+      /* Taking the address of a non-addressable field is verboten.  */
+      if (by_ref && repr->non_addressable)
+       return 0;
 
       if (!by_ref || (!repr->grp_maybe_modified
                      && !repr->grp_not_necessarilly_dereferenced))
        total_size += repr->size;
       else
        total_size += cur_parm_size;
+
+      new_param_count++;
     }
 
   gcc_assert (new_param_count > 0);
@@ -3734,6 +4004,7 @@ turn_representatives_into_adjustments (VEC (access_p, heap) *representatives,
              adj->base_index = index;
              adj->base = repr->base;
              adj->type = repr->type;
+             adj->alias_ptr_type = reference_alias_ptr_type (repr->expr);
              adj->offset = repr->offset;
              adj->by_ref = (POINTER_TYPE_P (TREE_TYPE (repr->base))
                             && (repr->grp_maybe_modified
@@ -3846,7 +4117,6 @@ get_replaced_param_substitute (struct ipa_parm_adjustment *adj)
       DECL_NAME (repl) = get_identifier (pretty_name);
       obstack_free (&name_obstack, pretty_name);
 
-      get_var_ann (repl);
       add_referenced_var (repl);
       adj->new_ssa_base = repl;
     }
@@ -4042,7 +4312,7 @@ sra_ipa_modify_assign (gimple *stmt_ptr, gimple_stmt_iterator *gsi,
            {
              /* V_C_Es of constructors can cause trouble (PR 42714).  */
              if (is_gimple_reg_type (TREE_TYPE (*lhs_p)))
-               *rhs_p = fold_convert (TREE_TYPE (*lhs_p), integer_zero_node);
+               *rhs_p = build_zero_cst (TREE_TYPE (*lhs_p));
              else
                *rhs_p = build_constructor (TREE_TYPE (*lhs_p), 0);
            }
@@ -4165,57 +4435,115 @@ static void
 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))
+    {
+      gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR));
+      gsip = &gsi;
+    }
   len = VEC_length (ipa_parm_adjustment_t, adjustments);
   for (i = 0; i < len; i++)
     {
       struct ipa_parm_adjustment *adj;
       imm_use_iterator ui;
-      gimple stmt;
-      tree name;
+      gimple stmt, def_temp;
+      tree name, vexpr, copy = NULL_TREE;
+      use_operand_p use_p;
 
       adj = VEC_index (ipa_parm_adjustment_t, adjustments, i);
       if (adj->copy_param || !is_gimple_reg (adj->base))
        continue;
       name = gimple_default_def (cfun, adj->base);
-      if (!name)
-       continue;
-      FOR_EACH_IMM_USE_STMT (stmt, ui, name)
+      vexpr = NULL;
+      if (name)
+       FOR_EACH_IMM_USE_STMT (stmt, ui, name)
+         {
+           /* All other users must have been removed by
+              ipa_sra_modify_function_body.  */
+           gcc_assert (is_gimple_debug (stmt));
+           if (vexpr == NULL && gsip != NULL)
+             {
+               gcc_assert (TREE_CODE (adj->base) == PARM_DECL);
+               vexpr = make_node (DEBUG_EXPR_DECL);
+               def_temp = gimple_build_debug_source_bind (vexpr, adj->base,
+                                                          NULL);
+               DECL_ARTIFICIAL (vexpr) = 1;
+               TREE_TYPE (vexpr) = TREE_TYPE (name);
+               DECL_MODE (vexpr) = DECL_MODE (adj->base);
+               gsi_insert_before (gsip, def_temp, GSI_SAME_STMT);
+             }
+           if (vexpr)
+             {
+               FOR_EACH_IMM_USE_ON_STMT (use_p, ui)
+                 SET_USE (use_p, vexpr);
+             }
+           else
+             gimple_debug_bind_reset_value (stmt);
+           update_stmt (stmt);
+         }
+      /* Create a VAR_DECL for debug info purposes.  */
+      if (!DECL_IGNORED_P (adj->base))
        {
-         /* All other users must have been removed by
-            ipa_sra_modify_function_body.  */
-         gcc_assert (is_gimple_debug (stmt));
-         gimple_debug_bind_reset_value (stmt);
-         update_stmt (stmt);
+         copy = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
+                            VAR_DECL, DECL_NAME (adj->base),
+                            TREE_TYPE (adj->base));
+         if (DECL_PT_UID_SET_P (adj->base))
+           SET_DECL_PT_UID (copy, DECL_PT_UID (adj->base));
+         TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (adj->base);
+         TREE_READONLY (copy) = TREE_READONLY (adj->base);
+         TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (adj->base);
+         DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (adj->base);
+         DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (adj->base);
+         DECL_IGNORED_P (copy) = DECL_IGNORED_P (adj->base);
+         DECL_ABSTRACT_ORIGIN (copy) = DECL_ORIGIN (adj->base);
+         DECL_SEEN_IN_BIND_EXPR_P (copy) = 1;
+         SET_DECL_RTL (copy, 0);
+         TREE_USED (copy) = 1;
+         DECL_CONTEXT (copy) = current_function_decl;
+         add_referenced_var (copy);
+         add_local_decl (cfun, copy);
+         DECL_CHAIN (copy) =
+           BLOCK_VARS (DECL_INITIAL (current_function_decl));
+         BLOCK_VARS (DECL_INITIAL (current_function_decl)) = copy;
+       }
+      if (gsip != NULL && copy && target_for_debug_bind (adj->base))
+       {
+         gcc_assert (TREE_CODE (adj->base) == PARM_DECL);
+         if (vexpr)
+           def_temp = gimple_build_debug_bind (copy, vexpr, NULL);
+         else
+           def_temp = gimple_build_debug_source_bind (copy, adj->base,
+                                                      NULL);
+         gsi_insert_before (gsip, def_temp, GSI_SAME_STMT);
        }
     }
 }
 
-/* Return true iff all callers have at least as many actual arguments as there
+/* Return false iff all callers have at least as many actual arguments as there
    are formal parameters in the current function.  */
 
 static bool
-all_callers_have_enough_arguments_p (struct cgraph_node *node)
+not_all_callers_have_enough_arguments_p (struct cgraph_node *node,
+                                        void *data ATTRIBUTE_UNUSED)
 {
   struct cgraph_edge *cs;
   for (cs = node->callers; cs; cs = cs->next_caller)
     if (!callsite_has_enough_arguments_p (cs->call_stmt))
-      return false;
+      return true;
 
-  return true;
+  return false;
 }
 
+/* Convert all callers of NODE.  */
 
-/* Convert all callers of NODE to pass parameters as given in ADJUSTMENTS.  */
-
-static void
-convert_callers (struct cgraph_node *node, tree old_decl,
-                ipa_parm_adjustment_vec adjustments)
+static bool
+convert_callers_for_node (struct cgraph_node *node,
+                         void *data)
 {
-  tree old_cur_fndecl = current_function_decl;
-  struct cgraph_edge *cs;
-  basic_block this_block;
+  ipa_parm_adjustment_vec adjustments = (ipa_parm_adjustment_vec)data;
   bitmap recomputed_callers = BITMAP_ALLOC (NULL);
+  struct cgraph_edge *cs;
 
   for (cs = node->callers; cs; cs = cs->next_caller)
     {
@@ -4234,10 +4562,26 @@ convert_callers (struct cgraph_node *node, tree old_decl,
     }
 
   for (cs = node->callers; cs; cs = cs->next_caller)
-    if (bitmap_set_bit (recomputed_callers, cs->caller->uid))
-      compute_inline_parameters (cs->caller);
+    if (bitmap_set_bit (recomputed_callers, cs->caller->uid)
+       && gimple_in_ssa_p (DECL_STRUCT_FUNCTION (cs->caller->decl)))
+      compute_inline_parameters (cs->caller, true);
   BITMAP_FREE (recomputed_callers);
 
+  return true;
+}
+
+/* Convert all callers of NODE to pass parameters as given in ADJUSTMENTS.  */
+
+static void
+convert_callers (struct cgraph_node *node, tree old_decl,
+                ipa_parm_adjustment_vec adjustments)
+{
+  tree old_cur_fndecl = current_function_decl;
+  basic_block this_block;
+
+  cgraph_for_node_and_aliases (node, convert_callers_for_node,
+                              adjustments, false);
+
   current_function_decl = old_cur_fndecl;
 
   if (!encountered_recursive_call)
@@ -4274,19 +4618,11 @@ static bool
 modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
 {
   struct cgraph_node *new_node;
-  struct cgraph_edge *cs;
   bool cfg_changed;
-  VEC (cgraph_edge_p, heap) * redirect_callers;
-  int node_callers;
-
-  node_callers = 0;
-  for (cs = node->callers; cs != NULL; cs = cs->next_caller)
-    node_callers++;
-  redirect_callers = VEC_alloc (cgraph_edge_p, heap, node_callers);
-  for (cs = node->callers; cs != NULL; cs = cs->next_caller)
-    VEC_quick_push (cgraph_edge_p, redirect_callers, cs);
+  VEC (cgraph_edge_p, heap) * redirect_callers = collect_callers_of_node (node);
 
   rebuild_cgraph_edges ();
+  free_dominance_info (CDI_DOMINATORS);
   pop_cfun ();
   current_function_decl = NULL_TREE;
 
@@ -4317,6 +4653,13 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
       return false;
     }
 
+  if (!node->local.can_change_signature)
+    {
+      if (dump_file)
+       fprintf (dump_file, "Function can not change signature.\n");
+      return false;
+    }
+
   if (!tree_versionable_function_p (node->decl))
     {
       if (dump_file)
@@ -4332,7 +4675,7 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
     }
 
   if ((DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))
-      && node->global.size >= MAX_INLINE_INSNS_AUTO)
+      && inline_summary(node)->size >= MAX_INLINE_INSNS_AUTO)
     {
       if (dump_file)
        fprintf (dump_file, "Function too big to be made truly local.\n");
@@ -4365,7 +4708,7 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
 static unsigned int
 ipa_early_sra (void)
 {
-  struct cgraph_node *node = cgraph_node (current_function_decl);
+  struct cgraph_node *node = cgraph_get_node (current_function_decl);
   ipa_parm_adjustment_vec adjustments;
   int ret = 0;
 
@@ -4382,7 +4725,8 @@ ipa_early_sra (void)
       goto simple_out;
     }
 
-  if (!all_callers_have_enough_arguments_p (node))
+  if (cgraph_for_node_and_aliases (node, not_all_callers_have_enough_arguments_p,
+                                  NULL, true))
     {
       if (dump_file)
        fprintf (dump_file, "There are callers with insufficient number of "
@@ -4462,8 +4806,6 @@ struct gimple_opt_pass pass_early_ipa_sra =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_dump_cgraph    /* todo_flags_finish */
+  TODO_dump_cgraph                     /* todo_flags_finish */
  }
 };
-
-