OSDN Git Service

Backport from git Libtool:
[pf3gnuchains/gcc-fork.git] / gcc / tree-sra.c
index fed7fbd..636e30b 100644 (file)
@@ -1,8 +1,8 @@
 /* Scalar Replacement of Aggregates (SRA) converts some structure
    references into scalar references, exposing them to the scalar
    optimizers.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007
-     Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
 This file is part of GCC.
@@ -37,7 +37,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "tree-inline.h"
 #include "tree-flow.h"
-#include "tree-gimple.h"
+#include "gimple.h"
 #include "tree-dump.h"
 #include "tree-pass.h"
 #include "timevar.h"
@@ -208,8 +208,9 @@ extern void debug_sra_elt_name (struct sra_elt *);
 
 /* Forward declarations.  */
 static tree generate_element_ref (struct sra_elt *);
-static tree sra_build_assignment (tree dst, tree src);
-static void mark_all_v_defs (tree list);
+static gimple_seq sra_build_assignment (tree dst, tree src);
+static void mark_all_v_defs_seq (gimple_seq);
+static void mark_all_v_defs_stmt (gimple);
 
 \f
 /* Return true if DECL is an SRA candidate.  */
@@ -268,6 +269,7 @@ sra_type_can_be_decomposed_p (tree type)
            {
              /* Reject incorrectly represented bit fields.  */
              if (DECL_BIT_FIELD (t)
+                 && INTEGRAL_TYPE_P (TREE_TYPE (t))
                  && (tree_low_cst (DECL_SIZE (t), 1)
                      != TYPE_PRECISION (TREE_TYPE (t))))
                goto fail;
@@ -307,6 +309,26 @@ sra_type_can_be_decomposed_p (tree type)
   return false;
 }
 
+/* Returns true if the TYPE is one of the available va_list types.
+   Otherwise it returns false.
+   Note, that for multiple calling conventions there can be more
+   than just one va_list type present.  */
+
+static bool
+is_va_list_type (tree type)
+{
+  tree h;
+
+  if (type == NULL_TREE)
+    return false;
+  h = targetm.canonical_va_list_type (type);
+  if (h == NULL_TREE)
+    return false;
+  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (h))
+        return true;
+  return false;
+}
+
 /* Return true if DECL can be decomposed into a set of independent
    (though not necessarily scalar) variables.  */
 
@@ -356,12 +378,10 @@ decl_can_be_decomposed_p (tree var)
   /* HACK: if we decompose a va_list_type_node before inlining, then we'll
      confuse tree-stdarg.c, and we won't be able to figure out which and
      how many arguments are accessed.  This really should be improved in
-     tree-stdarg.c, as the decomposition is truely a win.  This could also
+     tree-stdarg.c, as the decomposition is truly a win.  This could also
      be fixed if the stdarg pass ran early, but this can't be done until
      we've aliasing information early too.  See PR 30791.  */
-  if (early_sra
-      && TYPE_MAIN_VARIANT (TREE_TYPE (var))
-        == TYPE_MAIN_VARIANT (va_list_type_node))
+  if (early_sra && is_va_list_type (TREE_TYPE (var)))
     return false;
 
   return true;
@@ -486,7 +506,7 @@ sra_hash_tree (tree t)
 static hashval_t
 sra_elt_hash (const void *x)
 {
-  const struct sra_elt *e = x;
+  const struct sra_elt *const e = (const struct sra_elt *) x;
   const struct sra_elt *p;
   hashval_t h;
 
@@ -509,8 +529,8 @@ sra_elt_hash (const void *x)
 static int
 sra_elt_eq (const void *x, const void *y)
 {
-  const struct sra_elt *a = x;
-  const struct sra_elt *b = y;
+  const struct sra_elt *const a = (const struct sra_elt *) x;
+  const struct sra_elt *const b = (const struct sra_elt *) y;
   tree ae, be;
   const struct sra_elt *ap = a->parent;
   const struct sra_elt *bp = b->parent;
@@ -591,7 +611,7 @@ lookup_element (struct sra_elt *parent, tree child, tree type,
   elt = *slot;
   if (!elt && insert == INSERT)
     {
-      *slot = elt = obstack_alloc (&sra_obstack, sizeof (*elt));
+      *slot = elt = XOBNEW (&sra_obstack, struct sra_elt);
       memset (elt, 0, sizeof (*elt));
 
       elt->parent = parent;
@@ -700,7 +720,7 @@ maybe_lookup_element_for_expr (tree expr)
    references, and categorize them.  */
 
 /* A set of callbacks for phases 2 and 4.  They'll be invoked for the
-   various kinds of references seen.  In all cases, *BSI is an iterator
+   various kinds of references seen.  In all cases, *GSI is an iterator
    pointing to the statement being processed.  */
 struct sra_walk_fns
 {
@@ -710,21 +730,21 @@ struct sra_walk_fns
      is a left-hand-side reference.  USE_ALL is true if we saw something we
      couldn't quite identify and had to force the use of the entire object.  */
   void (*use) (struct sra_elt *elt, tree *expr_p,
-              block_stmt_iterator *bsi, bool is_output, bool use_all);
+              gimple_stmt_iterator *gsi, bool is_output, bool use_all);
 
   /* Invoked when we have a copy between two scalarizable references.  */
   void (*copy) (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
-               block_stmt_iterator *bsi);
+               gimple_stmt_iterator *gsi);
 
   /* Invoked when ELT is initialized from a constant.  VALUE may be NULL,
      in which case it should be treated as an empty CONSTRUCTOR.  */
-  void (*init) (struct sra_elt *elt, tree value, block_stmt_iterator *bsi);
+  void (*init) (struct sra_elt *elt, tree value, gimple_stmt_iterator *gsi);
 
   /* Invoked when we have a copy between one scalarizable reference ELT
      and one non-scalarizable reference OTHER without side-effects. 
      IS_OUTPUT is true if ELT is on the left-hand side.  */
   void (*ldst) (struct sra_elt *elt, tree other,
-               block_stmt_iterator *bsi, bool is_output);
+               gimple_stmt_iterator *gsi, bool is_output);
 
   /* True during phase 2, false during phase 4.  */
   /* ??? This is a hack.  */
@@ -758,7 +778,7 @@ sra_find_candidate_decl (tree *tp, int *walk_subtrees,
    If we find one, invoke FNS->USE.  */
 
 static void
-sra_walk_expr (tree *expr_p, block_stmt_iterator *bsi, bool is_output,
+sra_walk_expr (tree *expr_p, gimple_stmt_iterator *gsi, bool is_output,
               const struct sra_walk_fns *fns)
 {
   tree expr = *expr_p;
@@ -785,7 +805,7 @@ sra_walk_expr (tree *expr_p, block_stmt_iterator *bsi, bool is_output,
            if (disable_scalarization)
              elt->cannot_scalarize = true;
            else
-             fns->use (elt, expr_p, bsi, is_output, use_all_p);
+             fns->use (elt, expr_p, gsi, is_output, use_all_p);
          }
        return;
 
@@ -855,18 +875,28 @@ sra_walk_expr (tree *expr_p, block_stmt_iterator *bsi, bool is_output,
            if (elt)
              elt->is_vector_lhs = true;
          }
+
        /* A bit field reference (access to *multiple* fields simultaneously)
-          is not currently scalarized.  Consider this an access to the
-          complete outer element, to which walk_tree will bring us next.  */
-         
+          is not currently scalarized.  Consider this an access to the full
+          outer element, to which walk_tree will bring us next.  */
        goto use_all;
 
-      case VIEW_CONVERT_EXPR:
-      case NOP_EXPR:
-       /* Similarly, a view/nop explicitly wants to look at an object in a
+      CASE_CONVERT:
+       /* Similarly, a nop explicitly wants to look at an object in a
           type other than the one we've scalarized.  */
        goto use_all;
 
+      case VIEW_CONVERT_EXPR:
+       /* Likewise for a view conversion, but with an additional twist:
+          it can be on the LHS and, in this case, an access to the full
+          outer element would mean a killing def.  So we need to punt
+          if we haven't already a full access to the current element,
+          because we cannot pretend to have a killing def if we only
+          have a partial access at some level.  */
+       if (is_output && !use_all_p && inner != expr)
+         disable_scalarization = true;
+       goto use_all;
+
       case WITH_SIZE_EXPR:
        /* This is a transparent wrapper.  The entire inner expression really
           is being used.  */
@@ -887,60 +917,62 @@ sra_walk_expr (tree *expr_p, block_stmt_iterator *bsi, bool is_output,
       }
 }
 
-/* Walk a TREE_LIST of values looking for scalarizable aggregates.
+/* Walk the arguments of a GIMPLE_CALL looking for scalarizable aggregates.
    If we find one, invoke FNS->USE.  */
 
 static void
-sra_walk_tree_list (tree list, block_stmt_iterator *bsi, bool is_output,
-                   const struct sra_walk_fns *fns)
-{
-  tree op;
-  for (op = list; op ; op = TREE_CHAIN (op))
-    sra_walk_expr (&TREE_VALUE (op), bsi, is_output, fns);
-}
-
-/* Walk the arguments of a CALL_EXPR looking for scalarizable aggregates.
-   If we find one, invoke FNS->USE.  */
-
-static void
-sra_walk_call_expr (tree expr, block_stmt_iterator *bsi,
+sra_walk_gimple_call (gimple stmt, gimple_stmt_iterator *gsi,
                    const struct sra_walk_fns *fns)
 {
   int i;
-  int nargs = call_expr_nargs (expr);
+  int nargs = gimple_call_num_args (stmt);
+
   for (i = 0; i < nargs; i++)
-    sra_walk_expr (&CALL_EXPR_ARG (expr, i), bsi, false, fns);
+    sra_walk_expr (gimple_call_arg_ptr (stmt, i), gsi, false, fns);
+
+  if (gimple_call_lhs (stmt))
+    sra_walk_expr (gimple_call_lhs_ptr (stmt), gsi, true, fns);
 }
 
-/* Walk the inputs and outputs of an ASM_EXPR looking for scalarizable
+/* Walk the inputs and outputs of a GIMPLE_ASM looking for scalarizable
    aggregates.  If we find one, invoke FNS->USE.  */
 
 static void
-sra_walk_asm_expr (tree expr, block_stmt_iterator *bsi,
+sra_walk_gimple_asm (gimple stmt, gimple_stmt_iterator *gsi,
                   const struct sra_walk_fns *fns)
 {
-  sra_walk_tree_list (ASM_INPUTS (expr), bsi, false, fns);
-  sra_walk_tree_list (ASM_OUTPUTS (expr), bsi, true, fns);
+  size_t i;
+  for (i = 0; i < gimple_asm_ninputs (stmt); i++)
+    sra_walk_expr (&TREE_VALUE (gimple_asm_input_op (stmt, i)), gsi, false, fns);
+  for (i = 0; i < gimple_asm_noutputs (stmt); i++)
+    sra_walk_expr (&TREE_VALUE (gimple_asm_output_op (stmt, i)), gsi, true, fns);
 }
 
-/* Walk a GIMPLE_MODIFY_STMT and categorize the assignment appropriately.  */
+/* Walk a GIMPLE_ASSIGN and categorize the assignment appropriately.  */
 
 static void
-sra_walk_gimple_modify_stmt (tree expr, block_stmt_iterator *bsi,
-                            const struct sra_walk_fns *fns)
+sra_walk_gimple_assign (gimple stmt, gimple_stmt_iterator *gsi,
+                       const struct sra_walk_fns *fns)
 {
-  struct sra_elt *lhs_elt, *rhs_elt;
+  struct sra_elt *lhs_elt = NULL, *rhs_elt = NULL;
   tree lhs, rhs;
 
-  lhs = GIMPLE_STMT_OPERAND (expr, 0);
-  rhs = GIMPLE_STMT_OPERAND (expr, 1);
+  /* If there is more than 1 element on the RHS, only walk the lhs.  */
+  if (!gimple_assign_single_p (stmt))
+    {
+      sra_walk_expr (gimple_assign_lhs_ptr (stmt), gsi, true, fns);
+      return;
+    }
+
+  lhs = gimple_assign_lhs (stmt);
+  rhs = gimple_assign_rhs1 (stmt);
   lhs_elt = maybe_lookup_element_for_expr (lhs);
   rhs_elt = maybe_lookup_element_for_expr (rhs);
 
   /* If both sides are scalarizable, this is a COPY operation.  */
   if (lhs_elt && rhs_elt)
     {
-      fns->copy (lhs_elt, rhs_elt, bsi);
+      fns->copy (lhs_elt, rhs_elt, gsi);
       return;
     }
 
@@ -948,9 +980,9 @@ sra_walk_gimple_modify_stmt (tree expr, block_stmt_iterator *bsi,
   if (rhs_elt)
     {
       if (!rhs_elt->is_scalar && !TREE_SIDE_EFFECTS (lhs))
-       fns->ldst (rhs_elt, lhs, bsi, false);
+       fns->ldst (rhs_elt, lhs, gsi, false);
       else
-       fns->use (rhs_elt, &GIMPLE_STMT_OPERAND (expr, 1), bsi, false, false);
+       fns->use (rhs_elt, gimple_assign_rhs1_ptr (stmt), gsi, false, false);
     }
 
   /* If it isn't scalarizable, there may be scalarizable variables within, so
@@ -959,13 +991,7 @@ sra_walk_gimple_modify_stmt (tree expr, block_stmt_iterator *bsi,
      that the statements get inserted in the proper place, before any
      copy-out operations.  */
   else
-    {
-      tree call = get_call_expr_in (rhs);
-      if (call)
-       sra_walk_call_expr (call, bsi, fns);
-      else
-       sra_walk_expr (&GIMPLE_STMT_OPERAND (expr, 1), bsi, false, fns);
-    }
+    sra_walk_expr (gimple_assign_rhs1_ptr (stmt), gsi, false, fns);
 
   /* Likewise, handle the LHS being scalarizable.  We have cases similar
      to those above, but also want to handle RHS being constant.  */
@@ -976,15 +1002,16 @@ sra_walk_gimple_modify_stmt (tree expr, block_stmt_iterator *bsi,
       if (TREE_CODE (rhs) == COMPLEX_EXPR
          || TREE_CODE (rhs) == COMPLEX_CST
          || TREE_CODE (rhs) == CONSTRUCTOR)
-       fns->init (lhs_elt, rhs, bsi);
+       fns->init (lhs_elt, rhs, gsi);
 
       /* If this is an assignment from read-only memory, treat this as if
         we'd been passed the constructor directly.  Invoke INIT.  */
       else if (TREE_CODE (rhs) == VAR_DECL
               && TREE_STATIC (rhs)
+              && !DECL_EXTERNAL (rhs)
               && TREE_READONLY (rhs)
               && targetm.binds_local_p (rhs))
-       fns->init (lhs_elt, DECL_INITIAL (rhs), bsi);
+       fns->init (lhs_elt, DECL_INITIAL (rhs), gsi);
 
       /* If this is a copy from a non-scalarizable lvalue, invoke LDST.
         The lvalue requirement prevents us from trying to directly scalarize
@@ -992,19 +1019,19 @@ sra_walk_gimple_modify_stmt (tree expr, block_stmt_iterator *bsi,
         the function multiple times, and other evil things.  */
       else if (!lhs_elt->is_scalar
               && !TREE_SIDE_EFFECTS (rhs) && is_gimple_addressable (rhs))
-       fns->ldst (lhs_elt, rhs, bsi, true);
+       fns->ldst (lhs_elt, rhs, gsi, true);
 
       /* Otherwise we're being used in some context that requires the
         aggregate to be seen as a whole.  Invoke USE.  */
       else
-       fns->use (lhs_elt, &GIMPLE_STMT_OPERAND (expr, 0), bsi, true, false);
+       fns->use (lhs_elt, gimple_assign_lhs_ptr (stmt), gsi, true, false);
     }
 
   /* Similarly to above, LHS_ELT being null only means that the LHS as a
      whole is not a scalarizable reference.  There may be occurrences of
      scalarizable variables within, which implies a USE.  */
   else
-    sra_walk_expr (&GIMPLE_STMT_OPERAND (expr, 0), bsi, true, fns);
+    sra_walk_expr (gimple_assign_lhs_ptr (stmt), gsi, true, fns);
 }
 
 /* Entry point to the walk functions.  Search the entire function,
@@ -1015,22 +1042,20 @@ static void
 sra_walk_function (const struct sra_walk_fns *fns)
 {
   basic_block bb;
-  block_stmt_iterator si, ni;
+  gimple_stmt_iterator si, ni;
 
   /* ??? Phase 4 could derive some benefit to walking the function in
      dominator tree order.  */
 
   FOR_EACH_BB (bb)
-    for (si = bsi_start (bb); !bsi_end_p (si); si = ni)
+    for (si = gsi_start_bb (bb); !gsi_end_p (si); si = ni)
       {
-       tree stmt, t;
-       stmt_ann_t ann;
+       gimple stmt;
 
-       stmt = bsi_stmt (si);
-       ann = stmt_ann (stmt);
+       stmt = gsi_stmt (si);
 
        ni = si;
-       bsi_next (&ni);
+       gsi_next (&ni);
 
        /* If the statement has no virtual operands, then it doesn't
           make any structure references that we care about.  */
@@ -1038,35 +1063,28 @@ sra_walk_function (const struct sra_walk_fns *fns)
            && ZERO_SSA_OPERANDS (stmt, (SSA_OP_VIRTUAL_DEFS | SSA_OP_VUSE)))
              continue;
 
-       switch (TREE_CODE (stmt))
+       switch (gimple_code (stmt))
          {
-         case RETURN_EXPR:
+         case GIMPLE_RETURN:
            /* If we have "return <retval>" then the return value is
               already exposed for our pleasure.  Walk it as a USE to
               force all the components back in place for the return.
-
-              If we have an embedded assignment, then <retval> is of
-              a type that gets returned in registers in this ABI, and
-              we do not wish to extend their lifetimes.  Treat this
-              as a USE of the variable on the RHS of this assignment.  */
-
-           t = TREE_OPERAND (stmt, 0);
-           if (t == NULL_TREE)
+              */
+           if (gimple_return_retval (stmt)  == NULL_TREE)
              ;
-           else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
-             sra_walk_expr (&GIMPLE_STMT_OPERAND (t, 1), &si, false, fns);
            else
-             sra_walk_expr (&TREE_OPERAND (stmt, 0), &si, false, fns);
+             sra_walk_expr (gimple_return_retval_ptr (stmt), &si, false,
+                             fns);
            break;
 
-         case GIMPLE_MODIFY_STMT:
-           sra_walk_gimple_modify_stmt (stmt, &si, fns);
+         case GIMPLE_ASSIGN:
+           sra_walk_gimple_assign (stmt, &si, fns);
            break;
-         case CALL_EXPR:
-           sra_walk_call_expr (stmt, &si, fns);
+         case GIMPLE_CALL:
+           sra_walk_gimple_call (stmt, &si, fns);
            break;
-         case ASM_EXPR:
-           sra_walk_asm_expr (stmt, &si, fns);
+         case GIMPLE_ASM:
+           sra_walk_gimple_asm (stmt, &si, fns);
            break;
 
          default:
@@ -1107,7 +1125,7 @@ find_candidates_for_sra (void)
 
 static void
 scan_use (struct sra_elt *elt, tree *expr_p ATTRIBUTE_UNUSED,
-         block_stmt_iterator *bsi ATTRIBUTE_UNUSED,
+         gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED,
          bool is_output ATTRIBUTE_UNUSED, bool use_all ATTRIBUTE_UNUSED)
 {
   elt->n_uses += 1;
@@ -1115,7 +1133,7 @@ scan_use (struct sra_elt *elt, tree *expr_p ATTRIBUTE_UNUSED,
 
 static void
 scan_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
-          block_stmt_iterator *bsi ATTRIBUTE_UNUSED)
+          gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED)
 {
   lhs_elt->n_copies += 1;
   rhs_elt->n_copies += 1;
@@ -1123,14 +1141,14 @@ scan_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
 
 static void
 scan_init (struct sra_elt *lhs_elt, tree rhs ATTRIBUTE_UNUSED,
-          block_stmt_iterator *bsi ATTRIBUTE_UNUSED)
+          gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED)
 {
   lhs_elt->n_copies += 1;
 }
 
 static void
 scan_ldst (struct sra_elt *elt, tree other ATTRIBUTE_UNUSED,
-          block_stmt_iterator *bsi ATTRIBUTE_UNUSED,
+          gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED,
           bool is_output ATTRIBUTE_UNUSED)
 {
   elt->n_copies += 1;
@@ -1273,16 +1291,13 @@ instantiate_element (struct sra_elt *elt)
       DECL_SIZE_UNIT (var) = DECL_SIZE_UNIT (elt->element);
 
       elt->in_bitfld_block = 1;
-      elt->replacement = build3 (BIT_FIELD_REF, elt->type, var,
-                                DECL_SIZE (var),
-                                BITS_BIG_ENDIAN
-                                ? size_binop (MINUS_EXPR,
-                                              TYPE_SIZE (elt->type),
-                                              DECL_SIZE (var))
-                                : bitsize_int (0));
-      if (!INTEGRAL_TYPE_P (elt->type)
-         || TYPE_UNSIGNED (elt->type))
-       BIT_FIELD_REF_UNSIGNED (elt->replacement) = 1;
+      elt->replacement = fold_build3 (BIT_FIELD_REF, elt->type, var,
+                                     DECL_SIZE (var),
+                                     BYTES_BIG_ENDIAN
+                                     ? size_binop (MINUS_EXPR,
+                                                   TYPE_SIZE (elt->type),
+                                                   DECL_SIZE (var))
+                                     : bitsize_int (0));
     }
 
   /* For vectors, if used on the left hand side with BIT_FIELD_REF,
@@ -1324,10 +1339,12 @@ instantiate_element (struct sra_elt *elt)
       || (var != elt->replacement
          && TREE_CODE (elt->replacement) == BIT_FIELD_REF))
     {
-      tree init = sra_build_assignment (var, fold_convert (TREE_TYPE (var),
-                                                          integer_zero_node));
-      insert_edge_copies (init, ENTRY_BLOCK_PTR);
-      mark_all_v_defs (init);
+      gimple_seq init = sra_build_assignment (var,
+                                              fold_convert (TREE_TYPE (var),
+                                                            integer_zero_node)
+                                             );
+      insert_edge_copies_seq (init, ENTRY_BLOCK_PTR);
+      mark_all_v_defs_seq (init);
     }
 
   if (dump_file)
@@ -1465,6 +1482,10 @@ try_instantiate_multiple_fields (struct sra_elt *elt, tree f)
   tree type, var;
   struct sra_elt *block;
 
+  /* Point fields are typically best handled as standalone entities.  */
+  if (POINTER_TYPE_P (TREE_TYPE (f)))
+    return f;
+    
   if (!is_sra_scalar_type (TREE_TYPE (f))
       || !host_integerp (DECL_FIELD_OFFSET (f), 1)
       || !host_integerp (DECL_FIELD_BIT_OFFSET (f), 1)
@@ -1677,12 +1698,16 @@ try_instantiate_multiple_fields (struct sra_elt *elt, tree f)
 
   /* Create the field group as a single variable.  */
 
-  type = lang_hooks.types.type_for_mode (mode, 1);
+  /* We used to create a type for the mode above, but size turns
+     to be out not of mode-size.  As we need a matching type
+     to build a BIT_FIELD_REF, use a nonstandard integer type as
+     fallback.  */
+  type = lang_hooks.types.type_for_size (size, 1);
+  if (!type || TYPE_PRECISION (type) != size)
+    type = build_nonstandard_integer_type (size, 1);
   gcc_assert (type);
   var = build3 (BIT_FIELD_REF, type, NULL_TREE,
-               bitsize_int (size),
-               bitsize_int (bit));
-  BIT_FIELD_REF_UNSIGNED (var) = 1;
+               bitsize_int (size), bitsize_int (bit));
 
   block = instantiate_missing_elements_1 (elt, var, type);
   gcc_assert (block && block->is_scalar);
@@ -1692,11 +1717,10 @@ try_instantiate_multiple_fields (struct sra_elt *elt, tree f)
   if ((bit & ~alchk)
       || (HOST_WIDE_INT)size != tree_low_cst (DECL_SIZE (var), 1))
     {
-      block->replacement = build3 (BIT_FIELD_REF,
-                                  TREE_TYPE (block->element), var,
-                                  bitsize_int (size),
-                                  bitsize_int (bit & ~alchk));
-      BIT_FIELD_REF_UNSIGNED (block->replacement) = 1;
+      block->replacement = fold_build3 (BIT_FIELD_REF,
+                                       TREE_TYPE (block->element), var,
+                                       bitsize_int (size),
+                                       bitsize_int (bit & ~alchk));
     }
 
   block->in_bitfld_block = 2;
@@ -1711,15 +1735,14 @@ try_instantiate_multiple_fields (struct sra_elt *elt, tree f)
 
       gcc_assert (fld && fld->is_scalar && !fld->replacement);
 
-      fld->replacement = build3 (BIT_FIELD_REF, field_type, var,
-                                DECL_SIZE (f),
-                                bitsize_int
-                                ((TREE_INT_CST_LOW (DECL_FIELD_OFFSET (f))
-                                  * BITS_PER_UNIT
-                                  + (TREE_INT_CST_LOW
-                                     (DECL_FIELD_BIT_OFFSET (f))))
-                                 & ~alchk));
-      BIT_FIELD_REF_UNSIGNED (fld->replacement) = TYPE_UNSIGNED (field_type);
+      fld->replacement = fold_build3 (BIT_FIELD_REF, field_type, var,
+                                     DECL_SIZE (f),
+                                     bitsize_int
+                                     ((TREE_INT_CST_LOW (DECL_FIELD_OFFSET (f))
+                                       * BITS_PER_UNIT
+                                       + (TREE_INT_CST_LOW
+                                          (DECL_FIELD_BIT_OFFSET (f))))
+                                      & ~alchk));
       fld->in_bitfld_block = 1;
     }
 
@@ -1880,10 +1903,10 @@ decide_block_copy (struct sra_elt *elt)
             sensible default.  */
          max_size = SRA_MAX_STRUCTURE_SIZE
            ? SRA_MAX_STRUCTURE_SIZE
-           : MOVE_RATIO * UNITS_PER_WORD;
+           : MOVE_RATIO (optimize_function_for_speed_p (cfun)) * UNITS_PER_WORD;
          max_count = SRA_MAX_STRUCTURE_COUNT
            ? SRA_MAX_STRUCTURE_COUNT
-           : MOVE_RATIO;
+           : MOVE_RATIO (optimize_function_for_speed_p (cfun));
 
          full_size = tree_low_cst (size_tree, 1);
          full_count = count_type_elements (elt->type, false);
@@ -1998,7 +2021,7 @@ decide_instantiations (void)
    non-scalar.  */
 
 static void
-mark_all_v_defs_1 (tree stmt)
+mark_all_v_defs_stmt (gimple stmt)
 {
   tree sym;
   ssa_op_iter iter;
@@ -2018,18 +2041,13 @@ mark_all_v_defs_1 (tree stmt)
    LIST for renaming.  */
 
 static void
-mark_all_v_defs (tree list)
+mark_all_v_defs_seq (gimple_seq seq)
 {
-  if (TREE_CODE (list) != STATEMENT_LIST)
-    mark_all_v_defs_1 (list);
-  else
-    {
-      tree_stmt_iterator i;
-      for (i = tsi_start (list); !tsi_end_p (i); tsi_next (&i))
-       mark_all_v_defs_1 (tsi_stmt (i));
-    }
-}
+  gimple_stmt_iterator gsi;
 
+  for (gsi = gsi_start (seq); !gsi_end_p (gsi); gsi_next (&gsi))
+    mark_all_v_defs_stmt (gsi_stmt (gsi));
+}
 
 /* Mark every replacement under ELT with TREE_NO_WARNING.  */
 
@@ -2061,7 +2079,7 @@ generate_one_element_ref (struct sra_elt *elt, tree base)
       {
        tree field = elt->element;
 
-       /* We can't test elt->in_bitfld_blk here because, when this is
+       /* We can't test elt->in_bitfld_block here because, when this is
           called from instantiate_element, we haven't set this field
           yet.  */
        if (TREE_CODE (field) == BIT_FIELD_REF)
@@ -2123,34 +2141,44 @@ scalar_bitfield_p (tree bf)
 
 /* Create an assignment statement from SRC to DST.  */
 
-static tree
+static gimple_seq
 sra_build_assignment (tree dst, tree src)
 {
+  gimple stmt;
+  gimple_seq seq = NULL, seq2 = NULL;
   /* Turning BIT_FIELD_REFs into bit operations enables other passes
-     to do a much better job at optimizing the code.  */
+     to do a much better job at optimizing the code.
+     From dst = BIT_FIELD_REF <var, sz, off> we produce
+
+       SR.1 = (scalar type) var;
+       SR.2 = SR.1 >> off;
+       SR.3 = SR.2 & ((1 << sz) - 1);
+       ... possible sign extension of SR.3 ...
+       dst = (destination type) SR.3;
+   */
   if (scalar_bitfield_p (src))
     {
-      tree cst, cst2, mask, minshift, maxshift;
-      tree tmp, var, utype, stype;
-      tree list, stmt;
-      bool unsignedp = BIT_FIELD_REF_UNSIGNED (src);
+      tree var, shift, width;
+      tree utype, stype;
+      bool unsignedp = (INTEGRAL_TYPE_P (TREE_TYPE (src))
+                       ? TYPE_UNSIGNED (TREE_TYPE (src)) : true);
+      struct gimplify_ctx gctx;
 
       var = TREE_OPERAND (src, 0);
-      cst = TREE_OPERAND (src, 2);
-      cst2 = size_binop (PLUS_EXPR, TREE_OPERAND (src, 1),
-                        TREE_OPERAND (src, 2));
-
-      if (BITS_BIG_ENDIAN)
+      width = TREE_OPERAND (src, 1);
+      /* The offset needs to be adjusted to a right shift quantity
+        depending on the endianness.  */
+      if (BYTES_BIG_ENDIAN)
        {
-         maxshift = size_binop (MINUS_EXPR, TYPE_SIZE (TREE_TYPE (var)), cst);
-         minshift = size_binop (MINUS_EXPR, TYPE_SIZE (TREE_TYPE (var)), cst2);
+         tree tmp = size_binop (PLUS_EXPR, width, TREE_OPERAND (src, 2));
+         shift = size_binop (MINUS_EXPR, TYPE_SIZE (TREE_TYPE (var)), tmp);
        }
       else
-       {
-         maxshift = cst2;
-         minshift = cst;
-       }
+       shift = TREE_OPERAND (src, 2);
 
+      /* In weird cases we have non-integral types for the source or
+        destination object.
+        ???  For unknown reasons we also want an unsigned scalar type.  */
       stype = TREE_TYPE (var);
       if (!INTEGRAL_TYPE_P (stype))
        stype = lang_hooks.types.type_for_size (TREE_INT_CST_LOW
@@ -2165,122 +2193,72 @@ sra_build_assignment (tree dst, tree src)
       else if (!TYPE_UNSIGNED (utype))
        utype = unsigned_type_for (utype);
 
-      list = NULL;
-
-      cst2 = size_binop (MINUS_EXPR, maxshift, minshift);
-      if (tree_int_cst_equal (cst2, TYPE_SIZE (utype)))
-       {
-         unsignedp = true;
-         mask = NULL_TREE;
-       }
+      /* Convert the base var of the BIT_FIELD_REF to the scalar type
+        we use for computation if we cannot use it directly.  */
+      if (INTEGRAL_TYPE_P (TREE_TYPE (var)))
+       var = fold_convert (stype, var);
       else
-       {
-         mask = build_int_cst_wide (utype, 1, 0);
-         cst = int_const_binop (LSHIFT_EXPR, mask, cst2, true);
-         mask = int_const_binop (MINUS_EXPR, cst, mask, true);
-       }
-
-      tmp = make_rename_temp (stype, "SR");
-      if (TYPE_MAIN_VARIANT (TREE_TYPE (var)) != TYPE_MAIN_VARIANT (stype))
-       {
-         if (INTEGRAL_TYPE_P (TREE_TYPE (var)))
-           stmt = build_gimple_modify_stmt (tmp,
-                                            fold_convert (stype, var));
-         else
-           stmt = build_gimple_modify_stmt (tmp,
-                                            fold_build1 (VIEW_CONVERT_EXPR,
-                                                         stype, var));
-         append_to_statement_list (stmt, &list);
+       var = fold_build1 (VIEW_CONVERT_EXPR, stype, var);
 
-         var = tmp;
-       }
-
-      if (!integer_zerop (minshift))
-       {
-         tmp = make_rename_temp (stype, "SR");
-         stmt = build_gimple_modify_stmt (tmp,
-                                          fold_build2 (RSHIFT_EXPR, stype,
-                                                       var, minshift));
-         append_to_statement_list (stmt, &list);
+      if (!integer_zerop (shift))
+       var = fold_build2 (RSHIFT_EXPR, stype, var, shift);
 
-         var = tmp;
-       }
-
-      if (TYPE_MAIN_VARIANT (utype) != TYPE_MAIN_VARIANT (stype))
+      /* If we need a masking operation, produce one.  */
+      if (TREE_INT_CST_LOW (width) == TYPE_PRECISION (stype))
+       unsignedp = true;
+      else
        {
-         if (!mask && unsignedp
-             && (TYPE_MAIN_VARIANT (utype)
-                 == TYPE_MAIN_VARIANT (TREE_TYPE (dst))))
-           tmp = dst;
-         else
-           tmp = make_rename_temp (utype, "SR");
-
-         stmt = build_gimple_modify_stmt (tmp, fold_convert (utype, var));
-         append_to_statement_list (stmt, &list);
-
-         var = tmp;
+         tree one = build_int_cst_wide (stype, 1, 0);
+         tree mask = int_const_binop (LSHIFT_EXPR, one, width, 0);
+         mask = int_const_binop (MINUS_EXPR, mask, one, 0);
+         var = fold_build2 (BIT_AND_EXPR, stype, var, mask);
        }
 
-      if (mask)
-       {
-         if (!unsignedp
-             || (TYPE_MAIN_VARIANT (TREE_TYPE (dst))
-                 != TYPE_MAIN_VARIANT (utype)))
-           tmp = make_rename_temp (utype, "SR");
-         else
-           tmp = dst;
-
-         stmt = build_gimple_modify_stmt (tmp,
-                                          fold_build2 (BIT_AND_EXPR, utype,
-                                                       var, mask));
-         append_to_statement_list (stmt, &list);
-
-         var = tmp;
-       }
+      /* After shifting and masking, convert to the target type.  */
+      var = fold_convert (utype, var);
 
+      /* Perform sign extension, if required.
+        ???  This should never be necessary.  */
       if (!unsignedp)
        {
          tree signbit = int_const_binop (LSHIFT_EXPR,
                                          build_int_cst_wide (utype, 1, 0),
-                                         size_binop (MINUS_EXPR, cst2,
-                                                     bitsize_int (1)),
-                                         true);
-
-         tmp = make_rename_temp (utype, "SR");
-         stmt = build_gimple_modify_stmt (tmp,
-                                          fold_build2 (BIT_XOR_EXPR, utype,
-                                                       var, signbit));
-         append_to_statement_list (stmt, &list);
+                                         size_binop (MINUS_EXPR, width,
+                                                     bitsize_int (1)), 0);
 
-         var = tmp;
+         var = fold_build2 (BIT_XOR_EXPR, utype, var, signbit);
+         var = fold_build2 (MINUS_EXPR, utype, var, signbit);
+       }
 
-         if (TYPE_MAIN_VARIANT (TREE_TYPE (dst)) != TYPE_MAIN_VARIANT (utype))
-           tmp = make_rename_temp (utype, "SR");
-         else
-           tmp = dst;
+      /* fold_build3 (BIT_FIELD_REF, ...) sometimes returns a cast.  */
+      STRIP_NOPS (dst);
 
-         stmt = build_gimple_modify_stmt (tmp,
-                                          fold_build2 (MINUS_EXPR, utype,
-                                                       var, signbit));
-         append_to_statement_list (stmt, &list);
+      /* Finally, move and convert to the destination.  */
+      if (INTEGRAL_TYPE_P (TREE_TYPE (dst)))
+       var = fold_convert (TREE_TYPE (dst), var);
+      else
+       var = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (dst), var);
 
-         var = tmp;
-       }
+      push_gimplify_context (&gctx);
+      gctx.into_ssa = true;
+      gctx.allow_rhs_cond_expr = true;
 
-      if (var != dst)
-       {
-         if (INTEGRAL_TYPE_P (TREE_TYPE (dst)))
-           var = fold_convert (TREE_TYPE (dst), var);
-         else
-           var = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (dst), var);
+      gimplify_assign (dst, var, &seq);
 
-         stmt = build_gimple_modify_stmt (dst, var);
-         append_to_statement_list (stmt, &list);
-       }
+      if (gimple_referenced_vars (cfun))
+       for (var = gctx.temps; var; var = TREE_CHAIN (var))
+         add_referenced_var (var);
+      pop_gimplify_context (NULL);
 
-      return list;
+      return seq;
     }
 
+  /* fold_build3 (BIT_FIELD_REF, ...) sometimes returns a cast.  */
+  if (CONVERT_EXPR_P (dst))
+    {
+      STRIP_NOPS (dst);
+      src = fold_convert (TREE_TYPE (dst), src);
+    }
   /* It was hoped that we could perform some type sanity checking
      here, but since front-ends can emit accesses of fields in types
      different from their nominal types and copy structures containing
@@ -2288,8 +2266,24 @@ sra_build_assignment (tree dst, tree src)
      Since such accesses under different types require compatibility
      anyway, there's little point in making tests and/or adding
      conversions to ensure the types of src and dst are the same.
-     So we just assume type differences at this point are ok.  */
-  return build_gimple_modify_stmt (dst, src);
+     So we just assume type differences at this point are ok.
+     The only exception we make here are pointer types, which can be different
+     in e.g. structurally equal, but non-identical RECORD_TYPEs.  */
+  else if (POINTER_TYPE_P (TREE_TYPE (dst))
+          && !useless_type_conversion_p (TREE_TYPE (dst), TREE_TYPE (src)))
+    src = fold_convert (TREE_TYPE (dst), src);
+
+  /* ???  Only call the gimplifier if we need to.  Otherwise we may 
+     end up substituting with DECL_VALUE_EXPR - see PR37380.  */
+  if (!handled_component_p (src)
+      && !SSA_VAR_P (src))
+    {
+      src = force_gimple_operand (src, &seq2, false, NULL_TREE);
+      gimple_seq_add_seq (&seq, seq2);
+    }
+  stmt = gimple_build_assign (dst, src);
+  gimple_seq_add_stmt (&seq, stmt);
+  return seq;
 }
 
 /* BIT_FIELD_REFs must not be shared.  sra_build_elt_assignment()
@@ -2299,11 +2293,12 @@ sra_build_assignment (tree dst, tree src)
 /* Emit an assignment from SRC to DST, but if DST is a scalarizable
    BIT_FIELD_REF, turn it into bit operations.  */
 
-static tree
+static gimple_seq
 sra_build_bf_assignment (tree dst, tree src)
 {
   tree var, type, utype, tmp, tmp2, tmp3;
-  tree list, stmt;
+  gimple_seq seq;
+  gimple stmt;
   tree cst, cst2, mask;
   tree minshift, maxshift;
 
@@ -2315,14 +2310,14 @@ sra_build_bf_assignment (tree dst, tree src)
   if (!scalar_bitfield_p (dst))
     return sra_build_assignment (REPLDUP (dst), src);
 
-  list = NULL;
+  seq = NULL;
 
   cst = fold_convert (bitsizetype, TREE_OPERAND (dst, 2));
   cst2 = size_binop (PLUS_EXPR,
                     fold_convert (bitsizetype, TREE_OPERAND (dst, 1)),
                     cst);
 
-  if (BITS_BIG_ENDIAN)
+  if (BYTES_BIG_ENDIAN)
     {
       maxshift = size_binop (MINUS_EXPR, TYPE_SIZE (TREE_TYPE (var)), cst);
       minshift = size_binop (MINUS_EXPR, TYPE_SIZE (TREE_TYPE (var)), cst2);
@@ -2343,8 +2338,14 @@ sra_build_bf_assignment (tree dst, tree src)
     utype = unsigned_type_for (type);
 
   mask = build_int_cst_wide (utype, 1, 0);
-  cst = int_const_binop (LSHIFT_EXPR, mask, maxshift, true);
-  cst2 = int_const_binop (LSHIFT_EXPR, mask, minshift, true);
+  if (TREE_INT_CST_LOW (maxshift) == TYPE_PRECISION (utype))
+    cst = build_int_cst_wide (utype, 0, 0);
+  else
+    cst = int_const_binop (LSHIFT_EXPR, mask, maxshift, true);
+  if (integer_zerop (minshift))
+    cst2 = mask;
+  else
+    cst2 = int_const_binop (LSHIFT_EXPR, mask, minshift, true);
   mask = int_const_binop (MINUS_EXPR, cst, cst2, true);
   mask = fold_build1 (BIT_NOT_EXPR, utype, mask);
 
@@ -2354,15 +2355,18 @@ sra_build_bf_assignment (tree dst, tree src)
       tmp = var;
       if (!is_gimple_variable (tmp))
        tmp = unshare_expr (var);
+      else
+       TREE_NO_WARNING (var) = true;
 
       tmp2 = make_rename_temp (utype, "SR");
 
       if (INTEGRAL_TYPE_P (TREE_TYPE (var)))
-       stmt = build_gimple_modify_stmt (tmp2, fold_convert (utype, tmp));
+       tmp = fold_convert (utype, tmp);
       else
-       stmt = build_gimple_modify_stmt (tmp2, fold_build1 (VIEW_CONVERT_EXPR,
-                                                           utype, tmp));
-      append_to_statement_list (stmt, &list);
+       tmp = fold_build1 (VIEW_CONVERT_EXPR, utype, tmp);
+
+      stmt = gimple_build_assign (tmp2, tmp);
+      gimple_seq_add_stmt (&seq, stmt);
     }
   else
     tmp2 = var;
@@ -2370,10 +2374,9 @@ sra_build_bf_assignment (tree dst, tree src)
   if (!integer_zerop (mask))
     {
       tmp = make_rename_temp (utype, "SR");
-      stmt = build_gimple_modify_stmt (tmp,
-                                      fold_build2 (BIT_AND_EXPR, utype,
+      stmt = gimple_build_assign (tmp, fold_build2 (BIT_AND_EXPR, utype,
                                                    tmp2, mask));
-      append_to_statement_list (stmt, &list);
+      gimple_seq_add_stmt (&seq, stmt);
     }
   else
     tmp = mask;
@@ -2382,28 +2385,31 @@ sra_build_bf_assignment (tree dst, tree src)
     tmp2 = src;
   else if (INTEGRAL_TYPE_P (TREE_TYPE (src)))
     {
+      gimple_seq tmp_seq;
       tmp2 = make_rename_temp (TREE_TYPE (src), "SR");
-      stmt = sra_build_assignment (tmp2, src);
-      append_to_statement_list (stmt, &list);
+      tmp_seq = sra_build_assignment (tmp2, src);
+      gimple_seq_add_seq (&seq, tmp_seq);
     }
   else
     {
+      gimple_seq tmp_seq;
       tmp2 = make_rename_temp
        (lang_hooks.types.type_for_size
         (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (src))),
          1), "SR");
-      stmt = sra_build_assignment (tmp2, fold_build1 (VIEW_CONVERT_EXPR,
+      tmp_seq = sra_build_assignment (tmp2, fold_build1 (VIEW_CONVERT_EXPR,
                                                      TREE_TYPE (tmp2), src));
-      append_to_statement_list (stmt, &list);
+      gimple_seq_add_seq (&seq, tmp_seq);
     }
 
   if (!TYPE_UNSIGNED (TREE_TYPE (tmp2)))
     {
+      gimple_seq tmp_seq;
       tree ut = unsigned_type_for (TREE_TYPE (tmp2));
       tmp3 = make_rename_temp (ut, "SR");
       tmp2 = fold_convert (ut, tmp2);
-      stmt = sra_build_assignment (tmp3, tmp2);
-      append_to_statement_list (stmt, &list);
+      tmp_seq = sra_build_assignment (tmp3, tmp2);
+      gimple_seq_add_seq (&seq, tmp_seq);
 
       tmp2 = fold_build1 (BIT_NOT_EXPR, utype, mask);
       tmp2 = int_const_binop (RSHIFT_EXPR, tmp2, minshift, true);
@@ -2413,8 +2419,8 @@ sra_build_bf_assignment (tree dst, tree src)
       if (tmp3 != tmp2)
        {
          tmp3 = make_rename_temp (ut, "SR");
-         stmt = sra_build_assignment (tmp3, tmp2);
-         append_to_statement_list (stmt, &list);
+         tmp_seq = sra_build_assignment (tmp3, tmp2);
+          gimple_seq_add_seq (&seq, tmp_seq);
        }
 
       tmp2 = tmp3;
@@ -2422,20 +2428,20 @@ sra_build_bf_assignment (tree dst, tree src)
 
   if (TYPE_MAIN_VARIANT (TREE_TYPE (tmp2)) != TYPE_MAIN_VARIANT (utype))
     {
+      gimple_seq tmp_seq;
       tmp3 = make_rename_temp (utype, "SR");
       tmp2 = fold_convert (utype, tmp2);
-      stmt = sra_build_assignment (tmp3, tmp2);
-      append_to_statement_list (stmt, &list);
+      tmp_seq = sra_build_assignment (tmp3, tmp2);
+      gimple_seq_add_seq (&seq, tmp_seq);
       tmp2 = tmp3;
     }
 
   if (!integer_zerop (minshift))
     {
       tmp3 = make_rename_temp (utype, "SR");
-      stmt = build_gimple_modify_stmt (tmp3,
-                                      fold_build2 (LSHIFT_EXPR, utype,
-                                                   tmp2, minshift));
-      append_to_statement_list (stmt, &list);
+      stmt = gimple_build_assign (tmp3, fold_build2 (LSHIFT_EXPR, utype,
+                                                    tmp2, minshift));
+      gimple_seq_add_stmt (&seq, stmt);
       tmp2 = tmp3;
     }
 
@@ -2443,35 +2449,34 @@ sra_build_bf_assignment (tree dst, tree src)
     tmp3 = make_rename_temp (utype, "SR");
   else
     tmp3 = var;
-  stmt = build_gimple_modify_stmt (tmp3,
-                                  fold_build2 (BIT_IOR_EXPR, utype,
-                                               tmp, tmp2));
-  append_to_statement_list (stmt, &list);
+  stmt = gimple_build_assign (tmp3, fold_build2 (BIT_IOR_EXPR, utype,
+                                                tmp, tmp2));
+      gimple_seq_add_stmt (&seq, stmt);
 
   if (tmp3 != var)
     {
       if (TREE_TYPE (var) == type)
-       stmt = build_gimple_modify_stmt (var,
-                                        fold_convert (type, tmp3));
+       stmt = gimple_build_assign (var, fold_convert (type, tmp3));
       else
-       stmt = build_gimple_modify_stmt (var,
-                                        fold_build1 (VIEW_CONVERT_EXPR,
+       stmt = gimple_build_assign (var, fold_build1 (VIEW_CONVERT_EXPR,
                                                      TREE_TYPE (var), tmp3));
-      append_to_statement_list (stmt, &list);
+      gimple_seq_add_stmt (&seq, stmt);
     }
 
-  return list;
+  return seq;
 }
 
 /* Expand an assignment of SRC to the scalarized representation of
    ELT.  If it is a field group, try to widen the assignment to cover
    the full variable.  */
 
-static tree
+static gimple_seq
 sra_build_elt_assignment (struct sra_elt *elt, tree src)
 {
   tree dst = elt->replacement;
-  tree var, tmp, cst, cst2, list, stmt;
+  tree var, tmp, cst, cst2;
+  gimple stmt;
+  gimple_seq seq;
 
   if (TREE_CODE (dst) != BIT_FIELD_REF
       || !elt->in_bitfld_block)
@@ -2487,6 +2492,7 @@ sra_build_elt_assignment (struct sra_elt *elt, tree src)
   if (elt->in_bitfld_block == 2
       && TREE_CODE (src) == BIT_FIELD_REF)
     {
+      tmp = src;
       cst = TYPE_SIZE (TREE_TYPE (var));
       cst2 = size_binop (MINUS_EXPR, TREE_OPERAND (src, 2),
                         TREE_OPERAND (dst, 2));
@@ -2506,34 +2512,34 @@ sra_build_elt_assignment (struct sra_elt *elt, tree src)
          if (TYPE_MAIN_VARIANT (TREE_TYPE (var))
              != TYPE_MAIN_VARIANT (TREE_TYPE (src)))
            {
-             list = NULL;
+              gimple_seq tmp_seq;
+             seq = NULL;
 
-             if (!INTEGRAL_TYPE_P (TREE_TYPE (src))
-                 || !TYPE_UNSIGNED (TREE_TYPE (src)))
+             if (!INTEGRAL_TYPE_P (TREE_TYPE (src)))
                src = fold_build1 (VIEW_CONVERT_EXPR,
                                   lang_hooks.types.type_for_size
                                   (TREE_INT_CST_LOW
                                    (TYPE_SIZE (TREE_TYPE (src))),
                                    1), src);
+             gcc_assert (TYPE_UNSIGNED (TREE_TYPE (src)));
 
              tmp = make_rename_temp (TREE_TYPE (src), "SR");
-             stmt = build_gimple_modify_stmt (tmp, src);
-             append_to_statement_list (stmt, &list);
+             stmt = gimple_build_assign (tmp, src);
+             gimple_seq_add_stmt (&seq, stmt);
 
-             stmt = sra_build_assignment (var,
-                                          fold_convert (TREE_TYPE (var),
-                                                        tmp));
-             append_to_statement_list (stmt, &list);
+             tmp_seq = sra_build_assignment (var,
+                                             fold_convert (TREE_TYPE (var),
+                                                           tmp));
+             gimple_seq_add_seq (&seq, tmp_seq);
 
-             return list;
+             return seq;
            }
 
          src = fold_convert (TREE_TYPE (var), src);
        }
       else
        {
-         src = fold_build3 (BIT_FIELD_REF, TREE_TYPE (var), src, cst, cst2);
-         BIT_FIELD_REF_UNSIGNED (src) = 1;
+         src = fold_convert (TREE_TYPE (var), tmp);
        }
 
       return sra_build_assignment (var, src);
@@ -2549,9 +2555,10 @@ sra_build_elt_assignment (struct sra_elt *elt, tree src)
 
 static void
 generate_copy_inout (struct sra_elt *elt, bool copy_out, tree expr,
-                    tree *list_p)
+                    gimple_seq *seq_p)
 {
   struct sra_elt *c;
+  gimple_seq tmp_seq;
   tree t;
 
   if (!copy_out && TREE_CODE (expr) == SSA_NAME
@@ -2565,24 +2572,24 @@ generate_copy_inout (struct sra_elt *elt, bool copy_out, tree expr,
       i = c->replacement;
 
       t = build2 (COMPLEX_EXPR, elt->type, r, i);
-      t = sra_build_bf_assignment (expr, t);
-      SSA_NAME_DEF_STMT (expr) = t;
-      append_to_statement_list (t, list_p);
+      tmp_seq = sra_build_bf_assignment (expr, t);
+      SSA_NAME_DEF_STMT (expr) = gimple_seq_last_stmt (tmp_seq);
+      gimple_seq_add_seq (seq_p, tmp_seq);
     }
   else if (elt->replacement)
     {
       if (copy_out)
-       t = sra_build_elt_assignment (elt, expr);
+       tmp_seq = sra_build_elt_assignment (elt, expr);
       else
-       t = sra_build_bf_assignment (expr, REPLDUP (elt->replacement));
-      append_to_statement_list (t, list_p);
+       tmp_seq = sra_build_bf_assignment (expr, REPLDUP (elt->replacement));
+      gimple_seq_add_seq (seq_p, tmp_seq);
     }
   else
     {
       FOR_EACH_ACTUAL_CHILD (c, elt)
        {
          t = generate_one_element_ref (c, unshare_expr (expr));
-         generate_copy_inout (c, copy_out, t, list_p);
+         generate_copy_inout (c, copy_out, t, seq_p);
        }
     }
 }
@@ -2592,7 +2599,7 @@ generate_copy_inout (struct sra_elt *elt, bool copy_out, tree expr,
    correspondence of instantiated elements.  */
 
 static void
-generate_element_copy (struct sra_elt *dst, struct sra_elt *src, tree *list_p)
+generate_element_copy (struct sra_elt *dst, struct sra_elt *src, gimple_seq *seq_p)
 {
   struct sra_elt *dc, *sc;
 
@@ -2607,23 +2614,49 @@ generate_element_copy (struct sra_elt *dst, struct sra_elt *src, tree *list_p)
            {
              sc = lookup_element (src, dcs->element, NULL, NO_INSERT);
              gcc_assert (sc);
-             generate_element_copy (dcs, sc, list_p);
+             generate_element_copy (dcs, sc, seq_p);
            }
 
          continue;
        }
-      gcc_assert (sc);
-      generate_element_copy (dc, sc, list_p);
+
+      /* If DST and SRC are structs with the same elements, but do not have
+        the same TYPE_MAIN_VARIANT, then lookup of DST FIELD_DECL in SRC
+        will fail.  Try harder by finding the corresponding FIELD_DECL
+        in SRC.  */
+      if (!sc)
+       {
+         tree f;
+
+         gcc_assert (useless_type_conversion_p (dst->type, src->type));
+         gcc_assert (TREE_CODE (dc->element) == FIELD_DECL);
+         for (f = TYPE_FIELDS (src->type); f ; f = TREE_CHAIN (f))
+           if (simple_cst_equal (DECL_FIELD_OFFSET (f),
+                                 DECL_FIELD_OFFSET (dc->element)) > 0
+               && simple_cst_equal (DECL_FIELD_BIT_OFFSET (f),
+                                    DECL_FIELD_BIT_OFFSET (dc->element)) > 0
+               && simple_cst_equal (DECL_SIZE (f),
+                                    DECL_SIZE (dc->element)) > 0
+               && (useless_type_conversion_p (TREE_TYPE (dc->element),
+                                              TREE_TYPE (f))
+                   || (POINTER_TYPE_P (TREE_TYPE (dc->element))
+                       && POINTER_TYPE_P (TREE_TYPE (f)))))
+             break;
+         gcc_assert (f != NULL_TREE);
+         sc = lookup_element (src, f, NULL, NO_INSERT);
+       }
+
+      generate_element_copy (dc, sc, seq_p);
     }
 
   if (dst->replacement)
     {
-      tree t;
+      gimple_seq tmp_seq;
 
       gcc_assert (src->replacement);
 
-      t = sra_build_elt_assignment (dst, REPLDUP (src->replacement));
-      append_to_statement_list (t, list_p);
+      tmp_seq = sra_build_elt_assignment (dst, REPLDUP (src->replacement));
+      gimple_seq_add_seq (seq_p, tmp_seq);
     }
 }
 
@@ -2633,7 +2666,7 @@ generate_element_copy (struct sra_elt *dst, struct sra_elt *src, tree *list_p)
    with generate_element_init.  */
 
 static void
-generate_element_zero (struct sra_elt *elt, tree *list_p)
+generate_element_zero (struct sra_elt *elt, gimple_seq *seq_p)
 {
   struct sra_elt *c;
 
@@ -2645,17 +2678,18 @@ generate_element_zero (struct sra_elt *elt, tree *list_p)
 
   if (!elt->in_bitfld_block)
     FOR_EACH_ACTUAL_CHILD (c, elt)
-      generate_element_zero (c, list_p);
+      generate_element_zero (c, seq_p);
 
   if (elt->replacement)
     {
       tree t;
+      gimple_seq tmp_seq;
 
       gcc_assert (elt->is_scalar);
       t = fold_convert (elt->type, integer_zero_node);
 
-      t = sra_build_elt_assignment (elt, t);
-      append_to_statement_list (t, list_p);
+      tmp_seq = sra_build_elt_assignment (elt, t);
+      gimple_seq_add_seq (seq_p, tmp_seq);
     }
 }
 
@@ -2663,11 +2697,10 @@ generate_element_zero (struct sra_elt *elt, tree *list_p)
    Add the result to *LIST_P.  */
 
 static void
-generate_one_element_init (struct sra_elt *elt, tree init, tree *list_p)
+generate_one_element_init (struct sra_elt *elt, tree init, gimple_seq *seq_p)
 {
-  /* The replacement can be almost arbitrarily complex.  Gimplify.  */
-  tree stmt = sra_build_elt_assignment (elt, init);
-  gimplify_and_add (stmt, list_p);
+  gimple_seq tmp_seq = sra_build_elt_assignment (elt, init);
+  gimple_seq_add_seq (seq_p, tmp_seq);
 }
 
 /* Generate a set of assignment statements in *LIST_P to set all instantiated
@@ -2677,7 +2710,7 @@ generate_one_element_init (struct sra_elt *elt, tree init, tree *list_p)
    handle.  */
 
 static bool
-generate_element_init_1 (struct sra_elt *elt, tree init, tree *list_p)
+generate_element_init_1 (struct sra_elt *elt, tree init, gimple_seq *seq_p)
 {
   bool result = true;
   enum tree_code init_code;
@@ -2695,7 +2728,7 @@ generate_element_init_1 (struct sra_elt *elt, tree init, tree *list_p)
     {
       if (elt->replacement)
        {
-         generate_one_element_init (elt, init, list_p);
+         generate_one_element_init (elt, init, seq_p);
          elt->visited = true;
        }
       return result;
@@ -2713,13 +2746,19 @@ generate_element_init_1 (struct sra_elt *elt, tree init, tree *list_p)
          else
            t = (init_code == COMPLEX_EXPR
                 ? TREE_OPERAND (init, 1) : TREE_IMAGPART (init));
-         result &= generate_element_init_1 (sub, t, list_p);
+         result &= generate_element_init_1 (sub, t, seq_p);
        }
       break;
 
     case CONSTRUCTOR:
       FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx, purpose, value)
        {
+         /* Array constructors are routinely created with NULL indices.  */
+         if (purpose == NULL_TREE)
+           {
+             result = false;
+             break;
+           }
          if (TREE_CODE (purpose) == RANGE_EXPR)
            {
              tree lower = TREE_OPERAND (purpose, 0);
@@ -2729,7 +2768,7 @@ generate_element_init_1 (struct sra_elt *elt, tree init, tree *list_p)
                {
                  sub = lookup_element (elt, lower, NULL, NO_INSERT);
                  if (sub != NULL)
-                   result &= generate_element_init_1 (sub, value, list_p);
+                   result &= generate_element_init_1 (sub, value, seq_p);
                  if (tree_int_cst_equal (lower, upper))
                    break;
                  lower = int_const_binop (PLUS_EXPR, lower,
@@ -2740,7 +2779,7 @@ generate_element_init_1 (struct sra_elt *elt, tree init, tree *list_p)
            {
              sub = lookup_element (elt, purpose, NULL, NO_INSERT);
              if (sub != NULL)
-               result &= generate_element_init_1 (sub, value, list_p);
+               result &= generate_element_init_1 (sub, value, seq_p);
            }
        }
       break;
@@ -2757,95 +2796,86 @@ generate_element_init_1 (struct sra_elt *elt, tree init, tree *list_p)
    gimplification.  */
 
 static bool
-generate_element_init (struct sra_elt *elt, tree init, tree *list_p)
+generate_element_init (struct sra_elt *elt, tree init, gimple_seq *seq_p)
 {
   bool ret;
+  struct gimplify_ctx gctx;
 
-  push_gimplify_context ();
-  ret = generate_element_init_1 (elt, init, list_p);
+  push_gimplify_context (&gctx);
+  ret = generate_element_init_1 (elt, init, seq_p);
   pop_gimplify_context (NULL);
 
   /* The replacement can expose previously unreferenced variables.  */
-  if (ret && *list_p)
+  if (ret && *seq_p)
     {
-      tree_stmt_iterator i;
+      gimple_stmt_iterator i;
 
-      for (i = tsi_start (*list_p); !tsi_end_p (i); tsi_next (&i))
-       find_new_referenced_vars (tsi_stmt_ptr (i));
+      for (i = gsi_start (*seq_p); !gsi_end_p (i); gsi_next (&i))
+       find_new_referenced_vars (gsi_stmt (i));
     }
 
   return ret;
 }
 
-/* Insert STMT on all the outgoing edges out of BB.  Note that if BB
-   has more than one edge, STMT will be replicated for each edge.  Also,
-   abnormal edges will be ignored.  */
+/* Insert a gimple_seq SEQ on all the outgoing edges out of BB.  Note that
+   if BB has more than one edge, STMT will be replicated for each edge.
+   Also, abnormal edges will be ignored.  */
 
 void
-insert_edge_copies (tree stmt, basic_block bb)
+insert_edge_copies_seq (gimple_seq seq, basic_block bb)
 {
   edge e;
   edge_iterator ei;
-  bool first_copy;
+  unsigned n_copies = -1;
 
-  first_copy = true;
   FOR_EACH_EDGE (e, ei, bb->succs)
-    {
-      /* We don't need to insert copies on abnormal edges.  The
-        value of the scalar replacement is not guaranteed to
-        be valid through an abnormal edge.  */
-      if (!(e->flags & EDGE_ABNORMAL))
-       {
-         if (first_copy)
-           {
-             bsi_insert_on_edge (e, stmt);
-             first_copy = false;
-           }
-         else
-           bsi_insert_on_edge (e, unsave_expr_now (stmt));
-       }
-    }
+    if (!(e->flags & EDGE_ABNORMAL)) 
+      n_copies++;
+
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    if (!(e->flags & EDGE_ABNORMAL)) 
+      gsi_insert_seq_on_edge (e, n_copies-- > 0 ? gimple_seq_copy (seq) : seq);
 }
 
-/* Helper function to insert LIST before BSI, and set up line number info.  */
+/* Helper function to insert LIST before GSI, and set up line number info.  */
 
 void
-sra_insert_before (block_stmt_iterator *bsi, tree list)
+sra_insert_before (gimple_stmt_iterator *gsi, gimple_seq seq)
 {
-  tree stmt = bsi_stmt (*bsi);
+  gimple stmt = gsi_stmt (*gsi);
 
-  if (EXPR_HAS_LOCATION (stmt))
-    annotate_all_with_locus (&list, EXPR_LOCATION (stmt));
-  bsi_insert_before (bsi, list, BSI_SAME_STMT);
+  if (gimple_has_location (stmt))
+    annotate_all_with_location (seq, gimple_location (stmt));
+  gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
 }
 
-/* Similarly, but insert after BSI.  Handles insertion onto edges as well.  */
+/* Similarly, but insert after GSI.  Handles insertion onto edges as well.  */
 
 void
-sra_insert_after (block_stmt_iterator *bsi, tree list)
+sra_insert_after (gimple_stmt_iterator *gsi, gimple_seq seq)
 {
-  tree stmt = bsi_stmt (*bsi);
+  gimple stmt = gsi_stmt (*gsi);
 
-  if (EXPR_HAS_LOCATION (stmt))
-    annotate_all_with_locus (&list, EXPR_LOCATION (stmt));
+  if (gimple_has_location (stmt))
+    annotate_all_with_location (seq, gimple_location (stmt));
 
   if (stmt_ends_bb_p (stmt))
-    insert_edge_copies (list, bsi->bb);
+    insert_edge_copies_seq (seq, gsi_bb (*gsi));
   else
-    bsi_insert_after (bsi, list, BSI_SAME_STMT);
+    gsi_insert_seq_after (gsi, seq, GSI_SAME_STMT);
 }
 
-/* Similarly, but replace the statement at BSI.  */
+/* Similarly, but replace the statement at GSI.  */
 
 static void
-sra_replace (block_stmt_iterator *bsi, tree list)
+sra_replace (gimple_stmt_iterator *gsi, gimple_seq seq)
 {
-  sra_insert_before (bsi, list);
-  bsi_remove (bsi, false);
-  if (bsi_end_p (*bsi))
-    *bsi = bsi_last (bsi->bb);
+  sra_insert_before (gsi, seq);
+  gsi_remove (gsi, false);
+  if (gsi_end_p (*gsi))
+    *gsi = gsi_last (gsi_seq (*gsi));
   else
-    bsi_prev (bsi);
+    gsi_prev (gsi);
 }
 
 /* Data structure that bitfield_overlaps_p fills in with information
@@ -2870,7 +2900,7 @@ struct bitfield_overlap_info
 };
 
 /* Return true if a BIT_FIELD_REF<(FLD->parent), BLEN, BPOS>
-   expression (refereced as BF below) accesses any of the bits in FLD,
+   expression (referenced as BF below) accesses any of the bits in FLD,
    false if it doesn't.  If DATA is non-null, its field_len and
    field_pos are filled in such that BIT_FIELD_REF<(FLD->parent),
    field_len, field_pos> (referenced as BFLD below) represents the
@@ -2899,8 +2929,14 @@ bitfield_overlaps_p (tree blen, tree bpos, struct sra_elt *fld,
     }
   else if (TREE_CODE (fld->element) == INTEGER_CST)
     {
+      tree domain_type = TYPE_DOMAIN (TREE_TYPE (fld->parent->element));
       flen = fold_convert (bitsizetype, TYPE_SIZE (fld->type));
-      fpos = size_binop (MULT_EXPR, flen, fld->element);
+      fpos = fold_convert (bitsizetype, fld->element);
+      if (domain_type && TYPE_MIN_VALUE (domain_type))
+       fpos = size_binop (MINUS_EXPR, fpos,
+                          fold_convert (bitsizetype,
+                                        TYPE_MIN_VALUE (domain_type)));
+      fpos = size_binop (MULT_EXPR, flen, fpos);
     }
   else
     gcc_unreachable ();
@@ -2958,7 +2994,7 @@ bitfield_overlaps_p (tree blen, tree bpos, struct sra_elt *fld,
 
 static void
 sra_explode_bitfield_assignment (tree var, tree vpos, bool to_var,
-                                tree *listp, tree blen, tree bpos,
+                                gimple_seq *seq_p, tree blen, tree bpos,
                                 struct sra_elt *elt)
 {
   struct sra_elt *fld;
@@ -2976,16 +3012,21 @@ sra_explode_bitfield_assignment (tree var, tree vpos, bool to_var,
 
       if (fld->replacement)
        {
-         tree infld, invar, st;
+         tree infld, invar, type;
+          gimple_seq st;
 
          infld = fld->replacement;
 
+         type = unsigned_type_for (TREE_TYPE (infld));
+         if (TYPE_PRECISION (type) != TREE_INT_CST_LOW (flen))
+           type = build_nonstandard_integer_type (TREE_INT_CST_LOW (flen), 1);
+
          if (TREE_CODE (infld) == BIT_FIELD_REF)
            {
              fpos = size_binop (PLUS_EXPR, fpos, TREE_OPERAND (infld, 2));
              infld = TREE_OPERAND (infld, 0);
            }
-         else if (BITS_BIG_ENDIAN && DECL_P (fld->element)
+         else if (BYTES_BIG_ENDIAN && DECL_P (fld->element)
                   && !tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (infld)),
                                           DECL_SIZE (fld->element)))
            {
@@ -2995,27 +3036,21 @@ sra_explode_bitfield_assignment (tree var, tree vpos, bool to_var,
                                 DECL_SIZE (fld->element));
            }
 
-         infld = fold_build3 (BIT_FIELD_REF,
-                              lang_hooks.types.type_for_size
-                              (TREE_INT_CST_LOW (flen), 1),
-                              infld, flen, fpos);
-         BIT_FIELD_REF_UNSIGNED (infld) = 1;
+         infld = fold_build3 (BIT_FIELD_REF, type, infld, flen, fpos);
 
          invar = size_binop (MINUS_EXPR, flp.field_pos, bpos);
          if (flp.overlap_pos)
            invar = size_binop (PLUS_EXPR, invar, flp.overlap_pos);
          invar = size_binop (PLUS_EXPR, invar, vpos);
 
-         invar = fold_build3 (BIT_FIELD_REF, TREE_TYPE (infld),
-                              var, flen, invar);
-         BIT_FIELD_REF_UNSIGNED (invar) = 1;
+         invar = fold_build3 (BIT_FIELD_REF, type, var, flen, invar);
 
          if (to_var)
            st = sra_build_bf_assignment (invar, infld);
          else
            st = sra_build_bf_assignment (infld, invar);
 
-         append_to_statement_list (st, listp);
+         gimple_seq_add_seq (seq_p, st);
        }
       else
        {
@@ -3024,7 +3059,7 @@ sra_explode_bitfield_assignment (tree var, tree vpos, bool to_var,
          if (flp.overlap_pos)
            sub = size_binop (PLUS_EXPR, sub, flp.overlap_pos);
 
-         sra_explode_bitfield_assignment (var, sub, to_var, listp,
+         sra_explode_bitfield_assignment (var, sub, to_var, seq_p,
                                           flen, fpos, fld);
        }
     }
@@ -3037,7 +3072,8 @@ sra_explode_bitfield_assignment (tree var, tree vpos, bool to_var,
    full variable back to the scalarized variables.  */
 
 static void
-sra_sync_for_bitfield_assignment (tree *listbeforep, tree *listafterp,
+sra_sync_for_bitfield_assignment (gimple_seq *seq_before_p,
+                                  gimple_seq *seq_after_p,
                                  tree blen, tree bpos,
                                  struct sra_elt *elt)
 {
@@ -3050,18 +3086,18 @@ sra_sync_for_bitfield_assignment (tree *listbeforep, tree *listafterp,
        if (fld->replacement || (!flp.overlap_len && !flp.overlap_pos))
          {
            generate_copy_inout (fld, false, generate_element_ref (fld),
-                                listbeforep);
+                                seq_before_p);
            mark_no_warning (fld);
-           if (listafterp)
+           if (seq_after_p)
              generate_copy_inout (fld, true, generate_element_ref (fld),
-                                  listafterp);
+                                  seq_after_p);
          }
        else
          {
            tree flen = flp.overlap_len ? flp.overlap_len : flp.field_len;
            tree fpos = flp.overlap_pos ? flp.overlap_pos : bitsize_int (0);
 
-           sra_sync_for_bitfield_assignment (listbeforep, listafterp,
+           sra_sync_for_bitfield_assignment (seq_before_p, seq_after_p,
                                              flen, fpos, fld);
          }
       }
@@ -3072,10 +3108,10 @@ sra_sync_for_bitfield_assignment (tree *listbeforep, tree *listafterp,
    aggregate.  IS_OUTPUT is true if ELT is being modified.  */
 
 static void
-scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
+scalarize_use (struct sra_elt *elt, tree *expr_p, gimple_stmt_iterator *gsi,
               bool is_output, bool use_all)
 {
-  tree stmt = bsi_stmt (*bsi);
+  gimple stmt = gsi_stmt (*gsi);
   tree bfexpr;
 
   if (elt->replacement)
@@ -3087,52 +3123,43 @@ scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
       if (is_output
          && TREE_CODE (elt->replacement) == BIT_FIELD_REF
          && is_gimple_reg (TREE_OPERAND (elt->replacement, 0))
-         && TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
-         && &GIMPLE_STMT_OPERAND (stmt, 0) == expr_p)
+         && is_gimple_assign (stmt)
+         && gimple_assign_lhs_ptr (stmt) == expr_p)
        {
-         tree newstmt = sra_build_elt_assignment
-           (elt, GIMPLE_STMT_OPERAND (stmt, 1));
-         if (TREE_CODE (newstmt) != STATEMENT_LIST)
-           {
-             tree list = NULL;
-             append_to_statement_list (newstmt, &list);
-             newstmt = list;
-           }
-         sra_replace (bsi, newstmt);
+          gimple_seq newseq;
+          /* RHS must be a single operand. */
+          gcc_assert (gimple_assign_single_p (stmt));
+         newseq = sra_build_elt_assignment (elt, gimple_assign_rhs1 (stmt));
+         sra_replace (gsi, newseq);
          return;
        }
       else if (!is_output
               && TREE_CODE (elt->replacement) == BIT_FIELD_REF
-              && TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
-              && &GIMPLE_STMT_OPERAND (stmt, 1) == expr_p)
+              && is_gimple_assign (stmt)
+              && gimple_assign_rhs1_ptr (stmt) == expr_p)
        {
          tree tmp = make_rename_temp
-           (TREE_TYPE (GIMPLE_STMT_OPERAND (stmt, 0)), "SR");
-         tree newstmt = sra_build_assignment (tmp, REPLDUP (elt->replacement));
+           (TREE_TYPE (gimple_assign_lhs (stmt)), "SR");
+         gimple_seq newseq = sra_build_assignment (tmp, REPLDUP (elt->replacement));
 
-         if (TREE_CODE (newstmt) != STATEMENT_LIST)
-           {
-             tree list = NULL;
-             append_to_statement_list (newstmt, &list);
-             newstmt = list;
-           }
-         sra_insert_before (bsi, newstmt);
+         sra_insert_before (gsi, newseq);
          replacement = tmp;
        }
       if (is_output)
-         mark_all_v_defs (stmt);
+         mark_all_v_defs_stmt (stmt);
       *expr_p = REPLDUP (replacement);
       update_stmt (stmt);
     }
   else if (use_all && is_output
-          && TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
+          && is_gimple_assign (stmt)
           && TREE_CODE (bfexpr
-                        = GIMPLE_STMT_OPERAND (stmt, 0)) == BIT_FIELD_REF
+                        = gimple_assign_lhs (stmt)) == BIT_FIELD_REF
           && &TREE_OPERAND (bfexpr, 0) == expr_p
           && INTEGRAL_TYPE_P (TREE_TYPE (bfexpr))
           && TREE_CODE (TREE_TYPE (*expr_p)) == RECORD_TYPE)
     {
-      tree listbefore = NULL, listafter = NULL;
+      gimple_seq seq_before = NULL;
+      gimple_seq seq_after = NULL;
       tree blen = fold_convert (bitsizetype, TREE_OPERAND (bfexpr, 1));
       tree bpos = fold_convert (bitsizetype, TREE_OPERAND (bfexpr, 2));
       bool update = false;
@@ -3140,51 +3167,59 @@ scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
       if (!elt->use_block_copy)
        {
          tree type = TREE_TYPE (bfexpr);
-         tree var = make_rename_temp (type, "SR"), tmp, st;
+         tree var = make_rename_temp (type, "SR"), tmp, vpos;
+          gimple st;
 
-         GIMPLE_STMT_OPERAND (stmt, 0) = var;
+         gimple_assign_set_lhs (stmt, var);
          update = true;
 
          if (!TYPE_UNSIGNED (type))
            {
              type = unsigned_type_for (type);
              tmp = make_rename_temp (type, "SR");
-             st = build_gimple_modify_stmt (tmp,
-                                            fold_convert (type, var));
-             append_to_statement_list (st, &listafter);
+             st = gimple_build_assign (tmp, fold_convert (type, var));
+             gimple_seq_add_stmt (&seq_after, st);
              var = tmp;
            }
 
+         /* If VAR is wider than BLEN bits, it is padded at the
+            most-significant end.  We want to set VPOS such that
+            <BIT_FIELD_REF VAR BLEN VPOS> would refer to the
+            least-significant BLEN bits of VAR.  */
+         if (BYTES_BIG_ENDIAN)
+           vpos = size_binop (MINUS_EXPR, TYPE_SIZE (type), blen);
+         else
+           vpos = bitsize_int (0);
          sra_explode_bitfield_assignment
-           (var, bitsize_int (0), false, &listafter, blen, bpos, elt);
+           (var, vpos, false, &seq_after, blen, bpos, elt);
        }
       else
        sra_sync_for_bitfield_assignment
-         (&listbefore, &listafter, blen, bpos, elt);
+         (&seq_before, &seq_after, blen, bpos, elt);
 
-      if (listbefore)
+      if (seq_before)
        {
-         mark_all_v_defs (listbefore);
-         sra_insert_before (bsi, listbefore);
+         mark_all_v_defs_seq (seq_before);
+         sra_insert_before (gsi, seq_before);
        }
-      if (listafter)
+      if (seq_after)
        {
-         mark_all_v_defs (listafter);
-         sra_insert_after (bsi, listafter);
+         mark_all_v_defs_seq (seq_after);
+         sra_insert_after (gsi, seq_after);
        }
 
       if (update)
        update_stmt (stmt);
     }
   else if (use_all && !is_output
-          && TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
+          && is_gimple_assign (stmt)
           && TREE_CODE (bfexpr
-                        = GIMPLE_STMT_OPERAND (stmt, 1)) == BIT_FIELD_REF
-          && &TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt, 1), 0) == expr_p
+                        = gimple_assign_rhs1 (stmt)) == BIT_FIELD_REF
+          && &TREE_OPERAND (gimple_assign_rhs1 (stmt), 0) == expr_p
           && INTEGRAL_TYPE_P (TREE_TYPE (bfexpr))
           && TREE_CODE (TREE_TYPE (*expr_p)) == RECORD_TYPE)
     {
-      tree list = NULL;
+      gimple_seq seq = NULL;
       tree blen = fold_convert (bitsizetype, TREE_OPERAND (bfexpr, 1));
       tree bpos = fold_convert (bitsizetype, TREE_OPERAND (bfexpr, 2));
       bool update = false;
@@ -3192,31 +3227,47 @@ scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
       if (!elt->use_block_copy)
        {
          tree type = TREE_TYPE (bfexpr);
-         tree var;
+         tree var = make_rename_temp (type, "SR"), tmp, vpos;
+         gimple st = NULL;
 
-         if (!TYPE_UNSIGNED (type))
-           type = unsigned_type_for (type);
+         gimple_assign_set_rhs1 (stmt, var);
+         update = true;
 
-         var = make_rename_temp (type, "SR");
+         if (!TYPE_UNSIGNED (type))
+           {
+             type = unsigned_type_for (type);
+             tmp = make_rename_temp (type, "SR");
+             st = gimple_build_assign (var,
+                                       fold_convert (TREE_TYPE (var), tmp));
+             var = tmp;
+           }
 
-         append_to_statement_list (build_gimple_modify_stmt
-                                   (var, build_int_cst_wide (type, 0, 0)),
-                                   &list);
+         gimple_seq_add_stmt (&seq,
+                               gimple_build_assign
+                                (var, build_int_cst_wide (type, 0, 0)));
 
+         /* If VAR is wider than BLEN bits, it is padded at the
+            most-significant end.  We want to set VPOS such that
+            <BIT_FIELD_REF VAR BLEN VPOS> would refer to the
+            least-significant BLEN bits of VAR.  */
+         if (BYTES_BIG_ENDIAN)
+           vpos = size_binop (MINUS_EXPR, TYPE_SIZE (type), blen);
+         else
+           vpos = bitsize_int (0);
          sra_explode_bitfield_assignment
-           (var, bitsize_int (0), true, &list, blen, bpos, elt);
+           (var, vpos, true, &seq, blen, bpos, elt);
 
-         GIMPLE_STMT_OPERAND (stmt, 1) = var;
-         update = true;
+         if (st)
+           gimple_seq_add_stmt (&seq, st);
        }
       else
        sra_sync_for_bitfield_assignment
-         (&list, NULL, blen, bpos, elt);
+         (&seq, NULL, blen, bpos, elt);
 
-      if (list)
+      if (seq)
        {
-         mark_all_v_defs (list);
-         sra_insert_before (bsi, list);
+         mark_all_v_defs_seq (seq);
+         sra_insert_before (gsi, seq);
        }
 
       if (update)
@@ -3224,7 +3275,7 @@ scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
     }
   else
     {
-      tree list = NULL;
+      gimple_seq seq = NULL;
 
       /* Otherwise we need some copies.  If ELT is being read, then we
         want to store all (modified) sub-elements back into the
@@ -3240,15 +3291,15 @@ scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
         This optimization would be most effective if sra_walk_function
         processed the blocks in dominator order.  */
 
-      generate_copy_inout (elt, is_output, generate_element_ref (elt), &list);
-      if (list == NULL)
+      generate_copy_inout (elt, is_output, generate_element_ref (elt), &seq);
+      if (seq == NULL)
        return;
-      mark_all_v_defs (list);
+      mark_all_v_defs_seq (seq);
       if (is_output)
-       sra_insert_after (bsi, list);
+       sra_insert_after (gsi, seq);
       else
        {
-         sra_insert_before (bsi, list);
+         sra_insert_before (gsi, seq);
          if (use_all)
            mark_no_warning (elt);
        }
@@ -3260,21 +3311,24 @@ scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
 
 static void
 scalarize_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
-               block_stmt_iterator *bsi)
+               gimple_stmt_iterator *gsi)
 {
-  tree list, stmt;
+  gimple_seq seq;
+  gimple stmt;
 
   if (lhs_elt->replacement && rhs_elt->replacement)
     {
       /* If we have two scalar operands, modify the existing statement.  */
-      stmt = bsi_stmt (*bsi);
+      stmt = gsi_stmt (*gsi);
 
       /* See the commentary in sra_walk_function concerning
         RETURN_EXPR, and why we should never see one here.  */
-      gcc_assert (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT);
+      gcc_assert (is_gimple_assign (stmt));
+      gcc_assert (gimple_assign_copy_p (stmt));
+
 
-      GIMPLE_STMT_OPERAND (stmt, 0) = lhs_elt->replacement;
-      GIMPLE_STMT_OPERAND (stmt, 1) = REPLDUP (rhs_elt->replacement);
+      gimple_assign_set_lhs (stmt, lhs_elt->replacement);
+      gimple_assign_set_rhs1 (stmt, REPLDUP (rhs_elt->replacement));
       update_stmt (stmt);
     }
   else if (lhs_elt->use_block_copy || rhs_elt->use_block_copy)
@@ -3287,22 +3341,22 @@ scalarize_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
         would at least allow those elements that are instantiated in
         both structures to be optimized well.  */
 
-      list = NULL;
+      seq = NULL;
       generate_copy_inout (rhs_elt, false,
-                          generate_element_ref (rhs_elt), &list);
-      if (list)
+                          generate_element_ref (rhs_elt), &seq);
+      if (seq)
        {
-         mark_all_v_defs (list);
-         sra_insert_before (bsi, list);
+         mark_all_v_defs_seq (seq);
+         sra_insert_before (gsi, seq);
        }
 
-      list = NULL;
+      seq = NULL;
       generate_copy_inout (lhs_elt, true,
-                          generate_element_ref (lhs_elt), &list);
-      if (list)
+                          generate_element_ref (lhs_elt), &seq);
+      if (seq)
        {
-         mark_all_v_defs (list);
-         sra_insert_after (bsi, list);
+         mark_all_v_defs_seq (seq);
+         sra_insert_after (gsi, seq);
        }
     }
   else
@@ -3311,14 +3365,14 @@ scalarize_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
         case perform pair-wise element assignments and replace the
         original block copy statement.  */
 
-      stmt = bsi_stmt (*bsi);
-      mark_all_v_defs (stmt);
+      stmt = gsi_stmt (*gsi);
+      mark_all_v_defs_stmt (stmt);
 
-      list = NULL;
-      generate_element_copy (lhs_elt, rhs_elt, &list);
-      gcc_assert (list);
-      mark_all_v_defs (list);
-      sra_replace (bsi, list);
+      seq = NULL;
+      generate_element_copy (lhs_elt, rhs_elt, &seq);
+      gcc_assert (seq);
+      mark_all_v_defs_seq (seq);
+      sra_replace (gsi, seq);
     }
 }
 
@@ -3328,23 +3382,19 @@ scalarize_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
    CONSTRUCTOR.  */
 
 static void
-scalarize_init (struct sra_elt *lhs_elt, tree rhs, block_stmt_iterator *bsi)
+scalarize_init (struct sra_elt *lhs_elt, tree rhs, gimple_stmt_iterator *gsi)
 {
   bool result = true;
-  tree list = NULL;
+  gimple_seq seq = NULL, init_seq = NULL;
 
   /* Generate initialization statements for all members extant in the RHS.  */
   if (rhs)
     {
       /* Unshare the expression just in case this is from a decl's initial.  */
       rhs = unshare_expr (rhs);
-      result = generate_element_init (lhs_elt, rhs, &list);
+      result = generate_element_init (lhs_elt, rhs, &init_seq);
     }
 
-  /* CONSTRUCTOR is defined such that any member not mentioned is assigned
-     a zero value.  Initialize the rest of the instantiated elements.  */
-  generate_element_zero (lhs_elt, &list);
-
   if (!result)
     {
       /* If we failed to convert the entire initializer, then we must
@@ -3353,11 +3403,18 @@ scalarize_init (struct sra_elt *lhs_elt, tree rhs, block_stmt_iterator *bsi)
         constants.  The easiest way to do this is to generate a complete
         copy-out, and then follow that with the constant assignments
         that we were able to build.  DCE will clean things up.  */
-      tree list0 = NULL;
+      gimple_seq seq0 = NULL;
       generate_copy_inout (lhs_elt, true, generate_element_ref (lhs_elt),
-                          &list0);
-      append_to_statement_list (list, &list0);
-      list = list0;
+                          &seq0);
+      gimple_seq_add_seq (&seq0, seq);
+      seq = seq0;
+    }
+  else
+    {
+      /* CONSTRUCTOR is defined such that any member not mentioned is assigned
+        a zero value.  Initialize the rest of the instantiated elements.  */
+      generate_element_zero (lhs_elt, &seq);
+      gimple_seq_add_seq (&seq, init_seq);
     }
 
   if (lhs_elt->use_block_copy || !result)
@@ -3365,20 +3422,20 @@ scalarize_init (struct sra_elt *lhs_elt, tree rhs, block_stmt_iterator *bsi)
       /* Since LHS is not fully instantiated, we must leave the structure
         assignment in place.  Treating this case differently from a USE
         exposes constants to later optimizations.  */
-      if (list)
+      if (seq)
        {
-         mark_all_v_defs (list);
-         sra_insert_after (bsi, list);
+         mark_all_v_defs_seq (seq);
+         sra_insert_after (gsi, seq);
        }
     }
   else
     {
       /* The LHS is fully instantiated.  The list of initializations
         replaces the original structure assignment.  */
-      gcc_assert (list);
-      mark_all_v_defs (bsi_stmt (*bsi));
-      mark_all_v_defs (list);
-      sra_replace (bsi, list);
+      gcc_assert (seq);
+      mark_all_v_defs_stmt (gsi_stmt (*gsi));
+      mark_all_v_defs_seq (seq);
+      sra_replace (gsi, seq);
     }
 }
 
@@ -3407,7 +3464,7 @@ mark_notrap (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 
 static void
 scalarize_ldst (struct sra_elt *elt, tree other,
-               block_stmt_iterator *bsi, bool is_output)
+               gimple_stmt_iterator *gsi, bool is_output)
 {
   /* Shouldn't have gotten called for a scalar.  */
   gcc_assert (!elt->replacement);
@@ -3416,7 +3473,7 @@ scalarize_ldst (struct sra_elt *elt, tree other,
     {
       /* Since ELT is not fully instantiated, we have to leave the
         block copy in place.  Treat this as a USE.  */
-      scalarize_use (elt, NULL, bsi, is_output, false);
+      scalarize_use (elt, NULL, gsi, is_output, false);
     }
   else
     {
@@ -3424,19 +3481,21 @@ scalarize_ldst (struct sra_elt *elt, tree other,
         case we can have each element stored/loaded directly to/from the
         corresponding slot in OTHER.  This avoids a block copy.  */
 
-      tree list = NULL, stmt = bsi_stmt (*bsi);
+      gimple_seq seq = NULL;
+      gimple stmt = gsi_stmt (*gsi);
 
-      mark_all_v_defs (stmt);
-      generate_copy_inout (elt, is_output, other, &list);
-      gcc_assert (list);
-      mark_all_v_defs (list);
+      mark_all_v_defs_stmt (stmt);
+      generate_copy_inout (elt, is_output, other, &seq);
+      gcc_assert (seq);
+      mark_all_v_defs_seq (seq);
 
       /* Preserve EH semantics.  */
       if (stmt_ends_bb_p (stmt))
        {
-         tree_stmt_iterator tsi;
-         tree first, blist = NULL;
-         bool thr = tree_could_throw_p (stmt);
+         gimple_stmt_iterator si;
+         gimple first;
+          gimple_seq blist = NULL;
+         bool thr = stmt_could_throw_p (stmt);
 
          /* If the last statement of this BB created an EH edge
             before scalarization, we have to locate the first
@@ -3447,26 +3506,26 @@ scalarize_ldst (struct sra_elt *elt, tree other,
             list will be added to normal outgoing edges of the same
             BB.  If they access any memory, it's the same memory, so
             we can assume they won't throw.  */
-         tsi = tsi_start (list);
-         for (first = tsi_stmt (tsi);
-              thr && !tsi_end_p (tsi) && !tree_could_throw_p (first);
-              first = tsi_stmt (tsi))
+         si = gsi_start (seq);
+         for (first = gsi_stmt (si);
+              thr && !gsi_end_p (si) && !stmt_could_throw_p (first);
+              first = gsi_stmt (si))
            {
-             tsi_delink (&tsi);
-             append_to_statement_list (first, &blist);
+             gsi_remove (&si, false);
+             gimple_seq_add_stmt (&blist, first);
            }
 
          /* Extract the first remaining statement from LIST, this is
             the EH statement if there is one.  */
-         tsi_delink (&tsi);
+         gsi_remove (&si, false);
 
          if (blist)
-           sra_insert_before (bsi, blist);
+           sra_insert_before (gsi, blist);
 
          /* Replace the old statement with this new representative.  */
-         bsi_replace (bsi, first, true);
+         gsi_replace (gsi, first, true);
 
-         if (!tsi_end_p (tsi))
+         if (!gsi_end_p (si))
            {
              /* If any reference would trap, then they all would.  And more
                 to the point, the first would.  Therefore none of the rest
@@ -3475,16 +3534,16 @@ scalarize_ldst (struct sra_elt *elt, tree other,
                 TREE_THIS_NOTRAP in all INDIRECT_REFs.  */
              do
                {
-                 walk_tree (tsi_stmt_ptr (tsi), mark_notrap, NULL, NULL);
-                 tsi_next (&tsi);
+                 walk_gimple_stmt (&si, NULL, mark_notrap, NULL);
+                 gsi_next (&si);
                }
-             while (!tsi_end_p (tsi));
+             while (!gsi_end_p (si));
 
-             insert_edge_copies (list, bsi->bb);
+             insert_edge_copies_seq (seq, gsi_bb (*gsi));
            }
        }
       else
-       sra_replace (bsi, list);
+       sra_replace (gsi, seq);
     }
 }
 
@@ -3493,7 +3552,7 @@ scalarize_ldst (struct sra_elt *elt, tree other,
 static void
 scalarize_parms (void)
 {
-  tree list = NULL;
+  gimple_seq seq = NULL;
   unsigned i;
   bitmap_iterator bi;
 
@@ -3501,13 +3560,13 @@ scalarize_parms (void)
     {
       tree var = referenced_var (i);
       struct sra_elt *elt = lookup_element (NULL, var, NULL, NO_INSERT);
-      generate_copy_inout (elt, true, var, &list);
+      generate_copy_inout (elt, true, var, &seq);
     }
 
-  if (list)
+  if (seq)
     {
-      insert_edge_copies (list, ENTRY_BLOCK_PTR);
-      mark_all_v_defs (list);
+      insert_edge_copies_seq (seq, ENTRY_BLOCK_PTR);
+      mark_all_v_defs_seq (seq);
     }
 }
 
@@ -3522,7 +3581,7 @@ scalarize_function (void)
 
   sra_walk_function (&fns);
   scalarize_parms ();
-  bsi_commit_edge_inserts ();
+  gsi_commit_edge_inserts ();
 }
 
 \f
@@ -3572,13 +3631,14 @@ debug_sra_elt_name (struct sra_elt *elt)
 void 
 sra_init_cache (void)
 {
-  if (sra_type_decomp_cache) 
+  if (sra_type_decomp_cache)
     return;
 
   sra_type_decomp_cache = BITMAP_ALLOC (NULL);
   sra_type_inst_cache = BITMAP_ALLOC (NULL);
 }
 
+
 /* Main entry point.  */
 
 static unsigned int
@@ -3631,8 +3691,10 @@ gate_sra (void)
   return flag_tree_sra != 0;
 }
 
-struct tree_opt_pass pass_sra_early =
+struct gimple_opt_pass pass_sra_early =
 {
+ {
+  GIMPLE_PASS,
   "esra",                              /* name */
   gate_sra,                            /* gate */
   tree_sra_early,                      /* execute */
@@ -3647,12 +3709,14 @@ struct tree_opt_pass pass_sra_early =
   TODO_dump_func
   | TODO_update_ssa
   | TODO_ggc_collect
-  | TODO_verify_ssa,                   /* todo_flags_finish */
-  0                                    /* letter */
+  | TODO_verify_ssa                    /* todo_flags_finish */
+ }
 };
 
-struct tree_opt_pass pass_sra =
+struct gimple_opt_pass pass_sra =
 {
+ {
+  GIMPLE_PASS,
   "sra",                               /* name */
   gate_sra,                            /* gate */
   tree_sra,                            /* execute */
@@ -3667,6 +3731,6 @@ struct tree_opt_pass pass_sra =
   TODO_dump_func
   | TODO_update_ssa
   | TODO_ggc_collect
-  | TODO_verify_ssa,                   /* todo_flags_finish */
-  0                                    /* letter */
+  | TODO_verify_ssa                    /* todo_flags_finish */
+ }
 };