OSDN Git Service

PR middle-end/22156
[pf3gnuchains/gcc-fork.git] / gcc / tree-sra.c
index 0f76bb5..239fd84 100644 (file)
@@ -147,10 +147,6 @@ struct sra_elt
 
   /* True if there is BIT_FIELD_REF on the lhs with a vector. */
   bool is_vector_lhs;
-
-  /* 1 if the element is a field that is part of a block, 2 if the field
-     is the block itself, 0 if it's neither.  */
-  char in_bitfld_block;
 };
 
 #define IS_ELEMENT_FOR_GROUP(ELEMENT) (TREE_CODE (ELEMENT) == RANGE_EXPR)
@@ -465,12 +461,6 @@ sra_hash_tree (tree t)
       h = iterative_hash_expr (DECL_FIELD_BIT_OFFSET (t), h);
       break;
 
-    case BIT_FIELD_REF:
-      /* Don't take operand 0 into account, that's our parent.  */
-      h = iterative_hash_expr (TREE_OPERAND (t, 1), 0);
-      h = iterative_hash_expr (TREE_OPERAND (t, 2), h);
-      break;
-
     default:
       gcc_unreachable ();
     }
@@ -489,14 +479,12 @@ sra_elt_hash (const void *x)
 
   h = sra_hash_tree (e->element);
 
-  /* Take into account everything except bitfield blocks back up the
-     chain.  Given that chain lengths are rarely very long, this
-     should be acceptable.  If we truly identify this as a performance
-     problem, it should work to hash the pointer value
-     "e->parent".  */
+  /* Take into account everything back up the chain.  Given that chain
+     lengths are rarely very long, this should be acceptable.  If we
+     truly identify this as a performance problem, it should work to
+     hash the pointer value "e->parent".  */
   for (p = e->parent; p ; p = p->parent)
-    if (!p->in_bitfld_block)
-      h = (h * 65521) ^ sra_hash_tree (p->element);
+    h = (h * 65521) ^ sra_hash_tree (p->element);
 
   return h;
 }
@@ -509,17 +497,8 @@ sra_elt_eq (const void *x, const void *y)
   const struct sra_elt *a = x;
   const struct sra_elt *b = y;
   tree ae, be;
-  const struct sra_elt *ap = a->parent;
-  const struct sra_elt *bp = b->parent;
 
-  if (ap)
-    while (ap->in_bitfld_block)
-      ap = ap->parent;
-  if (bp)
-    while (bp->in_bitfld_block)
-      bp = bp->parent;
-
-  if (ap != bp)
+  if (a->parent != b->parent)
     return false;
 
   ae = a->element;
@@ -554,11 +533,6 @@ sra_elt_eq (const void *x, const void *y)
        return false;
       return fields_compatible_p (ae, be);
 
-    case BIT_FIELD_REF:
-      return
-       tree_int_cst_equal (TREE_OPERAND (ae, 1), TREE_OPERAND (be, 1))
-       && tree_int_cst_equal (TREE_OPERAND (ae, 2), TREE_OPERAND (be, 2));
-
     default:
       gcc_unreachable ();
     }
@@ -697,9 +671,10 @@ struct sra_walk_fns
   /* Invoked when ELT is required as a unit.  Note that ELT might refer to
      a leaf node, in which case this is a simple scalar reference.  *EXPR_P
      points to the location of the expression.  IS_OUTPUT is true if this
-     is a left-hand-side reference.  */
+     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);
+              block_stmt_iterator *bsi, 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,
@@ -753,6 +728,7 @@ sra_walk_expr (tree *expr_p, block_stmt_iterator *bsi, bool is_output,
   tree expr = *expr_p;
   tree inner = expr;
   bool disable_scalarization = false;
+  bool use_all_p = false;
 
   /* We're looking to collect a reference expression between EXPR and INNER,
      such that INNER is a scalarizable decl and all other nodes through EXPR
@@ -773,7 +749,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);
+             fns->use (elt, expr_p, bsi, is_output, use_all_p);
          }
        return;
 
@@ -860,6 +836,7 @@ sra_walk_expr (tree *expr_p, block_stmt_iterator *bsi, bool is_output,
       use_all:
         expr_p = &TREE_OPERAND (inner, 0);
        inner = expr = *expr_p;
+       use_all_p = true;
        break;
 
       default:
@@ -907,14 +884,11 @@ sra_walk_asm_expr (tree expr, block_stmt_iterator *bsi,
   sra_walk_tree_list (ASM_OUTPUTS (expr), bsi, true, fns);
 }
 
-static void sra_replace (block_stmt_iterator *bsi, tree list);
-static tree sra_build_elt_assignment (struct sra_elt *elt, tree src);
-
 /* Walk a GIMPLE_MODIFY_STMT and categorize the assignment appropriately.  */
 
 static void
 sra_walk_gimple_modify_stmt (tree expr, block_stmt_iterator *bsi,
-                            const struct sra_walk_fns *fns)
+                     const struct sra_walk_fns *fns)
 {
   struct sra_elt *lhs_elt, *rhs_elt;
   tree lhs, rhs;
@@ -937,7 +911,7 @@ sra_walk_gimple_modify_stmt (tree expr, block_stmt_iterator *bsi,
       if (!rhs_elt->is_scalar && !TREE_SIDE_EFFECTS (lhs))
        fns->ldst (rhs_elt, lhs, bsi, false);
       else
-       fns->use (rhs_elt, &GIMPLE_STMT_OPERAND (expr, 1), bsi, false);
+       fns->use (rhs_elt, &GIMPLE_STMT_OPERAND (expr, 1), bsi, false, false);
     }
 
   /* If it isn't scalarizable, there may be scalarizable variables within, so
@@ -984,9 +958,7 @@ sra_walk_gimple_modify_stmt (tree expr, block_stmt_iterator *bsi,
       /* 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);
-       }
+       fns->use (lhs_elt, &GIMPLE_STMT_OPERAND (expr, 0), bsi, true, false);
     }
 
   /* Similarly to above, LHS_ELT being null only means that the LHS as a
@@ -1097,7 +1069,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,
-         bool is_output ATTRIBUTE_UNUSED)
+         bool is_output ATTRIBUTE_UNUSED, bool use_all ATTRIBUTE_UNUSED)
 {
   elt->n_uses += 1;
 }
@@ -1205,15 +1177,6 @@ build_element_name_1 (struct sra_elt *elt)
       sprintf (buffer, HOST_WIDE_INT_PRINT_DEC, TREE_INT_CST_LOW (t));
       obstack_grow (&sra_obstack, buffer, strlen (buffer));
     }
-  else if (TREE_CODE (t) == BIT_FIELD_REF)
-    {
-      sprintf (buffer, "B" HOST_WIDE_INT_PRINT_DEC,
-              tree_low_cst (TREE_OPERAND (t, 2), 1));
-      obstack_grow (&sra_obstack, buffer, strlen (buffer));
-      sprintf (buffer, "F" HOST_WIDE_INT_PRINT_DEC,
-              tree_low_cst (TREE_OPERAND (t, 1), 1));
-      obstack_grow (&sra_obstack, buffer, strlen (buffer));
-    }
   else
     {
       tree name = DECL_NAME (t);
@@ -1246,12 +1209,9 @@ instantiate_element (struct sra_elt *elt)
 {
   struct sra_elt *base_elt;
   tree var, base;
-  bool nowarn = TREE_NO_WARNING (elt->element);
 
   for (base_elt = elt; base_elt->parent; base_elt = base_elt->parent)
-    if (!nowarn)
-      nowarn = base_elt->parent->n_uses
-       || TREE_NO_WARNING (base_elt->parent->element);
+    continue;
   base = base_elt->element;
 
   elt->replacement = var = make_rename_temp (elt->type, "SR");
@@ -1280,7 +1240,9 @@ instantiate_element (struct sra_elt *elt)
       DECL_DEBUG_EXPR_IS_FROM (var) = 1;
       
       DECL_IGNORED_P (var) = 0;
-      TREE_NO_WARNING (var) = nowarn;
+      TREE_NO_WARNING (var) = TREE_NO_WARNING (base);
+      if (elt->element && TREE_NO_WARNING (elt->element))
+       TREE_NO_WARNING (var) = 1;
     }
   else
     {
@@ -1375,7 +1337,7 @@ sum_instantiated_sizes (struct sra_elt *elt, unsigned HOST_WIDE_INT *sizep)
 
 static void instantiate_missing_elements (struct sra_elt *elt);
 
-static struct sra_elt *
+static void
 instantiate_missing_elements_1 (struct sra_elt *elt, tree child, tree type)
 {
   struct sra_elt *sub = lookup_element (elt, child, type, INSERT);
@@ -1386,266 +1348,6 @@ instantiate_missing_elements_1 (struct sra_elt *elt, tree child, tree type)
     }
   else
     instantiate_missing_elements (sub);
-  return sub;
-}
-
-/* Obtain the canonical type for field F of ELEMENT.  */
-
-static tree
-canon_type_for_field (tree f, tree element)
-{
-  tree field_type = TREE_TYPE (f);
-
-  /* canonicalize_component_ref() unwidens some bit-field types (not
-     marked as DECL_BIT_FIELD in C++), so we must do the same, lest we
-     may introduce type mismatches.  */
-  if (INTEGRAL_TYPE_P (field_type)
-      && DECL_MODE (f) != TYPE_MODE (field_type))
-    field_type = TREE_TYPE (get_unwidened (build3 (COMPONENT_REF,
-                                                  field_type,
-                                                  element,
-                                                  f, NULL_TREE),
-                                          NULL_TREE));
-
-  return field_type;
-}
-
-/* Look for adjacent fields of ELT starting at F that we'd like to
-   scalarize as a single variable.  Return the last field of the
-   group.  */
-
-static tree
-try_instantiate_multiple_fields (struct sra_elt *elt, tree f)
-{
-  unsigned HOST_WIDE_INT align, oalign, word, bit, size, alchk;
-  enum machine_mode mode;
-  tree first = f, prev;
-  tree type, var;
-  struct sra_elt *block;
-
-  if (!is_sra_scalar_type (TREE_TYPE (f))
-      || !host_integerp (DECL_FIELD_OFFSET (f), 1)
-      || !host_integerp (DECL_FIELD_BIT_OFFSET (f), 1)
-      || !host_integerp (DECL_SIZE (f), 1)
-      || lookup_element (elt, f, NULL, NO_INSERT))
-    return f;
-
-  /* Taking the alignment of elt->element is not enough, since it
-     might be just an array index or some such.  We shouldn't need to
-     initialize align here, but our optimizers don't always realize
-     that, if we leave the loop without initializing align, we'll fail
-     the assertion right after the loop.  */
-  align = (unsigned HOST_WIDE_INT)-1;
-  for (block = elt; block; block = block->parent)
-    if (DECL_P (block->element))
-      {
-       align = DECL_ALIGN (block->element);
-       break;
-      }
-  gcc_assert (block);
-
-  oalign = DECL_OFFSET_ALIGN (f);
-  word = tree_low_cst (DECL_FIELD_OFFSET (f), 1);
-  bit = tree_low_cst (DECL_FIELD_BIT_OFFSET (f), 1);
-  size = tree_low_cst (DECL_SIZE (f), 1);
-
-  if (align > oalign)
-    align = oalign;
-
-  alchk = align - 1;
-  alchk = ~alchk;
-
-  if ((bit & alchk) != ((bit + size - 1) & alchk))
-    return f;
-
-  /* Find adjacent fields in the same alignment word.  */
-
-  for (prev = f, f = TREE_CHAIN (f);
-       f && TREE_CODE (f) == FIELD_DECL
-        && is_sra_scalar_type (TREE_TYPE (f))
-        && host_integerp (DECL_FIELD_OFFSET (f), 1)
-        && host_integerp (DECL_FIELD_BIT_OFFSET (f), 1)
-        && host_integerp (DECL_SIZE (f), 1)
-        && (HOST_WIDE_INT)word == tree_low_cst (DECL_FIELD_OFFSET (f), 1)
-        && !lookup_element (elt, f, NULL, NO_INSERT);
-       prev = f, f = TREE_CHAIN (f))
-    {
-      unsigned HOST_WIDE_INT nbit, nsize;
-
-      nbit = tree_low_cst (DECL_FIELD_BIT_OFFSET (f), 1);
-      nsize = tree_low_cst (DECL_SIZE (f), 1);
-
-      if (bit + size == nbit)
-       {
-         if ((bit & alchk) != ((nbit + nsize - 1) & alchk))
-           break;
-         size += nsize;
-       }
-      else if (nbit + nsize == bit)
-       {
-         if ((nbit & alchk) != ((bit + size - 1) & alchk))
-           break;
-         bit = nbit;
-         size += nsize;
-       }
-      else
-       break;
-    }
-
-  f = prev;
-
-  if (f == first)
-    return f;
-
-  gcc_assert ((bit & alchk) == ((bit + size - 1) & alchk));
-
-  /* Try to widen the bit range so as to cover padding bits as well.  */
-
-  if ((bit & ~alchk) || size != align)
-    {
-      unsigned HOST_WIDE_INT mbit = bit & alchk;
-      unsigned HOST_WIDE_INT msize = align;
-
-      for (f = TYPE_FIELDS (elt->type);
-          f; f = TREE_CHAIN (f))
-       {
-         unsigned HOST_WIDE_INT fword, fbit, fsize;
-
-         /* Skip the fields from first to prev.  */
-         if (f == first)
-           {
-             f = prev;
-             continue;
-           }
-
-         if (!(TREE_CODE (f) == FIELD_DECL
-               && host_integerp (DECL_FIELD_OFFSET (f), 1)
-               && host_integerp (DECL_FIELD_BIT_OFFSET (f), 1)))
-           continue;
-
-         fword = tree_low_cst (DECL_FIELD_OFFSET (f), 1);
-         /* If we're past the selected word, we're fine.  */
-         if (word < fword)
-           continue;
-
-         fbit = tree_low_cst (DECL_FIELD_BIT_OFFSET (f), 1);
-
-         if (host_integerp (DECL_SIZE (f), 1))
-           fsize = tree_low_cst (DECL_SIZE (f), 1);
-         else
-           /* Assume a variable-sized field takes up all space till
-              the end of the word.  ??? Endianness issues?  */
-           fsize = align - fbit;
-
-         if (fword < word)
-           {
-             /* A large field might start at a previous word and
-                extend into the selected word.  Exclude those
-                bits.  ??? Endianness issues? */
-             HOST_WIDE_INT diff = fbit + fsize
-               - (HOST_WIDE_INT)((word - fword) * BITS_PER_UNIT + mbit);
-
-             if (diff <= 0)
-               continue;
-
-             mbit += diff;
-             msize -= diff;
-           }
-         else
-           {
-             gcc_assert (fword == word);
-
-             /* Non-overlapping, great.  */
-             if (fbit + fsize <= mbit
-                 || mbit + msize <= fbit)
-               continue;
-
-             if (fbit <= mbit)
-               {
-                 unsigned HOST_WIDE_INT diff = fbit + fsize - mbit;
-                 mbit += diff;
-                 msize -= diff;
-               }
-             else if (fbit > mbit)
-               msize -= (mbit + msize - fbit);
-             else
-               gcc_unreachable ();
-           }
-       }
-
-      bit = mbit;
-      size = msize;
-    }
-
-  /* Now we know the bit range we're interested in.  Find the smallest
-     machine mode we can use to access it.  */
-
-  for (mode = smallest_mode_for_size (size, MODE_INT);
-       ;
-       mode = GET_MODE_WIDER_MODE (mode))
-    {
-      gcc_assert (mode != VOIDmode);
-
-      alchk = GET_MODE_PRECISION (mode) - 1;
-      alchk = ~alchk;
-
-      if ((bit & alchk) == ((bit + size - 1) & alchk))
-       break;
-    }
-
-  gcc_assert (~alchk < align);
-
-  /* Create the field group as a single variable.  */
-
-  type = lang_hooks.types.type_for_mode (mode, 1);
-  gcc_assert (type);
-  var = build3 (BIT_FIELD_REF, type, NULL_TREE,
-               bitsize_int (size),
-               bitsize_int (word * BITS_PER_UNIT + bit));
-  BIT_FIELD_REF_UNSIGNED (var) = 1;
-
-  block = instantiate_missing_elements_1 (elt, var, type);
-  gcc_assert (block && block->is_scalar);
-
-  var = block->replacement;
-
-  if (((word * BITS_PER_UNIT + 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 ((word * BITS_PER_UNIT
-                                                + bit) & ~alchk));
-      BIT_FIELD_REF_UNSIGNED (block->replacement) = 1;
-      TREE_NO_WARNING (block->replacement) = 1;
-    }
-
-  block->in_bitfld_block = 2;
-
-  /* Add the member fields to the group, such that they access
-     portions of the group variable.  */
-
-  for (f = first; f != TREE_CHAIN (prev); f = TREE_CHAIN (f))
-    {
-      tree field_type = canon_type_for_field (f, elt->element);
-      struct sra_elt *fld = lookup_element (block, f, field_type, INSERT);
-
-      gcc_assert (fld && fld->is_scalar && !fld->replacement);
-
-      fld->replacement = build3 (BIT_FIELD_REF, field_type, var,
-                                DECL_SIZE (f),
-                                bitsize_int
-                                ((word * BITS_PER_UNIT
-                                  + (TREE_INT_CST_LOW
-                                     (DECL_FIELD_BIT_OFFSET (f))))
-                                 & ~alchk));
-      BIT_FIELD_REF_UNSIGNED (fld->replacement) = TYPE_UNSIGNED (field_type);
-      TREE_NO_WARNING (block->replacement) = 1;
-      fld->in_bitfld_block = 1;
-    }
-
-  return prev;
 }
 
 static void
@@ -1661,17 +1363,21 @@ instantiate_missing_elements (struct sra_elt *elt)
        for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
          if (TREE_CODE (f) == FIELD_DECL)
            {
-             tree last = try_instantiate_multiple_fields (elt, f);
-
-             if (last != f)
-               {
-                 f = last;
-                 continue;
-               }
-
-             instantiate_missing_elements_1 (elt, f,
-                                             canon_type_for_field
-                                             (f, elt->element));
+             tree field_type = TREE_TYPE (f);
+
+             /* canonicalize_component_ref() unwidens some bit-field
+                types (not marked as DECL_BIT_FIELD in C++), so we
+                must do the same, lest we may introduce type
+                mismatches.  */
+             if (INTEGRAL_TYPE_P (field_type)
+                 && DECL_MODE (f) != TYPE_MODE (field_type))
+               field_type = TREE_TYPE (get_unwidened (build3 (COMPONENT_REF,
+                                                              field_type,
+                                                              elt->element,
+                                                              f, NULL_TREE),
+                                                      NULL_TREE));
+
+             instantiate_missing_elements_1 (elt, f, field_type);
            }
        break;
       }
@@ -1983,16 +1689,6 @@ 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
-          called from instantiate_element, we haven't set this field
-          yet.  */
-       if (TREE_CODE (field) == BIT_FIELD_REF)
-         {
-           tree ret = copy_node (field);
-           TREE_OPERAND (ret, 0) = base;
-           return ret;
-         }
-
        /* Watch out for compatible records with differing field lists.  */
        if (DECL_FIELD_CONTEXT (field) != TYPE_MAIN_VARIANT (TREE_TYPE (base)))
          field = find_compatible_field (TREE_TYPE (base), field);
@@ -2045,126 +1741,6 @@ sra_build_assignment (tree dst, tree src)
   return build_gimple_modify_stmt (dst, src);
 }
 
-/* BIT_FIELD_REFs must not be shared.  sra_build_elt_assignment()
-   takes care of assignments, but we must create copies for uses.  */
-#define REPLDUP(t) (TREE_CODE (t) != BIT_FIELD_REF ? (t) : copy_node (t))
-
-static tree
-sra_build_elt_assignment (struct sra_elt *elt, tree src)
-{
-  tree dst = elt->replacement;
-  tree var, type, tmp, tmp2, tmp3;
-  tree list, stmt;
-  tree cst, cst2, mask;
-  tree minshift, maxshift;
-
-  if (TREE_CODE (dst) != BIT_FIELD_REF
-      || !elt->in_bitfld_block)
-    return sra_build_assignment (REPLDUP (dst), src);
-
-  var = TREE_OPERAND (dst, 0);
-
-  /* Try to widen the assignment to the entire variable.
-     We need the source to be a BIT_FIELD_REF as well, such that, for
-     BIT_FIELD_REF<d,sz,dp> = BIT_FIELD_REF<s,sz,sp>,
-     if sp >= dp, we can turn it into
-     d = BIT_FIELD_REF<s,sp+sz,sp-dp>.  */
-  if (elt->in_bitfld_block == 2
-      && TREE_CODE (src) == BIT_FIELD_REF
-      && !tree_int_cst_lt (TREE_OPERAND (src, 2), TREE_OPERAND (dst, 2)))
-    {
-      src = fold_build3 (BIT_FIELD_REF, TREE_TYPE (var),
-                        TREE_OPERAND (src, 0),
-                        size_binop (PLUS_EXPR, TREE_OPERAND (src, 1),
-                                    TREE_OPERAND (dst, 2)),
-                        size_binop (MINUS_EXPR, TREE_OPERAND (src, 2),
-                                    TREE_OPERAND (dst, 2)));
-      BIT_FIELD_REF_UNSIGNED (src) = 1;
-
-      return sra_build_assignment (var, src);
-    }
-
-  if (!is_gimple_reg (var))
-    return sra_build_assignment (REPLDUP (dst), src);
-
-  list = alloc_stmt_list ();
-
-  cst = TREE_OPERAND (dst, 2);
-  if (WORDS_BIG_ENDIAN)
-    {
-      cst = size_binop (MINUS_EXPR, DECL_SIZE (var), cst);
-      maxshift = cst;
-    }
-  else
-    minshift = cst;
-
-  cst2 = size_binop (PLUS_EXPR, TREE_OPERAND (dst, 1),
-                    TREE_OPERAND (dst, 2));
-  if (WORDS_BIG_ENDIAN)
-    {
-      cst2 = size_binop (MINUS_EXPR, DECL_SIZE (var), cst2);
-      minshift = cst2;
-    }
-  else
-    maxshift = cst2;
-
-  type = TREE_TYPE (var);
-
-  mask = build_int_cst_wide (type, 1, 0);
-  cst = int_const_binop (LSHIFT_EXPR, mask, maxshift, 1);
-  cst2 = int_const_binop (LSHIFT_EXPR, mask, minshift, 1);
-  mask = int_const_binop (MINUS_EXPR, cst, cst2, 1);
-  mask = fold_build1 (BIT_NOT_EXPR, type, mask);
-
-  if (!WORDS_BIG_ENDIAN)
-    cst2 = TREE_OPERAND (dst, 2);
-
-  tmp = make_rename_temp (type, "SR");
-  stmt = build_gimple_modify_stmt (tmp,
-                                  fold_build2 (BIT_AND_EXPR, type,
-                                               var, mask));
-  append_to_statement_list (stmt, &list);
-
-  if (is_gimple_reg (src))
-    tmp2 = src;
-  else
-    {
-      tmp2 = make_rename_temp (TREE_TYPE (src), "SR");
-      stmt = sra_build_assignment (tmp2, src);
-      append_to_statement_list (stmt, &list);
-    }
-
-  if (!TYPE_UNSIGNED (TREE_TYPE (tmp2))
-      || TYPE_MAIN_VARIANT (TREE_TYPE (tmp2)) != TYPE_MAIN_VARIANT (type))
-    {
-      tmp3 = make_rename_temp (type, "SR");
-      tmp2 = fold_build3 (BIT_FIELD_REF, type, tmp2, TREE_OPERAND (dst, 1),
-                         bitsize_int (0));
-      if (TREE_CODE (tmp2) == BIT_FIELD_REF)
-       BIT_FIELD_REF_UNSIGNED (tmp2) = 1;
-      stmt = sra_build_assignment (tmp3, tmp2);
-      append_to_statement_list (stmt, &list);
-      tmp2 = tmp3;
-    }
-
-  if (!integer_zerop (minshift))
-    {
-      tmp3 = make_rename_temp (type, "SR");
-      stmt = build_gimple_modify_stmt (tmp3,
-                                      fold_build2 (LSHIFT_EXPR, type,
-                                                   tmp2, minshift));
-      append_to_statement_list (stmt, &list);
-      tmp2 = tmp3;
-    }
-
-  stmt = build_gimple_modify_stmt (var,
-                                  fold_build2 (BIT_IOR_EXPR, type,
-                                               tmp, tmp2));
-  append_to_statement_list (stmt, &list);
-
-  return list;
-}
-
 /* Generate a set of assignment statements in *LIST_P to copy all
    instantiated elements under ELT to or from the equivalent structure
    rooted at EXPR.  COPY_OUT controls the direction of the copy, with
@@ -2195,9 +1771,9 @@ generate_copy_inout (struct sra_elt *elt, bool copy_out, tree expr,
   else if (elt->replacement)
     {
       if (copy_out)
-       t = sra_build_elt_assignment (elt, expr);
+       t = sra_build_assignment (elt->replacement, expr);
       else
-       t = sra_build_assignment (expr, REPLDUP (elt->replacement));
+       t = sra_build_assignment (expr, elt->replacement);
       append_to_statement_list (t, list_p);
     }
   else
@@ -2222,19 +1798,6 @@ generate_element_copy (struct sra_elt *dst, struct sra_elt *src, tree *list_p)
   FOR_EACH_ACTUAL_CHILD (dc, dst)
     {
       sc = lookup_element (src, dc->element, NULL, NO_INSERT);
-      if (!sc && dc->in_bitfld_block == 2)
-       {
-         struct sra_elt *dcs;
-
-         FOR_EACH_ACTUAL_CHILD (dcs, dc)
-           {
-             sc = lookup_element (src, dcs->element, NULL, NO_INSERT);
-             gcc_assert (sc);
-             generate_element_copy (dcs, sc, list_p);
-           }
-
-         continue;
-       }
       gcc_assert (sc);
       generate_element_copy (dc, sc, list_p);
     }
@@ -2245,7 +1808,7 @@ generate_element_copy (struct sra_elt *dst, struct sra_elt *src, tree *list_p)
 
       gcc_assert (src->replacement);
 
-      t = sra_build_elt_assignment (dst, REPLDUP (src->replacement));
+      t = sra_build_assignment (dst->replacement, src->replacement);
       append_to_statement_list (t, list_p);
     }
 }
@@ -2266,9 +1829,8 @@ generate_element_zero (struct sra_elt *elt, tree *list_p)
       return;
     }
 
-  if (!elt->in_bitfld_block)
-    FOR_EACH_ACTUAL_CHILD (c, elt)
-      generate_element_zero (c, list_p);
+  FOR_EACH_ACTUAL_CHILD (c, elt)
+    generate_element_zero (c, list_p);
 
   if (elt->replacement)
     {
@@ -2277,7 +1839,7 @@ generate_element_zero (struct sra_elt *elt, tree *list_p)
       gcc_assert (elt->is_scalar);
       t = fold_convert (elt->type, integer_zero_node);
 
-      t = sra_build_elt_assignment (elt, t);
+      t = sra_build_assignment (elt->replacement, t);
       append_to_statement_list (t, list_p);
     }
 }
@@ -2286,10 +1848,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 (tree var, tree init, tree *list_p)
 {
   /* The replacement can be almost arbitrarily complex.  Gimplify.  */
-  tree stmt = sra_build_elt_assignment (elt, init);
+  tree stmt = sra_build_assignment (var, init);
   gimplify_and_add (stmt, list_p);
 }
 
@@ -2318,7 +1880,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->replacement, init, list_p);
          elt->visited = true;
        }
       return result;
@@ -2477,7 +2039,7 @@ sra_replace (block_stmt_iterator *bsi, tree list)
 
 static void
 scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
-              bool is_output)
+              bool is_output, bool use_all)
 {
   tree list = NULL, stmt = bsi_stmt (*bsi);
 
@@ -2486,27 +2048,8 @@ scalarize_use (struct sra_elt *elt, tree *expr_p, block_stmt_iterator *bsi,
       /* If we have a replacement, then updating the reference is as
         simple as modifying the existing statement in place.  */
       if (is_output)
-       {
-         if (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)
-           {
-             tree newstmt = sra_build_elt_assignment
-               (elt, GIMPLE_STMT_OPERAND (stmt, 1));
-             if (TREE_CODE (newstmt) != STATEMENT_LIST)
-               {
-                 tree list = alloc_stmt_list ();
-                 append_to_statement_list (newstmt, &list);
-                 newstmt = list;
-               }
-             sra_replace (bsi, newstmt);
-             return;
-           }
-
-         mark_all_v_defs (stmt);
-       }
-      *expr_p = REPLDUP (elt->replacement);
+       mark_all_v_defs (stmt);
+      *expr_p = elt->replacement;
       update_stmt (stmt);
     }
   else
@@ -2524,23 +2067,17 @@ 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, false, generate_element_ref (elt), &list);
-      if (list)
-       {
-         mark_all_v_defs (list);
-         sra_insert_before (bsi, list);
-         mark_no_warning (elt);
-       }
-
+      generate_copy_inout (elt, is_output, generate_element_ref (elt), &list);
+      if (list == NULL)
+       return;
+      mark_all_v_defs (list);
       if (is_output)
+       sra_insert_after (bsi, list);
+      else
        {
-         list = NULL;
-         generate_copy_inout (elt, true, generate_element_ref (elt), &list);
-         if (list)
-           {
-             mark_all_v_defs (list);
-             sra_insert_after (bsi, list);
-           }
+         sra_insert_before (bsi, list);
+         if (use_all)
+           mark_no_warning (elt);
        }
     }
 }
@@ -2564,7 +2101,7 @@ scalarize_copy (struct sra_elt *lhs_elt, struct sra_elt *rhs_elt,
       gcc_assert (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT);
 
       GIMPLE_STMT_OPERAND (stmt, 0) = lhs_elt->replacement;
-      GIMPLE_STMT_OPERAND (stmt, 1) = REPLDUP (rhs_elt->replacement);
+      GIMPLE_STMT_OPERAND (stmt, 1) = rhs_elt->replacement;
       update_stmt (stmt);
     }
   else if (lhs_elt->use_block_copy || rhs_elt->use_block_copy)
@@ -2706,7 +2243,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);
+      scalarize_use (elt, NULL, bsi, is_output, false);
     }
   else
     {
@@ -2718,8 +2255,8 @@ scalarize_ldst (struct sra_elt *elt, tree other,
 
       mark_all_v_defs (stmt);
       generate_copy_inout (elt, is_output, other, &list);
-      gcc_assert (list);
       mark_all_v_defs (list);
+      gcc_assert (list);
 
       /* Preserve EH semantics.  */
       if (stmt_ends_bb_p (stmt))
@@ -2815,10 +2352,6 @@ dump_sra_elt_name (FILE *f, struct sra_elt *elt)
            fputc ('.', f);
          print_generic_expr (f, elt->element, dump_flags);
        }
-      else if (TREE_CODE (elt->element) == BIT_FIELD_REF)
-       fprintf (f, "$B" HOST_WIDE_INT_PRINT_DEC "F" HOST_WIDE_INT_PRINT_DEC,
-                tree_low_cst (TREE_OPERAND (elt->element, 2), 1),
-                tree_low_cst (TREE_OPERAND (elt->element, 1), 1));
       else if (TREE_CODE (elt->element) == RANGE_EXPR)
        fprintf (f, "["HOST_WIDE_INT_PRINT_DEC".."HOST_WIDE_INT_PRINT_DEC"]",
                 TREE_INT_CST_LOW (TREE_OPERAND (elt->element, 0)),